diff mbox

[FFmpeg-devel] Add a new channel layout API

Message ID 20181224173430.15734-1-onemda@gmail.com
State Superseded
Headers show

Commit Message

Paul B Mahol Dec. 24, 2018, 5:34 p.m. UTC
The new API is more extensible and allows for custom layouts.
More accurate information is exported, eg for decoders that do not
set a channel layout, lavc will not make one up for them.

Deprecate the old API working with just uint64_t bitmasks.

Original commit by Anton Khirnov <anton@khirnov.net>.
Expanded and completed by Vittorio Giovara <vittorio.giovara@gmail.com>.
Adopted for FFmpeg by Paul B Mahol <onemda@gmail.com>.

Signed-off-by: Anton Khirnov <anton@khirnov.net>
Signed-off-by: Vittorio Giovara <vittorio.giovara@gmail.com>
Signed-off-by: Paul B Mahol <onemda@gmail.com>
---
 libavutil/channel_layout.c | 387 ++++++++++++++++++++++++++++------
 libavutil/channel_layout.h | 411 ++++++++++++++++++++++++++++++++++---
 libavutil/version.h        |   3 +
 3 files changed, 711 insertions(+), 90 deletions(-)

Comments

Michael Niedermayer Dec. 25, 2018, 2:14 a.m. UTC | #1
On Mon, Dec 24, 2018 at 06:34:30PM +0100, Paul B Mahol wrote:
[...]
> -static const char *get_channel_name(int channel_id)
> +const char *av_channel_name(enum AVChannel channel_id)
>  {

>      if (channel_id < 0 || channel_id >= FF_ARRAY_ELEMS(channel_names))
>          return NULL;
> +    if ((unsigned) channel_id >= FF_ARRAY_ELEMS(channel_names))
> +        return "?";

this looks like a untended duplicate check

[...]

> +/**
> + * Check whether two channel layouts are semantically the same, i.e. the same
> + * channels are present on the same positions in both.
> + *
> + * If one of the channel layouts is AV_CHANNEL_ORDER_UNSPEC, while the other is
> + * not, they are considered to be unequal. If both are AV_CHANNEL_ORDER_UNSPEC,
> + * they are considered equal iff the channel counts are the same in both.
> + *
> + * @param chl input channel layout
> + * @param chl1 input channel layout
> + * @return 0 if chl and chl1 are equal, 1 if they are not equal. A negative
> + *         AVERROR code if one or both are invalid.
> + */
> +int av_channel_layout_compare(const AVChannelLayout *chl, const AVChannelLayout *chl1);

It could be usefull if this is a full compare function that allows sorting/ordering

[...]
Paul B Mahol Dec. 25, 2018, 1:11 p.m. UTC | #2
On 12/25/18, Michael Niedermayer <michael@niedermayer.cc> wrote:
> On Mon, Dec 24, 2018 at 06:34:30PM +0100, Paul B Mahol wrote:
> [...]
>> -static const char *get_channel_name(int channel_id)
>> +const char *av_channel_name(enum AVChannel channel_id)
>>  {
>
>>      if (channel_id < 0 || channel_id >= FF_ARRAY_ELEMS(channel_names))
>>          return NULL;
>> +    if ((unsigned) channel_id >= FF_ARRAY_ELEMS(channel_names))
>> +        return "?";
>
> this looks like a untended duplicate check
>
> [...]
>
>> +/**
>> + * Check whether two channel layouts are semantically the same, i.e. the
>> same
>> + * channels are present on the same positions in both.
>> + *
>> + * If one of the channel layouts is AV_CHANNEL_ORDER_UNSPEC, while the
>> other is
>> + * not, they are considered to be unequal. If both are
>> AV_CHANNEL_ORDER_UNSPEC,
>> + * they are considered equal iff the channel counts are the same in
>> both.
>> + *
>> + * @param chl input channel layout
>> + * @param chl1 input channel layout
>> + * @return 0 if chl and chl1 are equal, 1 if they are not equal. A
>> negative
>> + *         AVERROR code if one or both are invalid.
>> + */
>> +int av_channel_layout_compare(const AVChannelLayout *chl, const
>> AVChannelLayout *chl1);
>
> It could be usefull if this is a full compare function that allows
> sorting/ordering

Which kind of sorting? That could be only added later when needed.
Michael Niedermayer Dec. 25, 2018, 5:51 p.m. UTC | #3
On Tue, Dec 25, 2018 at 02:11:45PM +0100, Paul B Mahol wrote:
> On 12/25/18, Michael Niedermayer <michael@niedermayer.cc> wrote:
> > On Mon, Dec 24, 2018 at 06:34:30PM +0100, Paul B Mahol wrote:
> > [...]
> >> -static const char *get_channel_name(int channel_id)
> >> +const char *av_channel_name(enum AVChannel channel_id)
> >>  {
> >
> >>      if (channel_id < 0 || channel_id >= FF_ARRAY_ELEMS(channel_names))
> >>          return NULL;
> >> +    if ((unsigned) channel_id >= FF_ARRAY_ELEMS(channel_names))
> >> +        return "?";
> >
> > this looks like a untended duplicate check
> >
> > [...]
> >
> >> +/**
> >> + * Check whether two channel layouts are semantically the same, i.e. the
> >> same
> >> + * channels are present on the same positions in both.
> >> + *
> >> + * If one of the channel layouts is AV_CHANNEL_ORDER_UNSPEC, while the
> >> other is
> >> + * not, they are considered to be unequal. If both are
> >> AV_CHANNEL_ORDER_UNSPEC,
> >> + * they are considered equal iff the channel counts are the same in
> >> both.
> >> + *
> >> + * @param chl input channel layout
> >> + * @param chl1 input channel layout
> >> + * @return 0 if chl and chl1 are equal, 1 if they are not equal. A
> >> negative
> >> + *         AVERROR code if one or both are invalid.
> >> + */
> >> +int av_channel_layout_compare(const AVChannelLayout *chl, const
> >> AVChannelLayout *chl1);
> >
> > It could be usefull if this is a full compare function that allows
> > sorting/ordering
> 
> Which kind of sorting? 

it doesnt matter which sorting.
Having some allows some operations to be performed more efficient
than having none.
An example is merging 2 lists removing duplicates.
2 sorted lists can be merged in O(n) but if theres no way to sort
and just a equal / non equal check it requires O(n^2)


> That could be only added later when needed.

adding it later is fine but i think its better if the API
allows it.
This would not work with above as it requires "1 if they are not equal",
it could allow 1 or -1 (or just non zero) then it can be extended

thx

[...]
Nicolas George Dec. 26, 2018, 2:22 p.m. UTC | #4
Paul B Mahol (2018-12-24):
> The new API is more extensible and allows for custom layouts.
> More accurate information is exported, eg for decoders that do not
> set a channel layout, lavc will not make one up for them.
> 
> Deprecate the old API working with just uint64_t bitmasks.
> 
> Original commit by Anton Khirnov <anton@khirnov.net>.
> Expanded and completed by Vittorio Giovara <vittorio.giovara@gmail.com>.

> Adopted for FFmpeg by Paul B Mahol <onemda@gmail.com>.

Adapted?

Reviewing only the visible API for now.

> diff --git a/libavutil/channel_layout.h b/libavutil/channel_layout.h
> index 50bb8f03c5..e6c8c58b9c 100644
> --- a/libavutil/channel_layout.h
> +++ b/libavutil/channel_layout.h
> @@ -24,6 +24,9 @@
>  
>  #include <stdint.h>
>  
> +#include "version.h"
> +#include "attributes.h"
> +
>  /**
>   * @file
>   * audio channel layout utility functions
> @@ -34,6 +37,60 @@
>   * @{
>   */
>  
> +enum AVChannel {
> +    AV_CHAN_FRONT_LEFT,
> +    AV_CHAN_FRONT_RIGHT,
> +    AV_CHAN_FRONT_CENTER,
> +    AV_CHAN_LOW_FREQUENCY,
> +    AV_CHAN_BACK_LEFT,
> +    AV_CHAN_BACK_RIGHT,
> +    AV_CHAN_FRONT_LEFT_OF_CENTER,
> +    AV_CHAN_FRONT_RIGHT_OF_CENTER,
> +    AV_CHAN_BACK_CENTER,
> +    AV_CHAN_SIDE_LEFT,
> +    AV_CHAN_SIDE_RIGHT,
> +    AV_CHAN_TOP_CENTER,
> +    AV_CHAN_TOP_FRONT_LEFT,
> +    AV_CHAN_TOP_FRONT_CENTER,
> +    AV_CHAN_TOP_FRONT_RIGHT,
> +    AV_CHAN_TOP_BACK_LEFT,
> +    AV_CHAN_TOP_BACK_CENTER,
> +    AV_CHAN_TOP_BACK_RIGHT,
> +    /** Stereo downmix. */
> +    AV_CHAN_STEREO_LEFT = 29,
> +    /** See above. */
> +    AV_CHAN_STEREO_RIGHT,
> +    AV_CHAN_WIDE_LEFT,
> +    AV_CHAN_WIDE_RIGHT,
> +    AV_CHAN_SURROUND_DIRECT_LEFT,
> +    AV_CHAN_SURROUND_DIRECT_RIGHT,
> +    AV_CHAN_LOW_FREQUENCY_2,
> +
> +    /** Channel is empty can be safely skipped. */
> +    AV_CHAN_SILENCE = 64,
> +};
> +
> +enum AVChannelOrder {
> +    /**
> +     * The native channel order, i.e. the channels are in the same order in
> +     * which they are defined in the AVChannel enum. This supports up to 63
> +     * different channels.
> +     */
> +    AV_CHANNEL_ORDER_NATIVE,
> +    /**
> +     * The channel order does not correspond to any other predefined order and
> +     * is stored as an explicit map. For example, this could be used to support
> +     * layouts with 64 or more channels, or with channels that could be skipped.
> +     */
> +    AV_CHANNEL_ORDER_CUSTOM,
> +    /**
> +     * Only the channel count is specified, without any further information
> +     * about the channel order.
> +     */
> +    AV_CHANNEL_ORDER_UNSPEC,
> +};
> +
> +
>  /**
>   * @defgroup channel_masks Audio channel masks
>   *
> @@ -46,36 +103,41 @@
>   *
>   * @{
>   */
> -#define AV_CH_FRONT_LEFT             0x00000001
> -#define AV_CH_FRONT_RIGHT            0x00000002
> -#define AV_CH_FRONT_CENTER           0x00000004
> -#define AV_CH_LOW_FREQUENCY          0x00000008
> -#define AV_CH_BACK_LEFT              0x00000010
> -#define AV_CH_BACK_RIGHT             0x00000020
> -#define AV_CH_FRONT_LEFT_OF_CENTER   0x00000040
> -#define AV_CH_FRONT_RIGHT_OF_CENTER  0x00000080
> -#define AV_CH_BACK_CENTER            0x00000100
> -#define AV_CH_SIDE_LEFT              0x00000200
> -#define AV_CH_SIDE_RIGHT             0x00000400
> -#define AV_CH_TOP_CENTER             0x00000800
> -#define AV_CH_TOP_FRONT_LEFT         0x00001000
> -#define AV_CH_TOP_FRONT_CENTER       0x00002000
> -#define AV_CH_TOP_FRONT_RIGHT        0x00004000
> -#define AV_CH_TOP_BACK_LEFT          0x00008000
> -#define AV_CH_TOP_BACK_CENTER        0x00010000
> -#define AV_CH_TOP_BACK_RIGHT         0x00020000
> -#define AV_CH_STEREO_LEFT            0x20000000  ///< Stereo downmix.
> -#define AV_CH_STEREO_RIGHT           0x40000000  ///< See AV_CH_STEREO_LEFT.
> -#define AV_CH_WIDE_LEFT              0x0000000080000000ULL
> -#define AV_CH_WIDE_RIGHT             0x0000000100000000ULL
> -#define AV_CH_SURROUND_DIRECT_LEFT   0x0000000200000000ULL
> -#define AV_CH_SURROUND_DIRECT_RIGHT  0x0000000400000000ULL
> -#define AV_CH_LOW_FREQUENCY_2        0x0000000800000000ULL
> +#define AV_CH_FRONT_LEFT             (1ULL << AV_CHAN_FRONT_LEFT           )
> +#define AV_CH_FRONT_RIGHT            (1ULL << AV_CHAN_FRONT_RIGHT          )
> +#define AV_CH_FRONT_CENTER           (1ULL << AV_CHAN_FRONT_CENTER         )
> +#define AV_CH_LOW_FREQUENCY          (1ULL << AV_CHAN_LOW_FREQUENCY        )
> +#define AV_CH_BACK_LEFT              (1ULL << AV_CHAN_BACK_LEFT            )
> +#define AV_CH_BACK_RIGHT             (1ULL << AV_CHAN_BACK_RIGHT           )
> +#define AV_CH_FRONT_LEFT_OF_CENTER   (1ULL << AV_CHAN_FRONT_LEFT_OF_CENTER )
> +#define AV_CH_FRONT_RIGHT_OF_CENTER  (1ULL << AV_CHAN_FRONT_RIGHT_OF_CENTER)
> +#define AV_CH_BACK_CENTER            (1ULL << AV_CHAN_BACK_CENTER          )
> +#define AV_CH_SIDE_LEFT              (1ULL << AV_CHAN_SIDE_LEFT            )
> +#define AV_CH_SIDE_RIGHT             (1ULL << AV_CHAN_SIDE_RIGHT           )
> +#define AV_CH_TOP_CENTER             (1ULL << AV_CHAN_TOP_CENTER           )
> +#define AV_CH_TOP_FRONT_LEFT         (1ULL << AV_CHAN_TOP_FRONT_LEFT       )
> +#define AV_CH_TOP_FRONT_CENTER       (1ULL << AV_CHAN_TOP_FRONT_CENTER     )
> +#define AV_CH_TOP_FRONT_RIGHT        (1ULL << AV_CHAN_TOP_FRONT_RIGHT      )
> +#define AV_CH_TOP_BACK_LEFT          (1ULL << AV_CHAN_TOP_BACK_LEFT        )
> +#define AV_CH_TOP_BACK_CENTER        (1ULL << AV_CHAN_TOP_BACK_CENTER      )
> +#define AV_CH_TOP_BACK_RIGHT         (1ULL << AV_CHAN_TOP_BACK_RIGHT       )
> +#define AV_CH_STEREO_LEFT            (1ULL << AV_CHAN_STEREO_LEFT          )
> +#define AV_CH_STEREO_RIGHT           (1ULL << AV_CHAN_STEREO_RIGHT         )
> +#define AV_CH_WIDE_LEFT              (1ULL << AV_CHAN_WIDE_LEFT            )
> +#define AV_CH_WIDE_RIGHT             (1ULL << AV_CHAN_WIDE_RIGHT           )
> +#define AV_CH_SURROUND_DIRECT_LEFT   (1ULL << AV_CHAN_SURROUND_DIRECT_LEFT )
> +#define AV_CH_SURROUND_DIRECT_RIGHT  (1ULL << AV_CHAN_SURROUND_DIRECT_RIGHT)
> +#define AV_CH_LOW_FREQUENCY_2        (1ULL << AV_CHAN_LOW_FREQUENCY_2      )
>  
> +#if FF_API_OLD_CHANNEL_LAYOUT
>  /** 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. */
> +    to be the native codec channel order.
> +    @deprecated channel order is now indicated in a special field in
> +                AVChannelLayout
> +    */
>  #define AV_CH_LAYOUT_NATIVE          0x8000000000000000ULL
> +#endif
>  
>  /**
>   * @}
> @@ -122,6 +184,135 @@ enum AVMatrixEncoding {
>      AV_MATRIX_ENCODING_NB
>  };
>  
> +/**
> + * An AVChannelLayout holds information about the channel layout of audio data.
> + *
> + * A channel layout here is defined as a set of channels ordered in a specific
> + * way (unless the channel order is AV_CHANNEL_ORDER_UNSPEC, in which case an
> + * AVChannelLayout carries only the channel count).
> + *
> + * Unlike most structures in Libav, sizeof(AVChannelLayout) is a part of the
> + * public ABI and may be used by the caller. E.g. it may be allocated on stack.
> + * In particular, this structure can be initialized as follows:
> + * - default initialization with {0} or by setting all used fields correctly
> + * - with predefined layout as initializer (AV_CHANNEL_LAYOUT_STEREO, etc.)
> + * - with a constructor function such as av_channel_layout_default()
> + * On that note, this also applies:
> + * - copy via assigning is forbidden, av_channel_layout_copy() must be used
> + *   instead (and its return value should be checked)
> + * - if order is AV_CHANNEL_ORDER_CUSTOM, then it must be uninitialized with
> + *   av_channel_layout_uninit().
> + *
> + * No new fields may be added to it without a major version bump, except for
> + * new elements of the union fitting in sizeof(uint64_t).
> + *
> + * An AVChannelLayout can be constructed using the convenience function
> + * av_channel_layout_from_mask() / av_channel_layout_from_string(), or it can be
> + * built manually by the caller.
> + */
> +typedef struct AVChannelLayout {
> +    /**
> +     * Channel order used in this layout.
> +     * This is a mandatory field, will default to AV_CHANNEL_ORDER_NATIVE.
> +     */
> +    enum AVChannelOrder order;
> +
> +    /**
> +     * Number of channels in this layout. Mandatory field.
> +     */

> +    int nb_channels;

This should be unsigned.

> +
> +    /**
> +     * Details about which channels are present in this layout.
> +     * For AV_CHANNEL_ORDER_UNSPEC, this field is undefined and must not be
> +     * used.
> +     */
> +    union {
> +        /**
> +         * This member must be used for AV_CHANNEL_ORDER_NATIVE.
> +         * It is a bitmask, where the position of each set bit means that the
> +         * AVChannel with the corresponding value is present.
> +         *
> +         * I.e. when (mask & (1 << AV_CHAN_FOO)) is non-zero, then AV_CHAN_FOO
> +         * is present in the layout. Otherwise it is not present.
> +         *
> +         * @note when a channel layout using a bitmask is constructed or
> +         * modified manually (i.e.  not using any of the av_channel_layout_*
> +         * functions), the code doing it must ensure that the number of set bits
> +         * is equal to nb_channels.
> +         */
> +        uint64_t mask;
> +        /**
> +         * This member must be used when the channel order is
> +         * AV_CHANNEL_ORDER_CUSTOM. It is a nb_channels-sized array, with each
> +         * element signalling the presend of the AVChannel with the
> +         * corresponding value.
> +         *
> +         * I.e. when map[i] is equal to AV_CHAN_FOO, then AV_CH_FOO is the i-th
> +         * channel in the audio data.
> +         */
> +        enum AVChannel *map;
> +    } u;
> +} AVChannelLayout;
> +

> +#define AV_CHANNEL_LAYOUT_MONO \
> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 1,  .u = { .mask = AV_CH_LAYOUT_MONO }}

Does this mean that named fields is no longer an issue with any of the
supported compilers?

> +#define AV_CHANNEL_LAYOUT_STEREO \
> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 2,  .u = { .mask = AV_CH_LAYOUT_STEREO }}
> +#define AV_CHANNEL_LAYOUT_2POINT1 \
> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 3,  .u = { .mask = AV_CH_LAYOUT_2POINT1 }}
> +#define AV_CHANNEL_LAYOUT_2_1 \
> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 3,  .u = { .mask = AV_CH_LAYOUT_2_1 }}
> +#define AV_CHANNEL_LAYOUT_SURROUND \
> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 3,  .u = { .mask = AV_CH_LAYOUT_SURROUND }}
> +#define AV_CHANNEL_LAYOUT_3POINT1 \
> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 4,  .u = { .mask = AV_CH_LAYOUT_3POINT1 }}
> +#define AV_CHANNEL_LAYOUT_4POINT0 \
> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 4,  .u = { .mask = AV_CH_LAYOUT_4POINT0 }}
> +#define AV_CHANNEL_LAYOUT_4POINT1 \
> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 5,  .u = { .mask = AV_CH_LAYOUT_4POINT1 }}
> +#define AV_CHANNEL_LAYOUT_2_2 \
> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 4,  .u = { .mask = AV_CH_LAYOUT_2_2 }}
> +#define AV_CHANNEL_LAYOUT_QUAD \
> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 4,  .u = { .mask = AV_CH_LAYOUT_QUAD }}
> +#define AV_CHANNEL_LAYOUT_5POINT0 \
> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 5,  .u = { .mask = AV_CH_LAYOUT_5POINT0 }}
> +#define AV_CHANNEL_LAYOUT_5POINT1 \
> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 6,  .u = { .mask = AV_CH_LAYOUT_5POINT1 }}
> +#define AV_CHANNEL_LAYOUT_5POINT0_BACK \
> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 5,  .u = { .mask = AV_CH_LAYOUT_5POINT0_BACK }}
> +#define AV_CHANNEL_LAYOUT_5POINT1_BACK \
> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 6,  .u = { .mask = AV_CH_LAYOUT_5POINT1_BACK }}
> +#define AV_CHANNEL_LAYOUT_6POINT0 \
> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 6,  .u = { .mask = AV_CH_LAYOUT_6POINT0 }}
> +#define AV_CHANNEL_LAYOUT_6POINT0_FRONT \
> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 6,  .u = { .mask = AV_CH_LAYOUT_6POINT0_FRONT }}
> +#define AV_CHANNEL_LAYOUT_HEXAGONAL \
> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 6,  .u = { .mask = AV_CH_LAYOUT_HEXAGONAL }}
> +#define AV_CHANNEL_LAYOUT_6POINT1 \
> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 7,  .u = { .mask = AV_CH_LAYOUT_6POINT1 }}
> +#define AV_CHANNEL_LAYOUT_6POINT1_BACK \
> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 7,  .u = { .mask = AV_CH_LAYOUT_6POINT1_BACK }}
> +#define AV_CHANNEL_LAYOUT_6POINT1_FRONT \
> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 7,  .u = { .mask = AV_CH_LAYOUT_6POINT1_FRONT }}
> +#define AV_CHANNEL_LAYOUT_7POINT0 \
> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 7,  .u = { .mask = AV_CH_LAYOUT_7POINT0 }}
> +#define AV_CHANNEL_LAYOUT_7POINT0_FRONT \
> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 7,  .u = { .mask = AV_CH_LAYOUT_7POINT0_FRONT }}
> +#define AV_CHANNEL_LAYOUT_7POINT1 \
> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 8,  .u = { .mask = AV_CH_LAYOUT_7POINT1 }}
> +#define AV_CHANNEL_LAYOUT_7POINT1_WIDE \
> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 8,  .u = { .mask = AV_CH_LAYOUT_7POINT1_WIDE }}
> +#define AV_CHANNEL_LAYOUT_7POINT1_WIDE_BACK \
> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 8,  .u = { .mask = AV_CH_LAYOUT_7POINT1_WIDE_BACK }}
> +#define AV_CHANNEL_LAYOUT_OCTAGONAL \
> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 8,  .u = { .mask = AV_CH_LAYOUT_OCTAGONAL }}
> +#define AV_CHANNEL_LAYOUT_HEXADECAGONAL \
> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 16, .u = { .mask = AV_CH_LAYOUT_HEXAGONAL }}
> +#define AV_CHANNEL_LAYOUT_STEREO_DOWNMIX \
> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 2,  .u = { .mask = AV_CH_LAYOUT_STEREO_DOWNMIX }}
> +

