[FFmpeg-devel] [PATCH 001/289 v4] Add a new channel layout API
Marton Balint
cus at passwd.hu
Mon Jan 17 22:53:59 EET 2022
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
More information about the ffmpeg-devel
mailing list