On Mon, 17 Jan 2022, James Almer wrote:
[...]
-static const char *get_channel_name(int channel_id)
+static const char *get_channel_name(enum AVChannel channel_id)
{
- if (channel_id < 0 || channel_id >= FF_ARRAY_ELEMS(channel_names))
+ if ((unsigned) channel_id >= FF_ARRAY_ELEMS(channel_names) ||
+ !channel_names[channel_id].name)
return NULL;
return channel_names[channel_id].name;
}
-static const struct {
+void av_channel_name_bprint(AVBPrint *bp, enum AVChannel channel_id)
+{
+ av_bprint_clear(bp);
Clearing should not be done here. Maybe the user wants to construct a
string, and the channel name is only a part of it. If not, the user can
clear the bprint buffer himself before calling this.
+
+ if ((unsigned)channel_id < FF_ARRAY_ELEMS(channel_names))
+ av_bprintf(bp, "%s", channel_names[channel_id].name);
+ else
+ av_bprintf(bp, "USR%d", channel_id);
+}
+
+int av_channel_name(char *buf, size_t buf_size, enum AVChannel channel_id)
+{
+ AVBPrint bp;
+
+ if (!buf && buf_size)
+ return AVERROR(EINVAL);
+
+ av_bprint_init_for_buffer(&bp, buf, buf_size);
+ av_channel_name_bprint(&bp, channel_id);
+
+ return bp.len;
+}
+
+void av_channel_description_bprint(AVBPrint *bp, enum AVChannel channel_id)
+{
+ av_bprint_clear(bp);
Same here.
+
+ if ((unsigned)channel_id < FF_ARRAY_ELEMS(channel_names))
+ av_bprintf(bp, "%s", channel_names[channel_id].description);
+ else
+ av_bprintf(bp, "user %d", channel_id);
+}
+
+int av_channel_description(char *buf, size_t buf_size, enum AVChannel
channel_id)
+{
+ AVBPrint bp;
+
+ if (!buf && buf_size)
+ return AVERROR(EINVAL);
+
+ av_bprint_init_for_buffer(&bp, buf, buf_size);
+ av_channel_description_bprint(&bp, channel_id);
+
+ return bp.len;
+}
[...]
+int av_channel_layout_from_string(AVChannelLayout *channel_layout,
+ const char *str)
+{
+ int i;
+ int channels = 0, native = 1;
+ enum AVChannel highest_channel = AV_CHAN_NONE;
+ const char *dup = str;
+ char *end;
+ uint64_t mask = 0;
+
+ /* channel layout names */
+ for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++) {
+ if (channel_layout_map[i].name && !strcmp(str,
channel_layout_map[i].name)) {
+ *channel_layout = channel_layout_map[i].layout;
+ return 0;
+ }
+ }
+
+ /* channel names */
+ while (*dup) {
+ char *chname = av_get_token(&dup, "+");
+ if (!chname)
+ return AVERROR(ENOMEM);
+ if (*dup)
+ dup++; // skip separator
+ for (i = 0; i < FF_ARRAY_ELEMS(channel_names); i++) {
+ if (channel_names[i].name && !strcmp(chname,
channel_names[i].name)) {
+ if (i < highest_channel || mask & (1ULL << i))
+ native = 0; // Not a native layout, use a custom one
+ highest_channel = i;
+ mask |= 1ULL << i;
+ break;
+ }
+ }
+
+ if (i >= FF_ARRAY_ELEMS(channel_names)) {
+ char *endptr = chname;
+ enum AVChannel id = AV_CHAN_NONE;
+
+ if (!strncmp(chname, "USR", 3)) {
+ const char *p = chname + 3;
+ id = strtol(p, &endptr, 0);
+ }
+ if (id < 0 || *endptr) {
+ native = 0; // Unknown channel name
+ channels = 0;
+ mask = 0;
+ av_free(chname);
+ break;
+ }
+ if (id > 63)
+ native = 0; // Not a native layout, use a custom one
+ else {
+ if (id < highest_channel || mask & (1ULL << id))
+ native = 0; // Not a native layout, use a custom one
+ highest_channel = id;
+ mask |= 1ULL << id;
+ }
+ }
+ channels++;
+ av_free(chname);
+ }
+ if (mask && native) {
+ av_channel_layout_from_mask(channel_layout, mask);
+ return 0;
+ }
+
+ /* custom layout of channel names */
+ if (channels && !native) {
+ int idx = 0;
+
+ channel_layout->u.map = av_calloc(channels,
sizeof(*channel_layout->u.map));
+ if (!channel_layout->u.map)
+ return AVERROR(ENOMEM);
+
+ channel_layout->order = AV_CHANNEL_ORDER_CUSTOM;
+ channel_layout->nb_channels = channels;
+
+ dup = str;
+ while (*dup) {
+ char *chname = av_get_token(&dup, "+");
+ if (!chname) {
+ av_freep(&channel_layout->u.map);
+ return AVERROR(ENOMEM);
+ }
+ if (*dup)
+ dup++; // skip separator
+ for (i = 0; i < FF_ARRAY_ELEMS(channel_names); i++) {
+ if (channel_names[i].name && !strcmp(chname,
channel_names[i].name)) {
+ channel_layout->u.map[idx++].id = i;
+ break;
+ }
+ }
+ if (i >= FF_ARRAY_ELEMS(channel_names)) {
+ const char *p = chname + 3;
+ channel_layout->u.map[idx++].id = strtol(p, NULL, 0);
+ }
+ av_free(chname);
+ }
+
+ return 0;
+ }
+
+ /* channel layout mask */
+ if (!strncmp(str, "0x", 2) && sscanf(str + 2, "%"SCNx64, &mask) == 1) {
+ av_channel_layout_from_mask(channel_layout, mask);
+ return 0;
+ }
+
+ errno = 0;
+ channels = strtol(str, &end, 10);
+
+ /* number of channels */
+ if (!errno && *end == 'c' && !*(end + 1) && channels >= 0) {
+ av_channel_layout_default(channel_layout, channels);
+ return 0;
+ }
+
+ /* number of unordered channels */
+ if (!errno && (!*end || (*end == 'C' && !*(end + 1)) || av_strnstr(str,
"channels", strlen(str)))
+ && channels >= 0) {
+ channel_layout->order = AV_CHANNEL_ORDER_UNSPEC;
+ channel_layout->nb_channels = channels;
+ return 0;
+ }
+
+ return AVERROR_INVALIDDATA;
rather AVERROR(EINVAL), no?
+}
+
+void av_channel_layout_uninit(AVChannelLayout *channel_layout)
+{
+ if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM)
+ av_freep(&channel_layout->u.map);
+ memset(channel_layout, 0, sizeof(*channel_layout));
+}
+
+int av_channel_layout_copy(AVChannelLayout *dst, const AVChannelLayout *src)
+{
+ av_channel_layout_uninit(dst);
+ *dst = *src;
+ if (src->order == AV_CHANNEL_ORDER_CUSTOM) {
+ dst->u.map = av_malloc_array(src->nb_channels, sizeof(*dst->u.map));
+ if (!dst->u.map)
+ return AVERROR(ENOMEM);
+ memcpy(dst->u.map, src->u.map, src->nb_channels * sizeof(*src->u.map));
+ }
+ return 0;
+}
+
+int av_channel_layout_describe_bprint(const AVChannelLayout *channel_layout,
+ AVBPrint *bp)
+{
+ int i;
+
+ av_bprint_clear(bp);
Same as above, clearing should not be done.
Thanks,
Marton
_______________________________________________
ffmpeg-devel mailing list
[email protected]
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
[email protected] with subject "unsubscribe".