<snip deprecating stuff>

> +
> +/**
> + * This is the inverse function of @ref av_channel_from_string().
> + *

> + * @return a string describing a given channel, "?" if not found.

AFAIR, none of our other get_name()-style API return "?" if not found,
they all return NULL and let the application set a substitution string.
Let us make this API consistent.

> + */
> +const char *av_channel_name(enum AVChannel channel);
> +

> +/**
> + * This is the inverse function of @ref av_channel_name().
> + *
> + * @return a channel described by the given string, or a negative AVERROR value.
> + */
> +int av_channel_from_string(const char *name);

If it is really the exact inverse of av_channel_name(), then it should
be av_channel_from_name(). If it accepts other syntaxes too, then they
should be documented.

> +
> +/**
> + * Initialize a native channel layout from a bitmask indicating which channels
> + * are present.
> + *
> + * @note channel_layout should be properly allocated as described above.
> + *
> + * @param channel_layout the layout structure to be initialized
> + * @param mask bitmask describing the channel layout
> + */
> +void av_channel_layout_from_mask(AVChannelLayout *channel_layout, uint64_t mask);
> +
> +/**
> + * Initialize a channel layout from a given string description.

> + * The input string can be represented by:
> + *  - the formal channel layout name (returned by av_channel_layout_describe())
> + *  - single or multiple channel names (returned by av_channel_name()
> + *    or concatenated with "|")
> + *  - a hexadecimal value of a channel layout (eg. "0x4")
> + *  - the number of channels with default layout (eg. "5")
> + *  - the number of unordered channels (eg. "4 channels")

av_get_channel_layout() used to use '+' instead of '|', and I think it
is better. For once, '+' is not a special character for shells.

> + *
> + * @note channel_layout should be properly allocated as described above.
> + *
> + * @param channel_layout input channel layout
> + * @param str string describing the channel layout
> + * @return 0 channel layout was detected, AVERROR_INVALIDATATA otherwise
> + */
> +int av_channel_layout_from_string(AVChannelLayout *channel_layout,
> +                                  const char *str);
> +
> +/**
> + * Get the default channel layout for a given number of channels.
> + *
> + * @note channel_layout should be properly allocated as described above.
> + *
> + * @param channel_layout the layout structure to be initialized
> + * @param nb_channels number of channels
> + */

> +void av_channel_layout_default(AVChannelLayout *ch_layout, int nb_channels);

unsigned channels

> +
> +/**
> + * Free any allocated data in the channel layout and reset the channel
> + * count to 0.
> + *
> + * @note this only used for structure initialization and for freeing the
> + *       allocated memory for AV_CHANNEL_ORDER_CUSTOM order.
> + *
> + * @param channel_layout the layout structure to be uninitialized
> + */
> +void av_channel_layout_uninit(AVChannelLayout *channel_layout);
> +
> +/**
> + * Make a copy of a channel layout. This differs from just assigning src to dst
> + * in that it allocates and copies the map for AV_CHANNEL_ORDER_CUSTOM.
> + *
> + * @note the destination channel_layout will be always uninitialized before copy.
> + *
> + * @param dst destination channel layout
> + * @param src source channel layout
> + * @return 0 on success, a negative AVERROR on error.
> + */
> +int av_channel_layout_copy(AVChannelLayout *dst, const AVChannelLayout *src);
> +

> +/**
> + * Get a human-readable string describing the channel layout properties.
> + *
> + * @note The returned string is allocated with av_malloc(),
> + *       and must be freed by the caller with av_free().
> + *
> + * @param channel_layout channel layout to be described
> + * @return a string describing the structure or NULL on failure in the same
> + *         format that is accepted by @ref av_channel_layout_from_string().
> + */
> +char *av_channel_layout_describe(const AVChannelLayout *channel_layout);

There should also be av_channel_layout_describe_to_bprint() to let the
user control the buffer allocation with more ease.

