[FFmpeg-devel] [PATCH] [RFC] channel_layout: add support for ambisonics
Rostislav Pehlivanov
atomnuker at gmail.com
Thu Nov 29 04:02:43 EET 2018
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
More information about the ffmpeg-devel
mailing list