summaryrefslogtreecommitdiffstats
path: root/media/ffvpx/libavutil/channel_layout.c
diff options
context:
space:
mode:
Diffstat (limited to 'media/ffvpx/libavutil/channel_layout.c')
-rw-r--r--media/ffvpx/libavutil/channel_layout.c543
1 files changed, 247 insertions, 296 deletions
diff --git a/media/ffvpx/libavutil/channel_layout.c b/media/ffvpx/libavutil/channel_layout.c
index b59d798f29..fd6718e0e7 100644
--- a/media/ffvpx/libavutil/channel_layout.c
+++ b/media/ffvpx/libavutil/channel_layout.c
@@ -33,6 +33,7 @@
#include "common.h"
#include "error.h"
#include "macros.h"
+#include "mem.h"
#include "opt.h"
#define CHAN_IS_AMBI(x) ((x) >= AV_CHAN_AMBISONIC_BASE &&\
@@ -76,14 +77,6 @@ static const struct channel_name channel_names[] = {
[AV_CHAN_BOTTOM_FRONT_RIGHT ] = { "BFR", "bottom front right" },
};
-static const char *get_channel_name(enum AVChannel channel_id)
-{
- if ((unsigned) channel_id >= FF_ARRAY_ELEMS(channel_names) ||
- !channel_names[channel_id].name)
- return NULL;
- return channel_names[channel_id].name;
-}
-
void av_channel_name_bprint(AVBPrint *bp, enum AVChannel channel_id)
{
if (channel_id >= AV_CHAN_AMBISONIC_BASE &&
@@ -94,6 +87,10 @@ void av_channel_name_bprint(AVBPrint *bp, enum AVChannel channel_id)
av_bprintf(bp, "%s", channel_names[channel_id].name);
else if (channel_id == AV_CHAN_NONE)
av_bprintf(bp, "NONE");
+ else if (channel_id == AV_CHAN_UNKNOWN)
+ av_bprintf(bp, "UNK");
+ else if (channel_id == AV_CHAN_UNUSED)
+ av_bprintf(bp, "UNSD");
else
av_bprintf(bp, "USR%d", channel_id);
}
@@ -123,6 +120,10 @@ void av_channel_description_bprint(AVBPrint *bp, enum AVChannel channel_id)
av_bprintf(bp, "%s", channel_names[channel_id].description);
else if (channel_id == AV_CHAN_NONE)
av_bprintf(bp, "none");
+ else if (channel_id == AV_CHAN_UNKNOWN)
+ av_bprintf(bp, "unknown");
+ else if (channel_id == AV_CHAN_UNUSED)
+ av_bprintf(bp, "unused");
else
av_bprintf(bp, "user %d", channel_id);
}
@@ -159,6 +160,11 @@ enum AVChannel av_channel_from_string(const char *str)
if (channel_names[i].name && !strcmp(str, channel_names[i].name))
return i;
}
+ if (!strcmp(str, "UNK"))
+ return AV_CHAN_UNKNOWN;
+ if (!strcmp(str, "UNSD"))
+ return AV_CHAN_UNUSED;
+
if (!strncmp(str, "USR", 3)) {
const char *p = str + 3;
id = strtol(p, &endptr, 0);
@@ -214,199 +220,82 @@ static const struct channel_layout_name channel_layout_map[] = {
{ "22.2", AV_CHANNEL_LAYOUT_22POINT2, },
};
-#if FF_API_OLD_CHANNEL_LAYOUT
-FF_DISABLE_DEPRECATION_WARNINGS
-static uint64_t get_channel_layout_single(const char *name, int name_len)
+int av_channel_layout_custom_init(AVChannelLayout *channel_layout, int nb_channels)
{
- int i;
- char *end;
- int64_t layout;
-
- for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++) {
- if (strlen(channel_layout_map[i].name) == name_len &&
- !memcmp(channel_layout_map[i].name, name, name_len))
- return channel_layout_map[i].layout.u.mask;
- }
- for (i = 0; i < FF_ARRAY_ELEMS(channel_names); i++)
- if (channel_names[i].name &&
- strlen(channel_names[i].name) == name_len &&
- !memcmp(channel_names[i].name, name, name_len))
- return (int64_t)1 << i;
-
- errno = 0;
- i = strtol(name, &end, 10);
-
- if (!errno && (end + 1 - name == name_len && *end == 'c'))
- return av_get_default_channel_layout(i);
-
- errno = 0;
- layout = strtoll(name, &end, 0);
- if (!errno && end - name == name_len)
- return FFMAX(layout, 0);
- return 0;
-}
-
-uint64_t av_get_channel_layout(const char *name)
-{
- const char *n, *e;
- const char *name_end = name + strlen(name);
- int64_t layout = 0, layout_single;
-
- for (n = name; n < name_end; n = e + 1) {
- for (e = n; e < name_end && *e != '+' && *e != '|'; e++);
- layout_single = get_channel_layout_single(n, e - n);
- if (!layout_single)
- return 0;
- layout |= layout_single;
- }
- return layout;
-}
-
-int av_get_extended_channel_layout(const char *name, uint64_t* channel_layout, int* nb_channels)
-{
- int nb = 0;
- char *end;
- uint64_t layout = av_get_channel_layout(name);
-
- if (layout) {
- *channel_layout = layout;
- *nb_channels = av_get_channel_layout_nb_channels(layout);
- return 0;
- }
-
- nb = strtol(name, &end, 10);
- if (!errno && *end == 'C' && *(end + 1) == '\0' && nb > 0 && nb < 64) {
- *channel_layout = 0;
- *nb_channels = nb;
- return 0;
- }
-
- return AVERROR(EINVAL);
-}
-
-void av_bprint_channel_layout(struct AVBPrint *bp,
- int nb_channels, uint64_t channel_layout)
-{
- int i;
+ AVChannelCustom *map;
if (nb_channels <= 0)
- nb_channels = av_get_channel_layout_nb_channels(channel_layout);
-
- for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++)
- if (nb_channels == channel_layout_map[i].layout.nb_channels &&
- channel_layout == channel_layout_map[i].layout.u.mask) {
- av_bprintf(bp, "%s", channel_layout_map[i].name);
- return;
- }
-
- av_bprintf(bp, "%d channels", nb_channels);
- if (channel_layout) {
- int i, ch;
- av_bprintf(bp, " (");
- for (i = 0, ch = 0; i < 64; i++) {
- if ((channel_layout & (UINT64_C(1) << i))) {
- const char *name = get_channel_name(i);
- if (name) {
- if (ch > 0)
- av_bprintf(bp, "+");
- av_bprintf(bp, "%s", name);
- }
- ch++;
- }
- }
- av_bprintf(bp, ")");
- }
-}
-
-void av_get_channel_layout_string(char *buf, int buf_size,
- int nb_channels, uint64_t channel_layout)
-{
- AVBPrint bp;
+ return AVERROR(EINVAL);
- av_bprint_init_for_buffer(&bp, buf, buf_size);
- av_bprint_channel_layout(&bp, nb_channels, channel_layout);
-}
+ map = av_calloc(nb_channels, sizeof(*channel_layout->u.map));
+ if (!map)
+ return AVERROR(ENOMEM);
+ for (int i = 0; i < nb_channels; i++)
+ map[i].id = AV_CHAN_UNKNOWN;
-int av_get_channel_layout_nb_channels(uint64_t channel_layout)
-{
- return av_popcount64(channel_layout);
-}
+ channel_layout->order = AV_CHANNEL_ORDER_CUSTOM;
+ channel_layout->nb_channels = nb_channels;
+ channel_layout->u.map = map;
-int64_t av_get_default_channel_layout(int nb_channels) {
- int i;
- for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++)
- if (nb_channels == channel_layout_map[i].layout.nb_channels)
- return channel_layout_map[i].layout.u.mask;
return 0;
}
-int av_get_channel_layout_channel_index(uint64_t channel_layout,
- uint64_t channel)
+int av_channel_layout_from_mask(AVChannelLayout *channel_layout,
+ uint64_t mask)
{
- if (!(channel_layout & channel) ||
- av_get_channel_layout_nb_channels(channel) != 1)
+ if (!mask)
return AVERROR(EINVAL);
- channel_layout &= channel - 1;
- return av_get_channel_layout_nb_channels(channel_layout);
-}
-const char *av_get_channel_name(uint64_t channel)
-{
- int i;
- if (av_get_channel_layout_nb_channels(channel) != 1)
- return NULL;
- for (i = 0; i < 64; i++)
- if ((1ULL<<i) & channel)
- return get_channel_name(i);
- return NULL;
-}
+ channel_layout->order = AV_CHANNEL_ORDER_NATIVE;
+ channel_layout->nb_channels = av_popcount64(mask);
+ channel_layout->u.mask = mask;
-const char *av_get_channel_description(uint64_t channel)
-{
- int i;
- if (av_get_channel_layout_nb_channels(channel) != 1)
- return NULL;
- for (i = 0; i < FF_ARRAY_ELEMS(channel_names); i++)
- if ((1ULL<<i) & channel)
- return channel_names[i].description;
- return NULL;
+ return 0;
}
-uint64_t av_channel_layout_extract_channel(uint64_t channel_layout, int index)
+static int parse_channel_list(AVChannelLayout *ch_layout, const char *str)
{
- int i;
+ int ret;
+ int nb_channels = 0;
+ AVChannelCustom *map = NULL;
+ AVChannelCustom custom = {0};
- if (av_get_channel_layout_nb_channels(channel_layout) <= index)
- return 0;
+ while (*str) {
+ char *channel, *chname;
+ int ret = av_opt_get_key_value(&str, "@", "+", AV_OPT_FLAG_IMPLICIT_KEY, &channel, &chname);
+ if (ret < 0) {
+ av_freep(&map);
+ return ret;
+ }
+ if (*str)
+ str++; // skip separator
+ if (!channel) {
+ channel = chname;
+ chname = NULL;
+ }
+ av_strlcpy(custom.name, chname ? chname : "", sizeof(custom.name));
+ custom.id = av_channel_from_string(channel);
+ av_free(channel);
+ av_free(chname);
+ if (custom.id == AV_CHAN_NONE) {
+ av_freep(&map);
+ return AVERROR(EINVAL);
+ }
- for (i = 0; i < 64; i++) {
- if ((1ULL << i) & channel_layout && !index--)
- return 1ULL << i;
+ av_dynarray2_add((void **)&map, &nb_channels, sizeof(custom), (void *)&custom);
+ if (!map)
+ return AVERROR(ENOMEM);
}
- return 0;
-}
-
-int av_get_standard_channel_layout(unsigned index, uint64_t *layout,
- const char **name)
-{
- if (index >= FF_ARRAY_ELEMS(channel_layout_map))
- return AVERROR_EOF;
- if (layout) *layout = channel_layout_map[index].layout.u.mask;
- if (name) *name = channel_layout_map[index].name;
- return 0;
-}
-FF_ENABLE_DEPRECATION_WARNINGS
-#endif
-int av_channel_layout_from_mask(AVChannelLayout *channel_layout,
- uint64_t mask)
-{
- if (!mask)
+ if (!nb_channels)
return AVERROR(EINVAL);
- channel_layout->order = AV_CHANNEL_ORDER_NATIVE;
- channel_layout->nb_channels = av_popcount64(mask);
- channel_layout->u.mask = mask;
+ ch_layout->order = AV_CHANNEL_ORDER_CUSTOM;
+ ch_layout->u.map = map;
+ ch_layout->nb_channels = nb_channels;
+
+ ret = av_channel_layout_retype(ch_layout, 0, AV_CHANNEL_LAYOUT_RETYPE_FLAG_CANONICAL);
+ av_assert0(ret == 0);
return 0;
}
@@ -414,10 +303,8 @@ int av_channel_layout_from_mask(AVChannelLayout *channel_layout,
int av_channel_layout_from_string(AVChannelLayout *channel_layout,
const char *str)
{
- int i;
- int channels = 0, nb_channels = 0, native = 1;
- enum AVChannel highest_channel = AV_CHAN_NONE;
- const char *dup;
+ int i, matches, ret;
+ int channels = 0, nb_channels = 0;
char *chlist, *end;
uint64_t mask = 0;
@@ -429,6 +316,10 @@ int av_channel_layout_from_string(AVChannelLayout *channel_layout,
}
}
+ /* This function is a channel layout initializer, so we have to
+ * zero-initialize before we start setting fields individually. */
+ memset(channel_layout, 0, sizeof(*channel_layout));
+
/* ambisonic */
if (!strncmp(str, "ambisonic ", 10)) {
const char *p = str + 10;
@@ -470,6 +361,7 @@ int av_channel_layout_from_string(AVChannelLayout *channel_layout,
for (i = 0; i < extra.nb_channels; i++) {
enum AVChannel ch = av_channel_layout_channel_from_index(&extra, i);
if (CHAN_IS_AMBI(ch)) {
+ av_channel_layout_uninit(channel_layout);
av_channel_layout_uninit(&extra);
return AVERROR(EINVAL);
}
@@ -493,121 +385,20 @@ int av_channel_layout_from_string(AVChannelLayout *channel_layout,
return AVERROR(ENOMEM);
/* channel names */
- av_sscanf(str, "%d channels (%[^)]", &nb_channels, chlist);
- end = strchr(str, ')');
-
- dup = chlist;
- while (*dup) {
- char *channel, *chname;
- int ret = av_opt_get_key_value(&dup, "@", "+", AV_OPT_FLAG_IMPLICIT_KEY, &channel, &chname);
- if (ret < 0) {
- av_free(chlist);
- return ret;
- }
- if (*dup)
- dup++; // skip separator
- if (channel && !*channel)
- av_freep(&channel);
- for (i = 0; i < FF_ARRAY_ELEMS(channel_names); i++) {
- if (channel_names[i].name && !strcmp(channel ? channel : chname, channel_names[i].name)) {
- if (channel || i < highest_channel || mask & (1ULL << i))
- native = 0; // Not a native layout, use a custom one
- highest_channel = i;
- mask |= 1ULL << i;
- break;
- }
- }
-
- if (!channel && 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(channel);
- av_free(chname);
- }
-
- if (mask && native) {
- av_free(chlist);
- if (nb_channels && ((nb_channels != channels) || (!end || *++end)))
- return AVERROR(EINVAL);
- av_channel_layout_from_mask(channel_layout, mask);
- return 0;
- }
-
- /* custom layout of channel names */
- if (channels && !native) {
- int idx = 0;
+ matches = av_sscanf(str, "%d channels (%[^)]", &nb_channels, chlist);
+ ret = parse_channel_list(channel_layout, chlist);
+ av_freep(&chlist);
+ if (ret < 0 && ret != AVERROR(EINVAL))
+ return ret;
- if (nb_channels && ((nb_channels != channels) || (!end || *++end))) {
- av_free(chlist);
+ if (ret >= 0) {
+ end = strchr(str, ')');
+ if (matches == 2 && (nb_channels != channel_layout->nb_channels || !end || *++end)) {
+ av_channel_layout_uninit(channel_layout);
return AVERROR(EINVAL);
}
-
- channel_layout->u.map = av_calloc(channels, sizeof(*channel_layout->u.map));
- if (!channel_layout->u.map) {
- av_free(chlist);
- return AVERROR(ENOMEM);
- }
-
- channel_layout->order = AV_CHANNEL_ORDER_CUSTOM;
- channel_layout->nb_channels = channels;
-
- dup = chlist;
- while (*dup) {
- char *channel, *chname;
- int ret = av_opt_get_key_value(&dup, "@", "+", AV_OPT_FLAG_IMPLICIT_KEY, &channel, &chname);
- if (ret < 0) {
- av_freep(&channel_layout->u.map);
- av_free(chlist);
- return ret;
- }
- if (*dup)
- dup++; // skip separator
- for (i = 0; i < FF_ARRAY_ELEMS(channel_names); i++) {
- if (channel_names[i].name && !strcmp(channel ? channel : chname, channel_names[i].name)) {
- channel_layout->u.map[idx].id = i;
- if (channel)
- av_strlcpy(channel_layout->u.map[idx].name, chname, sizeof(channel_layout->u.map[idx].name));
- idx++;
- break;
- }
- }
- if (i >= FF_ARRAY_ELEMS(channel_names)) {
- const char *p = (channel ? channel : chname) + 3;
- channel_layout->u.map[idx].id = strtol(p, NULL, 0);
- if (channel)
- av_strlcpy(channel_layout->u.map[idx].name, chname, sizeof(channel_layout->u.map[idx].name));
- idx++;
- }
- av_free(channel);
- av_free(chname);
- }
- av_free(chlist);
-
return 0;
}
- av_freep(&chlist);
errno = 0;
mask = strtoull(str, &end, 0);
@@ -659,6 +450,29 @@ int av_channel_layout_copy(AVChannelLayout *dst, const AVChannelLayout *src)
return 0;
}
+static int64_t masked_description(const AVChannelLayout *channel_layout, int start_channel)
+{
+ uint64_t mask = 0;
+ for (int i = start_channel; i < channel_layout->nb_channels; i++) {
+ enum AVChannel ch = channel_layout->u.map[i].id;
+ if (ch >= 0 && ch < 63 && mask < (1ULL << ch))
+ mask |= (1ULL << ch);
+ else
+ return AVERROR(EINVAL);
+ }
+ return mask;
+}
+
+static int has_channel_names(const AVChannelLayout *channel_layout)
+{
+ if (channel_layout->order != AV_CHANNEL_ORDER_CUSTOM)
+ return 0;
+ for (int i = 0; i < channel_layout->nb_channels; i++)
+ if (channel_layout->u.map[i].name[0])
+ return 1;
+ return 0;
+}
+
/**
* If the layout is n-th order standard-order ambisonic, with optional
* extra non-diegetic channels at the end, return the order.
@@ -702,6 +516,33 @@ static int ambisonic_order(const AVChannelLayout *channel_layout)
return order;
}
+static enum AVChannelOrder canonical_order(AVChannelLayout *channel_layout)
+{
+ int has_known_channel = 0;
+ int order;
+
+ if (channel_layout->order != AV_CHANNEL_ORDER_CUSTOM)
+ return channel_layout->order;
+
+ if (has_channel_names(channel_layout))
+ return AV_CHANNEL_ORDER_CUSTOM;
+
+ for (int i = 0; i < channel_layout->nb_channels && !has_known_channel; i++)
+ if (channel_layout->u.map[i].id != AV_CHAN_UNKNOWN)
+ has_known_channel = 1;
+ if (!has_known_channel)
+ return AV_CHANNEL_ORDER_UNSPEC;
+
+ if (masked_description(channel_layout, 0) > 0)
+ return AV_CHANNEL_ORDER_NATIVE;
+
+ order = ambisonic_order(channel_layout);
+ if (order >= 0 && masked_description(channel_layout, (order + 1) * (order + 1)) >= 0)
+ return AV_CHANNEL_ORDER_AMBISONIC;
+
+ return AV_CHANNEL_ORDER_CUSTOM;
+}
+
/**
* If the custom layout is n-th order standard-order ambisonic, with optional
* extra non-diegetic channels at the end, write its string description in bp.
@@ -726,9 +567,17 @@ static int try_describe_ambisonic(AVBPrint *bp, const AVChannelLayout *channel_l
extra.nb_channels = av_popcount64(channel_layout->u.mask);
extra.u.mask = channel_layout->u.mask;
} else {
- extra.order = AV_CHANNEL_ORDER_CUSTOM;
- extra.nb_channels = channel_layout->nb_channels - nb_ambi_channels;
- extra.u.map = channel_layout->u.map + nb_ambi_channels;
+ int64_t mask;
+ if (!has_channel_names(channel_layout) &&
+ (mask = masked_description(channel_layout, nb_ambi_channels)) > 0) {
+ extra.order = AV_CHANNEL_ORDER_NATIVE;
+ extra.nb_channels = av_popcount64(mask);
+ extra.u.mask = mask;
+ } else {
+ extra.order = AV_CHANNEL_ORDER_CUSTOM;
+ extra.nb_channels = channel_layout->nb_channels - nb_ambi_channels;
+ extra.u.map = channel_layout->u.map + nb_ambi_channels;
+ }
}
av_bprint_chars(bp, '+', 1);
@@ -754,9 +603,17 @@ int av_channel_layout_describe_bprint(const AVChannelLayout *channel_layout,
// fall-through
case AV_CHANNEL_ORDER_CUSTOM:
if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) {
+ int64_t mask;
int res = try_describe_ambisonic(bp, channel_layout);
if (res >= 0)
return 0;
+ if (!has_channel_names(channel_layout) &&
+ (mask = masked_description(channel_layout, 0)) > 0) {
+ AVChannelLayout native = { .order = AV_CHANNEL_ORDER_NATIVE,
+ .nb_channels = av_popcount64(mask),
+ .u.mask = mask };
+ return av_channel_layout_describe_bprint(&native, bp);
+ }
}
if (channel_layout->nb_channels)
av_bprintf(bp, "%d channels (", channel_layout->nb_channels);
@@ -1016,3 +873,97 @@ uint64_t av_channel_layout_subset(const AVChannelLayout *channel_layout,
return ret;
}
+
+int av_channel_layout_retype(AVChannelLayout *channel_layout, enum AVChannelOrder order, int flags)
+{
+ int allow_lossy = !(flags & AV_CHANNEL_LAYOUT_RETYPE_FLAG_LOSSLESS);
+ int lossy;
+
+ if (!av_channel_layout_check(channel_layout))
+ return AVERROR(EINVAL);
+
+ if (flags & AV_CHANNEL_LAYOUT_RETYPE_FLAG_CANONICAL)
+ order = canonical_order(channel_layout);
+
+ if (channel_layout->order == order)
+ return 0;
+
+ switch (order) {
+ case AV_CHANNEL_ORDER_UNSPEC: {
+ int nb_channels = channel_layout->nb_channels;
+ if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) {
+ lossy = 0;
+ for (int i = 0; i < nb_channels; i++) {
+ if (channel_layout->u.map[i].id != AV_CHAN_UNKNOWN || channel_layout->u.map[i].name[0]) {
+ lossy = 1;
+ break;
+ }
+ }
+ } else {
+ lossy = 1;
+ }
+ if (!lossy || allow_lossy) {
+ void *opaque = channel_layout->opaque;
+ av_channel_layout_uninit(channel_layout);
+ channel_layout->order = AV_CHANNEL_ORDER_UNSPEC;
+ channel_layout->nb_channels = nb_channels;
+ channel_layout->opaque = opaque;
+ return lossy;
+ }
+ return AVERROR(ENOSYS);
+ }
+ case AV_CHANNEL_ORDER_NATIVE:
+ if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) {
+ int64_t mask = masked_description(channel_layout, 0);
+ if (mask < 0)
+ return AVERROR(ENOSYS);
+ lossy = has_channel_names(channel_layout);
+ if (!lossy || allow_lossy) {
+ void *opaque = channel_layout->opaque;
+ av_channel_layout_uninit(channel_layout);
+ av_channel_layout_from_mask(channel_layout, mask);
+ channel_layout->opaque = opaque;
+ return lossy;
+ }
+ }
+ return AVERROR(ENOSYS);
+ case AV_CHANNEL_ORDER_CUSTOM: {
+ AVChannelLayout custom = { 0 };
+ int ret = av_channel_layout_custom_init(&custom, channel_layout->nb_channels);
+ void *opaque = channel_layout->opaque;
+ if (ret < 0)
+ return ret;
+ if (channel_layout->order != AV_CHANNEL_ORDER_UNSPEC)
+ for (int i = 0; i < channel_layout->nb_channels; i++)
+ custom.u.map[i].id = av_channel_layout_channel_from_index(channel_layout, i);
+ av_channel_layout_uninit(channel_layout);
+ *channel_layout = custom;
+ channel_layout->opaque = opaque;
+ return 0;
+ }
+ case AV_CHANNEL_ORDER_AMBISONIC:
+ if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) {
+ int64_t mask;
+ int nb_channels = channel_layout->nb_channels;
+ int order = ambisonic_order(channel_layout);
+ if (order < 0)
+ return AVERROR(ENOSYS);
+ mask = masked_description(channel_layout, (order + 1) * (order + 1));
+ if (mask < 0)
+ return AVERROR(ENOSYS);
+ lossy = has_channel_names(channel_layout);
+ if (!lossy || allow_lossy) {
+ void *opaque = channel_layout->opaque;
+ av_channel_layout_uninit(channel_layout);
+ channel_layout->order = AV_CHANNEL_ORDER_AMBISONIC;
+ channel_layout->nb_channels = nb_channels;
+ channel_layout->u.mask = mask;
+ channel_layout->opaque = opaque;
+ return lossy;
+ }
+ }
+ return AVERROR(ENOSYS);
+ default:
+ return AVERROR(EINVAL);
+ }
+}