> +
> +/**
> + * Get the channel with the given index in a channel layout.
> + *
> + * @param channel_layout input channel layout
> + * @return channel with the index idx in channel_layout on success or a negative
> + *                 AVERROR on failure (if idx is not valid or the channel order
> + *                 is unspecified)
> + */
> +int av_channel_layout_get_channel(const AVChannelLayout *channel_layout, int idx);
> +
> +/**
> + * Get the index of a given channel in a channel layout. In case multiple
> + * channels are found, only the first match will be returned.
> + *
> + * @param channel_layout input channel layout
> + * @return index of channel in channel_layout on success or a negative number if
> + *         channel is not present in channel_layout.
> + */
> +int av_channel_layout_channel_index(const AVChannelLayout *channel_layout,
> +                                    enum AVChannel channel);
> +
> +/**
> + * Find out what channels from a given set are present in a channel layout,
> + * without regard for their positions.
> + *
> + * @param channel_layout input channel layout
> + * @param mask a combination of AV_CH_* representing a set of channels
> + * @return a bitfield representing all the channels from mask that are present
> + *         in channel_layout
> + */
> +uint64_t av_channel_layout_subset(const AVChannelLayout *channel_layout,
> +                                  uint64_t mask);
> +
> +/**
> + * Check whether a channel layout is valid, i.e. can possibly describe audio
> + * data.
> + *
> + * @param channel_layout input channel layout
> + * @return 1 if channel_layout is valid, 0 otherwise.
> + */
> +int av_channel_layout_check(const AVChannelLayout *channel_layout);
> +
> +/**
> + * Check whether two channel layouts are semantically the same, i.e. the same
> + * channels are present on the same positions in both.
> + *
> + * If one of the channel layouts is AV_CHANNEL_ORDER_UNSPEC, while the other is
> + * not, they are considered to be unequal. If both are AV_CHANNEL_ORDER_UNSPEC,
> + * they are considered equal iff the channel counts are the same in both.
> + *
> + * @param chl input channel layout
> + * @param chl1 input channel layout
> + * @return 0 if chl and chl1 are equal, 1 if they are not equal. A negative
> + *         AVERROR code if one or both are invalid.
> + */
> +int av_channel_layout_compare(const AVChannelLayout *chl, const AVChannelLayout *chl1);
> +
>  /**
>   * @}
>   * @}

No more remarks for the first round of review.

Regards,
Paul B Mahol Dec. 26, 2018, 3:07 p.m. UTC | #5
On 12/26/18, Nicolas George <george@nsup.org> wrote:
> Paul B Mahol (2018-12-24):
>> The new API is more extensible and allows for custom layouts.
>> More accurate information is exported, eg for decoders that do not
>> set a channel layout, lavc will not make one up for them.
>>
>> Deprecate the old API working with just uint64_t bitmasks.
>>
>> Original commit by Anton Khirnov <anton@khirnov.net>.
>> Expanded and completed by Vittorio Giovara <vittorio.giovara@gmail.com>.
>
>> Adopted for FFmpeg by Paul B Mahol <onemda@gmail.com>.
>
> Adapted?
>
> Reviewing only the visible API for now.
>
>> diff --git a/libavutil/channel_layout.h b/libavutil/channel_layout.h
>> index 50bb8f03c5..e6c8c58b9c 100644
>> --- a/libavutil/channel_layout.h
>> +++ b/libavutil/channel_layout.h
>> @@ -24,6 +24,9 @@
>>
>>  #include <stdint.h>
>>
>> +#include "version.h"
>> +#include "attributes.h"
>> +
>>  /**
>>   * @file
>>   * audio channel layout utility functions
>> @@ -34,6 +37,60 @@
>>   * @{
>>   */
>>
>> +enum AVChannel {
>> +    AV_CHAN_FRONT_LEFT,
>> +    AV_CHAN_FRONT_RIGHT,
>> +    AV_CHAN_FRONT_CENTER,
>> +    AV_CHAN_LOW_FREQUENCY,
>> +    AV_CHAN_BACK_LEFT,
>> +    AV_CHAN_BACK_RIGHT,
>> +    AV_CHAN_FRONT_LEFT_OF_CENTER,
>> +    AV_CHAN_FRONT_RIGHT_OF_CENTER,
>> +    AV_CHAN_BACK_CENTER,
>> +    AV_CHAN_SIDE_LEFT,
>> +    AV_CHAN_SIDE_RIGHT,
>> +    AV_CHAN_TOP_CENTER,
>> +    AV_CHAN_TOP_FRONT_LEFT,
>> +    AV_CHAN_TOP_FRONT_CENTER,
>> +    AV_CHAN_TOP_FRONT_RIGHT,
>> +    AV_CHAN_TOP_BACK_LEFT,
>> +    AV_CHAN_TOP_BACK_CENTER,
>> +    AV_CHAN_TOP_BACK_RIGHT,
>> +    /** Stereo downmix. */
>> +    AV_CHAN_STEREO_LEFT = 29,
>> +    /** See above. */
>> +    AV_CHAN_STEREO_RIGHT,
>> +    AV_CHAN_WIDE_LEFT,
>> +    AV_CHAN_WIDE_RIGHT,
>> +    AV_CHAN_SURROUND_DIRECT_LEFT,
>> +    AV_CHAN_SURROUND_DIRECT_RIGHT,
>> +    AV_CHAN_LOW_FREQUENCY_2,
>> +
>> +    /** Channel is empty can be safely skipped. */
>> +    AV_CHAN_SILENCE = 64,
>> +};
>> +
>> +enum AVChannelOrder {
>> +    /**
>> +     * The native channel order, i.e. the channels are in the same order
>> in
>> +     * which they are defined in the AVChannel enum. This supports up to
>> 63
>> +     * different channels.
>> +     */
>> +    AV_CHANNEL_ORDER_NATIVE,
>> +    /**
>> +     * The channel order does not correspond to any other predefined
>> order and
>> +     * is stored as an explicit map. For example, this could be used to
>> support
>> +     * layouts with 64 or more channels, or with channels that could be
>> skipped.
>> +     */
>> +    AV_CHANNEL_ORDER_CUSTOM,
>> +    /**
>> +     * Only the channel count is specified, without any further
>> information
>> +     * about the channel order.
>> +     */
>> +    AV_CHANNEL_ORDER_UNSPEC,
>> +};
>> +
>> +
>>  /**
>>   * @defgroup channel_masks Audio channel masks
>>   *
>> @@ -46,36 +103,41 @@
>>   *
>>   * @{
>>   */
>> -#define AV_CH_FRONT_LEFT             0x00000001
>> -#define AV_CH_FRONT_RIGHT            0x00000002
>> -#define AV_CH_FRONT_CENTER           0x00000004
>> -#define AV_CH_LOW_FREQUENCY          0x00000008
>> -#define AV_CH_BACK_LEFT              0x00000010
>> -#define AV_CH_BACK_RIGHT             0x00000020
>> -#define AV_CH_FRONT_LEFT_OF_CENTER   0x00000040
>> -#define AV_CH_FRONT_RIGHT_OF_CENTER  0x00000080
>> -#define AV_CH_BACK_CENTER            0x00000100
>> -#define AV_CH_SIDE_LEFT              0x00000200
>> -#define AV_CH_SIDE_RIGHT             0x00000400
>> -#define AV_CH_TOP_CENTER             0x00000800
>> -#define AV_CH_TOP_FRONT_LEFT         0x00001000
>> -#define AV_CH_TOP_FRONT_CENTER       0x00002000
>> -#define AV_CH_TOP_FRONT_RIGHT        0x00004000
>> -#define AV_CH_TOP_BACK_LEFT          0x00008000
>> -#define AV_CH_TOP_BACK_CENTER        0x00010000
>> -#define AV_CH_TOP_BACK_RIGHT         0x00020000
>> -#define AV_CH_STEREO_LEFT            0x20000000  ///< Stereo downmix.
>> -#define AV_CH_STEREO_RIGHT           0x40000000  ///< See
>> AV_CH_STEREO_LEFT.
>> -#define AV_CH_WIDE_LEFT              0x0000000080000000ULL
>> -#define AV_CH_WIDE_RIGHT             0x0000000100000000ULL
>> -#define AV_CH_SURROUND_DIRECT_LEFT   0x0000000200000000ULL
>> -#define AV_CH_SURROUND_DIRECT_RIGHT  0x0000000400000000ULL
>> -#define AV_CH_LOW_FREQUENCY_2        0x0000000800000000ULL
>> +#define AV_CH_FRONT_LEFT             (1ULL << AV_CHAN_FRONT_LEFT
>>  )
>> +#define AV_CH_FRONT_RIGHT            (1ULL << AV_CHAN_FRONT_RIGHT
>>  )
>> +#define AV_CH_FRONT_CENTER           (1ULL << AV_CHAN_FRONT_CENTER
>>  )
>> +#define AV_CH_LOW_FREQUENCY          (1ULL << AV_CHAN_LOW_FREQUENCY
>>  )
>> +#define AV_CH_BACK_LEFT              (1ULL << AV_CHAN_BACK_LEFT
>>  )
>> +#define AV_CH_BACK_RIGHT             (1ULL << AV_CHAN_BACK_RIGHT
>>  )
>> +#define AV_CH_FRONT_LEFT_OF_CENTER   (1ULL <<
>> AV_CHAN_FRONT_LEFT_OF_CENTER )
>> +#define AV_CH_FRONT_RIGHT_OF_CENTER  (1ULL <<
>> AV_CHAN_FRONT_RIGHT_OF_CENTER)
>> +#define AV_CH_BACK_CENTER            (1ULL << AV_CHAN_BACK_CENTER
>>  )
>> +#define AV_CH_SIDE_LEFT              (1ULL << AV_CHAN_SIDE_LEFT
>>  )
>> +#define AV_CH_SIDE_RIGHT             (1ULL << AV_CHAN_SIDE_RIGHT
>>  )
>> +#define AV_CH_TOP_CENTER             (1ULL << AV_CHAN_TOP_CENTER
>>  )
>> +#define AV_CH_TOP_FRONT_LEFT         (1ULL << AV_CHAN_TOP_FRONT_LEFT
>>  )
>> +#define AV_CH_TOP_FRONT_CENTER       (1ULL << AV_CHAN_TOP_FRONT_CENTER
>>  )
>> +#define AV_CH_TOP_FRONT_RIGHT        (1ULL << AV_CHAN_TOP_FRONT_RIGHT
>>  )
>> +#define AV_CH_TOP_BACK_LEFT          (1ULL << AV_CHAN_TOP_BACK_LEFT
>>  )
>> +#define AV_CH_TOP_BACK_CENTER        (1ULL << AV_CHAN_TOP_BACK_CENTER
>>  )
>> +#define AV_CH_TOP_BACK_RIGHT         (1ULL << AV_CHAN_TOP_BACK_RIGHT
>>  )
>> +#define AV_CH_STEREO_LEFT            (1ULL << AV_CHAN_STEREO_LEFT
>>  )
>> +#define AV_CH_STEREO_RIGHT           (1ULL << AV_CHAN_STEREO_RIGHT
>>  )
>> +#define AV_CH_WIDE_LEFT              (1ULL << AV_CHAN_WIDE_LEFT
>>  )
>> +#define AV_CH_WIDE_RIGHT             (1ULL << AV_CHAN_WIDE_RIGHT
>>  )
>> +#define AV_CH_SURROUND_DIRECT_LEFT   (1ULL <<
>> AV_CHAN_SURROUND_DIRECT_LEFT )
>> +#define AV_CH_SURROUND_DIRECT_RIGHT  (1ULL <<
>> AV_CHAN_SURROUND_DIRECT_RIGHT)
>> +#define AV_CH_LOW_FREQUENCY_2        (1ULL << AV_CHAN_LOW_FREQUENCY_2
>>  )
>>
>> +#if FF_API_OLD_CHANNEL_LAYOUT
>>  /** 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. */
>> +    to be the native codec channel order.
>> +    @deprecated channel order is now indicated in a special field in
>> +                AVChannelLayout
>> +    */
>>  #define AV_CH_LAYOUT_NATIVE          0x8000000000000000ULL
>> +#endif
>>
>>  /**
>>   * @}
>> @@ -122,6 +184,135 @@ enum AVMatrixEncoding {
>>      AV_MATRIX_ENCODING_NB
>>  };
>>
>> +/**
>> + * An AVChannelLayout holds information about the channel layout of audio
>> data.
>> + *
>> + * A channel layout here is defined as a set of channels ordered in a
>> specific
>> + * way (unless the channel order is AV_CHANNEL_ORDER_UNSPEC, in which
>> case an
>> + * AVChannelLayout carries only the channel count).
>> + *
>> + * Unlike most structures in Libav, sizeof(AVChannelLayout) is a part of
>> the
>> + * public ABI and may be used by the caller. E.g. it may be allocated on
>> stack.
>> + * In particular, this structure can be initialized as follows:
>> + * - default initialization with {0} or by setting all used fields
>> correctly
>> + * - with predefined layout as initializer (AV_CHANNEL_LAYOUT_STEREO,
>> etc.)
>> + * - with a constructor function such as av_channel_layout_default()
>> + * On that note, this also applies:
>> + * - copy via assigning is forbidden, av_channel_layout_copy() must be
>> used
>> + *   instead (and its return value should be checked)
>> + * - if order is AV_CHANNEL_ORDER_CUSTOM, then it must be uninitialized
>> with
>> + *   av_channel_layout_uninit().
>> + *
>> + * No new fields may be added to it without a major version bump, except
>> for
>> + * new elements of the union fitting in sizeof(uint64_t).
>> + *
>> + * An AVChannelLayout can be constructed using the convenience function
>> + * av_channel_layout_from_mask() / av_channel_layout_from_string(), or it
>> can be
>> + * built manually by the caller.
>> + */
>> +typedef struct AVChannelLayout {
>> +    /**
>> +     * Channel order used in this layout.
>> +     * This is a mandatory field, will default to
>> AV_CHANNEL_ORDER_NATIVE.
>> +     */
>> +    enum AVChannelOrder order;
>> +
>> +    /**
>> +     * Number of channels in this layout. Mandatory field.
>> +     */
>
>> +    int nb_channels;
>
> This should be unsigned.
>
>> +
>> +    /**
>> +     * Details about which channels are present in this layout.
>> +     * For AV_CHANNEL_ORDER_UNSPEC, this field is undefined and must not
>> be
>> +     * used.
>> +     */
>> +    union {
>> +        /**
>> +         * This member must be used for AV_CHANNEL_ORDER_NATIVE.
>> +         * It is a bitmask, where the position of each set bit means that
>> the
>> +         * AVChannel with the corresponding value is present.
>> +         *
>> +         * I.e. when (mask & (1 << AV_CHAN_FOO)) is non-zero, then
>> AV_CHAN_FOO
>> +         * is present in the layout. Otherwise it is not present.
>> +         *
>> +         * @note when a channel layout using a bitmask is constructed or
>> +         * modified manually (i.e.  not using any of the
>> av_channel_layout_*
>> +         * functions), the code doing it must ensure that the number of
>> set bits
>> +         * is equal to nb_channels.
>> +         */
>> +        uint64_t mask;
>> +        /**
>> +         * This member must be used when the channel order is
>> +         * AV_CHANNEL_ORDER_CUSTOM. It is a nb_channels-sized array, with
>> each
>> +         * element signalling the presend of the AVChannel with the
>> +         * corresponding value.
>> +         *
>> +         * I.e. when map[i] is equal to AV_CHAN_FOO, then AV_CH_FOO is
>> the i-th
>> +         * channel in the audio data.
>> +         */
>> +        enum AVChannel *map;
>> +    } u;
>> +} AVChannelLayout;
>> +
>
>> +#define AV_CHANNEL_LAYOUT_MONO \
>> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 1,  .u = { .mask =
>> AV_CH_LAYOUT_MONO }}
>
> Does this mean that named fields is no longer an issue with any of the
> supported compilers?
>
>> +#define AV_CHANNEL_LAYOUT_STEREO \
>> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 2,  .u = { .mask =
>> AV_CH_LAYOUT_STEREO }}
>> +#define AV_CHANNEL_LAYOUT_2POINT1 \
>> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 3,  .u = { .mask =
>> AV_CH_LAYOUT_2POINT1 }}
>> +#define AV_CHANNEL_LAYOUT_2_1 \
>> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 3,  .u = { .mask =
>> AV_CH_LAYOUT_2_1 }}
>> +#define AV_CHANNEL_LAYOUT_SURROUND \
>> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 3,  .u = { .mask =
>> AV_CH_LAYOUT_SURROUND }}
>> +#define AV_CHANNEL_LAYOUT_3POINT1 \
>> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 4,  .u = { .mask =
>> AV_CH_LAYOUT_3POINT1 }}
>> +#define AV_CHANNEL_LAYOUT_4POINT0 \
>> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 4,  .u = { .mask =
>> AV_CH_LAYOUT_4POINT0 }}
>> +#define AV_CHANNEL_LAYOUT_4POINT1 \
>> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 5,  .u = { .mask =
>> AV_CH_LAYOUT_4POINT1 }}
>> +#define AV_CHANNEL_LAYOUT_2_2 \
>> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 4,  .u = { .mask =
>> AV_CH_LAYOUT_2_2 }}
>> +#define AV_CHANNEL_LAYOUT_QUAD \
>> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 4,  .u = { .mask =
>> AV_CH_LAYOUT_QUAD }}
>> +#define AV_CHANNEL_LAYOUT_5POINT0 \
>> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 5,  .u = { .mask =
>> AV_CH_LAYOUT_5POINT0 }}
>> +#define AV_CHANNEL_LAYOUT_5POINT1 \
>> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 6,  .u = { .mask =
>> AV_CH_LAYOUT_5POINT1 }}
>> +#define AV_CHANNEL_LAYOUT_5POINT0_BACK \
>> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 5,  .u = { .mask =
>> AV_CH_LAYOUT_5POINT0_BACK }}
>> +#define AV_CHANNEL_LAYOUT_5POINT1_BACK \
>> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 6,  .u = { .mask =
>> AV_CH_LAYOUT_5POINT1_BACK }}
>> +#define AV_CHANNEL_LAYOUT_6POINT0 \
>> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 6,  .u = { .mask =
>> AV_CH_LAYOUT_6POINT0 }}
>> +#define AV_CHANNEL_LAYOUT_6POINT0_FRONT \
>> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 6,  .u = { .mask =
>> AV_CH_LAYOUT_6POINT0_FRONT }}
>> +#define AV_CHANNEL_LAYOUT_HEXAGONAL \
>> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 6,  .u = { .mask =
>> AV_CH_LAYOUT_HEXAGONAL }}
>> +#define AV_CHANNEL_LAYOUT_6POINT1 \
>> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 7,  .u = { .mask =
>> AV_CH_LAYOUT_6POINT1 }}
>> +#define AV_CHANNEL_LAYOUT_6POINT1_BACK \
>> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 7,  .u = { .mask =
>> AV_CH_LAYOUT_6POINT1_BACK }}
>> +#define AV_CHANNEL_LAYOUT_6POINT1_FRONT \
>> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 7,  .u = { .mask =
>> AV_CH_LAYOUT_6POINT1_FRONT }}
>> +#define AV_CHANNEL_LAYOUT_7POINT0 \
>> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 7,  .u = { .mask =
>> AV_CH_LAYOUT_7POINT0 }}
>> +#define AV_CHANNEL_LAYOUT_7POINT0_FRONT \
>> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 7,  .u = { .mask =
>> AV_CH_LAYOUT_7POINT0_FRONT }}
>> +#define AV_CHANNEL_LAYOUT_7POINT1 \
>> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 8,  .u = { .mask =
>> AV_CH_LAYOUT_7POINT1 }}
>> +#define AV_CHANNEL_LAYOUT_7POINT1_WIDE \
>> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 8,  .u = { .mask =
>> AV_CH_LAYOUT_7POINT1_WIDE }}
>> +#define AV_CHANNEL_LAYOUT_7POINT1_WIDE_BACK \
>> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 8,  .u = { .mask =
>> AV_CH_LAYOUT_7POINT1_WIDE_BACK }}
>> +#define AV_CHANNEL_LAYOUT_OCTAGONAL \
>> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 8,  .u = { .mask =
>> AV_CH_LAYOUT_OCTAGONAL }}
>> +#define AV_CHANNEL_LAYOUT_HEXADECAGONAL \
>> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 16, .u = { .mask =
>> AV_CH_LAYOUT_HEXAGONAL }}
>> +#define AV_CHANNEL_LAYOUT_STEREO_DOWNMIX \
>> +    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 2,  .u = { .mask =
>> AV_CH_LAYOUT_STEREO_DOWNMIX }}
>> +
>
> <snip deprecating stuff>
>
>> +
>> +/**
>> + * This is the inverse function of @ref av_channel_from_string().
>> + *
>
>> + * @return a string describing a given channel, "?" if not found.
>
> AFAIR, none of our other get_name()-style API return "?" if not found,
> they all return NULL and let the application set a substitution string.
> Let us make this API consistent.
>
>> + */
>> +const char *av_channel_name(enum AVChannel channel);
>> +
>
>> +/**
>> + * This is the inverse function of @ref av_channel_name().
>> + *
>> + * @return a channel described by the given string, or a negative AVERROR
>> value.
>> + */
>> +int av_channel_from_string(const char *name);
>
> If it is really the exact inverse of av_channel_name(), then it should
> be av_channel_from_name(). If it accepts other syntaxes too, then they
> should be documented.
>
>> +
>> +/**
>> + * Initialize a native channel layout from a bitmask indicating which
>> channels
>> + * are present.
>> + *
>> + * @note channel_layout should be properly allocated as described above.
>> + *
>> + * @param channel_layout the layout structure to be initialized
>> + * @param mask bitmask describing the channel layout
>> + */
>> +void av_channel_layout_from_mask(AVChannelLayout *channel_layout,
>> uint64_t mask);
>> +
>> +/**
>> + * Initialize a channel layout from a given string description.
>
>> + * The input string can be represented by:
>> + *  - the formal channel layout name (returned by
>> av_channel_layout_describe())
>> + *  - single or multiple channel names (returned by av_channel_name()
>> + *    or concatenated with "|")
>> + *  - a hexadecimal value of a channel layout (eg. "0x4")
>> + *  - the number of channels with default layout (eg. "5")
>> + *  - the number of unordered channels (eg. "4 channels")
>
> av_get_channel_layout() used to use '+' instead of '|', and I think it
> is better. For once, '+' is not a special character for shells.

Look folk, I'm not paid to do this nor I'm paid to read your "reviews"
so I will ignore this one.

>
>> + *
>> + * @note channel_layout should be properly allocated as described above.
>> + *
>> + * @param channel_layout input channel layout
>> + * @param str string describing the channel layout
>> + * @return 0 channel layout was detected, AVERROR_INVALIDATATA otherwise
>> + */
>> +int av_channel_layout_from_string(AVChannelLayout *channel_layout,
>> +                                  const char *str);
>> +
>> +/**
>> + * Get the default channel layout for a given number of channels.
>> + *
>> + * @note channel_layout should be properly allocated as described above.
>> + *
>> + * @param channel_layout the layout structure to be initialized
>> + * @param nb_channels number of channels
>> + */
>
>> +void av_channel_layout_default(AVChannelLayout *ch_layout, int
>> nb_channels);
>
> unsigned channels
>
>> +
>> +/**
>> + * Free any allocated data in the channel layout and reset the channel
>> + * count to 0.
>> + *
>> + * @note this only used for structure initialization and for freeing the
>> + *       allocated memory for AV_CHANNEL_ORDER_CUSTOM order.
>> + *
>> + * @param channel_layout the layout structure to be uninitialized
>> + */
>> +void av_channel_layout_uninit(AVChannelLayout *channel_layout);
>> +
>> +/**
>> + * Make a copy of a channel layout. This differs from just assigning src
>> to dst
>> + * in that it allocates and copies the map for AV_CHANNEL_ORDER_CUSTOM.
>> + *
>> + * @note the destination channel_layout will be always uninitialized
>> before copy.
>> + *
>> + * @param dst destination channel layout
>> + * @param src source channel layout
>> + * @return 0 on success, a negative AVERROR on error.
>> + */
>> +int av_channel_layout_copy(AVChannelLayout *dst, const AVChannelLayout
>> *src);
>> +
>
>> +/**
>> + * Get a human-readable string describing the channel layout properties.
>> + *
>> + * @note The returned string is allocated with av_malloc(),
>> + *       and must be freed by the caller with av_free().
>> + *
>> + * @param channel_layout channel layout to be described
>> + * @return a string describing the structure or NULL on failure in the
>> same
>> + *         format that is accepted by @ref
>> av_channel_layout_from_string().
>> + */
>> +char *av_channel_layout_describe(const AVChannelLayout *channel_layout);
>
> There should also be av_channel_layout_describe_to_bprint() to let the
> user control the buffer allocation with more ease.
>
>> +
>> +/**
>> + * Get the channel with the given index in a channel layout.
>> + *
>> + * @param channel_layout input channel layout
>> + * @return channel with the index idx in channel_layout on success or a
>> negative
>> + *                 AVERROR on failure (if idx is not valid or the channel
>> order
>> + *                 is unspecified)
>> + */
>> +int av_channel_layout_get_channel(const AVChannelLayout *channel_layout,
>> int idx);
>> +
>> +/**
>> + * Get the index of a given channel in a channel layout. In case
>> multiple
>> + * channels are found, only the first match will be returned.
>> + *
>> + * @param channel_layout input channel layout
>> + * @return index of channel in channel_layout on success or a negative
>> number if
>> + *         channel is not present in channel_layout.
>> + */
>> +int av_channel_layout_channel_index(const AVChannelLayout
>> *channel_layout,
>> +                                    enum AVChannel channel);
>> +
>> +/**
>> + * Find out what channels from a given set are present in a channel
>> layout,
>> + * without regard for their positions.
>> + *
>> + * @param channel_layout input channel layout
>> + * @param mask a combination of AV_CH_* representing a set of channels
>> + * @return a bitfield representing all the channels from mask that are
>> present
>> + *         in channel_layout
>> + */
>> +uint64_t av_channel_layout_subset(const AVChannelLayout *channel_layout,
>> +                                  uint64_t mask);
>> +
>> +/**
>> + * Check whether a channel layout is valid, i.e. can possibly describe
>> audio
>> + * data.
>> + *
>> + * @param channel_layout input channel layout
>> + * @return 1 if channel_layout is valid, 0 otherwise.
>> + */
>> +int av_channel_layout_check(const AVChannelLayout *channel_layout);
>> +
>> +/**
>> + * Check whether two channel layouts are semantically the same, i.e. the
>> same
>> + * channels are present on the same positions in both.
>> + *
>> + * If one of the channel layouts is AV_CHANNEL_ORDER_UNSPEC, while the
>> other is
>> + * not, they are considered to be unequal. If both are
>> AV_CHANNEL_ORDER_UNSPEC,
>> + * they are considered equal iff the channel counts are the same in
>> both.
>> + *
>> + * @param chl input channel layout
>> + * @param chl1 input channel layout
>> + * @return 0 if chl and chl1 are equal, 1 if they are not equal. A
>> negative
>> + *         AVERROR code if one or both are invalid.
>> + */
>> +int av_channel_layout_compare(const AVChannelLayout *chl, const
>> AVChannelLayout *chl1);
>> +
>>  /**
>>   * @}
>>   * @}
>
> No more remarks for the first round of review.
>
> Regards,
>
> --
>   Nicolas George
>
Nicolas George Dec. 26, 2018, 3:15 p.m. UTC | #6
Paul B Mahol (2018-12-26):
> Look folk, I'm not paid to do this nor I'm paid to read your "reviews"

Neither am I. What does it have to do with anything?

> so I will ignore this one.

You are not allowed to do that. FFmpeg is not your personal project, it
is a collective endeavour governed by consensus. This patch cannot go in
until consensus is reached, and consensus cannot be reached unless you
take reviews into account.

Regards,
James Almer Dec. 26, 2018, 3:15 p.m. UTC | #7
On 12/26/2018 12:07 PM, Paul B Mahol wrote:
> On 12/26/18, Nicolas George <george@nsup.org> wrote:
>>> +
>>> +/**
>>> + * Initialize a native channel layout from a bitmask indicating which
>>> channels
>>> + * are present.
>>> + *
>>> + * @note channel_layout should be properly allocated as described above.
>>> + *
>>> + * @param channel_layout the layout structure to be initialized
>>> + * @param mask bitmask describing the channel layout
>>> + */
>>> +void av_channel_layout_from_mask(AVChannelLayout *channel_layout,
>>> uint64_t mask);
>>> +
>>> +/**
>>> + * Initialize a channel layout from a given string description.
>>
>>> + * The input string can be represented by:
>>> + *  - the formal channel layout name (returned by
>>> av_channel_layout_describe())
>>> + *  - single or multiple channel names (returned by av_channel_name()
>>> + *    or concatenated with "|")
>>> + *  - a hexadecimal value of a channel layout (eg. "0x4")
>>> + *  - the number of channels with default layout (eg. "5")
>>> + *  - the number of unordered channels (eg. "4 channels")
>>
>> av_get_channel_layout() used to use '+' instead of '|', and I think it
>> is better. For once, '+' is not a special character for shells.
> 
> Look folk, I'm not paid to do this nor I'm paid to read your "reviews"
> so I will ignore this one.
What prompted you to reply this way? Was there a need to be this
aggressive with a review?

What do you or anyone wins with this?
Paul B Mahol Dec. 26, 2018, 7:35 p.m. UTC | #8
On 12/26/18, James Almer <jamrial@gmail.com> wrote:
> On 12/26/2018 12:07 PM, Paul B Mahol wrote:
>> On 12/26/18, Nicolas George <george@nsup.org> wrote:
>>>> +
>>>> +/**
>>>> + * Initialize a native channel layout from a bitmask indicating which
>>>> channels
>>>> + * are present.
>>>> + *
>>>> + * @note channel_layout should be properly allocated as described
>>>> above.
>>>> + *
>>>> + * @param channel_layout the layout structure to be initialized
>>>> + * @param mask bitmask describing the channel layout
>>>> + */
>>>> +void av_channel_layout_from_mask(AVChannelLayout *channel_layout,
>>>> uint64_t mask);
>>>> +
>>>> +/**
>>>> + * Initialize a channel layout from a given string description.
>>>
>>>> + * The input string can be represented by:
>>>> + *  - the formal channel layout name (returned by
>>>> av_channel_layout_describe())
>>>> + *  - single or multiple channel names (returned by av_channel_name()
>>>> + *    or concatenated with "|")
>>>> + *  - a hexadecimal value of a channel layout (eg. "0x4")
>>>> + *  - the number of channels with default layout (eg. "5")
>>>> + *  - the number of unordered channels (eg. "4 channels")
>>>
>>> av_get_channel_layout() used to use '+' instead of '|', and I think it
>>> is better. For once, '+' is not a special character for shells.
>>
>> Look folk, I'm not paid to do this nor I'm paid to read your "reviews"
>> so I will ignore this one.
> What prompted you to reply this way? Was there a need to be this
> aggressive with a review?
>
> What do you or anyone wins with this?

You called for this, I'm not gonna continue working on this.

All thanks to very "nice" reviewers like all of you.
James Almer Dec. 26, 2018, 8:40 p.m. UTC | #9
On 12/26/2018 4:35 PM, Paul B Mahol wrote:
> On 12/26/18, James Almer <jamrial@gmail.com> wrote:
>> On 12/26/2018 12:07 PM, Paul B Mahol wrote:
>>> On 12/26/18, Nicolas George <george@nsup.org> wrote:
>>>>> +
>>>>> +/**
>>>>> + * Initialize a native channel layout from a bitmask indicating which
>>>>> channels
>>>>> + * are present.
>>>>> + *
>>>>> + * @note channel_layout should be properly allocated as described
>>>>> above.
>>>>> + *
>>>>> + * @param channel_layout the layout structure to be initialized
>>>>> + * @param mask bitmask describing the channel layout
>>>>> + */
>>>>> +void av_channel_layout_from_mask(AVChannelLayout *channel_layout,
>>>>> uint64_t mask);
>>>>> +
>>>>> +/**
>>>>> + * Initialize a channel layout from a given string description.
>>>>
>>>>> + * The input string can be represented by:
>>>>> + *  - the formal channel layout name (returned by
>>>>> av_channel_layout_describe())
>>>>> + *  - single or multiple channel names (returned by av_channel_name()
>>>>> + *    or concatenated with "|")
>>>>> + *  - a hexadecimal value of a channel layout (eg. "0x4")
>>>>> + *  - the number of channels with default layout (eg. "5")
>>>>> + *  - the number of unordered channels (eg. "4 channels")
>>>>
>>>> av_get_channel_layout() used to use '+' instead of '|', and I think it
>>>> is better. For once, '+' is not a special character for shells.
>>>
>>> Look folk, I'm not paid to do this nor I'm paid to read your "reviews"
>>> so I will ignore this one.
>> What prompted you to reply this way? Was there a need to be this
>> aggressive with a review?
>>
>> What do you or anyone wins with this?
> 
> You called for this, I'm not gonna continue working on this.
> 
> All thanks to very "nice" reviewers like all of you.

You're making no sense...
Paul B Mahol Dec. 30, 2018, 3:23 p.m. UTC | #10
On 12/26/18, Nicolas George <george@nsup.org> wrote:
>> + * The input string can be represented by:
>> + *  - the formal channel layout name (returned by
>> av_channel_layout_describe())
>> + *  - single or multiple channel names (returned by av_channel_name()
>> + *    or concatenated with "|")
>> + *  - a hexadecimal value of a channel layout (eg. "0x4")
>> + *  - the number of channels with default layout (eg. "5")
>> + *  - the number of unordered channels (eg. "4 channels")
>
> av_get_channel_layout() used to use '+' instead of '|', and I think it
> is better. For once, '+' is not a special character for shells.

Can not work if user wants to define custom channel layout from
already available channels.
Nicolas George Dec. 30, 2018, 3:26 p.m. UTC | #11
Paul B Mahol (2018-12-30):
> On 12/26/18, Nicolas George <george@nsup.org> wrote:
> >> + * The input string can be represented by:
> >> + *  - the formal channel layout name (returned by
> >> av_channel_layout_describe())
> >> + *  - single or multiple channel names (returned by av_channel_name()
> >> + *    or concatenated with "|")
> >> + *  - a hexadecimal value of a channel layout (eg. "0x4")
> >> + *  - the number of channels with default layout (eg. "5")
> >> + *  - the number of unordered channels (eg. "4 channels")
> >
> > av_get_channel_layout() used to use '+' instead of '|', and I think it
> > is better. For once, '+' is not a special character for shells.
> 
> Can not work if user wants to define custom channel layout from
> already available channels.

Please explain why.

Regards,
Paul B Mahol Dec. 30, 2018, 3:40 p.m. UTC | #12
On 12/30/18, Nicolas George <george@nsup.org> wrote:
> Paul B Mahol (2018-12-30):
>> On 12/26/18, Nicolas George <george@nsup.org> wrote:
>> >> + * The input string can be represented by:
>> >> + *  - the formal channel layout name (returned by
>> >> av_channel_layout_describe())
>> >> + *  - single or multiple channel names (returned by av_channel_name()
>> >> + *    or concatenated with "|")
>> >> + *  - a hexadecimal value of a channel layout (eg. "0x4")
>> >> + *  - the number of channels with default layout (eg. "5")
>> >> + *  - the number of unordered channels (eg. "4 channels")
>> >
>> > av_get_channel_layout() used to use '+' instead of '|', and I think it
>> > is better. For once, '+' is not a special character for shells.
>>
>> Can not work if user wants to define custom channel layout from
>> already available channels.
>
> Please explain why.

Input #0, wv, from
'/home/computer/Downloads/Run_The_Race_-_3rd_Order_Ambisonic_SN3D.wv':
  Duration: 00:11:07.67, start: 0.000000, bitrate: 6084 kb/s
    Stream #0:0: Audio: wavpack, 44100 Hz, 16 channels
(FL+FR+FC+LFE+BL+BR+FLC+FRC+BC+SL+SR+TC+TFL+TFC+TFR+TBL), s16p
Nicolas George Dec. 30, 2018, 3:47 p.m. UTC | #13
Paul B Mahol (2018-12-30):
> >> > av_get_channel_layout() used to use '+' instead of '|', and I think it
> >> > is better. For once, '+' is not a special character for shells.
> >>
> >> Can not work if user wants to define custom channel layout from
> >> already available channels.
> >
> > Please explain why.
> 
> Input #0, wv, from
> '/home/computer/Downloads/Run_The_Race_-_3rd_Order_Ambisonic_SN3D.wv':
>   Duration: 00:11:07.67, start: 0.000000, bitrate: 6084 kb/s
>     Stream #0:0: Audio: wavpack, 44100 Hz, 16 channels
> (FL+FR+FC+LFE+BL+BR+FLC+FRC+BC+SL+SR+TC+TFL+TFC+TFR+TBL), s16p

Yes... and...?
Paul B Mahol Dec. 30, 2018, 4:27 p.m. UTC | #14
On 12/30/18, Nicolas George <george@nsup.org> wrote:
> Paul B Mahol (2018-12-30):
>> >> > av_get_channel_layout() used to use '+' instead of '|', and I think
>> >> > it
>> >> > is better. For once, '+' is not a special character for shells.
>> >>
>> >> Can not work if user wants to define custom channel layout from
>> >> already available channels.
>> >
>> > Please explain why.
>>
>> Input #0, wv, from
>> '/home/computer/Downloads/Run_The_Race_-_3rd_Order_Ambisonic_SN3D.wv':
>>   Duration: 00:11:07.67, start: 0.000000, bitrate: 6084 kb/s
>>     Stream #0:0: Audio: wavpack, 44100 Hz, 16 channels
>> (FL+FR+FC+LFE+BL+BR+FLC+FRC+BC+SL+SR+TC+TFL+TFC+TFR+TBL), s16p
>
> Yes... and...?

From this is obvious that user can not use '+' to separate channel
layouts if it is already used to define channel layouts.

Do you need better explanation now?
Nicolas George Dec. 30, 2018, 6:17 p.m. UTC | #15
Paul B Mahol (2018-12-30):
> >> Input #0, wv, from
> >> '/home/computer/Downloads/Run_The_Race_-_3rd_Order_Ambisonic_SN3D.wv':
> >>   Duration: 00:11:07.67, start: 0.000000, bitrate: 6084 kb/s
> >>     Stream #0:0: Audio: wavpack, 44100 Hz, 16 channels
> >> (FL+FR+FC+LFE+BL+BR+FLC+FRC+BC+SL+SR+TC+TFL+TFC+TFR+TBL), s16p
> >
> > Yes... and...?
> 
> From this is obvious that user can not use '+' to separate channel
> layouts if it is already used to define channel layouts.
> 
> Do you need better explanation now?

Well, quoting the original patch:

+ * The input string can be represented by:
+ *  - the formal channel layout name (returned by av_channel_layout_describe())
+ *  - single or multiple channel names (returned by av_channel_name()
+ *    or concatenated with "|")
+ *  - a hexadecimal value of a channel layout (eg. "0x4")
+ *  - the number of channels with default layout (eg. "5")
+ *  - the number of unordered channels (eg. "4 channels")

There is no mention about '+'. So I guess this paragraph needs to be
rewritten to actually match what is being done.

And if + is not possible, | is still a bad choice. Use a character that
is not special for standard shells, I am sure we can find some; maybe /.
Paul B Mahol Dec. 30, 2018, 6:26 p.m. UTC | #16
On 12/30/18, Nicolas George <george@nsup.org> wrote:
> Paul B Mahol (2018-12-30):
>> >> Input #0, wv, from
>> >> '/home/computer/Downloads/Run_The_Race_-_3rd_Order_Ambisonic_SN3D.wv':
>> >>   Duration: 00:11:07.67, start: 0.000000, bitrate: 6084 kb/s
>> >>     Stream #0:0: Audio: wavpack, 44100 Hz, 16 channels
>> >> (FL+FR+FC+LFE+BL+BR+FLC+FRC+BC+SL+SR+TC+TFL+TFC+TFR+TBL), s16p
>> >
>> > Yes... and...?
>>
>> From this is obvious that user can not use '+' to separate channel
>> layouts if it is already used to define channel layouts.
>>
>> Do you need better explanation now?
>
> Well, quoting the original patch:
>
> + * The input string can be represented by:
> + *  - the formal channel layout name (returned by
> av_channel_layout_describe())
> + *  - single or multiple channel names (returned by av_channel_name()
> + *    or concatenated with "|")
> + *  - a hexadecimal value of a channel layout (eg. "0x4")
> + *  - the number of channels with default layout (eg. "5")
> + *  - the number of unordered channels (eg. "4 channels")
>
> There is no mention about '+'. So I guess this paragraph needs to be
> rewritten to actually match what is being done.
>
> And if + is not possible, | is still a bad choice. Use a character that
> is not special for standard shells, I am sure we can find some; maybe /.
>

Please no, | is used in bunch of scripts.
Nicolas George Dec. 30, 2018, 6:27 p.m. UTC | #17
Paul B Mahol (2018-12-30):
> Please no, | is used in bunch of scripts.

What scripts? How can they use an API that is still in early discussion?

Also, discussing this is moot until you rephrase the documentation.
Paul B Mahol Dec. 30, 2018, 6:33 p.m. UTC | #18
On 12/30/18, Nicolas George <george@nsup.org> wrote:
> Paul B Mahol (2018-12-30):
>> Please no, | is used in bunch of scripts.
>
> What scripts? How can they use an API that is still in early discussion?

aformat for example use | to split channel layouts.

>
> Also, discussing this is moot until you rephrase the documentation.

Documentation follows old legacy usage.

Can you please stop bikeshedding and arguing with me just because
you enjoy it?

I'm kindly asking you, whichever agenda you follow, please stop.

I'm doing this to add support for ambisonics and you just stopped it.
Nicolas George Dec. 30, 2018, 6:39 p.m. UTC | #19
Paul B Mahol (2018-12-30):
> aformat for example use | to split channel layouts.

Where?

> Documentation follows old legacy usage.

I am talking about the documentation of the patch you are proposing.

> Can you please stop bikeshedding and arguing with me just because
> you enjoy it?

Can you refrain from making baseless accusations? I am concerned about
the quality of a new API. Mistakes done now will bother us for a long
time; it is therefore a good idea to take the time to think things
through.

Please assume that everybody has at least as much goodwill as yourself.

If you want the discussion to go faster, I would suggest you change your
habit of giving half a bit of information per mail: explain your point
in details, with examples, and you will need to do it only once. If you
keep this style of posting, each question will take a dozen mails: you
are wasting your own time like that as well as the time of everybody
else.
Paul B Mahol Dec. 30, 2018, 6:44 p.m. UTC | #20
On 12/30/18, Nicolas George <george@nsup.org> wrote:
> Paul B Mahol (2018-12-30):
>> aformat for example use | to split channel layouts.
>
> Where?

http://ffmpeg.org/ffmpeg-filters.html#aformat-1http://ffmpeg.org/ffmpeg-filters.html#aformat-1

Do you want to change above thing too?

What you propose instead?
Nicolas George Dec. 30, 2018, 6:48 p.m. UTC | #21
Paul B Mahol (2018-12-30):
> http://ffmpeg.org/ffmpeg-filters.html#aformat-1http://ffmpeg.org/ffmpeg-filters.html#aformat-1

Your link was slightly broken.

> Do you want to change above thing too?

No, but I would have objected if I had noticed at the time.

But thanks for finding that example: that shows that | cannot be used in
channel layout descriptions, since aformat splits on |. You have to use
another character, there is no choice about it.

Regards,
Paul B Mahol Dec. 30, 2018, 6:53 p.m. UTC | #22
On 12/30/18, Nicolas George <george@nsup.org> wrote:
> Paul B Mahol (2018-12-30):
>> http://ffmpeg.org/ffmpeg-filters.html#aformat-1http://ffmpeg.org/ffmpeg-filters.html#aformat-1
>
> Your link was slightly broken.
>
>> Do you want to change above thing too?
>
> No, but I would have objected if I had noticed at the time.
>
> But thanks for finding that example: that shows that | cannot be used in
> channel layout descriptions, since aformat splits on |. You have to use
> another character, there is no choice about it.

I will use +.
Nicolas George Dec. 30, 2018, 6:55 p.m. UTC | #23
Paul B Mahol (2018-12-30):
> I will use +.

That was my suggestion in the beginning, so I am obviously for. But what
happened to your reasons for rejecting it?

(Once again, too little information in your mail => wasted time for both
of us.)
Paul B Mahol Dec. 30, 2018, 7:13 p.m. UTC | #24
On 12/30/18, Nicolas George <george@nsup.org> wrote:
> Paul B Mahol (2018-12-30):
>> I will use +.
>
> That was my suggestion in the beginning, so I am obviously for. But what
> happened to your reasons for rejecting it?

I thought that adapted patch by me had this issue already resolved.
I did not carefully read full patch.
Anyway I would spot this issue for sure at later point.
diff mbox

Patch

diff --git a/libavutil/channel_layout.c b/libavutil/channel_layout.c
index 3bd5ee29b7..a52f78bb9f 100644
--- a/libavutil/channel_layout.c
+++ b/libavutil/channel_layout.c
@@ -37,75 +37,89 @@  struct channel_name {
 };
 
 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"       },
+    [AV_CHAN_FRONT_LEFT              ] = { "FL" },
+    [AV_CHAN_FRONT_RIGHT             ] = { "FR" },
+    [AV_CHAN_FRONT_CENTER            ] = { "FC" },
+    [AV_CHAN_LOW_FREQUENCY           ] = { "LFE" },
+    [AV_CHAN_BACK_LEFT               ] = { "BL" },
+    [AV_CHAN_BACK_RIGHT              ] = { "BR" },
+    [AV_CHAN_FRONT_LEFT_OF_CENTER    ] = { "FLC" },
+    [AV_CHAN_FRONT_RIGHT_OF_CENTER   ] = { "FRC" },
+    [AV_CHAN_BACK_CENTER             ] = { "BC" },
+    [AV_CHAN_SIDE_LEFT               ] = { "SL" },
+    [AV_CHAN_SIDE_RIGHT              ] = { "SR" },
+    [AV_CHAN_TOP_CENTER              ] = { "TC" },
+    [AV_CHAN_TOP_FRONT_LEFT          ] = { "TFL" },
+    [AV_CHAN_TOP_FRONT_CENTER        ] = { "TFC" },
+    [AV_CHAN_TOP_FRONT_RIGHT         ] = { "TFR" },
+    [AV_CHAN_TOP_BACK_LEFT           ] = { "TBL" },
+    [AV_CHAN_TOP_BACK_CENTER         ] = { "TBC" },
+    [AV_CHAN_TOP_BACK_RIGHT          ] = { "TBR" },
+    [AV_CHAN_STEREO_LEFT             ] = { "DL" },
+    [AV_CHAN_STEREO_RIGHT            ] = { "DR" },
+    [AV_CHAN_WIDE_LEFT               ] = { "WL" },
+    [AV_CHAN_WIDE_RIGHT              ] = { "WR" },
+    [AV_CHAN_SURROUND_DIRECT_LEFT    ] = { "SDL" },
+    [AV_CHAN_SURROUND_DIRECT_RIGHT   ] = { "SDR" },
+    [AV_CHAN_LOW_FREQUENCY_2         ] = { "LFE2" },
+    [AV_CHAN_SILENCE                 ] = { "PAD" },
 };
 
-static const char *get_channel_name(int channel_id)
+const char *av_channel_name(enum AVChannel channel_id)
 {
     if (channel_id < 0 || channel_id >= FF_ARRAY_ELEMS(channel_names))
         return NULL;
+    if ((unsigned) channel_id >= FF_ARRAY_ELEMS(channel_names))
+        return "?";
     return channel_names[channel_id].name;
 }
 
+int av_channel_from_string(const char *str)
+{
+    for (int i = 0; i < FF_ARRAY_ELEMS(channel_names); i++) {
+        if (channel_names[i].name && !strcmp(str, channel_names[i].name)) {
+            return i;
+        }
+    }
+    return AVERROR(EINVAL);
+}
+
 static const struct {
     const char *name;
-    int         nb_channels;
-    uint64_t     layout;
+    AVChannelLayout layout;
 } channel_layout_map[] = {
-    { "mono",        1,  AV_CH_LAYOUT_MONO },
-    { "stereo",      2,  AV_CH_LAYOUT_STEREO },
-    { "2.1",         3,  AV_CH_LAYOUT_2POINT1 },
-    { "3.0",         3,  AV_CH_LAYOUT_SURROUND },
-    { "3.0(back)",   3,  AV_CH_LAYOUT_2_1 },
-    { "4.0",         4,  AV_CH_LAYOUT_4POINT0 },
-    { "quad",        4,  AV_CH_LAYOUT_QUAD },
-    { "quad(side)",  4,  AV_CH_LAYOUT_2_2 },
-    { "3.1",         4,  AV_CH_LAYOUT_3POINT1 },
-    { "5.0",         5,  AV_CH_LAYOUT_5POINT0_BACK },
-    { "5.0(side)",   5,  AV_CH_LAYOUT_5POINT0 },
-    { "4.1",         5,  AV_CH_LAYOUT_4POINT1 },
-    { "5.1",         6,  AV_CH_LAYOUT_5POINT1_BACK },
-    { "5.1(side)",   6,  AV_CH_LAYOUT_5POINT1 },
-    { "6.0",         6,  AV_CH_LAYOUT_6POINT0 },
-    { "6.0(front)",  6,  AV_CH_LAYOUT_6POINT0_FRONT },
-    { "hexagonal",   6,  AV_CH_LAYOUT_HEXAGONAL },
-    { "6.1",         7,  AV_CH_LAYOUT_6POINT1 },
-    { "6.1(back)",   7,  AV_CH_LAYOUT_6POINT1_BACK },
-    { "6.1(front)",  7,  AV_CH_LAYOUT_6POINT1_FRONT },
-    { "7.0",         7,  AV_CH_LAYOUT_7POINT0 },
-    { "7.0(front)",  7,  AV_CH_LAYOUT_7POINT0_FRONT },
-    { "7.1",         8,  AV_CH_LAYOUT_7POINT1 },
-    { "7.1(wide)",   8,  AV_CH_LAYOUT_7POINT1_WIDE_BACK },
-    { "7.1(wide-side)",   8,  AV_CH_LAYOUT_7POINT1_WIDE },
-    { "octagonal",   8,  AV_CH_LAYOUT_OCTAGONAL },
-    { "hexadecagonal", 16, AV_CH_LAYOUT_HEXADECAGONAL },
-    { "downmix",     2,  AV_CH_LAYOUT_STEREO_DOWNMIX, },
+    { "mono",           AV_CHANNEL_LAYOUT_MONO                },
+    { "stereo",         AV_CHANNEL_LAYOUT_STEREO              },
+    { "2.1",            AV_CHANNEL_LAYOUT_2POINT1             },
+    { "3.0",            AV_CHANNEL_LAYOUT_SURROUND            },
+    { "3.0(back)",      AV_CHANNEL_LAYOUT_2_1                 },
+    { "4.0",            AV_CHANNEL_LAYOUT_4POINT0             },
+    { "quad",           AV_CHANNEL_LAYOUT_QUAD                },
+    { "quad(side)",     AV_CHANNEL_LAYOUT_2_2                 },
+    { "3.1",            AV_CHANNEL_LAYOUT_3POINT1             },
+    { "5.0",            AV_CHANNEL_LAYOUT_5POINT0_BACK        },
+    { "5.0(side)",      AV_CHANNEL_LAYOUT_5POINT0             },
+    { "4.1",            AV_CHANNEL_LAYOUT_4POINT1             },
+    { "5.1",            AV_CHANNEL_LAYOUT_5POINT1_BACK        },
+    { "5.1(side)",      AV_CHANNEL_LAYOUT_5POINT1             },
+    { "6.0",            AV_CHANNEL_LAYOUT_6POINT0             },
+    { "6.0(front)",     AV_CHANNEL_LAYOUT_6POINT0_FRONT       },
+    { "hexagonal",      AV_CHANNEL_LAYOUT_HEXAGONAL           },
+    { "6.1",            AV_CHANNEL_LAYOUT_6POINT1             },
+    { "6.1(back)",      AV_CHANNEL_LAYOUT_6POINT1_BACK        },
+    { "6.1(front)",     AV_CHANNEL_LAYOUT_6POINT1_FRONT       },
+    { "7.0",            AV_CHANNEL_LAYOUT_7POINT0             },
+    { "7.0(front)",     AV_CHANNEL_LAYOUT_7POINT0_FRONT       },
+    { "7.1",            AV_CHANNEL_LAYOUT_7POINT1             },
+    { "7.1(wide)",      AV_CHANNEL_LAYOUT_7POINT1_WIDE        },
+    { "7.1(wide-back)", AV_CHANNEL_LAYOUT_7POINT1_WIDE_BACK   },
+    { "octagonal",      AV_CHANNEL_LAYOUT_OCTAGONAL           },
+    { "hexadecagonal",  AV_CHANNEL_LAYOUT_HEXADECAGONAL       },
+    { "downmix",        AV_CHANNEL_LAYOUT_STEREO_DOWNMIX,     },
 };
 
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
 static uint64_t get_channel_layout_single(const char *name, int name_len)
 {
     int i;
@@ -115,7 +129,7 @@  static uint64_t get_channel_layout_single(const char *name, int name_len)
     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;
+            return channel_layout_map[i].layout.u.mask;
     }
     for (i = 0; i < FF_ARRAY_ELEMS(channel_names); i++)
         if (channel_names[i].name &&
@@ -183,8 +197,8 @@  void av_bprint_channel_layout(struct AVBPrint *bp,
         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].nb_channels &&
-            channel_layout == channel_layout_map[i].layout) {
+        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;
         }
@@ -195,7 +209,7 @@  void av_bprint_channel_layout(struct AVBPrint *bp,
         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);
+                const char *name = av_channel_name(i);
                 if (name) {
                     if (ch > 0)
                         av_bprintf(bp, "+");
@@ -225,8 +239,8 @@  int av_get_channel_layout_nb_channels(uint64_t channel_layout)
 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].nb_channels)
-            return channel_layout_map[i].layout;
+        if (nb_channels == channel_layout_map[i].layout.nb_channels)
+            return channel_layout_map[i].layout.u.mask;
     return 0;
 }
 
@@ -247,7 +261,7 @@  const char *av_get_channel_name(uint64_t channel)
         return NULL;
     for (i = 0; i < 64; i++)
         if ((1ULL<<i) & channel)
-            return get_channel_name(i);
+            return av_channel_name(i);
     return NULL;
 }
 
@@ -281,7 +295,252 @@  int av_get_standard_channel_layout(unsigned index, uint64_t *layout,
 {
     if (index >= FF_ARRAY_ELEMS(channel_layout_map))
         return AVERROR_EOF;
-    if (layout) *layout = channel_layout_map[index].layout;
+    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
+
+void av_channel_layout_from_mask(AVChannelLayout *channel_layout,
+                                 uint64_t mask)
+{
+    channel_layout->order       = AV_CHANNEL_ORDER_NATIVE;
+    channel_layout->nb_channels = av_popcount64(mask);
+    channel_layout->u.mask      = mask;
+}
+
+int av_channel_layout_from_string(AVChannelLayout *channel_layout,
+                                  const char *str)
+{
+    int i, channels;
+    const char *dup = str;
+    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)) {
+                mask |= 1ULL << i;
+            }
+        }
+        av_free(chname);
+    }
+    if (mask) {
+        av_channel_layout_from_mask(channel_layout, mask);
+        return 0;
+    }
+
+    /* channel layout mask */
+    if (!strncmp(str, "0x", 2) && sscanf(str, "%"PRIx64, &mask) == 1) {
+        av_channel_layout_from_mask(channel_layout, mask);
+        return 0;
+    }
+
+    /* number of channels */
+    if (sscanf(str, "%d", &channels) == 1) {
+        av_channel_layout_default(channel_layout, channels);
+        return 0;
+    }
+
+    /* number of unordered channels */
+    if (sscanf(str, "%d channels", &channel_layout->nb_channels) == 1) {
+        channel_layout->order = AV_CHANNEL_ORDER_UNSPEC;
+        return 0;
+    }
+
+    return AVERROR_INVALIDDATA;
+}
+
+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(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;
+}
+
+char *av_channel_layout_describe(const AVChannelLayout *channel_layout)
+{
+    int i;
+
+    switch (channel_layout->order) {
+    case AV_CHANNEL_ORDER_NATIVE:
+        for (i = 0; channel_layout_map[i].name; i++)
+            if (channel_layout->u.mask == channel_layout_map[i].layout.u.mask)
+                return av_strdup(channel_layout_map[i].name);
+        // fall-through
+    case AV_CHANNEL_ORDER_CUSTOM: {
+        // max 4 bytes for channel name + a separator
+        int size = 5 * channel_layout->nb_channels + 1;
+        char *ret;
+
+        ret = av_mallocz(size);
+        if (!ret)
+            return NULL;
+
+        for (i = 0; i < channel_layout->nb_channels; i++) {
+            enum AVChannel ch = av_channel_layout_get_channel(channel_layout, i);
+            const char *ch_name = av_channel_name(ch);
+
+            if (i)
+                av_strlcat(ret, "|", size);
+            av_strlcat(ret, ch_name, size);
+        }
+        return ret;
+        }
+    case AV_CHANNEL_ORDER_UNSPEC: {
+        char buf[64];
+        snprintf(buf, sizeof(buf), "%d channels", channel_layout->nb_channels);
+        return av_strdup(buf);
+        }
+    default:
+        return NULL;
+    }
+}
+
+int av_channel_layout_get_channel(const AVChannelLayout *channel_layout, int idx)
+{
+    int i;
+
+    if (idx < 0 || idx >= channel_layout->nb_channels)
+        return AVERROR(EINVAL);
+
+    switch (channel_layout->order) {
+    case AV_CHANNEL_ORDER_CUSTOM:
+        return channel_layout->u.map[idx];
+    case AV_CHANNEL_ORDER_NATIVE:
+        for (i = 0; i < 64; i++) {
+            if ((1ULL << i) & channel_layout->u.mask && !idx--)
+                return i;
+        }
+    default:
+        return AVERROR(EINVAL);
+    }
+}
+
+int av_channel_layout_channel_index(const AVChannelLayout *channel_layout,
+                                    enum AVChannel channel)
+{
+    int i;
+
+    switch (channel_layout->order) {
+    case AV_CHANNEL_ORDER_CUSTOM:
+        for (i = 0; i < channel_layout->nb_channels; i++)
+            if (channel_layout->u.map[i] == channel)
+                return i;
+        return AVERROR(EINVAL);
+    case AV_CHANNEL_ORDER_NATIVE: {
+        uint64_t mask = channel_layout->u.mask;
+        if (!(mask & (1ULL << channel)))
+            return AVERROR(EINVAL);
+        mask &= (1ULL << channel) - 1;
+        return av_popcount64(mask);
+        }
+    default:
+        return AVERROR(EINVAL);
+    }
+}
+
+int av_channel_layout_check(const AVChannelLayout *channel_layout)
+{
+    if (!channel_layout || channel_layout->nb_channels <= 0)
+        return 0;
+
+    switch (channel_layout->order) {
+    case AV_CHANNEL_ORDER_NATIVE:
+        return av_popcount64(channel_layout->u.mask) == channel_layout->nb_channels;
+    case AV_CHANNEL_ORDER_CUSTOM:
+        return !!channel_layout->u.map;
+    case AV_CHANNEL_ORDER_UNSPEC:
+        return 1;
+    default:
+        return 0;
+    }
+}
+
+int av_channel_layout_compare(const AVChannelLayout *chl, const AVChannelLayout *chl1)
+{
+    /* different channel counts -> not equal */
+    if (chl->nb_channels != chl1->nb_channels)
+        return 1;
+
+    /* if only one is unspecified -> not equal */
+    if ((chl->order  == AV_CHANNEL_ORDER_UNSPEC) !=
+        (chl1->order == AV_CHANNEL_ORDER_UNSPEC))
+        return 1;
+    /* both are unspecified -> equal */
+    else if (chl->order == AV_CHANNEL_ORDER_UNSPEC)
+        return 0;
+
+    /* can compare masks directly */
+    if (chl->order != AV_CHANNEL_ORDER_CUSTOM &&
+        chl->order == chl1->order)
+        return chl->u.mask != chl1->u.mask;
+
+    /* compare channel by channel */
+    for (int i = 0; i < chl->nb_channels; i++)
+        if (av_channel_layout_get_channel(chl,  i) !=
+            av_channel_layout_get_channel(chl1, i))
+            return 1;
+    return 0;
+}
+
+void av_channel_layout_default(AVChannelLayout *ch_layout, int nb_channels)
+{
+    switch (nb_channels) {
+    case 1: *ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO;     break;
+    case 2: *ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO;   break;
+    case 3: *ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_SURROUND; break;
+    case 4: *ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_QUAD;     break;
+    case 5: *ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_5POINT0;  break;
+    case 6: *ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_5POINT1;  break;
+    case 7: *ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_6POINT1;  break;
+    case 8: *ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_7POINT1;  break;
+    default:
+        ch_layout->order       = AV_CHANNEL_ORDER_UNSPEC;
+        ch_layout->nb_channels = nb_channels;
+    }
+}
+
+uint64_t av_channel_layout_subset(const AVChannelLayout *channel_layout,
+                                  uint64_t mask)
+{
+    uint64_t ret = 0;
+    int i;
+
+    if (channel_layout->order == AV_CHANNEL_ORDER_NATIVE)
+        return channel_layout->u.mask & mask;
+
+    for (i = 0; i < 64; i++)
+        if (mask & (1ULL << i) && av_channel_layout_channel_index(channel_layout, i) >= 0)
+            ret |= (1ULL << i);
+
+    return ret;
+}
diff --git a/libavutil/channel_layout.h b/libavutil/channel_layout.h
index 50bb8f03c5..e6c8c58b9c 100644
--- a/libavutil/channel_layout.h
+++ b/libavutil/channel_layout.h
@@ -24,6 +24,9 @@ 
 
 #include <stdint.h>
 
