This is an RFC to add support for tagging channel layouts as ambisonics in a backward-compatible way. For now ambisonics up to third order are supported. The functions have been updated to support and propagate the AV_CH_LAYOUT_AMBISONICS flag. This is messy but does not require a new API for layouts. Perhaps the new proposed API might be a better solution, comments are welcome. --- doc/APIchanges | 4 ++ libavutil/channel_layout.c | 85 +++++++++++++++++++++----------------- libavutil/channel_layout.h | 19 ++++++++- libavutil/version.h | 4 +- 4 files changed, 72 insertions(+), 40 deletions(-)
diff --git a/doc/APIchanges b/doc/APIchanges index db1879e6e2..88e2d0764b 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -15,6 +15,10 @@ libavutil: 2017-10-21 API changes, most recent first: +2018-xx-xx - xxxxxxxxxx - lavu 56.25.100 - channel_layout.h + Add AV_CH_LAYOUT_AMBISONICS, AV_CH_LAYOUT_AMBISONICS_1ST, + AV_CH_LAYOUT_AMBISONICS_2ND and AV_CH_LAYOUT_AMBISONICS_3RD. + -------- 8< --------- FFmpeg 4.1 was cut here -------- 8< --------- 2018-10-27 - 718044dc19 - lavu 56.21.100 - pixdesc.h diff --git a/libavutil/channel_layout.c b/libavutil/channel_layout.c index 3bd5ee29b7..30297138fe 100644 --- a/libavutil/channel_layout.c +++ b/libavutil/channel_layout.c @@ -33,42 +33,45 @@ struct channel_name { const char *name; + const char *ambisonics_name; const char *description; + const char *ambisonics_description; }; static const struct channel_name channel_names[] = { - [0] = { "FL", "front left" }, - [1] = { "FR", "front right" }, - [2] = { "FC", "front center" }, - [3] = { "LFE", "low frequency" }, - [4] = { "BL", "back left" }, - [5] = { "BR", "back right" }, - [6] = { "FLC", "front left-of-center" }, - [7] = { "FRC", "front right-of-center" }, - [8] = { "BC", "back center" }, - [9] = { "SL", "side left" }, - [10] = { "SR", "side right" }, - [11] = { "TC", "top center" }, - [12] = { "TFL", "top front left" }, - [13] = { "TFC", "top front center" }, - [14] = { "TFR", "top front right" }, - [15] = { "TBL", "top back left" }, - [16] = { "TBC", "top back center" }, - [17] = { "TBR", "top back right" }, - [29] = { "DL", "downmix left" }, - [30] = { "DR", "downmix right" }, - [31] = { "WL", "wide left" }, - [32] = { "WR", "wide right" }, - [33] = { "SDL", "surround direct left" }, - [34] = { "SDR", "surround direct right" }, - [35] = { "LFE2", "low frequency 2" }, + [0] = { "FL", "1", "front left", "ambisonics component 1" }, + [1] = { "FR", "2", "front right", "ambisonics component 2" }, + [2] = { "FC", "0", "front center", "ambisonics component 0" }, + [3] = { "LFE", "3", "low frequency", "ambisonics component 3" }, + [4] = { "BL", "4", "back left", "ambisonics component 4" }, + [5] = { "BR", "5", "back right", "ambisonics component 5" }, + [6] = { "FLC", "6", "front left-of-center", "ambisonics component 6" }, + [7] = { "FRC", "7", "front right-of-center", "ambisonics component 7" }, + [8] = { "BC", "8", "back center", "ambisonics component 8" }, + [9] = { "SL", "9", "side left", "ambisonics component 9" }, + [10] = { "SR", "10", "side right", "ambisonics component 10" }, + [11] = { "TC", "11", "top center", "ambisonics component 11" }, + [12] = { "TFL", "12", "top front left", "ambisonics component 12" }, + [13] = { "TFC", "13", "top front center", "ambisonics component 13" }, + [14] = { "TFR", "14", "top front right", "ambisonics component 14" }, + [15] = { "TBL", "15", "top back left", "ambisonics component 15" }, + [16] = { "TBC", NULL, "top back center", NULL }, + [17] = { "TBR", NULL, "top back right", NULL }, + [29] = { "DL", NULL, "downmix left", NULL }, + [30] = { "DR", NULL, "downmix right", NULL }, + [31] = { "WL", NULL, "wide left", NULL }, + [32] = { "WR", NULL, "wide right", NULL }, + [33] = { "SDL", NULL, "surround direct left", NULL }, + [34] = { "SDR", NULL, "surround direct right", NULL }, + [35] = { "LFE2", NULL, "low frequency 2", NULL }, }; -static const char *get_channel_name(int channel_id) +static const char *get_channel_name(int channel_id, int ambisonics) { if (channel_id < 0 || channel_id >= FF_ARRAY_ELEMS(channel_names)) return NULL; - return channel_names[channel_id].name; + return ambisonics ? channel_names[channel_id].ambisonics_name : + channel_names[channel_id].name; } static const struct { @@ -104,6 +107,10 @@ static const struct { { "octagonal", 8, AV_CH_LAYOUT_OCTAGONAL }, { "hexadecagonal", 16, AV_CH_LAYOUT_HEXADECAGONAL }, { "downmix", 2, AV_CH_LAYOUT_STEREO_DOWNMIX, }, + { "ambisonics_0th", 1, AV_CH_LAYOUT_AMBISONICS | AV_CH_LAYOUT_MONO }, + { "ambisonics_1st", 4, AV_CH_LAYOUT_AMBISONICS | (1 << 4) - 1 }, + { "ambisonics_2nd", 9, AV_CH_LAYOUT_AMBISONICS | (1 << 9) - 1 }, + { "ambisonics_3rd", 16, AV_CH_LAYOUT_AMBISONICS | (1 << 16) - 1 }, }; static uint64_t get_channel_layout_single(const char *name, int name_len) @@ -194,8 +201,8 @@ void av_bprint_channel_layout(struct AVBPrint *bp, 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 (((channel_layout & ~AV_CH_LAYOUT_AMBISONICS) & (UINT64_C(1) << i))) { + const char *name = get_channel_name(i, channel_layout & AV_CH_LAYOUT_AMBISONICS); if (name) { if (ch > 0) av_bprintf(bp, "+"); @@ -219,7 +226,7 @@ void av_get_channel_layout_string(char *buf, int buf_size, int av_get_channel_layout_nb_channels(uint64_t channel_layout) { - return av_popcount64(channel_layout); + return av_popcount64(channel_layout & ~AV_CH_LAYOUT_AMBISONICS); } int64_t av_get_default_channel_layout(int nb_channels) { @@ -233,7 +240,7 @@ int64_t av_get_default_channel_layout(int nb_channels) { int av_get_channel_layout_channel_index(uint64_t channel_layout, uint64_t channel) { - if (!(channel_layout & channel) || + if (!((channel_layout & ~AV_CH_LAYOUT_AMBISONICS) & channel) || av_get_channel_layout_nb_channels(channel) != 1) return AVERROR(EINVAL); channel_layout &= channel - 1; @@ -246,8 +253,8 @@ const char *av_get_channel_name(uint64_t channel) 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); + if ((1ULL<<i) & (channel & ~AV_CH_LAYOUT_AMBISONICS)) + return get_channel_name(i, channel & AV_CH_LAYOUT_AMBISONICS); return NULL; } @@ -257,8 +264,12 @@ const char *av_get_channel_description(uint64_t channel) 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; + if ((1ULL<<i) & (channel & ~AV_CH_LAYOUT_AMBISONICS)) { + if (channel & AV_CH_LAYOUT_AMBISONICS) + return channel_names[i].ambisonics_description; + else + return channel_names[i].description; + } return NULL; } @@ -270,8 +281,8 @@ uint64_t av_channel_layout_extract_channel(uint64_t channel_layout, int index) return 0; for (i = 0; i < 64; i++) { - if ((1ULL << i) & channel_layout && !index--) - return 1ULL << i; + if ((1ULL << i) & (channel_layout & ~AV_CH_LAYOUT_AMBISONICS) && !index--) + return (1ULL << i) & (channel_layout & AV_CH_LAYOUT_AMBISONICS); } return 0; } diff --git a/libavutil/channel_layout.h b/libavutil/channel_layout.h index 50bb8f03c5..8fd006647d 100644 --- a/libavutil/channel_layout.h +++ b/libavutil/channel_layout.h @@ -72,6 +72,17 @@ #define AV_CH_SURROUND_DIRECT_RIGHT 0x0000000400000000ULL #define AV_CH_LOW_FREQUENCY_2 0x0000000800000000ULL +/** Indicates channel layout is ambisonics. + If this is flagged, the number of channels must be either 1, 4, 9 or 16 + All functions will work as stated, with the flag being preserved where + possible. + The layout, channel descriptions and names follow the "Ambisonics Channel + Number (ACN)" specifications, published as + [Michael Chapman et al., + A standard for interchange of Ambisonic signal sets, + Ambisonics Symposium, Graz 2009] */ +#define AV_CH_LAYOUT_AMBISONICS 0x4000000000000000ULL + /** Channel mask value used for AVCodecContext.request_channel_layout to indicate that the user requests the channel order of the decoder output to be the native codec channel order. */ @@ -111,6 +122,11 @@ #define AV_CH_LAYOUT_HEXADECAGONAL (AV_CH_LAYOUT_OCTAGONAL|AV_CH_WIDE_LEFT|AV_CH_WIDE_RIGHT|AV_CH_TOP_BACK_LEFT|AV_CH_TOP_BACK_RIGHT|AV_CH_TOP_BACK_CENTER|AV_CH_TOP_FRONT_CENTER|AV_CH_TOP_FRONT_LEFT|AV_CH_TOP_FRONT_RIGHT) #define AV_CH_LAYOUT_STEREO_DOWNMIX (AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT) +#define AV_CH_LAYOUT_AMBISONICS_0TH (AV_CH_LAYOUT_MONO | AV_CH_LAYOUT_AMBISONICS) +#define AV_CH_LAYOUT_AMBISONICS_1ST (((1 << 4) - 1) | AV_CH_LAYOUT_AMBISONICS) +#define AV_CH_LAYOUT_AMBISONICS_2ND (((1 << 9) - 1) | AV_CH_LAYOUT_AMBISONICS) +#define AV_CH_LAYOUT_AMBISONICS_3ST (((1 << 16) - 1) | AV_CH_LAYOUT_AMBISONICS) + enum AVMatrixEncoding { AV_MATRIX_ENCODING_NONE, AV_MATRIX_ENCODING_DOLBY, @@ -200,6 +216,7 @@ uint64_t av_channel_layout_extract_channel(uint64_t channel_layout, int index); /** * Get the name of a given channel. * + * @param channel a channel layout with a single channel and a flag * @return channel name on success, NULL on error. */ const char *av_get_channel_name(uint64_t channel); @@ -207,7 +224,7 @@ const char *av_get_channel_name(uint64_t channel); /** * Get the description of a given channel. * - * @param channel a channel layout with a single channel + * @param channel a channel layout with a single channel and a flag * @return channel description on success, NULL on error */ const char *av_get_channel_description(uint64_t channel); diff --git a/libavutil/version.h b/libavutil/version.h index 62112a6049..f9976151a7 100644 --- a/libavutil/version.h +++ b/libavutil/version.h @@ -79,8 +79,8 @@ */ #define LIBAVUTIL_VERSION_MAJOR 56 -#define LIBAVUTIL_VERSION_MINOR 24 -#define LIBAVUTIL_VERSION_MICRO 101 +#define LIBAVUTIL_VERSION_MINOR 25 +#define LIBAVUTIL_VERSION_MICRO 100 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ LIBAVUTIL_VERSION_MINOR, \ -- 2.19.2 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel