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 ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".