+#include "version.h"
+#include "attributes.h"
+
 /**
  * @file
  * audio channel layout utility functions
@@ -34,6 +37,60 @@ 
  * @{
  */
 
+enum AVChannel {
+    AV_CHAN_FRONT_LEFT,
+    AV_CHAN_FRONT_RIGHT,
+    AV_CHAN_FRONT_CENTER,
+    AV_CHAN_LOW_FREQUENCY,
+    AV_CHAN_BACK_LEFT,
+    AV_CHAN_BACK_RIGHT,
+    AV_CHAN_FRONT_LEFT_OF_CENTER,
+    AV_CHAN_FRONT_RIGHT_OF_CENTER,
+    AV_CHAN_BACK_CENTER,
+    AV_CHAN_SIDE_LEFT,
+    AV_CHAN_SIDE_RIGHT,
+    AV_CHAN_TOP_CENTER,
+    AV_CHAN_TOP_FRONT_LEFT,
+    AV_CHAN_TOP_FRONT_CENTER,
+    AV_CHAN_TOP_FRONT_RIGHT,
+    AV_CHAN_TOP_BACK_LEFT,
+    AV_CHAN_TOP_BACK_CENTER,
+    AV_CHAN_TOP_BACK_RIGHT,
+    /** Stereo downmix. */
+    AV_CHAN_STEREO_LEFT = 29,
+    /** See above. */
+    AV_CHAN_STEREO_RIGHT,
+    AV_CHAN_WIDE_LEFT,
+    AV_CHAN_WIDE_RIGHT,
+    AV_CHAN_SURROUND_DIRECT_LEFT,
+    AV_CHAN_SURROUND_DIRECT_RIGHT,
+    AV_CHAN_LOW_FREQUENCY_2,
+
+    /** Channel is empty can be safely skipped. */
+    AV_CHAN_SILENCE = 64,
+};
+
+enum AVChannelOrder {
+    /**
+     * The native channel order, i.e. the channels are in the same order in
+     * which they are defined in the AVChannel enum. This supports up to 63
+     * different channels.
+     */
+    AV_CHANNEL_ORDER_NATIVE,
+    /**
+     * The channel order does not correspond to any other predefined order and
+     * is stored as an explicit map. For example, this could be used to support
+     * layouts with 64 or more channels, or with channels that could be skipped.
+     */
+    AV_CHANNEL_ORDER_CUSTOM,
+    /**
+     * Only the channel count is specified, without any further information
+     * about the channel order.
+     */
+    AV_CHANNEL_ORDER_UNSPEC,
+};
+
+
 /**
  * @defgroup channel_masks Audio channel masks
  *
@@ -46,36 +103,41 @@ 
  *
  * @{
  */
-#define AV_CH_FRONT_LEFT             0x00000001
-#define AV_CH_FRONT_RIGHT            0x00000002
-#define AV_CH_FRONT_CENTER           0x00000004
-#define AV_CH_LOW_FREQUENCY          0x00000008
-#define AV_CH_BACK_LEFT              0x00000010
-#define AV_CH_BACK_RIGHT             0x00000020
-#define AV_CH_FRONT_LEFT_OF_CENTER   0x00000040
-#define AV_CH_FRONT_RIGHT_OF_CENTER  0x00000080
-#define AV_CH_BACK_CENTER            0x00000100
-#define AV_CH_SIDE_LEFT              0x00000200
-#define AV_CH_SIDE_RIGHT             0x00000400
-#define AV_CH_TOP_CENTER             0x00000800
-#define AV_CH_TOP_FRONT_LEFT         0x00001000
-#define AV_CH_TOP_FRONT_CENTER       0x00002000
-#define AV_CH_TOP_FRONT_RIGHT        0x00004000
-#define AV_CH_TOP_BACK_LEFT          0x00008000
-#define AV_CH_TOP_BACK_CENTER        0x00010000
-#define AV_CH_TOP_BACK_RIGHT         0x00020000
-#define AV_CH_STEREO_LEFT            0x20000000  ///< Stereo downmix.
-#define AV_CH_STEREO_RIGHT           0x40000000  ///< See AV_CH_STEREO_LEFT.
-#define AV_CH_WIDE_LEFT              0x0000000080000000ULL
-#define AV_CH_WIDE_RIGHT             0x0000000100000000ULL
-#define AV_CH_SURROUND_DIRECT_LEFT   0x0000000200000000ULL
-#define AV_CH_SURROUND_DIRECT_RIGHT  0x0000000400000000ULL
-#define AV_CH_LOW_FREQUENCY_2        0x0000000800000000ULL
+#define AV_CH_FRONT_LEFT             (1ULL << AV_CHAN_FRONT_LEFT           )
+#define AV_CH_FRONT_RIGHT            (1ULL << AV_CHAN_FRONT_RIGHT          )
+#define AV_CH_FRONT_CENTER           (1ULL << AV_CHAN_FRONT_CENTER         )
+#define AV_CH_LOW_FREQUENCY          (1ULL << AV_CHAN_LOW_FREQUENCY        )
+#define AV_CH_BACK_LEFT              (1ULL << AV_CHAN_BACK_LEFT            )
+#define AV_CH_BACK_RIGHT             (1ULL << AV_CHAN_BACK_RIGHT           )
+#define AV_CH_FRONT_LEFT_OF_CENTER   (1ULL << AV_CHAN_FRONT_LEFT_OF_CENTER )
+#define AV_CH_FRONT_RIGHT_OF_CENTER  (1ULL << AV_CHAN_FRONT_RIGHT_OF_CENTER)
+#define AV_CH_BACK_CENTER            (1ULL << AV_CHAN_BACK_CENTER          )
+#define AV_CH_SIDE_LEFT              (1ULL << AV_CHAN_SIDE_LEFT            )
+#define AV_CH_SIDE_RIGHT             (1ULL << AV_CHAN_SIDE_RIGHT           )
+#define AV_CH_TOP_CENTER             (1ULL << AV_CHAN_TOP_CENTER           )
+#define AV_CH_TOP_FRONT_LEFT         (1ULL << AV_CHAN_TOP_FRONT_LEFT       )
+#define AV_CH_TOP_FRONT_CENTER       (1ULL << AV_CHAN_TOP_FRONT_CENTER     )
+#define AV_CH_TOP_FRONT_RIGHT        (1ULL << AV_CHAN_TOP_FRONT_RIGHT      )
+#define AV_CH_TOP_BACK_LEFT          (1ULL << AV_CHAN_TOP_BACK_LEFT        )
+#define AV_CH_TOP_BACK_CENTER        (1ULL << AV_CHAN_TOP_BACK_CENTER      )
+#define AV_CH_TOP_BACK_RIGHT         (1ULL << AV_CHAN_TOP_BACK_RIGHT       )
+#define AV_CH_STEREO_LEFT            (1ULL << AV_CHAN_STEREO_LEFT          )
+#define AV_CH_STEREO_RIGHT           (1ULL << AV_CHAN_STEREO_RIGHT         )
+#define AV_CH_WIDE_LEFT              (1ULL << AV_CHAN_WIDE_LEFT            )
+#define AV_CH_WIDE_RIGHT             (1ULL << AV_CHAN_WIDE_RIGHT           )
+#define AV_CH_SURROUND_DIRECT_LEFT   (1ULL << AV_CHAN_SURROUND_DIRECT_LEFT )
+#define AV_CH_SURROUND_DIRECT_RIGHT  (1ULL << AV_CHAN_SURROUND_DIRECT_RIGHT)
+#define AV_CH_LOW_FREQUENCY_2        (1ULL << AV_CHAN_LOW_FREQUENCY_2      )
 
+#if FF_API_OLD_CHANNEL_LAYOUT
 /** 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. */
+    to be the native codec channel order.
+    @deprecated channel order is now indicated in a special field in
+                AVChannelLayout
+    */
 #define AV_CH_LAYOUT_NATIVE          0x8000000000000000ULL
+#endif
 
 /**
  * @}
@@ -122,6 +184,135 @@  enum AVMatrixEncoding {
     AV_MATRIX_ENCODING_NB
 };
 
+/**
+ * An AVChannelLayout holds information about the channel layout of audio data.
+ *
+ * A channel layout here is defined as a set of channels ordered in a specific
+ * way (unless the channel order is AV_CHANNEL_ORDER_UNSPEC, in which case an
+ * AVChannelLayout carries only the channel count).
+ *
+ * Unlike most structures in Libav, sizeof(AVChannelLayout) is a part of the
+ * public ABI and may be used by the caller. E.g. it may be allocated on stack.
+ * In particular, this structure can be initialized as follows:
+ * - default initialization with {0} or by setting all used fields correctly
+ * - with predefined layout as initializer (AV_CHANNEL_LAYOUT_STEREO, etc.)
+ * - with a constructor function such as av_channel_layout_default()
+ * On that note, this also applies:
+ * - copy via assigning is forbidden, av_channel_layout_copy() must be used
+ *   instead (and its return value should be checked)
+ * - if order is AV_CHANNEL_ORDER_CUSTOM, then it must be uninitialized with
+ *   av_channel_layout_uninit().
+ *
+ * No new fields may be added to it without a major version bump, except for
+ * new elements of the union fitting in sizeof(uint64_t).
+ *
+ * An AVChannelLayout can be constructed using the convenience function
+ * av_channel_layout_from_mask() / av_channel_layout_from_string(), or it can be
+ * built manually by the caller.
+ */
+typedef struct AVChannelLayout {
+    /**
+     * Channel order used in this layout.
+     * This is a mandatory field, will default to AV_CHANNEL_ORDER_NATIVE.
+     */
+    enum AVChannelOrder order;
+
+    /**
+     * Number of channels in this layout. Mandatory field.
+     */
+    int nb_channels;
+
+    /**
+     * Details about which channels are present in this layout.
+     * For AV_CHANNEL_ORDER_UNSPEC, this field is undefined and must not be
+     * used.
+     */
+    union {
+        /**
+         * This member must be used for AV_CHANNEL_ORDER_NATIVE.
+         * It is a bitmask, where the position of each set bit means that the
+         * AVChannel with the corresponding value is present.
+         *
+         * I.e. when (mask & (1 << AV_CHAN_FOO)) is non-zero, then AV_CHAN_FOO
+         * is present in the layout. Otherwise it is not present.
+         *
+         * @note when a channel layout using a bitmask is constructed or
+         * modified manually (i.e.  not using any of the av_channel_layout_*
+         * functions), the code doing it must ensure that the number of set bits
+         * is equal to nb_channels.
+         */
+        uint64_t mask;
+        /**
+         * This member must be used when the channel order is
+         * AV_CHANNEL_ORDER_CUSTOM. It is a nb_channels-sized array, with each
+         * element signalling the presend of the AVChannel with the
+         * corresponding value.
+         *
+         * I.e. when map[i] is equal to AV_CHAN_FOO, then AV_CH_FOO is the i-th
+         * channel in the audio data.
+         */
+        enum AVChannel *map;
+    } u;
+} AVChannelLayout;
+
+#define AV_CHANNEL_LAYOUT_MONO \
+    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 1,  .u = { .mask = AV_CH_LAYOUT_MONO }}
+#define AV_CHANNEL_LAYOUT_STEREO \
+    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 2,  .u = { .mask = AV_CH_LAYOUT_STEREO }}
+#define AV_CHANNEL_LAYOUT_2POINT1 \
+    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 3,  .u = { .mask = AV_CH_LAYOUT_2POINT1 }}
+#define AV_CHANNEL_LAYOUT_2_1 \
+    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 3,  .u = { .mask = AV_CH_LAYOUT_2_1 }}
+#define AV_CHANNEL_LAYOUT_SURROUND \
+    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 3,  .u = { .mask = AV_CH_LAYOUT_SURROUND }}
+#define AV_CHANNEL_LAYOUT_3POINT1 \
+    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 4,  .u = { .mask = AV_CH_LAYOUT_3POINT1 }}
+#define AV_CHANNEL_LAYOUT_4POINT0 \
+    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 4,  .u = { .mask = AV_CH_LAYOUT_4POINT0 }}
+#define AV_CHANNEL_LAYOUT_4POINT1 \
+    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 5,  .u = { .mask = AV_CH_LAYOUT_4POINT1 }}
+#define AV_CHANNEL_LAYOUT_2_2 \
+    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 4,  .u = { .mask = AV_CH_LAYOUT_2_2 }}
+#define AV_CHANNEL_LAYOUT_QUAD \
+    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 4,  .u = { .mask = AV_CH_LAYOUT_QUAD }}
+#define AV_CHANNEL_LAYOUT_5POINT0 \
+    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 5,  .u = { .mask = AV_CH_LAYOUT_5POINT0 }}
+#define AV_CHANNEL_LAYOUT_5POINT1 \
+    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 6,  .u = { .mask = AV_CH_LAYOUT_5POINT1 }}
+#define AV_CHANNEL_LAYOUT_5POINT0_BACK \
+    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 5,  .u = { .mask = AV_CH_LAYOUT_5POINT0_BACK }}
+#define AV_CHANNEL_LAYOUT_5POINT1_BACK \
+    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 6,  .u = { .mask = AV_CH_LAYOUT_5POINT1_BACK }}
+#define AV_CHANNEL_LAYOUT_6POINT0 \
+    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 6,  .u = { .mask = AV_CH_LAYOUT_6POINT0 }}
+#define AV_CHANNEL_LAYOUT_6POINT0_FRONT \
+    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 6,  .u = { .mask = AV_CH_LAYOUT_6POINT0_FRONT }}
+#define AV_CHANNEL_LAYOUT_HEXAGONAL \
+    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 6,  .u = { .mask = AV_CH_LAYOUT_HEXAGONAL }}
+#define AV_CHANNEL_LAYOUT_6POINT1 \
+    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 7,  .u = { .mask = AV_CH_LAYOUT_6POINT1 }}
+#define AV_CHANNEL_LAYOUT_6POINT1_BACK \
+    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 7,  .u = { .mask = AV_CH_LAYOUT_6POINT1_BACK }}
+#define AV_CHANNEL_LAYOUT_6POINT1_FRONT \
+    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 7,  .u = { .mask = AV_CH_LAYOUT_6POINT1_FRONT }}
+#define AV_CHANNEL_LAYOUT_7POINT0 \
+    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 7,  .u = { .mask = AV_CH_LAYOUT_7POINT0 }}
+#define AV_CHANNEL_LAYOUT_7POINT0_FRONT \
+    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 7,  .u = { .mask = AV_CH_LAYOUT_7POINT0_FRONT }}
+#define AV_CHANNEL_LAYOUT_7POINT1 \
+    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 8,  .u = { .mask = AV_CH_LAYOUT_7POINT1 }}
+#define AV_CHANNEL_LAYOUT_7POINT1_WIDE \
+    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 8,  .u = { .mask = AV_CH_LAYOUT_7POINT1_WIDE }}
+#define AV_CHANNEL_LAYOUT_7POINT1_WIDE_BACK \
+    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 8,  .u = { .mask = AV_CH_LAYOUT_7POINT1_WIDE_BACK }}
+#define AV_CHANNEL_LAYOUT_OCTAGONAL \
+    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 8,  .u = { .mask = AV_CH_LAYOUT_OCTAGONAL }}
+#define AV_CHANNEL_LAYOUT_HEXADECAGONAL \
+    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 16, .u = { .mask = AV_CH_LAYOUT_HEXAGONAL }}
+#define AV_CHANNEL_LAYOUT_STEREO_DOWNMIX \
+    { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 2,  .u = { .mask = AV_CH_LAYOUT_STEREO_DOWNMIX }}
+
+#if FF_API_OLD_CHANNEL_LAYOUT
 /**
  * Return a channel layout id that matches name, or 0 if no match is found.
  *
@@ -138,7 +329,10 @@  enum AVMatrixEncoding {
  *   AV_CH_* macros).
  *
  * Example: "stereo+FC" = "2c+FC" = "2c+1c" = "0x7"
+ *
+ * @deprecated use av_channel_layout_from_string()
  */
+attribute_deprecated
 uint64_t av_get_channel_layout(const char *name);
 
 /**
@@ -161,7 +355,9 @@  int av_get_extended_channel_layout(const char *name, uint64_t* channel_layout, i
  *
  * @param buf put here the string containing the channel layout
  * @param buf_size size in bytes of the buffer
+ * @deprecated use av_channel_layout_describe()
  */
+attribute_deprecated
 void av_get_channel_layout_string(char *buf, int buf_size, int nb_channels, uint64_t channel_layout);
 
 struct AVBPrint;
@@ -172,12 +368,17 @@  void av_bprint_channel_layout(struct AVBPrint *bp, int nb_channels, uint64_t cha
 
 /**
  * Return the number of channels in the channel layout.
+ * @deprecated use AVChannelLayout.nb_channels
  */
+attribute_deprecated
 int av_get_channel_layout_nb_channels(uint64_t channel_layout);
 
 /**
  * Return default channel layout for a given number of channels.
+ *
+ * @deprecated use av_channel_layout_default()
  */
+attribute_deprecated
 int64_t av_get_default_channel_layout(int nb_channels);
 
 /**
@@ -188,20 +389,28 @@  int64_t av_get_default_channel_layout(int nb_channels);
  *
  * @return index of channel in channel_layout on success, a negative AVERROR
  *         on error.
+ *
+ * @deprecated use av_channel_layout_channel_index()
  */
+attribute_deprecated
 int av_get_channel_layout_channel_index(uint64_t channel_layout,
                                         uint64_t channel);
 
 /**
  * Get the channel with the given index in channel_layout.
+ * @deprecated use av_channel_layout_get_channel()
  */
+attribute_deprecated
 uint64_t av_channel_layout_extract_channel(uint64_t channel_layout, int index);
 
 /**
  * Get the name of a given channel.
  *
  * @return channel name on success, NULL on error.
+ *
+ * @deprecated use av_channel_name()
  */
+attribute_deprecated
 const char *av_get_channel_name(uint64_t channel);
 
 /**
@@ -210,6 +419,7 @@  const char *av_get_channel_name(uint64_t channel);
  * @param channel  a channel layout with a single channel
  * @return  channel description on success, NULL on error
  */
+attribute_deprecated
 const char *av_get_channel_description(uint64_t channel);
 
 /**
@@ -221,9 +431,158 @@  const char *av_get_channel_description(uint64_t channel);
  * @return  0  if the layout exists,
  *          <0 if index is beyond the limits
  */
+attribute_deprecated
 int av_get_standard_channel_layout(unsigned index, uint64_t *layout,
                                    const char **name);
 
+#endif
+
+/**
+ * This is the inverse function of @ref av_channel_from_string().
+ *
+ * @return a string describing a given channel, "?" if not found.
+ */
+const char *av_channel_name(enum AVChannel channel);
+
+/**
+ * This is the inverse function of @ref av_channel_name().
+ *
+ * @return a channel described by the given string, or a negative AVERROR value.
+ */
+int av_channel_from_string(const char *name);
+
+/**
+ * Initialize a native channel layout from a bitmask indicating which channels
+ * are present.
+ *
+ * @note channel_layout should be properly allocated as described above.
+ *
+ * @param channel_layout the layout structure to be initialized
+ * @param mask bitmask describing the channel layout
+ */
+void av_channel_layout_from_mask(AVChannelLayout *channel_layout, uint64_t mask);
+
+/**
+ * Initialize a channel layout from a given string description.
+ * The input string can be represented by:
+ *  - the formal channel layout name (returned by av_channel_layout_describe())
+ *  - single or multiple channel names (returned by av_channel_name()
+ *    or concatenated with "|")
+ *  - a hexadecimal value of a channel layout (eg. "0x4")
+ *  - the number of channels with default layout (eg. "5")
+ *  - the number of unordered channels (eg. "4 channels")
+ *
+ * @note channel_layout should be properly allocated as described above.
+ *
+ * @param channel_layout input channel layout
+ * @param str string describing the channel layout
+ * @return 0 channel layout was detected, AVERROR_INVALIDATATA otherwise
+ */
+int av_channel_layout_from_string(AVChannelLayout *channel_layout,
+                                  const char *str);
+
+/**
+ * Get the default channel layout for a given number of channels.
+ *
+ * @note channel_layout should be properly allocated as described above.
+ *
+ * @param channel_layout the layout structure to be initialized
+ * @param nb_channels number of channels
+ */
+void av_channel_layout_default(AVChannelLayout *ch_layout, int nb_channels);
+
+/**
+ * Free any allocated data in the channel layout and reset the channel
+ * count to 0.
+ *
+ * @note this only used for structure initialization and for freeing the
+ *       allocated memory for AV_CHANNEL_ORDER_CUSTOM order.
+ *
+ * @param channel_layout the layout structure to be uninitialized
+ */
+void av_channel_layout_uninit(AVChannelLayout *channel_layout);
+
+/**
+ * Make a copy of a channel layout. This differs from just assigning src to dst
+ * in that it allocates and copies the map for AV_CHANNEL_ORDER_CUSTOM.
+ *
+ * @note the destination channel_layout will be always uninitialized before copy.
+ *
+ * @param dst destination channel layout
+ * @param src source channel layout
+ * @return 0 on success, a negative AVERROR on error.
+ */
+int av_channel_layout_copy(AVChannelLayout *dst, const AVChannelLayout *src);
+
+/**
+ * Get a human-readable string describing the channel layout properties.
+ *
+ * @note The returned string is allocated with av_malloc(),
+ *       and must be freed by the caller with av_free().
+ *
+ * @param channel_layout channel layout to be described
+ * @return a string describing the structure or NULL on failure in the same
+ *         format that is accepted by @ref av_channel_layout_from_string().
+ */
+char *av_channel_layout_describe(const AVChannelLayout *channel_layout);
+
+/**
+ * Get the channel with the given index in a channel layout.
+ *
+ * @param channel_layout input channel layout
+ * @return channel with the index idx in channel_layout on success or a negative
+ *                 AVERROR on failure (if idx is not valid or the channel order
+ *                 is unspecified)
+ */
+int av_channel_layout_get_channel(const AVChannelLayout *channel_layout, int idx);
+
+/**
+ * Get the index of a given channel in a channel layout. In case multiple
+ * channels are found, only the first match will be returned.
+ *
+ * @param channel_layout input channel layout
+ * @return index of channel in channel_layout on success or a negative number if
+ *         channel is not present in channel_layout.
+ */
+int av_channel_layout_channel_index(const AVChannelLayout *channel_layout,
+                                    enum AVChannel channel);
+
+/**
+ * Find out what channels from a given set are present in a channel layout,
+ * without regard for their positions.
+ *
+ * @param channel_layout input channel layout
+ * @param mask a combination of AV_CH_* representing a set of channels
+ * @return a bitfield representing all the channels from mask that are present
+ *         in channel_layout
+ */
+uint64_t av_channel_layout_subset(const AVChannelLayout *channel_layout,
+                                  uint64_t mask);
+
+/**
+ * Check whether a channel layout is valid, i.e. can possibly describe audio
+ * data.
+ *
+ * @param channel_layout input channel layout
+ * @return 1 if channel_layout is valid, 0 otherwise.
+ */
+int av_channel_layout_check(const AVChannelLayout *channel_layout);
+
+/**
+ * Check whether two channel layouts are semantically the same, i.e. the same
+ * channels are present on the same positions in both.
+ *
+ * If one of the channel layouts is AV_CHANNEL_ORDER_UNSPEC, while the other is
+ * not, they are considered to be unequal. If both are AV_CHANNEL_ORDER_UNSPEC,
+ * they are considered equal iff the channel counts are the same in both.
+ *
+ * @param chl input channel layout
+ * @param chl1 input channel layout
+ * @return 0 if chl and chl1 are equal, 1 if they are not equal. A negative
+ *         AVERROR code if one or both are invalid.
+ */
+int av_channel_layout_compare(const AVChannelLayout *chl, const AVChannelLayout *chl1);
+
 /**
  * @}
  * @}
diff --git a/libavutil/version.h b/libavutil/version.h
index f9976151a7..275c4f0e35 100644
--- a/libavutil/version.h
+++ b/libavutil/version.h
@@ -129,6 +129,9 @@ 
 #ifndef FF_API_PSEUDOPAL
 #define FF_API_PSEUDOPAL                (LIBAVUTIL_VERSION_MAJOR < 57)
 #endif
+#ifndef FF_API_OLD_CHANNEL_LAYOUT
+#define FF_API_OLD_CHANNEL_LAYOUT       (LIBAVUTIL_VERSION_MAJOR < 57)
+#endif
 
 
 /**