diff mbox series

[FFmpeg-devel,275/281] avfilter: convert to new channel layout API

Message ID 20220113020913.870-6-jamrial@gmail.com
State New
Headers show
Series New channel layout API | expand

Commit Message

James Almer Jan. 13, 2022, 2:09 a.m. UTC
Signed-off-by: James Almer <jamrial@gmail.com>
---
 libavfilter/aeval.c                |  35 ++--
 libavfilter/af_acontrast.c         |   2 +-
 libavfilter/af_acrossover.c        |   6 +-
 libavfilter/af_acrusher.c          |   4 +-
 libavfilter/af_adeclick.c          |  14 +-
 libavfilter/af_adecorrelate.c      |  12 +-
 libavfilter/af_adelay.c            |   8 +-
 libavfilter/af_adenorm.c           |   6 +-
 libavfilter/af_aderivative.c       |   2 +-
 libavfilter/af_adynamicequalizer.c |   6 +-
 libavfilter/af_adynamicsmooth.c    |   2 +-
 libavfilter/af_aecho.c             |   8 +-
 libavfilter/af_aemphasis.c         |   6 +-
 libavfilter/af_aexciter.c          |  10 +-
 libavfilter/af_afade.c             |  10 +-
 libavfilter/af_afftdn.c            |  26 +--
 libavfilter/af_afftfilt.c          |  30 ++--
 libavfilter/af_afir.c              |  49 +++---
 libavfilter/af_aformat.c           |  33 +++-
 libavfilter/af_afreqshift.c        |   6 +-
 libavfilter/af_afwtdn.c            |   8 +-
 libavfilter/af_agate.c             |  14 +-
 libavfilter/af_aiir.c              |  34 ++--
 libavfilter/af_alimiter.c          |  10 +-
 libavfilter/af_amerge.c            |  40 +++--
 libavfilter/af_amix.c              |   4 +-
 libavfilter/af_amultiply.c         |   4 +-
 libavfilter/af_anequalizer.c       |  14 +-
 libavfilter/af_anlmdn.c            |   4 +-
 libavfilter/af_anlms.c             |   6 +-
 libavfilter/af_apad.c              |   2 +-
 libavfilter/af_aphaser.c           |   4 +-
 libavfilter/af_apsyclip.c          |   8 +-
 libavfilter/af_apulsator.c         |   2 +-
 libavfilter/af_aresample.c         |  52 +++---
 libavfilter/af_arnndn.c            |   8 +-
 libavfilter/af_asdr.c              |   8 +-
 libavfilter/af_asetnsamples.c      |   4 +-
 libavfilter/af_ashowinfo.c         |  17 +-
 libavfilter/af_asoftclip.c         |   2 +-
 libavfilter/af_aspectralstats.c    |   4 +-
 libavfilter/af_asr.c               |   2 +-
 libavfilter/af_astats.c            |  10 +-
 libavfilter/af_asubboost.c         |   8 +-
 libavfilter/af_asupercut.c         |   6 +-
 libavfilter/af_atempo.c            |   2 +-
 libavfilter/af_atilt.c             |   6 +-
 libavfilter/af_axcorrelate.c       |   8 +-
 libavfilter/af_biquads.c           |  54 +++---
 libavfilter/af_bs2b.c              |   2 +-
 libavfilter/af_channelmap.c        |  90 ++++++----
 libavfilter/af_channelsplit.c      |  42 +++--
 libavfilter/af_chorus.c            |  14 +-
 libavfilter/af_compand.c           |  14 +-
 libavfilter/af_compensationdelay.c |   9 +-
 libavfilter/af_crossfeed.c         |   2 +-
 libavfilter/af_crystalizer.c       |   4 +-
 libavfilter/af_dcshift.c           |   4 +-
 libavfilter/af_deesser.c           |   6 +-
 libavfilter/af_drmeter.c           |   4 +-
 libavfilter/af_dynaudnorm.c        |  24 +--
 libavfilter/af_earwax.c            |   2 +-
 libavfilter/af_extrastereo.c       |   2 +-
 libavfilter/af_firequalizer.c      |  31 ++--
 libavfilter/af_flanger.c           |   6 +-
 libavfilter/af_haas.c              |   2 +-
 libavfilter/af_hdcd.c              |  28 +--
 libavfilter/af_headphone.c         |  40 ++---
 libavfilter/af_join.c              | 270 +++++++++++++++++++----------
 libavfilter/af_ladspa.c            |  18 +-
 libavfilter/af_loudnorm.c          |  86 ++++-----
 libavfilter/af_lv2.c               |  19 +-
 libavfilter/af_mcompand.c          |  16 +-
 libavfilter/af_pan.c               |  74 +++-----
 libavfilter/af_replaygain.c        |   2 +-
 libavfilter/af_rubberband.c        |   2 +-
 libavfilter/af_sidechaincompress.c |  18 +-
 libavfilter/af_silencedetect.c     |   8 +-
 libavfilter/af_silenceremove.c     |  76 ++++----
 libavfilter/af_sofalizer.c         |  96 +++++-----
 libavfilter/af_speechnorm.c        |  28 +--
 libavfilter/af_stereotools.c       |   2 +-
 libavfilter/af_stereowiden.c       |   2 +-
 libavfilter/af_superequalizer.c    |   2 +-
 libavfilter/af_surround.c          |  90 +++++-----
 libavfilter/af_tremolo.c           |   2 +-
 libavfilter/af_vibrato.c           |   6 +-
 libavfilter/af_volume.c            |   4 +-
 libavfilter/af_volumedetect.c      |   2 +-
 libavfilter/asrc_afirsrc.c         |   2 +-
 libavfilter/asrc_anoisesrc.c       |   2 +-
 libavfilter/asrc_anullsrc.c        |  13 +-
 libavfilter/asrc_flite.c           |   6 +-
 libavfilter/asrc_hilbert.c         |   2 +-
 libavfilter/asrc_sinc.c            |   2 +-
 libavfilter/asrc_sine.c            |   2 +-
 libavfilter/audio.c                |  18 +-
 libavfilter/avf_abitscope.c        |  10 +-
 libavfilter/avf_ahistogram.c       |   6 +-
 libavfilter/avf_aphasemeter.c      |   2 +-
 libavfilter/avf_avectorscope.c     |   2 +-
 libavfilter/avf_concat.c           |   2 +-
 libavfilter/avf_showcqt.c          |   3 +-
 libavfilter/avf_showfreqs.c        |   4 +-
 libavfilter/avf_showspatial.c      |   4 +-
 libavfilter/avf_showspectrum.c     |  15 +-
 libavfilter/avf_showvolume.c       |  31 ++--
 libavfilter/avf_showwaves.c        |  12 +-
 libavfilter/avfilter.c             |  21 ++-
 libavfilter/avfilter.h             |  16 +-
 libavfilter/avfiltergraph.c        |  84 +++++----
 libavfilter/buffersink.c           |  36 +++-
 libavfilter/buffersink.h           |   7 +-
 libavfilter/buffersrc.c            |  94 +++++++---
 libavfilter/buffersrc.h            |   9 +
 libavfilter/f_ebur128.c            |  10 +-
 libavfilter/f_graphmonitor.c       |   2 +-
 libavfilter/f_loop.c               |   4 +-
 libavfilter/f_reverse.c            |   4 +-
 libavfilter/f_streamselect.c       |   6 +-
 libavfilter/formats.c              | 151 +++++++++++-----
 libavfilter/formats.h              |  16 +-
 libavfilter/framepool.c            |   5 +
 libavfilter/framequeue.c           |   4 +-
 libavfilter/graphdump.c            |   4 +-
 libavfilter/internal.h             |   2 +-
 libavfilter/src_movie.c            |  19 +-
 libavfilter/tests/filtfmts.c       |   3 +-
 libavfilter/tests/formats.c        |   4 +-
 libavfilter/trim.c                 |   2 +-
 libavfilter/vaf_spectrumsynth.c    |   2 +-
 tests/ref/fate/filter-formats      |  20 +--
 132 files changed, 1413 insertions(+), 1019 deletions(-)

Comments

Anton Khirnov Feb. 14, 2022, 3:49 p.m. UTC | #1
Quoting James Almer (2022-01-13 03:09:07)
> diff --git a/libavfilter/af_apulsator.c b/libavfilter/af_apulsator.c
> index c2a8de0e0b..c3ca752035 100644
> --- a/libavfilter/af_apulsator.c
> +++ b/libavfilter/af_apulsator.c
> @@ -192,7 +192,7 @@ static int query_formats(AVFilterContext *ctx)
>  
>      if ((ret = ff_add_format                 (&formats, AV_SAMPLE_FMT_DBL  )) < 0 ||
>          (ret = ff_set_common_formats         (ctx     , formats            )) < 0 ||
> -        (ret = ff_add_channel_layout         (&layout , AV_CH_LAYOUT_STEREO)) < 0 ||
> +        (ret = ff_add_channel_layout         (&layout , &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO)) < 0 ||

completion fail?

> diff --git a/libavfilter/af_sofalizer.c b/libavfilter/af_sofalizer.c
> index 20b717bdf8..246ddeffb9 100644
> --- a/libavfilter/af_sofalizer.c
> +++ b/libavfilter/af_sofalizer.c
> @@ -187,25 +187,15 @@ static int preload_sofa(AVFilterContext *ctx, char *filename, int *samplingrate)
>  
>  static int parse_channel_name(AVFilterContext *ctx, char **arg, int *rchannel)
>  {
> -    int len, i, channel_id = 0;
> -    int64_t layout, layout0;
> +    int len, channel_id = 0;
>      char buf[8] = {0};
>  
>      /* try to parse a channel name, e.g. "FL" */
>      if (av_sscanf(*arg, "%7[A-Z]%n", buf, &len)) {
> -        layout0 = layout = av_get_channel_layout(buf);
> -        /* channel_id <- first set bit in layout */
> -        for (i = 32; i > 0; i >>= 1) {
> -            if (layout >= 1LL << i) {
> -                channel_id += i;
> -                layout >>= i;
> -            }
> -        }
> -        /* reject layouts that are not a single channel */
> -        if (channel_id >= 64 || layout0 != 1LL << channel_id) {

You should keep the range check, because the id gets used as index into
vspkrpos[64].


> -            av_log(ctx, AV_LOG_WARNING, "Failed to parse \'%s\' as channel name.\n", buf);
> -            return AVERROR(EINVAL);
> -        }
> +        channel_id = av_channel_from_string(buf);
> +        if (channel_id < 0)
> +            return channel_id;
> +
>          *rchannel = channel_id;
>          *arg += len;
>          return 0;
> @@ -221,7 +211,7 @@ static int parse_channel_name(AVFilterContext *ctx, char **arg, int *rchannel)
>      return AVERROR(EINVAL);
>  }
>  
> -static void parse_speaker_pos(AVFilterContext *ctx, int64_t in_channel_layout)
> +static void parse_speaker_pos(AVFilterContext *ctx)
>  {
>      SOFAlizerContext *s = ctx->priv;
>      char *arg, *tokenizer, *p, *args = av_strdup(s->speakers_pos);
> @@ -256,10 +246,10 @@ static int get_speaker_pos(AVFilterContext *ctx,
>                             float *speaker_azim, float *speaker_elev)
>  {
>      struct SOFAlizerContext *s = ctx->priv;
> -    uint64_t channels_layout = ctx->inputs[0]->channel_layout;
> +    AVChannelLayout *channel_layout = &ctx->inputs[0]->ch_layout;
>      float azim[64] = { 0 };
>      float elev[64] = { 0 };
> -    int m, ch, n_conv = ctx->inputs[0]->channels; /* get no. input channels */
> +    int m, ch, n_conv = ctx->inputs[0]->ch_layout.nb_channels; /* get no. input channels */
>  
>      if (n_conv < 0 || n_conv > 64)
>          return AVERROR(EINVAL);
> @@ -267,45 +257,45 @@ static int get_speaker_pos(AVFilterContext *ctx,
>      s->lfe_channel = -1;
>  
>      if (s->speakers_pos)
> -        parse_speaker_pos(ctx, channels_layout);
> +        parse_speaker_pos(ctx);
>  
>      /* set speaker positions according to input channel configuration: */
>      for (m = 0, ch = 0; ch < n_conv && m < 64; m++) {
> -        uint64_t mask = channels_layout & (1ULL << m);
> -
> -        switch (mask) {
> -        case AV_CH_FRONT_LEFT:            azim[ch] =  30;      break;
> -        case AV_CH_FRONT_RIGHT:           azim[ch] = 330;      break;
> -        case AV_CH_FRONT_CENTER:          azim[ch] =   0;      break;
> -        case AV_CH_LOW_FREQUENCY:
> -        case AV_CH_LOW_FREQUENCY_2:       s->lfe_channel = ch; break;
> -        case AV_CH_BACK_LEFT:             azim[ch] = 150;      break;
> -        case AV_CH_BACK_RIGHT:            azim[ch] = 210;      break;
> -        case AV_CH_BACK_CENTER:           azim[ch] = 180;      break;
> -        case AV_CH_SIDE_LEFT:             azim[ch] =  90;      break;
> -        case AV_CH_SIDE_RIGHT:            azim[ch] = 270;      break;
> -        case AV_CH_FRONT_LEFT_OF_CENTER:  azim[ch] =  15;      break;
> -        case AV_CH_FRONT_RIGHT_OF_CENTER: azim[ch] = 345;      break;
> -        case AV_CH_TOP_CENTER:            azim[ch] =   0;
> +        int chan = av_channel_layout_channel_from_index(channel_layout, m);
> +
> +        switch (chan) {
> +        case AV_CHAN_FRONT_LEFT:          azim[ch] =  30;      break;
> +        case AV_CHAN_FRONT_RIGHT:         azim[ch] = 330;      break;
> +        case AV_CHAN_FRONT_CENTER:        azim[ch] =   0;      break;
> +        case AV_CHAN_LOW_FREQUENCY:
> +        case AV_CHAN_LOW_FREQUENCY_2:     s->lfe_channel = ch; break;
> +        case AV_CHAN_BACK_LEFT:           azim[ch] = 150;      break;
> +        case AV_CHAN_BACK_RIGHT:          azim[ch] = 210;      break;
> +        case AV_CHAN_BACK_CENTER:         azim[ch] = 180;      break;
> +        case AV_CHAN_SIDE_LEFT:           azim[ch] =  90;      break;
> +        case AV_CHAN_SIDE_RIGHT:          azim[ch] = 270;      break;
> +        case AV_CHAN_FRONT_LEFT_OF_CENTER:  azim[ch] =  15;    break;
> +        case AV_CHAN_FRONT_RIGHT_OF_CENTER: azim[ch] = 345;    break;
> +        case AV_CHAN_TOP_CENTER:          azim[ch] =   0;
>                                            elev[ch] =  90;      break;
> -        case AV_CH_TOP_FRONT_LEFT:        azim[ch] =  30;
> +        case AV_CHAN_TOP_FRONT_LEFT:      azim[ch] =  30;
>                                            elev[ch] =  45;      break;
> -        case AV_CH_TOP_FRONT_CENTER:      azim[ch] =   0;
> +        case AV_CHAN_TOP_FRONT_CENTER:    azim[ch] =   0;
>                                            elev[ch] =  45;      break;
> -        case AV_CH_TOP_FRONT_RIGHT:       azim[ch] = 330;
> +        case AV_CHAN_TOP_FRONT_RIGHT:     azim[ch] = 330;
>                                            elev[ch] =  45;      break;
> -        case AV_CH_TOP_BACK_LEFT:         azim[ch] = 150;
> +        case AV_CHAN_TOP_BACK_LEFT:       azim[ch] = 150;
>                                            elev[ch] =  45;      break;
> -        case AV_CH_TOP_BACK_RIGHT:        azim[ch] = 210;
> +        case AV_CHAN_TOP_BACK_RIGHT:      azim[ch] = 210;
>                                            elev[ch] =  45;      break;
> -        case AV_CH_TOP_BACK_CENTER:       azim[ch] = 180;
> +        case AV_CHAN_TOP_BACK_CENTER:     azim[ch] = 180;
>                                            elev[ch] =  45;      break;
> -        case AV_CH_WIDE_LEFT:             azim[ch] =  90;      break;
> -        case AV_CH_WIDE_RIGHT:            azim[ch] = 270;      break;
> -        case AV_CH_SURROUND_DIRECT_LEFT:  azim[ch] =  90;      break;
> -        case AV_CH_SURROUND_DIRECT_RIGHT: azim[ch] = 270;      break;
> -        case AV_CH_STEREO_LEFT:           azim[ch] =  90;      break;
> -        case AV_CH_STEREO_RIGHT:          azim[ch] = 270;      break;
> +        case AV_CHAN_WIDE_LEFT:           azim[ch] =  90;      break;
> +        case AV_CHAN_WIDE_RIGHT:          azim[ch] = 270;      break;
> +        case AV_CHAN_SURROUND_DIRECT_LEFT:  azim[ch] =  90;    break;
> +        case AV_CHAN_SURROUND_DIRECT_RIGHT: azim[ch] = 270;    break;
> +        case AV_CHAN_STEREO_LEFT:         azim[ch] =  90;      break;
> +        case AV_CHAN_STEREO_RIGHT:        azim[ch] = 270;      break;
>          case 0:                                                break;

case 0 makes no sense now

>          default:
>              return AVERROR(EINVAL);
> @@ -316,7 +306,7 @@ static int get_speaker_pos(AVFilterContext *ctx,
>              elev[ch] = s->vspkrpos[m].elev;
>          }
>  
> -        if (mask)
> +        if (chan)

and this check should be removed I think

> diff --git a/libavfilter/buffersink.h b/libavfilter/buffersink.h
> index 69ed0f29a8..ae90ae87fa 100644
> --- a/libavfilter/buffersink.h
> +++ b/libavfilter/buffersink.h
> @@ -46,7 +46,7 @@
>   * - av_buffersink_get_h(),
>   * - av_buffersink_get_sample_aspect_ratio(),
>   * - av_buffersink_get_channels(),
> - * - av_buffersink_get_channel_layout(),
> + * - av_buffersink_get_ch_layout(),

should mention that the layout should be uninited by the caller

> diff --git a/libavfilter/f_ebur128.c b/libavfilter/f_ebur128.c
> index 88d6a1fe46..2a6edba3d8 100644
> --- a/libavfilter/f_ebur128.c
> +++ b/libavfilter/f_ebur128.c
> @@ -422,7 +422,7 @@ static int config_audio_output(AVFilterLink *outlink)
>      int i;
>      AVFilterContext *ctx = outlink->src;
>      EBUR128Context *ebur128 = ctx->priv;
> -    const int nb_channels = av_get_channel_layout_nb_channels(outlink->channel_layout);
> +    const int nb_channels = outlink->ch_layout.nb_channels;
>  
>  #define BACK_MASK (AV_CH_BACK_LEFT    |AV_CH_BACK_CENTER    |AV_CH_BACK_RIGHT| \
>                     AV_CH_TOP_BACK_LEFT|AV_CH_TOP_BACK_CENTER|AV_CH_TOP_BACK_RIGHT| \
> @@ -439,8 +439,8 @@ static int config_audio_output(AVFilterLink *outlink)
>  
>      for (i = 0; i < nb_channels; i++) {
>          /* channel weighting */
> -        const uint64_t chl = av_channel_layout_extract_channel(outlink->channel_layout, i);
> -        if (chl & (AV_CH_LOW_FREQUENCY|AV_CH_LOW_FREQUENCY_2)) {
> +        const int chl = av_channel_layout_channel_from_index(&outlink->ch_layout, i);

enum AVChannel?

> +        if (chl == AV_CHAN_LOW_FREQUENCY || chl == AV_CHAN_LOW_FREQUENCY_2) {
>              ebur128->ch_weighting[i] = 0;
>          } else if (chl & BACK_MASK) {

This looks broken.

> diff --git a/libavfilter/formats.h b/libavfilter/formats.h
> index a884d15213..e55180f45c 100644
> --- a/libavfilter/formats.h
> +++ b/libavfilter/formats.h
> @@ -83,7 +83,7 @@ struct AVFilterFormats {
>   *   (e.g. AV_CH_LAYOUT_STEREO and FF_COUNT2LAYOUT(2).
>   */
>  struct AVFilterChannelLayouts {
> -    uint64_t *channel_layouts;  ///< list of channel layouts
> +    AVChannelLayout *channel_layouts; ///< list of channel layouts
>      int    nb_channel_layouts;  ///< number of channel layouts
>      char all_layouts;           ///< accept any known channel layout
>      char all_counts;            ///< accept any channel layout or count
> @@ -99,14 +99,16 @@ struct AVFilterChannelLayouts {
>   * The result is only valid inside AVFilterChannelLayouts and immediately
>   * related functions.
>   */
> -#define FF_COUNT2LAYOUT(c) (0x8000000000000000ULL | (c))
> +#define FF_COUNT2LAYOUT(c) ((AVChannelLayout) { .order = AV_CHANNEL_ORDER_UNSPEC, .nb_channels = c })
>  
>  /**
>   * Decode a channel count encoded as a channel layout.
>   * Return 0 if the channel layout was a real one.
>   */
> -#define FF_LAYOUT2COUNT(l) (((l) & 0x8000000000000000ULL) ? \
> -                           (int)((l) & 0x7FFFFFFF) : 0)
> +#define FF_LAYOUT2COUNT(l) (((l)->order == AV_CHANNEL_ORDER_UNSPEC) ? \
> +                            (l)->nb_channels : 0)
> +
> +#define KNOWN(l) (!FF_LAYOUT2COUNT(l)) /* for readability */
>  
>  /**
>   * Construct an empty AVFilterChannelLayouts/AVFilterFormats struct --
> @@ -126,7 +128,7 @@ av_warn_unused_result
>  AVFilterChannelLayouts *ff_all_channel_counts(void);
>  
>  av_warn_unused_result
> -AVFilterChannelLayouts *ff_make_format64_list(const int64_t *fmts);
> +AVFilterChannelLayouts *ff_make_format64_list(const AVChannelLayout *fmts);

The function name no longer makes sense
Anton Khirnov Feb. 15, 2022, 11:50 a.m. UTC | #2
Quoting James Almer (2022-01-13 03:09:07)
> diff --git a/libavfilter/af_aformat.c b/libavfilter/af_aformat.c
> index ed3c75311a..96704e041c 100644
> --- a/libavfilter/af_aformat.c
> +++ b/libavfilter/af_aformat.c
> @@ -104,9 +104,36 @@ static av_cold int init(AVFilterContext *ctx)
>                    ff_add_format, av_get_sample_fmt, AV_SAMPLE_FMT_NONE, "sample format");
>      PARSE_FORMATS(s->sample_rates_str, int, s->sample_rates, ff_add_format,
>                    get_sample_rate, 0, "sample rate");
> -    PARSE_FORMATS(s->channel_layouts_str, uint64_t, s->channel_layouts,
> -                  ff_add_channel_layout, av_get_channel_layout, 0,
> -                  "channel layout");
> +    {
> +        AVChannelLayout fmt = { 0 };
> +        const char *cur = s->channel_layouts_str;
> +        int ret;
> +
> +        if (s->channel_layouts_str && strchr(s->channel_layouts_str, ',')) {
> +            av_log(ctx, AV_LOG_WARNING, "This syntax is deprecated, use '|' to "
> +                   "separate channel layout.\n");

It might be unclear to the user what "this syntax" refers to, maybe make
it "Using ',' to separate channel layouts is deprecated"

> diff --git a/libavfilter/af_biquads.c b/libavfilter/af_biquads.c
> index ee42b2a034..2a0747a037 100644
> --- a/libavfilter/af_biquads.c
> +++ b/libavfilter/af_biquads.c
> @@ -125,7 +125,7 @@ typedef struct BiquadsContext {
>      double frequency;
>      double width;
>      double mix;
> -    uint64_t channels;
> +    AVChannelLayout ch_layout;
>      int normalize;
>      int order;
>  
> @@ -716,11 +716,11 @@ static int config_filter(AVFilterLink *outlink, int reset)
>          s->b2 *= factor;
>      }
>  
> -    s->cache = av_realloc_f(s->cache, sizeof(ChanCache), inlink->channels);
> +    s->cache = av_realloc_f(s->cache, sizeof(ChanCache), inlink->ch_layout.nb_channels);
>      if (!s->cache)
>          return AVERROR(ENOMEM);
>      if (reset)
> -        memset(s->cache, 0, sizeof(ChanCache) * inlink->channels);
> +        memset(s->cache, 0, sizeof(ChanCache) * inlink->ch_layout.nb_channels);
>  
>      switch (s->transform_type) {
>      case DI:
> @@ -838,12 +838,14 @@ static int filter_channel(AVFilterContext *ctx, void *arg, int jobnr, int nb_job
>      AVFrame *buf = td->in;
>      AVFrame *out_buf = td->out;
>      BiquadsContext *s = ctx->priv;
> -    const int start = (buf->channels * jobnr) / nb_jobs;
> -    const int end = (buf->channels * (jobnr+1)) / nb_jobs;
> +    const int start = (buf->ch_layout.nb_channels * jobnr) / nb_jobs;
> +    const int end = (buf->ch_layout.nb_channels * (jobnr+1)) / nb_jobs;
>      int ch;
>  
>      for (ch = start; ch < end; ch++) {
> -        if (!((av_channel_layout_extract_channel(inlink->channel_layout, ch) & s->channels))) {
> +        if (!(av_channel_layout_channel_from_index(&inlink->ch_layout, ch) >= 0 &&
> +              av_channel_layout_channel_from_index(&s->ch_layout, ch) >= 0)) {

This doesn't look right. The original code tests whether the channel
with index ch in inlink->channel_layout is present in s->channels.

The new code tests whether the channel with index ch exists in both
inlink->ch_layout and s->ch_layout (the test is also broken, because it
should compare against AV_CHAN_NONE).

Same applies to af_speechnorm

> diff --git a/libavfilter/af_headphone.c b/libavfilter/af_headphone.c
> index b2030dbbbb..2fe36368c1 100644
> --- a/libavfilter/af_headphone.c
> +++ b/libavfilter/af_headphone.c
> @@ -85,13 +85,13 @@ typedef struct HeadphoneContext {
>      uint64_t mapping[64];
>  } HeadphoneContext;
>  
> -static int parse_channel_name(const char *arg, uint64_t *rchannel)
> +static int parse_channel_name(const char *arg, int *rchannel)

enum AVChannel everywhere?

>  {
> -    uint64_t layout = av_get_channel_layout(arg);
> +    int channel = av_channel_from_string(arg);
>  
> -    if (av_get_channel_layout_nb_channels(layout) != 1)
> +    if (channel < 0)
>          return AVERROR(EINVAL);
> -    *rchannel = layout;
> +    *rchannel = channel;
>      return 0;
>  }
>  
> @@ -103,14 +103,14 @@ static void parse_map(AVFilterContext *ctx)
>  
>      p = s->map;
>      while ((arg = av_strtok(p, "|", &tokenizer))) {
> -        uint64_t out_channel;
> +        int out_channel;
>  
>          p = NULL;
>          if (parse_channel_name(arg, &out_channel)) {
>              av_log(ctx, AV_LOG_WARNING, "Failed to parse \'%s\' as channel name.\n", arg);
>              continue;
>          }
> -        if (used_channels & out_channel) {
> +        if (used_channels & (1ULL << out_channel)) {

should check that out_channel < 64

> diff --git a/libavfilter/af_surround.c b/libavfilter/af_surround.c
> index ccd85148e9..71d713e4ed 100644
> --- a/libavfilter/af_surround.c
> +++ b/libavfilter/af_surround.c
> @@ -92,8 +92,8 @@ typedef struct AudioSurroundContext {
>      float lowcut;
>      float highcut;
>  
> -    uint64_t out_channel_layout;
> -    uint64_t in_channel_layout;
> +    AVChannelLayout out_channel_layout;
> +    AVChannelLayout in_channel_layout;
>      int nb_in_channels;
>      int nb_out_channels;
>  
> @@ -171,7 +171,7 @@ static int query_formats(AVFilterContext *ctx)
>          return ret;
>  
>      layouts = NULL;
> -    ret = ff_add_channel_layout(&layouts, s->out_channel_layout);
> +    ret = ff_add_channel_layout(&layouts, &s->out_channel_layout);
>      if (ret)
>          return ret;
>  
> @@ -180,7 +180,7 @@ static int query_formats(AVFilterContext *ctx)
>          return ret;
>  
>      layouts = NULL;
> -    ret = ff_add_channel_layout(&layouts, s->in_channel_layout);
> +    ret = ff_add_channel_layout(&layouts, &s->in_channel_layout);
>      if (ret)
>          return ret;
>  
> @@ -197,12 +197,12 @@ static int config_input(AVFilterLink *inlink)
>      AudioSurroundContext *s = ctx->priv;
>      int ch;
>  
> -    s->rdft = av_calloc(inlink->channels, sizeof(*s->rdft));
> +    s->rdft = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->rdft));
>      if (!s->rdft)
>          return AVERROR(ENOMEM);
> -    s->nb_in_channels = inlink->channels;
> +    s->nb_in_channels = inlink->ch_layout.nb_channels;
>  
> -    for (ch = 0; ch < inlink->channels; ch++) {
> +    for (ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {
>          s->rdft[ch]  = av_rdft_init(ff_log2(s->buf_size), DFT_R2C);
>          if (!s->rdft[ch])
>              return AVERROR(ENOMEM);
> @@ -212,31 +212,31 @@ static int config_input(AVFilterLink *inlink)
>          return AVERROR(ENOMEM);
>      for (ch = 0;  ch < s->nb_in_channels; ch++)
>          s->input_levels[ch] = s->level_in;
> -    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_FRONT_CENTER);
> +    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_FRONT_CENTER);
>      if (ch >= 0)
>          s->input_levels[ch] *= s->fc_in;
> -    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_FRONT_LEFT);
> +    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_FRONT_LEFT);
>      if (ch >= 0)
>          s->input_levels[ch] *= s->fl_in;
> -    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_FRONT_RIGHT);
> +    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_FRONT_RIGHT);
>      if (ch >= 0)
>          s->input_levels[ch] *= s->fr_in;
> -    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_SIDE_LEFT);
> +    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_SIDE_LEFT);
>      if (ch >= 0)
>          s->input_levels[ch] *= s->sl_in;
> -    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_SIDE_RIGHT);
> +    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_SIDE_RIGHT);
>      if (ch >= 0)
>          s->input_levels[ch] *= s->sr_in;
> -    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_BACK_LEFT);
> +    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_BACK_LEFT);
>      if (ch >= 0)
>          s->input_levels[ch] *= s->bl_in;
> -    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_BACK_RIGHT);
> +    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_BACK_RIGHT);
>      if (ch >= 0)
>          s->input_levels[ch] *= s->br_in;
> -    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_BACK_CENTER);
> +    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_BACK_CENTER);
>      if (ch >= 0)
>          s->input_levels[ch] *= s->bc_in;
> -    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_LOW_FREQUENCY);
> +    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_LOW_FREQUENCY);
>      if (ch >= 0)

Make all those compare to AV_CHAN_NONE
James Almer Feb. 15, 2022, 12:27 p.m. UTC | #3
On 2/15/2022 8:50 AM, Anton Khirnov wrote:
> Quoting James Almer (2022-01-13 03:09:07)
>> @@ -212,31 +212,31 @@ static int config_input(AVFilterLink *inlink)
>>           return AVERROR(ENOMEM);
>>       for (ch = 0;  ch < s->nb_in_channels; ch++)
>>           s->input_levels[ch] = s->level_in;
>> -    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_FRONT_CENTER);
>> +    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_FRONT_CENTER);
>>       if (ch >= 0)
>>           s->input_levels[ch] *= s->fc_in;
>> -    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_FRONT_LEFT);
>> +    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_FRONT_LEFT);
>>       if (ch >= 0)
>>           s->input_levels[ch] *= s->fl_in;
>> -    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_FRONT_RIGHT);
>> +    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_FRONT_RIGHT);
>>       if (ch >= 0)
>>           s->input_levels[ch] *= s->fr_in;
>> -    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_SIDE_LEFT);
>> +    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_SIDE_LEFT);
>>       if (ch >= 0)
>>           s->input_levels[ch] *= s->sl_in;
>> -    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_SIDE_RIGHT);
>> +    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_SIDE_RIGHT);
>>       if (ch >= 0)
>>           s->input_levels[ch] *= s->sr_in;
>> -    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_BACK_LEFT);
>> +    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_BACK_LEFT);
>>       if (ch >= 0)
>>           s->input_levels[ch] *= s->bl_in;
>> -    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_BACK_RIGHT);
>> +    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_BACK_RIGHT);
>>       if (ch >= 0)
>>           s->input_levels[ch] *= s->br_in;
>> -    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_BACK_CENTER);
>> +    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_BACK_CENTER);
>>       if (ch >= 0)
>>           s->input_levels[ch] *= s->bc_in;
>> -    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_LOW_FREQUENCY);
>> +    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_LOW_FREQUENCY);
>>       if (ch >= 0)
> 
> Make all those compare to AV_CHAN_NONE

ch is an index, so either >= 0, or EINVAL.
Anton Khirnov Feb. 15, 2022, 12:34 p.m. UTC | #4
Quoting James Almer (2022-02-15 13:27:37)
> On 2/15/2022 8:50 AM, Anton Khirnov wrote:
> > Quoting James Almer (2022-01-13 03:09:07)
> >> @@ -212,31 +212,31 @@ static int config_input(AVFilterLink *inlink)
> >>           return AVERROR(ENOMEM);
> >>       for (ch = 0;  ch < s->nb_in_channels; ch++)
> >>           s->input_levels[ch] = s->level_in;
> >> -    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_FRONT_CENTER);
> >> +    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_FRONT_CENTER);
> >>       if (ch >= 0)
> >>           s->input_levels[ch] *= s->fc_in;
> >> -    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_FRONT_LEFT);
> >> +    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_FRONT_LEFT);
> >>       if (ch >= 0)
> >>           s->input_levels[ch] *= s->fl_in;
> >> -    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_FRONT_RIGHT);
> >> +    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_FRONT_RIGHT);
> >>       if (ch >= 0)
> >>           s->input_levels[ch] *= s->fr_in;
> >> -    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_SIDE_LEFT);
> >> +    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_SIDE_LEFT);
> >>       if (ch >= 0)
> >>           s->input_levels[ch] *= s->sl_in;
> >> -    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_SIDE_RIGHT);
> >> +    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_SIDE_RIGHT);
> >>       if (ch >= 0)
> >>           s->input_levels[ch] *= s->sr_in;
> >> -    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_BACK_LEFT);
> >> +    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_BACK_LEFT);
> >>       if (ch >= 0)
> >>           s->input_levels[ch] *= s->bl_in;
> >> -    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_BACK_RIGHT);
> >> +    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_BACK_RIGHT);
> >>       if (ch >= 0)
> >>           s->input_levels[ch] *= s->br_in;
> >> -    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_BACK_CENTER);
> >> +    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_BACK_CENTER);
> >>       if (ch >= 0)
> >>           s->input_levels[ch] *= s->bc_in;
> >> -    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_LOW_FREQUENCY);
> >> +    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_LOW_FREQUENCY);
> >>       if (ch >= 0)
> > 
> > Make all those compare to AV_CHAN_NONE
> 
> ch is an index, so either >= 0, or EINVAL.

right, nevermind then
James Almer Feb. 15, 2022, 6:52 p.m. UTC | #5
On 2/15/2022 8:50 AM, Anton Khirnov wrote:
> Quoting James Almer (2022-01-13 03:09:07)
>> diff --git a/libavfilter/af_aformat.c b/libavfilter/af_aformat.c
>> index ed3c75311a..96704e041c 100644
>> --- a/libavfilter/af_aformat.c
>> +++ b/libavfilter/af_aformat.c
>> @@ -104,9 +104,36 @@ static av_cold int init(AVFilterContext *ctx)
>>                     ff_add_format, av_get_sample_fmt, AV_SAMPLE_FMT_NONE, "sample format");
>>       PARSE_FORMATS(s->sample_rates_str, int, s->sample_rates, ff_add_format,
>>                     get_sample_rate, 0, "sample rate");
>> -    PARSE_FORMATS(s->channel_layouts_str, uint64_t, s->channel_layouts,
>> -                  ff_add_channel_layout, av_get_channel_layout, 0,
>> -                  "channel layout");
>> +    {
>> +        AVChannelLayout fmt = { 0 };
>> +        const char *cur = s->channel_layouts_str;
>> +        int ret;
>> +
>> +        if (s->channel_layouts_str && strchr(s->channel_layouts_str, ',')) {
>> +            av_log(ctx, AV_LOG_WARNING, "This syntax is deprecated, use '|' to "
>> +                   "separate channel layout.\n");
> It might be unclear to the user what "this syntax" refers to, maybe make
> it "Using ',' to separate channel layouts is deprecated"

This is copy-paste from the PARSE_FORMATS() macro. I'd rather leave 
changing it to a separate commit, and do it for sample rate and sample 
format too.
Anton Khirnov Feb. 16, 2022, 6:15 p.m. UTC | #6
Quoting James Almer (2022-01-13 03:09:07)
> diff --git a/libavfilter/af_channelsplit.c b/libavfilter/af_channelsplit.c
> index 1a2519dd32..31453823c5 100644
> --- a/libavfilter/af_channelsplit.c
> +++ b/libavfilter/af_channelsplit.c
> @@ -36,7 +36,7 @@
>  typedef struct ChannelSplitContext {
>      const AVClass *class;
>  
> -    uint64_t channel_layout;
> +    AVChannelLayout channel_layout;
>      char    *channel_layout_str;
>      char    *channels_str;
>  
> @@ -57,11 +57,11 @@ AVFILTER_DEFINE_CLASS(channelsplit);
>  static av_cold int init(AVFilterContext *ctx)
>  {
>      ChannelSplitContext *s = ctx->priv;
> -    uint64_t channel_layout;
> +    AVChannelLayout channel_layout = { 0 };
>      int nb_channels;
>      int all = 0, ret = 0, i;
>  
> -    if (!(s->channel_layout = av_get_channel_layout(s->channel_layout_str))) {
> +    if ((ret = av_channel_layout_from_string(&s->channel_layout, s->channel_layout_str)) < 0) {
>          av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout '%s'.\n",
>                 s->channel_layout_str);
>          ret = AVERROR(EINVAL);
> @@ -70,27 +70,32 @@ static av_cold int init(AVFilterContext *ctx)
>  
>  
>      if (!strcmp(s->channels_str, "all")) {
> -        nb_channels = av_get_channel_layout_nb_channels(s->channel_layout);
> +        nb_channels = s->channel_layout.nb_channels;
>          channel_layout = s->channel_layout;
>          all = 1;
>      } else {
> -        if ((ret = av_get_extended_channel_layout(s->channels_str, &channel_layout, &nb_channels)) < 0)
> +        if ((ret = av_channel_layout_from_string(&channel_layout, s->channels_str)) < 0)
>              return ret;
>      }
>  
>      for (i = 0; i < nb_channels; i++) {
> -        uint64_t channel = av_channel_layout_extract_channel(channel_layout, i);
> -        AVFilterPad pad  = { 0 };
> +        int channel = av_channel_layout_channel_from_index(&channel_layout, i);
> +        char buf[64];
> +        AVFilterPad pad = { .flags = AVFILTERPAD_FLAG_FREE_NAME };
>  
> +        av_channel_name(buf, sizeof(buf), channel);
>          pad.type = AVMEDIA_TYPE_AUDIO;
> -        pad.name = av_get_channel_name(channel);
> +        pad.name = av_strdup(buf);
> +        if (!pad.name)
> +            return AVERROR(ENOMEM);
>  
>          if (all) {
>              s->map[i] = i;

Should either make map dynamically allocated or check that there are
fewer than 64 channels in the layout.

>          } else {
> -            if ((ret = av_get_channel_layout_channel_index(s->channel_layout, channel)) < 0) {
> +            if ((ret = av_channel_layout_index_from_channel(&s->channel_layout, channel)) < 0) {
>                  av_log(ctx, AV_LOG_ERROR, "Channel name '%s' not present in channel layout '%s'.\n",
> -                       av_get_channel_name(channel), s->channel_layout_str);
> +                       pad.name, s->channel_layout_str);
> +                av_freep(&pad.name);
>                  return ret;
>              }
>  
> @@ -115,15 +120,18 @@ static int query_formats(AVFilterContext *ctx)
>          (ret = ff_set_common_all_samplerates(ctx)) < 0)
>          return ret;
>  
> -    if ((ret = ff_add_channel_layout(&in_layouts, s->channel_layout)) < 0 ||
> +    if ((ret = ff_add_channel_layout(&in_layouts, &s->channel_layout)) < 0 ||
>          (ret = ff_channel_layouts_ref(in_layouts, &ctx->inputs[0]->outcfg.channel_layouts)) < 0)
>          return ret;
>  
>      for (i = 0; i < ctx->nb_outputs; i++) {
> +        AVChannelLayout channel_layout = { 0 };
>          AVFilterChannelLayouts *out_layouts = NULL;
> -        uint64_t channel = av_channel_layout_extract_channel(s->channel_layout, s->map[i]);
> +        int channel = av_channel_layout_channel_from_index(&s->channel_layout, s->map[i]);
>  
> -        if ((ret = ff_add_channel_layout(&out_layouts, channel)) < 0 ||
> +        if ((channel < 0) ||
> +            (ret = av_channel_layout_from_mask(&channel_layout, 1ULL << channel)) < 0 ||
> +            (ret = ff_add_channel_layout(&out_layouts, &channel_layout)) < 0 ||
>              (ret = ff_channel_layouts_ref(out_layouts, &ctx->outputs[i]->incfg.channel_layouts)) < 0)
>              return ret;
>      }
> @@ -139,6 +147,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
>  
>      for (i = 0; i < ctx->nb_outputs; i++) {
>          AVFrame *buf_out = av_frame_clone(buf);
> +        int channel = av_channel_layout_channel_from_index(&buf->ch_layout, s->map[i]);
>  
>          if (!buf_out) {
>              ret = AVERROR(ENOMEM);
> @@ -146,9 +155,16 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
>          }
>  
>          buf_out->data[0] = buf_out->extended_data[0] = buf_out->extended_data[s->map[i]];
> +        ret = av_channel_layout_from_mask(&buf_out->ch_layout, 1ULL << channel);

potential invalid shift?

> diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
> index 7362bcdab5..acb2d7db51 100644
> --- a/libavfilter/avfilter.c
> +++ b/libavfilter/avfilter.c
> @@ -204,6 +204,7 @@ void avfilter_link_free(AVFilterLink **link)
>  
>      ff_framequeue_free(&(*link)->fifo);
>      ff_frame_pool_uninit((FFFramePool**)&(*link)->frame_pool);
> +    av_channel_layout_uninit(&(*link)->ch_layout);
>  
>      av_freep(link);
>  }
> @@ -405,7 +406,7 @@ void ff_tlog_link(void *ctx, AVFilterLink *link, int end)
>                  end ? "\n" : "");
>      } else {
>          char buf[128];
> -        av_get_channel_layout_string(buf, sizeof(buf), -1, link->channel_layout);
> +        av_channel_layout_describe(&link->ch_layout, buf, sizeof(buf));
>  
>          ff_tlog(ctx,
>                  "link[%p r:%d cl:%s fmt:%s %s->%s]%s",
> @@ -1036,11 +1037,21 @@ int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
>              av_log(link->dst, AV_LOG_ERROR, "Format change is not supported\n");
>              goto error;
>          }
> -        if (frame->channels != link->channels) {
> +#if FF_API_OLD_CHANNEL_LAYOUT
> +FF_DISABLE_DEPRECATION_WARNINGS
> +        if (frame->channels != link->ch_layout.nb_channels) {
>              av_log(link->dst, AV_LOG_ERROR, "Channel count change is not supported\n");
>              goto error;
>          }
> -        if (frame->channel_layout != link->channel_layout) {
> +        if (frame->channel_layout && frame->channel_layout != link->channel_layout) {
> +            av_log(link->dst, AV_LOG_ERROR, "Channel layout change is not supported\n");
> +            goto error;
> +        }
> +FF_ENABLE_DEPRECATION_WARNINGS
> +        if (av_channel_layout_check(&frame->ch_layout) && av_channel_layout_compare(&frame->ch_layout, &link->ch_layout)) {
> +#else
> +        if (av_channel_layout_compare(&frame->ch_layout, &link->ch_layout)) {
> +#endif

Is all this still needed? Presumably after this patch all sources make
sure the old and new fields are in sync, so we could just assert here,
or not check at all.

> diff --git a/libavfilter/src_movie.c b/libavfilter/src_movie.c
> index b89a680883..3ebd279df7 100644
> --- a/libavfilter/src_movie.c
> +++ b/libavfilter/src_movie.c
> @@ -189,23 +189,24 @@ static int guess_channel_layout(MovieStream *st, int st_index, void *log_ctx)
>  {
>      AVCodecParameters *dec_par = st->st->codecpar;
>      char buf[256];
> -    int64_t chl = av_get_default_channel_layout(dec_par->channels);
> +    AVChannelLayout chl = { 0 };
>  
> -    if (!chl) {
> +    av_channel_layout_default(&chl, dec_par->ch_layout.nb_channels);
> +
> +    if (!KNOWN(&chl)) {
>          av_log(log_ctx, AV_LOG_ERROR,
>                 "Channel layout is not set in stream %d, and could not "
>                 "be guessed from the number of channels (%d)\n",
> -               st_index, dec_par->channels);
> +               st_index, dec_par->ch_layout.nb_channels);
>          return AVERROR(EINVAL);

Should this still be an error? Unspec layouts should now be properly
supported by (almost?) everything.
James Almer Feb. 18, 2022, 1:07 p.m. UTC | #7
On 2/16/2022 3:15 PM, Anton Khirnov wrote:
>> diff --git a/libavfilter/src_movie.c b/libavfilter/src_movie.c
>> index b89a680883..3ebd279df7 100644
>> --- a/libavfilter/src_movie.c
>> +++ b/libavfilter/src_movie.c
>> @@ -189,23 +189,24 @@ static int guess_channel_layout(MovieStream *st, int st_index, void *log_ctx)
>>   {
>>       AVCodecParameters *dec_par = st->st->codecpar;
>>       char buf[256];
>> -    int64_t chl = av_get_default_channel_layout(dec_par->channels);
>> +    AVChannelLayout chl = { 0 };
>>   
>> -    if (!chl) {
>> +    av_channel_layout_default(&chl, dec_par->ch_layout.nb_channels);
>> +
>> +    if (!KNOWN(&chl)) {
>>           av_log(log_ctx, AV_LOG_ERROR,
>>                  "Channel layout is not set in stream %d, and could not "
>>                  "be guessed from the number of channels (%d)\n",
>> -               st_index, dec_par->channels);
>> +               st_index, dec_par->ch_layout.nb_channels);
>>           return AVERROR(EINVAL);
> Should this still be an error? Unspec layouts should now be properly
> supported by (almost?) everything.

Probably, but making it no longer abort if a native channel layout can't 
be guessed is a behavior change that I'd rather leave for a different 
patch, if you don't mind.

> 
> -- Anton Khirnov _______________________________________________ 
> ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org 
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit 
> link above, or email ffmpeg-devel-request@ffmpeg.org with subject 
> "unsubscribe".
diff mbox series

Patch

diff --git a/libavfilter/aeval.c b/libavfilter/aeval.c
index 42cfa81325..86cb0990dd 100644
--- a/libavfilter/aeval.c
+++ b/libavfilter/aeval.c
@@ -57,7 +57,7 @@  typedef struct EvalContext {
     const AVClass *class;
     char *sample_rate_str;
     int sample_rate;
-    int64_t chlayout;
+    AVChannelLayout chlayout;
     char *chlayout_str;
     int nb_channels;            ///< number of output channels
     int nb_in_channels;         ///< number of input channels
@@ -70,7 +70,6 @@  typedef struct EvalContext {
     uint64_t n;
     double var_values[VAR_VARS_NB];
     double *channel_values;
-    int64_t out_channel_layout;
 } EvalContext;
 
 static double val(void *priv, double ch)
@@ -181,7 +180,7 @@  static av_cold int init(AVFilterContext *ctx)
             if (ret < 0)
                 return ret;
 
-            ret = parse_channel_expressions(ctx, av_get_channel_layout_nb_channels(eval->chlayout));
+            ret = parse_channel_expressions(ctx, eval->chlayout.nb_channels);
             if (ret < 0)
                 return ret;
         }
@@ -190,8 +189,8 @@  static av_cold int init(AVFilterContext *ctx)
         if ((ret = parse_channel_expressions(ctx, -1)) < 0)
             return ret;
 
-        eval->chlayout = av_get_default_channel_layout(eval->nb_channels);
-        if (!eval->chlayout && eval->nb_channels <= 0) {
+        av_channel_layout_default(&eval->chlayout, eval->nb_channels);
+        if (eval->nb_channels <= 0) {
             av_log(ctx, AV_LOG_ERROR, "Invalid number of channels '%d' provided\n",
                    eval->nb_channels);
             return AVERROR(EINVAL);
@@ -217,6 +216,7 @@  static av_cold void uninit(AVFilterContext *ctx)
     }
     av_freep(&eval->expr);
     av_freep(&eval->channel_values);
+    av_channel_layout_uninit(&eval->chlayout);
 }
 
 static int config_props(AVFilterLink *outlink)
@@ -229,9 +229,9 @@  static int config_props(AVFilterLink *outlink)
 
     eval->var_values[VAR_S] = eval->sample_rate;
     eval->var_values[VAR_NB_IN_CHANNELS] = NAN;
-    eval->var_values[VAR_NB_OUT_CHANNELS] = outlink->channels;
+    eval->var_values[VAR_NB_OUT_CHANNELS] = outlink->ch_layout.nb_channels;
 
-    av_get_channel_layout_string(buf, sizeof(buf), 0, eval->chlayout);
+    av_channel_layout_describe(&eval->chlayout, buf, sizeof(buf));
 
     av_log(outlink->src, AV_LOG_VERBOSE,
            "sample_rate:%d chlayout:%s duration:%"PRId64"\n",
@@ -244,7 +244,7 @@  static int query_formats(AVFilterContext *ctx)
 {
     EvalContext *eval = ctx->priv;
     static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_DBLP, AV_SAMPLE_FMT_NONE };
-    int64_t chlayouts[] = { eval->chlayout ? eval->chlayout : FF_COUNT2LAYOUT(eval->nb_channels) , -1 };
+    AVChannelLayout chlayouts[] = { eval->chlayout.nb_channels ? eval->chlayout : FF_COUNT2LAYOUT(eval->nb_channels), { 0 } };
     int sample_rates[] = { eval->sample_rate, -1 };
     int ret;
 
@@ -365,9 +365,7 @@  static int aeval_query_formats(AVFilterContext *ctx)
     } else {
         // outlink supports only requested output channel layout
         layouts = NULL;
-        if ((ret = ff_add_channel_layout(&layouts,
-                              eval->out_channel_layout ? eval->out_channel_layout :
-                              FF_COUNT2LAYOUT(eval->nb_channels))) < 0)
+        if ((ret = ff_add_channel_layout(&layouts, &FF_COUNT2LAYOUT(eval->nb_channels))) < 0)
             return ret;
         if ((ret = ff_channel_layouts_ref(layouts, &outlink->incfg.channel_layouts)) < 0)
             return ret;
@@ -387,20 +385,21 @@  static int aeval_config_output(AVFilterLink *outlink)
     int ret;
 
     if (eval->same_chlayout) {
-        eval->chlayout = inlink->channel_layout;
+        if ((ret = av_channel_layout_copy(&eval->chlayout, &inlink->ch_layout)) < 0)
+            return ret;
 
-        if ((ret = parse_channel_expressions(ctx, inlink->channels)) < 0)
+        if ((ret = parse_channel_expressions(ctx, inlink->ch_layout.nb_channels)) < 0)
             return ret;
     }
 
     eval->n = 0;
-    eval->nb_in_channels = eval->var_values[VAR_NB_IN_CHANNELS] = inlink->channels;
-    eval->var_values[VAR_NB_OUT_CHANNELS] = outlink->channels;
+    eval->nb_in_channels = eval->var_values[VAR_NB_IN_CHANNELS] = inlink->ch_layout.nb_channels;
+    eval->var_values[VAR_NB_OUT_CHANNELS] = outlink->ch_layout.nb_channels;
     eval->var_values[VAR_S] = inlink->sample_rate;
     eval->var_values[VAR_T] = NAN;
 
     eval->channel_values = av_realloc_f(eval->channel_values,
-                                        inlink->channels, sizeof(*eval->channel_values));
+                                        inlink->ch_layout.nb_channels, sizeof(*eval->channel_values));
     if (!eval->channel_values)
         return AVERROR(ENOMEM);
 
@@ -430,10 +429,10 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
         eval->var_values[VAR_N] = eval->n;
         eval->var_values[VAR_T] = t0 + i * (double)1/inlink->sample_rate;
 
-        for (j = 0; j < inlink->channels; j++)
+        for (j = 0; j < inlink->ch_layout.nb_channels; j++)
             eval->channel_values[j] = *((double *) in->extended_data[j] + i);
 
-        for (j = 0; j < outlink->channels; j++) {
+        for (j = 0; j < outlink->ch_layout.nb_channels; j++) {
             eval->var_values[VAR_CH] = j;
             *((double *) out->extended_data[j] + i) =
                 av_expr_eval(eval->expr[j], eval->var_values, eval);
diff --git a/libavfilter/af_acontrast.c b/libavfilter/af_acontrast.c
index db7ff79d25..a4ed29e30a 100644
--- a/libavfilter/af_acontrast.c
+++ b/libavfilter/af_acontrast.c
@@ -152,7 +152,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     }
 
     s->filter((void **)out->extended_data, (const void **)in->extended_data,
-              in->nb_samples, in->channels, s->contrast / 750);
+              in->nb_samples, in->ch_layout.nb_channels, s->contrast / 750);
 
     if (out != in)
         av_frame_free(&in);
diff --git a/libavfilter/af_acrossover.c b/libavfilter/af_acrossover.c
index 9c00e1ddc2..05ea53fd83 100644
--- a/libavfilter/af_acrossover.c
+++ b/libavfilter/af_acrossover.c
@@ -356,8 +356,8 @@  static int filter_channels_## name(AVFilterContext *ctx, void *arg, int jobnr, i
     AudioCrossoverContext *s = ctx->priv;                                                   \
     AVFrame *in = s->input_frame;                                                           \
     AVFrame **frames = s->frames;                                                           \
-    const int start = (in->channels * jobnr) / nb_jobs;                                     \
-    const int end = (in->channels * (jobnr+1)) / nb_jobs;                                   \
+    const int start = (in->ch_layout.nb_channels * jobnr) / nb_jobs;                        \
+    const int end = (in->ch_layout.nb_channels * (jobnr+1)) / nb_jobs;                      \
     const int nb_samples = in->nb_samples;                                                  \
     const int nb_outs = ctx->nb_outputs;                                                    \
     const int first_order = s->first_order;                                                 \
@@ -498,7 +498,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 
     s->input_frame = in;
     ff_filter_execute(ctx, s->filter_channels, NULL, NULL,
-                      FFMIN(inlink->channels, ff_filter_get_nb_threads(ctx)));
+                      FFMIN(inlink->ch_layout.nb_channels, ff_filter_get_nb_threads(ctx)));
 
     for (i = 0; i < ctx->nb_outputs; i++) {
         ret = ff_filter_frame(ctx->outputs[i], frames[i]);
diff --git a/libavfilter/af_acrusher.c b/libavfilter/af_acrusher.c
index 14d66e88ea..d59211ee29 100644
--- a/libavfilter/af_acrusher.c
+++ b/libavfilter/af_acrusher.c
@@ -244,7 +244,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
             s->round = round(s->samples);
         }
 
-        for (c = 0; c < inlink->channels; c++) {
+        for (c = 0; c < inlink->ch_layout.nb_channels; c++) {
             double sample = src[c] * level_in;
 
             sample = mix * samplereduction(s, &s->sr[c], sample) + src[c] * (1. - mix) * level_in;
@@ -296,7 +296,7 @@  static int config_input(AVFilterLink *inlink)
     s->lfo.amount = .5;
 
     if (!s->sr)
-        s->sr = av_calloc(inlink->channels, sizeof(*s->sr));
+        s->sr = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->sr));
     if (!s->sr)
         return AVERROR(ENOMEM);
 
diff --git a/libavfilter/af_adeclick.c b/libavfilter/af_adeclick.c
index 77336e50bb..2db9a29fd3 100644
--- a/libavfilter/af_adeclick.c
+++ b/libavfilter/af_adeclick.c
@@ -151,7 +151,7 @@  static int config_input(AVFilterLink *inlink)
     s->efifo = av_audio_fifo_alloc(inlink->format, 1, s->window_size);
     if (!s->efifo)
         return AVERROR(ENOMEM);
-    s->fifo = av_audio_fifo_alloc(inlink->format, inlink->channels, s->window_size);
+    s->fifo = av_audio_fifo_alloc(inlink->format, inlink->ch_layout.nb_channels, s->window_size);
     if (!s->fifo)
         return AVERROR(ENOMEM);
     s->overlap_skip = s->method ? (s->window_size - s->hop_size) / 2 : 0;
@@ -160,12 +160,12 @@  static int config_input(AVFilterLink *inlink)
                             s->overlap_skip);
     }
 
-    s->nb_channels = inlink->channels;
-    s->chan = av_calloc(inlink->channels, sizeof(*s->chan));
+    s->nb_channels = inlink->ch_layout.nb_channels;
+    s->chan = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->chan));
     if (!s->chan)
         return AVERROR(ENOMEM);
 
-    for (i = 0; i < inlink->channels; i++) {
+    for (i = 0; i < inlink->ch_layout.nb_channels; i++) {
         DeclickChannel *c = &s->chan[i];
 
         c->detection = av_calloc(s->window_size, sizeof(*c->detection));
@@ -557,11 +557,11 @@  static int filter_frame(AVFilterLink *inlink)
         goto fail;
 
     td.out = out;
-    ret = ff_filter_execute(ctx, filter_channel, &td, NULL, inlink->channels);
+    ret = ff_filter_execute(ctx, filter_channel, &td, NULL, inlink->ch_layout.nb_channels);
     if (ret < 0)
         goto fail;
 
-    for (ch = 0; ch < s->in->channels; ch++) {
+    for (ch = 0; ch < s->in->ch_layout.nb_channels; ch++) {
         double *is = (double *)s->is->extended_data[ch];
 
         for (j = 0; j < s->hop_size; j++) {
@@ -580,7 +580,7 @@  static int filter_frame(AVFilterLink *inlink)
     s->pts += av_rescale_q(s->hop_size, (AVRational){1, outlink->sample_rate}, outlink->time_base);
 
     s->detected_errors += detected_errors;
-    s->nb_samples += out->nb_samples * inlink->channels;
+    s->nb_samples += out->nb_samples * inlink->ch_layout.nb_channels;
 
     ret = ff_filter_frame(outlink, out);
     if (ret < 0)
diff --git a/libavfilter/af_adecorrelate.c b/libavfilter/af_adecorrelate.c
index bac7937c10..cadc62c1f7 100644
--- a/libavfilter/af_adecorrelate.c
+++ b/libavfilter/af_adecorrelate.c
@@ -131,12 +131,12 @@  static int config_input(AVFilterLink *inlink)
         s->seed = av_get_random_seed();
     av_lfg_init(&s->c, s->seed);
 
-    s->nb_channels = inlink->channels;
-    s->ap = av_calloc(inlink->channels, sizeof(*s->ap));
+    s->nb_channels = inlink->ch_layout.nb_channels;
+    s->ap = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->ap));
     if (!s->ap)
         return AVERROR(ENOMEM);
 
-    for (int i = 0; i < inlink->channels; i++) {
+    for (int i = 0; i < inlink->ch_layout.nb_channels; i++) {
         for (int j = 0; j < s->stages; j++) {
             ret = ap_init(&s->ap[i][j], inlink->sample_rate,
                           (double)av_lfg_get(&s->c) / 0xffffffff * 2.2917e-3 + 0.83333e-3);
@@ -160,8 +160,8 @@  static int filter_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo
     ThreadData *td = arg;
     AVFrame *out = td->out;
     AVFrame *in = td->in;
-    const int start = (in->channels * jobnr) / nb_jobs;
-    const int end = (in->channels * (jobnr+1)) / nb_jobs;
+    const int start = (in->ch_layout.nb_channels * jobnr) / nb_jobs;
+    const int end = (in->ch_layout.nb_channels * (jobnr+1)) / nb_jobs;
 
     for (int ch = start; ch < end; ch++)
         s->filter_channel(ctx, ch, in, out);
@@ -189,7 +189,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 
     td.in = in; td.out = out;
     ff_filter_execute(ctx, filter_channels, &td, NULL,
-                      FFMIN(inlink->channels, ff_filter_get_nb_threads(ctx)));
+                      FFMIN(inlink->ch_layout.nb_channels, ff_filter_get_nb_threads(ctx)));
 
     if (out != in)
         av_frame_free(&in);
diff --git a/libavfilter/af_adelay.c b/libavfilter/af_adelay.c
index ed8a8ae739..c7a8763b36 100644
--- a/libavfilter/af_adelay.c
+++ b/libavfilter/af_adelay.c
@@ -103,10 +103,10 @@  static int config_input(AVFilterLink *inlink)
     char *p, *arg, *saveptr = NULL;
     int i;
 
-    s->chandelay = av_calloc(inlink->channels, sizeof(*s->chandelay));
+    s->chandelay = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->chandelay));
     if (!s->chandelay)
         return AVERROR(ENOMEM);
-    s->nb_delays = inlink->channels;
+    s->nb_delays = inlink->ch_layout.nb_channels;
     s->block_align = av_get_bytes_per_sample(inlink->format);
 
     p = s->delays;
@@ -242,7 +242,7 @@  static int activate(AVFilterContext *ctx)
 
         av_samples_set_silence(frame->extended_data, 0,
                                frame->nb_samples,
-                               outlink->channels,
+                               outlink->ch_layout.nb_channels,
                                frame->format);
 
         frame->pts = s->next_pts;
@@ -274,7 +274,7 @@  static int activate(AVFilterContext *ctx)
 
         av_samples_set_silence(frame->extended_data, 0,
                                frame->nb_samples,
-                               outlink->channels,
+                               outlink->ch_layout.nb_channels,
                                frame->format);
 
         frame->pts = s->next_pts;
diff --git a/libavfilter/af_adenorm.c b/libavfilter/af_adenorm.c
index 3ad1e7f594..04e3338b1a 100644
--- a/libavfilter/af_adenorm.c
+++ b/libavfilter/af_adenorm.c
@@ -200,8 +200,8 @@  static int filter_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo
     ThreadData *td = arg;
     AVFrame *out = td->out;
     AVFrame *in = td->in;
-    const int start = (in->channels * jobnr) / nb_jobs;
-    const int end = (in->channels * (jobnr+1)) / nb_jobs;
+    const int start = (in->ch_layout.nb_channels * jobnr) / nb_jobs;
+    const int end = (in->ch_layout.nb_channels * (jobnr+1)) / nb_jobs;
 
     for (int ch = start; ch < end; ch++) {
         s->filter(ctx, out->extended_data[ch],
@@ -234,7 +234,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     s->level = exp(s->level_db / 20. * M_LN10);
     td.in = in; td.out = out;
     ff_filter_execute(ctx, filter_channels, &td, NULL,
-                      FFMIN(inlink->channels, ff_filter_get_nb_threads(ctx)));
+                      FFMIN(inlink->ch_layout.nb_channels, ff_filter_get_nb_threads(ctx)));
 
     s->in_samples += in->nb_samples;
 
diff --git a/libavfilter/af_aderivative.c b/libavfilter/af_aderivative.c
index baa272d609..0ebb233a58 100644
--- a/libavfilter/af_aderivative.c
+++ b/libavfilter/af_aderivative.c
@@ -120,7 +120,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     }
 
     s->filter((void **)out->extended_data, (void **)s->prev->extended_data, (const void **)in->extended_data,
-              in->nb_samples, in->channels);
+              in->nb_samples, in->ch_layout.nb_channels);
 
     av_frame_free(&in);
     return ff_filter_frame(outlink, out);
diff --git a/libavfilter/af_adynamicequalizer.c b/libavfilter/af_adynamicequalizer.c
index f377a5db3d..4ebdd1815d 100644
--- a/libavfilter/af_adynamicequalizer.c
+++ b/libavfilter/af_adynamicequalizer.c
@@ -157,8 +157,8 @@  static int filter_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo
     const double tqfactor = s->tqfactor;
     const double fg = tan(M_PI * tfrequency / sample_rate);
     const double dg = tan(M_PI * dfrequency / sample_rate);
-    const int start = (in->channels * jobnr) / nb_jobs;
-    const int end = (in->channels * (jobnr+1)) / nb_jobs;
+    const int start = (in->ch_layout.nb_channels * jobnr) / nb_jobs;
+    const int end = (in->ch_layout.nb_channels * (jobnr+1)) / nb_jobs;
     const int mode = s->mode;
     const double knee = s->knee;
     const double slew = s->slew;
@@ -245,7 +245,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     td.in = in;
     td.out = out;
     ff_filter_execute(ctx, filter_channels, &td, NULL,
-                     FFMIN(outlink->channels, ff_filter_get_nb_threads(ctx)));
+                     FFMIN(outlink->ch_layout.nb_channels, ff_filter_get_nb_threads(ctx)));
 
     if (out != in)
         av_frame_free(&in);
diff --git a/libavfilter/af_adynamicsmooth.c b/libavfilter/af_adynamicsmooth.c
index 4e00fecc6a..3f98d09f5d 100644
--- a/libavfilter/af_adynamicsmooth.c
+++ b/libavfilter/af_adynamicsmooth.c
@@ -63,7 +63,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
         av_frame_copy_props(out, in);
     }
 
-    for (int ch = 0; ch < out->channels; ch++) {
+    for (int ch = 0; ch < out->ch_layout.nb_channels; ch++) {
         const double *src = (const double *)in->extended_data[ch];
         double *dst = (double *)out->extended_data[ch];
         double *coeffs = (double *)s->coeffs->extended_data[ch];
diff --git a/libavfilter/af_aecho.c b/libavfilter/af_aecho.c
index 73d9f1ac7f..e610c30d59 100644
--- a/libavfilter/af_aecho.c
+++ b/libavfilter/af_aecho.c
@@ -236,7 +236,7 @@  static int config_output(AVFilterLink *outlink)
     av_freep(&s->delayptrs);
 
     return av_samples_alloc_array_and_samples(&s->delayptrs, NULL,
-                                              outlink->channels,
+                                              outlink->ch_layout.nb_channels,
                                               s->max_samples,
                                               outlink->format, 0);
 }
@@ -259,7 +259,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
     }
 
     s->echo_samples(s, s->delayptrs, frame->extended_data, out_frame->extended_data,
-                    frame->nb_samples, inlink->channels);
+                    frame->nb_samples, inlink->ch_layout.nb_channels);
 
     s->next_pts = frame->pts + av_rescale_q(frame->nb_samples, (AVRational){1, inlink->sample_rate}, inlink->time_base);
 
@@ -282,11 +282,11 @@  static int request_frame(AVFilterLink *outlink)
 
     av_samples_set_silence(frame->extended_data, 0,
                            frame->nb_samples,
-                           outlink->channels,
+                           outlink->ch_layout.nb_channels,
                            frame->format);
 
     s->echo_samples(s, s->delayptrs, frame->extended_data, frame->extended_data,
-                    frame->nb_samples, outlink->channels);
+                    frame->nb_samples, outlink->ch_layout.nb_channels);
 
     frame->pts = s->next_pts;
     if (s->next_pts != AV_NOPTS_VALUE)
diff --git a/libavfilter/af_aemphasis.c b/libavfilter/af_aemphasis.c
index 1adfcdb63b..91878987d3 100644
--- a/libavfilter/af_aemphasis.c
+++ b/libavfilter/af_aemphasis.c
@@ -105,8 +105,8 @@  static int filter_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo
     ThreadData *td = arg;
     AVFrame *out = td->out;
     AVFrame *in = td->in;
-    const int start = (in->channels * jobnr) / nb_jobs;
-    const int end = (in->channels * (jobnr+1)) / nb_jobs;
+    const int start = (in->ch_layout.nb_channels * jobnr) / nb_jobs;
+    const int end = (in->ch_layout.nb_channels * (jobnr+1)) / nb_jobs;
 
     for (int ch = start; ch < end; ch++) {
         const double *src = (const double *)in->extended_data[ch];
@@ -144,7 +144,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 
     td.in = in; td.out = out;
     ff_filter_execute(ctx, filter_channels, &td, NULL,
-                      FFMIN(inlink->channels, ff_filter_get_nb_threads(ctx)));
+                      FFMIN(inlink->ch_layout.nb_channels, ff_filter_get_nb_threads(ctx)));
 
     if (in != out)
         av_frame_free(&in);
diff --git a/libavfilter/af_aexciter.c b/libavfilter/af_aexciter.c
index 5d76f290a0..8e829f992b 100644
--- a/libavfilter/af_aexciter.c
+++ b/libavfilter/af_aexciter.c
@@ -195,7 +195,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 
     dst = (double *)out->data[0];
     for (int n = 0; n < in->nb_samples; n++) {
-        for (int c = 0; c < inlink->channels; c++) {
+        for (int c = 0; c < inlink->ch_layout.nb_channels; c++) {
             double sample = src[c] * level_in;
 
             sample = distortion_process(s, &s->cp[c], sample);
@@ -208,8 +208,8 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
                 dst[c] = sample;
         }
 
-        src += inlink->channels;
-        dst += inlink->channels;
+        src += inlink->ch_layout.nb_channels;
+        dst += inlink->ch_layout.nb_channels;
     }
 
     if (in != out)
@@ -231,11 +231,11 @@  static int config_input(AVFilterLink *inlink)
     AExciterContext *s = ctx->priv;
 
     if (!s->cp)
-        s->cp = av_calloc(inlink->channels, sizeof(*s->cp));
+        s->cp = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->cp));
     if (!s->cp)
         return AVERROR(ENOMEM);
 
-    for (int i = 0; i < inlink->channels; i++)
+    for (int i = 0; i < inlink->ch_layout.nb_channels; i++)
         set_params(&s->cp[i], s->blend, s->drive, inlink->sample_rate,
                    s->freq, s->ceil);
 
diff --git a/libavfilter/af_afade.c b/libavfilter/af_afade.c
index c57709050e..e31467ee2b 100644
--- a/libavfilter/af_afade.c
+++ b/libavfilter/af_afade.c
@@ -289,7 +289,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
     if ((!s->type && (cur_sample + nb_samples < s->start_sample)) ||
         ( s->type && (s->start_sample + s->nb_samples < cur_sample))) {
         av_samples_set_silence(out_buf->extended_data, 0, nb_samples,
-                               out_buf->channels, out_buf->format);
+                               out_buf->ch_layout.nb_channels, out_buf->format);
     } else {
         int64_t start;
 
@@ -299,7 +299,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
             start = s->start_sample + s->nb_samples - cur_sample;
 
         s->fade_samples(out_buf->extended_data, buf->extended_data,
-                        nb_samples, buf->channels,
+                        nb_samples, buf->ch_layout.nb_channels,
                         s->type ? -1 : 1, start,
                         s->nb_samples, s->curve);
     }
@@ -502,7 +502,7 @@  static int activate(AVFilterContext *ctx)
 
             s->crossfade_samples(out->extended_data, cf[0]->extended_data,
                                  cf[1]->extended_data,
-                                 s->nb_samples, out->channels,
+                                 s->nb_samples, out->ch_layout.nb_channels,
                                  s->curve, s->curve2);
             out->pts = s->pts;
             s->pts += av_rescale_q(s->nb_samples,
@@ -523,7 +523,7 @@  static int activate(AVFilterContext *ctx)
             }
 
             s->fade_samples(out->extended_data, cf[0]->extended_data, s->nb_samples,
-                            outlink->channels, -1, s->nb_samples - 1, s->nb_samples, s->curve);
+                            outlink->ch_layout.nb_channels, -1, s->nb_samples - 1, s->nb_samples, s->curve);
             out->pts = s->pts;
             s->pts += av_rescale_q(s->nb_samples,
                 (AVRational){ 1, outlink->sample_rate }, outlink->time_base);
@@ -543,7 +543,7 @@  static int activate(AVFilterContext *ctx)
             }
 
             s->fade_samples(out->extended_data, cf[1]->extended_data, s->nb_samples,
-                            outlink->channels, 1, 0, s->nb_samples, s->curve2);
+                            outlink->ch_layout.nb_channels, 1, 0, s->nb_samples, s->curve2);
             out->pts = s->pts;
             s->pts += av_rescale_q(s->nb_samples,
                 (AVRational){ 1, outlink->sample_rate }, outlink->time_base);
diff --git a/libavfilter/af_afftdn.c b/libavfilter/af_afftdn.c
index d1dbbc667b..a70a969ab9 100644
--- a/libavfilter/af_afftdn.c
+++ b/libavfilter/af_afftdn.c
@@ -616,12 +616,12 @@  static int config_input(AVFilterLink *inlink)
     double wscale, sar, sum, sdiv;
     int i, j, k, m, n, ret;
 
-    s->dnch = av_calloc(inlink->channels, sizeof(*s->dnch));
+    s->dnch = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->dnch));
     if (!s->dnch)
         return AVERROR(ENOMEM);
 
     s->pts = AV_NOPTS_VALUE;
-    s->channels = inlink->channels;
+    s->channels = inlink->ch_layout.nb_channels;
     s->sample_rate = inlink->sample_rate;
     s->sample_advance = s->sample_rate / 80;
     s->window_length = 3 * s->sample_advance;
@@ -680,7 +680,7 @@  static int config_input(AVFilterLink *inlink)
     if (!s->band_alpha || !s->band_beta)
         return AVERROR(ENOMEM);
 
-    for (int ch = 0; ch < inlink->channels; ch++) {
+    for (int ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {
         DeNoiseChannel *dnch = &s->dnch[ch];
         float scale;
 
@@ -761,7 +761,7 @@  static int config_input(AVFilterLink *inlink)
             return AVERROR(ENOMEM);
     }
 
-    for (int ch = 0; ch < inlink->channels; ch++) {
+    for (int ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {
         DeNoiseChannel *dnch = &s->dnch[ch];
         double *prior_band_excit = dnch->prior_band_excit;
         double *prior = dnch->prior;
@@ -857,7 +857,7 @@  static int config_input(AVFilterLink *inlink)
     }
     s->noise_band_count = s->noise_band_edge[16];
 
-    s->fifo = av_audio_fifo_alloc(inlink->format, inlink->channels, s->fft_length);
+    s->fifo = av_audio_fifo_alloc(inlink->format, inlink->ch_layout.nb_channels, s->fft_length);
     if (!s->fifo)
         return AVERROR(ENOMEM);
 
@@ -1095,8 +1095,8 @@  static int filter_channel(AVFilterContext *ctx, void *arg, int jobnr, int nb_job
     AudioFFTDeNoiseContext *s = ctx->priv;
     ThreadData *td = arg;
     AVFrame *in = td->in;
-    const int start = (in->channels * jobnr) / nb_jobs;
-    const int end = (in->channels * (jobnr+1)) / nb_jobs;
+    const int start = (in->ch_layout.nb_channels * jobnr) / nb_jobs;
+    const int end = (in->ch_layout.nb_channels * (jobnr+1)) / nb_jobs;
 
     for (int ch = start; ch < end; ch++) {
         DeNoiseChannel *dnch = &s->dnch[ch];
@@ -1179,7 +1179,7 @@  static int output_frame(AVFilterLink *inlink)
         goto end;
 
     if (s->track_noise) {
-        for (int ch = 0; ch < inlink->channels; ch++) {
+        for (int ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {
             DeNoiseChannel *dnch = &s->dnch[ch];
             double levels[15];
 
@@ -1192,7 +1192,7 @@  static int output_frame(AVFilterLink *inlink)
     }
 
     if (s->sample_noise_start) {
-        for (int ch = 0; ch < inlink->channels; ch++) {
+        for (int ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {
             DeNoiseChannel *dnch = &s->dnch[ch];
 
             init_sample_noise(dnch);
@@ -1202,7 +1202,7 @@  static int output_frame(AVFilterLink *inlink)
     }
 
     if (s->sample_noise) {
-        for (int ch = 0; ch < inlink->channels; ch++) {
+        for (int ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {
             DeNoiseChannel *dnch = &s->dnch[ch];
 
             sample_noise_block(s, dnch, in, ch);
@@ -1210,7 +1210,7 @@  static int output_frame(AVFilterLink *inlink)
     }
 
     if (s->sample_noise_end) {
-        for (int ch = 0; ch < inlink->channels; ch++) {
+        for (int ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {
             DeNoiseChannel *dnch = &s->dnch[ch];
             double sample_noise[15];
 
@@ -1225,7 +1225,7 @@  static int output_frame(AVFilterLink *inlink)
     s->block_count++;
     td.in = in;
     ff_filter_execute(ctx, filter_channel, &td, NULL,
-                      FFMIN(outlink->channels, ff_filter_get_nb_threads(ctx)));
+                      FFMIN(outlink->ch_layout.nb_channels, ff_filter_get_nb_threads(ctx)));
 
     out = ff_get_audio_buffer(outlink, s->sample_advance);
     if (!out) {
@@ -1233,7 +1233,7 @@  static int output_frame(AVFilterLink *inlink)
         goto end;
     }
 
-    for (int ch = 0; ch < inlink->channels; ch++) {
+    for (int ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {
         DeNoiseChannel *dnch = &s->dnch[ch];
         double *src = dnch->out_samples;
         float *orig = (float *)in->extended_data[ch];
diff --git a/libavfilter/af_afftfilt.c b/libavfilter/af_afftfilt.c
index 691feeae36..2e3b9a0eca 100644
--- a/libavfilter/af_afftfilt.c
+++ b/libavfilter/af_afftfilt.c
@@ -112,7 +112,7 @@  static int config_input(AVFilterLink *inlink)
     const char *last_expr = "1";
     int buf_size;
 
-    s->channels = inlink->channels;
+    s->channels = inlink->ch_layout.nb_channels;
     s->pts  = AV_NOPTS_VALUE;
     ret = av_tx_init(&s->fft, &s->tx_fn, AV_TX_FLOAT_FFT, 0, s->fft_size, &scale, 0);
     if (ret < 0)
@@ -125,19 +125,19 @@  static int config_input(AVFilterLink *inlink)
     s->window_size = s->fft_size;
     buf_size = FFALIGN(s->window_size, av_cpu_max_align());
 
-    s->fft_in = av_calloc(inlink->channels, sizeof(*s->fft_in));
+    s->fft_in = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->fft_in));
     if (!s->fft_in)
         return AVERROR(ENOMEM);
 
-    s->fft_out = av_calloc(inlink->channels, sizeof(*s->fft_out));
+    s->fft_out = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->fft_out));
     if (!s->fft_out)
         return AVERROR(ENOMEM);
 
-    s->fft_temp = av_calloc(inlink->channels, sizeof(*s->fft_temp));
+    s->fft_temp = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->fft_temp));
     if (!s->fft_temp)
         return AVERROR(ENOMEM);
 
-    for (ch = 0; ch < inlink->channels; ch++) {
+    for (ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {
         s->fft_in[ch] = av_calloc(buf_size, sizeof(**s->fft_in));
         if (!s->fft_in[ch])
             return AVERROR(ENOMEM);
@@ -151,11 +151,11 @@  static int config_input(AVFilterLink *inlink)
             return AVERROR(ENOMEM);
     }
 
-    s->real = av_calloc(inlink->channels, sizeof(*s->real));
+    s->real = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->real));
     if (!s->real)
         return AVERROR(ENOMEM);
 
-    s->imag = av_calloc(inlink->channels, sizeof(*s->imag));
+    s->imag = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->imag));
     if (!s->imag)
         return AVERROR(ENOMEM);
 
@@ -163,7 +163,7 @@  static int config_input(AVFilterLink *inlink)
     if (!args)
         return AVERROR(ENOMEM);
 
-    for (ch = 0; ch < inlink->channels; ch++) {
+    for (ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {
         char *arg = av_strtok(ch == 0 ? args : NULL, "|", &saveptr);
 
         ret = av_expr_parse(&s->real[ch], arg ? arg : last_expr, var_names,
@@ -183,7 +183,7 @@  static int config_input(AVFilterLink *inlink)
 
     saveptr = NULL;
     last_expr = "1";
-    for (ch = 0; ch < inlink->channels; ch++) {
+    for (ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {
         char *arg = av_strtok(ch == 0 ? args : NULL, "|", &saveptr);
 
         ret = av_expr_parse(&s->imag[ch], arg ? arg : last_expr, var_names,
@@ -196,7 +196,7 @@  static int config_input(AVFilterLink *inlink)
 
     av_freep(&args);
 
-    s->fifo = av_audio_fifo_alloc(inlink->format, inlink->channels, s->window_size);
+    s->fifo = av_audio_fifo_alloc(inlink->format, inlink->ch_layout.nb_channels, s->window_size);
     if (!s->fifo)
         return AVERROR(ENOMEM);
 
@@ -243,7 +243,7 @@  static int filter_frame(AVFilterLink *inlink)
     if (ret < 0)
         goto fail;
 
-    for (ch = 0; ch < inlink->channels; ch++) {
+    for (ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {
         const float *src = (float *)in->extended_data[ch];
         AVComplexFloat *fft_in = s->fft_in[ch];
 
@@ -261,16 +261,16 @@  static int filter_frame(AVFilterLink *inlink)
     values[VAR_PTS]         = s->pts;
     values[VAR_SAMPLE_RATE] = inlink->sample_rate;
     values[VAR_NBBINS]      = window_size / 2;
-    values[VAR_CHANNELS]    = inlink->channels;
+    values[VAR_CHANNELS]    = inlink->ch_layout.nb_channels;
 
-    for (ch = 0; ch < inlink->channels; ch++) {
+    for (ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {
         AVComplexFloat *fft_in = s->fft_in[ch];
         AVComplexFloat *fft_out = s->fft_out[ch];
 
         s->tx_fn(s->fft, fft_out, fft_in, sizeof(float));
     }
 
-    for (ch = 0; ch < inlink->channels; ch++) {
+    for (ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {
         AVComplexFloat *fft_out = s->fft_out[ch];
         AVComplexFloat *fft_temp = s->fft_temp[ch];
         float *buf = (float *)s->buffer->extended_data[ch];
@@ -319,7 +319,7 @@  static int filter_frame(AVFilterLink *inlink)
     out->pts = s->pts;
     s->pts += av_rescale_q(s->hop_size, (AVRational){1, outlink->sample_rate}, outlink->time_base);
 
-    for (ch = 0; ch < inlink->channels; ch++) {
+    for (ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {
         float *dst = (float *)out->extended_data[ch];
         float *buf = (float *)s->buffer->extended_data[ch];
 
diff --git a/libavfilter/af_afir.c b/libavfilter/af_afir.c
index ace5087e90..fa4cad82e2 100644
--- a/libavfilter/af_afir.c
+++ b/libavfilter/af_afir.c
@@ -201,8 +201,8 @@  static int fir_channel(AVFilterContext *ctx, AVFrame *out, int ch)
 static int fir_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
 {
     AVFrame *out = arg;
-    const int start = (out->channels * jobnr) / nb_jobs;
-    const int end = (out->channels * (jobnr+1)) / nb_jobs;
+    const int start = (out->ch_layout.nb_channels * jobnr) / nb_jobs;
+    const int end = (out->ch_layout.nb_channels * (jobnr+1)) / nb_jobs;
 
     for (int ch = start; ch < end; ch++) {
         fir_channel(ctx, out, ch);
@@ -226,7 +226,7 @@  static int fir_frame(AudioFIRContext *s, AVFrame *in, AVFilterLink *outlink)
         s->pts = in->pts;
     s->in = in;
     ff_filter_execute(ctx, fir_channels, out, NULL,
-                      FFMIN(outlink->channels, ff_filter_get_nb_threads(ctx)));
+                      FFMIN(outlink->ch_layout.nb_channels, ff_filter_get_nb_threads(ctx)));
 
     out->pts = s->pts;
     if (s->pts != AV_NOPTS_VALUE)
@@ -304,7 +304,7 @@  static void draw_response(AVFilterContext *ctx, AVFrame *out)
     if (!mag || !phase || !delay)
         goto end;
 
-    channel = av_clip(s->ir_channel, 0, s->ir[s->selir]->channels - 1);
+    channel = av_clip(s->ir_channel, 0, s->ir[s->selir]->ch_layout.nb_channels - 1);
     for (i = 0; i < s->w; i++) {
         const float *src = (const float *)s->ir[s->selir]->extended_data[channel];
         double w = i * M_PI / (s->w - 1);
@@ -381,8 +381,8 @@  static int init_segment(AVFilterContext *ctx, AudioFIRSegment *seg,
 {
     AudioFIRContext *s = ctx->priv;
 
-    seg->rdft  = av_calloc(ctx->inputs[0]->channels, sizeof(*seg->rdft));
-    seg->irdft = av_calloc(ctx->inputs[0]->channels, sizeof(*seg->irdft));
+    seg->rdft  = av_calloc(ctx->inputs[0]->ch_layout.nb_channels, sizeof(*seg->rdft));
+    seg->irdft = av_calloc(ctx->inputs[0]->ch_layout.nb_channels, sizeof(*seg->irdft));
     if (!seg->rdft || !seg->irdft)
         return AVERROR(ENOMEM);
 
@@ -394,12 +394,12 @@  static int init_segment(AVFilterContext *ctx, AudioFIRSegment *seg,
     seg->input_size    = offset + s->min_part_size;
     seg->input_offset  = offset;
 
-    seg->part_index    = av_calloc(ctx->inputs[0]->channels, sizeof(*seg->part_index));
-    seg->output_offset = av_calloc(ctx->inputs[0]->channels, sizeof(*seg->output_offset));
+    seg->part_index    = av_calloc(ctx->inputs[0]->ch_layout.nb_channels, sizeof(*seg->part_index));
+    seg->output_offset = av_calloc(ctx->inputs[0]->ch_layout.nb_channels, sizeof(*seg->output_offset));
     if (!seg->part_index || !seg->output_offset)
         return AVERROR(ENOMEM);
 
-    for (int ch = 0; ch < ctx->inputs[0]->channels && part_size >= 8; ch++) {
+    for (int ch = 0; ch < ctx->inputs[0]->ch_layout.nb_channels && part_size >= 8; ch++) {
         seg->rdft[ch]  = av_rdft_init(av_log2(2 * part_size), DFT_R2C);
         seg->irdft[ch] = av_rdft_init(av_log2(2 * part_size), IDFT_C2R);
         if (!seg->rdft[ch] || !seg->irdft[ch])
@@ -506,25 +506,25 @@  static int convert_coeffs(AVFilterContext *ctx)
         /* nothing to do */
         break;
     case 0:
-        for (ch = 0; ch < ctx->inputs[1 + s->selir]->channels; ch++) {
+        for (ch = 0; ch < ctx->inputs[1 + s->selir]->ch_layout.nb_channels; ch++) {
             float *time = (float *)s->ir[s->selir]->extended_data[!s->one2many * ch];
 
             for (i = 0; i < cur_nb_taps; i++)
                 power += FFABS(time[i]);
         }
-        s->gain = ctx->inputs[1 + s->selir]->channels / power;
+        s->gain = ctx->inputs[1 + s->selir]->ch_layout.nb_channels / power;
         break;
     case 1:
-        for (ch = 0; ch < ctx->inputs[1 + s->selir]->channels; ch++) {
+        for (ch = 0; ch < ctx->inputs[1 + s->selir]->ch_layout.nb_channels; ch++) {
             float *time = (float *)s->ir[s->selir]->extended_data[!s->one2many * ch];
 
             for (i = 0; i < cur_nb_taps; i++)
                 power += time[i];
         }
-        s->gain = ctx->inputs[1 + s->selir]->channels / power;
+        s->gain = ctx->inputs[1 + s->selir]->ch_layout.nb_channels / power;
         break;
     case 2:
-        for (ch = 0; ch < ctx->inputs[1 + s->selir]->channels; ch++) {
+        for (ch = 0; ch < ctx->inputs[1 + s->selir]->ch_layout.nb_channels; ch++) {
             float *time = (float *)s->ir[s->selir]->extended_data[!s->one2many * ch];
 
             for (i = 0; i < cur_nb_taps; i++)
@@ -538,7 +538,7 @@  static int convert_coeffs(AVFilterContext *ctx)
 
     s->gain = FFMIN(s->gain * s->ir_gain, 1.f);
     av_log(ctx, AV_LOG_DEBUG, "power %f, gain %f\n", power, s->gain);
-    for (ch = 0; ch < ctx->inputs[1 + s->selir]->channels; ch++) {
+    for (ch = 0; ch < ctx->inputs[1 + s->selir]->ch_layout.nb_channels; ch++) {
         float *time = (float *)s->ir[s->selir]->extended_data[!s->one2many * ch];
 
         s->fdsp->vector_fmul_scalar(time, time, s->gain, FFALIGN(cur_nb_taps, 4));
@@ -547,7 +547,7 @@  static int convert_coeffs(AVFilterContext *ctx)
     av_log(ctx, AV_LOG_DEBUG, "nb_taps: %d\n", cur_nb_taps);
     av_log(ctx, AV_LOG_DEBUG, "nb_segments: %d\n", s->nb_segments);
 
-    for (ch = 0; ch < ctx->inputs[1 + s->selir]->channels; ch++) {
+    for (ch = 0; ch < ctx->inputs[1 + s->selir]->ch_layout.nb_channels; ch++) {
         float *time = (float *)s->ir[s->selir]->extended_data[!s->one2many * ch];
         int toffset = 0;
 
@@ -745,7 +745,7 @@  static int query_formats(AVFilterContext *ctx)
         if ((ret = ff_channel_layouts_ref(layouts, &ctx->outputs[0]->incfg.channel_layouts)) < 0)
             return ret;
 
-        ret = ff_add_channel_layout(&mono, AV_CH_LAYOUT_MONO);
+        ret = ff_add_channel_layout(&mono, &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO);
         if (ret)
             return ret;
         for (int i = 1; i < ctx->nb_inputs; i++) {
@@ -764,15 +764,22 @@  static int config_output(AVFilterLink *outlink)
 {
     AVFilterContext *ctx = outlink->src;
     AudioFIRContext *s = ctx->priv;
+    int ret;
 
-    s->one2many = ctx->inputs[1 + s->selir]->channels == 1;
+    s->one2many = ctx->inputs[1 + s->selir]->ch_layout.nb_channels == 1;
     outlink->sample_rate = ctx->inputs[0]->sample_rate;
     outlink->time_base   = ctx->inputs[0]->time_base;
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
     outlink->channel_layout = ctx->inputs[0]->channel_layout;
-    outlink->channels = ctx->inputs[0]->channels;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+    if ((ret = av_channel_layout_copy(&outlink->ch_layout, &ctx->inputs[0]->ch_layout)) < 0)
+        return ret;
+    outlink->ch_layout.nb_channels = ctx->inputs[0]->ch_layout.nb_channels;
 
-    s->nb_channels = outlink->channels;
-    s->nb_coef_channels = ctx->inputs[1 + s->selir]->channels;
+    s->nb_channels = outlink->ch_layout.nb_channels;
+    s->nb_coef_channels = ctx->inputs[1 + s->selir]->ch_layout.nb_channels;
     s->pts = AV_NOPTS_VALUE;
 
     return 0;
diff --git a/libavfilter/af_aformat.c b/libavfilter/af_aformat.c
index ed3c75311a..96704e041c 100644
--- a/libavfilter/af_aformat.c
+++ b/libavfilter/af_aformat.c
@@ -104,9 +104,36 @@  static av_cold int init(AVFilterContext *ctx)
                   ff_add_format, av_get_sample_fmt, AV_SAMPLE_FMT_NONE, "sample format");
     PARSE_FORMATS(s->sample_rates_str, int, s->sample_rates, ff_add_format,
                   get_sample_rate, 0, "sample rate");
-    PARSE_FORMATS(s->channel_layouts_str, uint64_t, s->channel_layouts,
-                  ff_add_channel_layout, av_get_channel_layout, 0,
-                  "channel layout");
+    {
+        AVChannelLayout fmt = { 0 };
+        const char *cur = s->channel_layouts_str;
+        int ret;
+
+        if (s->channel_layouts_str && strchr(s->channel_layouts_str, ',')) {
+            av_log(ctx, AV_LOG_WARNING, "This syntax is deprecated, use '|' to "
+                   "separate channel layout.\n");
+        }
+
+        while (cur && *cur) {
+            char *chl = av_get_token(&cur, "|,");
+            if (!chl)
+                return AVERROR(ENOMEM);
+            if (*cur)
+                cur++;
+
+            ret = av_channel_layout_from_string(&fmt, chl);
+            if (ret < 0) {
+                av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout: %s.\n", chl);
+                av_free(chl);
+                return ret;
+            }
+            ret = ff_add_channel_layout(&s->channel_layouts, &fmt);
+            av_channel_layout_uninit(&fmt);
+            av_free(chl);
+            if (ret < 0)
+                return ret;
+        }
+    }
 
     return 0;
 }
diff --git a/libavfilter/af_afreqshift.c b/libavfilter/af_afreqshift.c
index 731e97afef..70bf8e419f 100644
--- a/libavfilter/af_afreqshift.c
+++ b/libavfilter/af_afreqshift.c
@@ -290,8 +290,8 @@  static int filter_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo
     ThreadData *td = arg;
     AVFrame *out = td->out;
     AVFrame *in = td->in;
-    const int start = (in->channels * jobnr) / nb_jobs;
-    const int end = (in->channels * (jobnr+1)) / nb_jobs;
+    const int start = (in->ch_layout.nb_channels * jobnr) / nb_jobs;
+    const int end = (in->ch_layout.nb_channels * (jobnr+1)) / nb_jobs;
 
     for (int ch = start; ch < end; ch++)
         s->filter_channel(ctx, ch, in, out);
@@ -324,7 +324,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 
     td.in = in; td.out = out;
     ff_filter_execute(ctx, filter_channels, &td, NULL,
-                      FFMIN(inlink->channels, ff_filter_get_nb_threads(ctx)));
+                      FFMIN(inlink->ch_layout.nb_channels, ff_filter_get_nb_threads(ctx)));
 
     s->in_samples += in->nb_samples;
 
diff --git a/libavfilter/af_afwtdn.c b/libavfilter/af_afwtdn.c
index 09b504d634..cf41b6f4bc 100644
--- a/libavfilter/af_afwtdn.c
+++ b/libavfilter/af_afwtdn.c
@@ -1037,14 +1037,14 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
         s->padd_samples -= s->nb_samples - (in ? in->nb_samples: 0);
         if (in)
             av_samples_copy(new_in->extended_data, in->extended_data, 0, 0,
-                            in->nb_samples, in->channels, in->format);
+                            in->nb_samples, in->ch_layout.nb_channels, in->format);
         av_frame_free(&in);
         in = new_in;
     }
 
     td.in  = in;
     td.out = out;
-    ff_filter_execute(ctx, s->filter_channel, &td, NULL, inlink->channels);
+    ff_filter_execute(ctx, s->filter_channel, &td, NULL, inlink->ch_layout.nb_channels);
     if (s->need_profile)
         s->got_profile = 1;
 
@@ -1059,7 +1059,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
         FF_FILTER_FORWARD_WANTED(outlink, inlink);
         return 0;
     } else if (s->drop_samples > 0) {
-        for (int ch = 0; ch < out->channels; ch++) {
+        for (int ch = 0; ch < out->ch_layout.nb_channels; ch++) {
             memmove(out->extended_data[ch],
                     out->extended_data[ch] + s->drop_samples * sizeof(double),
                     (in->nb_samples - s->drop_samples) * sizeof(double));
@@ -1164,7 +1164,7 @@  static int config_output(AVFilterLink *outlink)
         !s->new_stddev || !s->new_absmean)
         return AVERROR(ENOMEM);
 
-    s->channels = outlink->channels;
+    s->channels = outlink->ch_layout.nb_channels;
     s->overlap_length = max_left_ext(s->wavelet_length, s->levels);
     s->prev_length = s->overlap_length;
     s->drop_samples = s->overlap_length;
diff --git a/libavfilter/af_agate.c b/libavfilter/af_agate.c
index 682f17c7dd..8e93a3a82b 100644
--- a/libavfilter/af_agate.c
+++ b/libavfilter/af_agate.c
@@ -150,19 +150,19 @@  static void gate(AudioGateContext *s,
     const double release_coeff = s->release_coeff;
     int n, c;
 
-    for (n = 0; n < nb_samples; n++, src += inlink->channels, dst += inlink->channels, scsrc += sclink->channels) {
+    for (n = 0; n < nb_samples; n++, src += inlink->ch_layout.nb_channels, dst += inlink->ch_layout.nb_channels, scsrc += sclink->ch_layout.nb_channels) {
         double abs_sample = fabs(scsrc[0] * level_sc), gain = 1.0;
         double factor;
         int detected;
 
         if (s->link == 1) {
-            for (c = 1; c < sclink->channels; c++)
+            for (c = 1; c < sclink->ch_layout.nb_channels; c++)
                 abs_sample = FFMAX(fabs(scsrc[c] * level_sc), abs_sample);
         } else {
-            for (c = 1; c < sclink->channels; c++)
+            for (c = 1; c < sclink->ch_layout.nb_channels; c++)
                 abs_sample += fabs(scsrc[c] * level_sc);
 
-            abs_sample /= sclink->channels;
+            abs_sample /= sclink->ch_layout.nb_channels;
         }
 
         if (s->detection)
@@ -181,7 +181,7 @@  static void gate(AudioGateContext *s,
                                s->range, s->mode);
 
         factor = ctx->is_disabled ? 1.f : level_in * gain * makeup;
-        for (c = 0; c < inlink->channels; c++)
+        for (c = 0; c < inlink->ch_layout.nb_channels; c++)
             dst[c] = src[c] * factor;
     }
 }
@@ -344,8 +344,8 @@  static int scconfig_output(AVFilterLink *outlink)
 
     outlink->time_base   = ctx->inputs[0]->time_base;
 
-    s->fifo[0] = av_audio_fifo_alloc(ctx->inputs[0]->format, ctx->inputs[0]->channels, 1024);
-    s->fifo[1] = av_audio_fifo_alloc(ctx->inputs[1]->format, ctx->inputs[1]->channels, 1024);
+    s->fifo[0] = av_audio_fifo_alloc(ctx->inputs[0]->format, ctx->inputs[0]->ch_layout.nb_channels, 1024);
+    s->fifo[1] = av_audio_fifo_alloc(ctx->inputs[1]->format, ctx->inputs[1]->ch_layout.nb_channels, 1024);
     if (!s->fifo[0] || !s->fifo[1])
         return AVERROR(ENOMEM);
 
diff --git a/libavfilter/af_aiir.c b/libavfilter/af_aiir.c
index 8a4b4814f6..3e7ec78b63 100644
--- a/libavfilter/af_aiir.c
+++ b/libavfilter/af_aiir.c
@@ -1263,35 +1263,35 @@  static int config_output(AVFilterLink *outlink)
     AVFilterLink *inlink = ctx->inputs[0];
     int ch, ret, i;
 
-    s->channels = inlink->channels;
+    s->channels = inlink->ch_layout.nb_channels;
     s->iir = av_calloc(s->channels, sizeof(*s->iir));
     if (!s->iir)
         return AVERROR(ENOMEM);
 
-    ret = read_gains(ctx, s->g_str, inlink->channels);
+    ret = read_gains(ctx, s->g_str, inlink->ch_layout.nb_channels);
     if (ret < 0)
         return ret;
 
-    ret = read_channels(ctx, inlink->channels, s->a_str, 0);
+    ret = read_channels(ctx, inlink->ch_layout.nb_channels, s->a_str, 0);
     if (ret < 0)
         return ret;
 
-    ret = read_channels(ctx, inlink->channels, s->b_str, 1);
+    ret = read_channels(ctx, inlink->ch_layout.nb_channels, s->b_str, 1);
     if (ret < 0)
         return ret;
 
     if (s->format == -1) {
-        convert_sf2tf(ctx, inlink->channels);
+        convert_sf2tf(ctx, inlink->ch_layout.nb_channels);
         s->format = 0;
     } else if (s->format == 2) {
-        convert_pr2zp(ctx, inlink->channels);
+        convert_pr2zp(ctx, inlink->ch_layout.nb_channels);
     } else if (s->format == 3) {
-        convert_pd2zp(ctx, inlink->channels);
+        convert_pd2zp(ctx, inlink->ch_layout.nb_channels);
     } else if (s->format == 4) {
-        convert_sp2zp(ctx, inlink->channels);
+        convert_sp2zp(ctx, inlink->ch_layout.nb_channels);
     }
     if (s->format > 0) {
-        check_stability(ctx, inlink->channels);
+        check_stability(ctx, inlink->ch_layout.nb_channels);
     }
 
     av_frame_free(&s->video);
@@ -1309,7 +1309,7 @@  static int config_output(AVFilterLink *outlink)
     if (s->format > 0 && s->process == 0) {
         av_log(ctx, AV_LOG_WARNING, "Direct processsing is not recommended for zp coefficients format.\n");
 
-        ret = convert_zp2tf(ctx, inlink->channels);
+        ret = convert_zp2tf(ctx, inlink->ch_layout.nb_channels);
         if (ret < 0)
             return ret;
     } else if (s->format == -2 && s->process > 0) {
@@ -1322,21 +1322,21 @@  static int config_output(AVFilterLink *outlink)
         av_log(ctx, AV_LOG_ERROR, "Parallel processing is not implemented for transfer function.\n");
         return AVERROR_PATCHWELCOME;
     } else if (s->format > 0 && s->process == 1) {
-        ret = decompose_zp2biquads(ctx, inlink->channels);
+        ret = decompose_zp2biquads(ctx, inlink->ch_layout.nb_channels);
         if (ret < 0)
             return ret;
     } else if (s->format > 0 && s->process == 2) {
         if (s->precision > 1)
             av_log(ctx, AV_LOG_WARNING, "Parallel processing is not recommended for fixed-point precisions.\n");
-        ret = decompose_zp2biquads(ctx, inlink->channels);
+        ret = decompose_zp2biquads(ctx, inlink->ch_layout.nb_channels);
         if (ret < 0)
             return ret;
-        ret = convert_serial2parallel(ctx, inlink->channels);
+        ret = convert_serial2parallel(ctx, inlink->ch_layout.nb_channels);
         if (ret < 0)
             return ret;
     }
 
-    for (ch = 0; s->format == -2 && ch < inlink->channels; ch++) {
+    for (ch = 0; s->format == -2 && ch < inlink->ch_layout.nb_channels; ch++) {
         IIRChannel *iir = &s->iir[ch];
 
         if (iir->nb_ab[0] != iir->nb_ab[1] + 1) {
@@ -1345,7 +1345,7 @@  static int config_output(AVFilterLink *outlink)
         }
     }
 
-    for (ch = 0; s->format == 0 && ch < inlink->channels; ch++) {
+    for (ch = 0; s->format == 0 && ch < inlink->ch_layout.nb_channels; ch++) {
         IIRChannel *iir = &s->iir[ch];
 
         for (i = 1; i < iir->nb_ab[0]; i++) {
@@ -1401,9 +1401,9 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 
     td.in  = in;
     td.out = out;
-    ff_filter_execute(ctx, s->iir_channel, &td, NULL, outlink->channels);
+    ff_filter_execute(ctx, s->iir_channel, &td, NULL, outlink->ch_layout.nb_channels);
 
-    for (ch = 0; ch < outlink->channels; ch++) {
+    for (ch = 0; ch < outlink->ch_layout.nb_channels; ch++) {
         if (s->iir[ch].clippings > 0)
             av_log(ctx, AV_LOG_WARNING, "Channel %d clipping %d times. Please reduce gain.\n",
                    ch, s->iir[ch].clippings);
diff --git a/libavfilter/af_alimiter.c b/libavfilter/af_alimiter.c
index 211941a511..133f98f165 100644
--- a/libavfilter/af_alimiter.c
+++ b/libavfilter/af_alimiter.c
@@ -116,7 +116,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     AudioLimiterContext *s = ctx->priv;
     AVFilterLink *outlink = ctx->outputs[0];
     const double *src = (const double *)in->data[0];
-    const int channels = inlink->channels;
+    const int channels = inlink->ch_layout.nb_channels;
     const int buffer_size = s->buffer_size;
     double *dst, *buffer = s->buffer;
     const double release = s->release;
@@ -281,8 +281,8 @@  static int config_input(AVFilterLink *inlink)
     AudioLimiterContext *s = ctx->priv;
     int obuffer_size;
 
-    obuffer_size = inlink->sample_rate * inlink->channels * 100 / 1000. + inlink->channels;
-    if (obuffer_size < inlink->channels)
+    obuffer_size = inlink->sample_rate * inlink->ch_layout.nb_channels * 100 / 1000. + inlink->ch_layout.nb_channels;
+    if (obuffer_size < inlink->ch_layout.nb_channels)
         return AVERROR(EINVAL);
 
     s->buffer = av_calloc(obuffer_size, sizeof(*s->buffer));
@@ -292,8 +292,8 @@  static int config_input(AVFilterLink *inlink)
         return AVERROR(ENOMEM);
 
     memset(s->nextpos, -1, obuffer_size * sizeof(*s->nextpos));
-    s->buffer_size = inlink->sample_rate * s->attack * inlink->channels;
-    s->buffer_size -= s->buffer_size % inlink->channels;
+    s->buffer_size = inlink->sample_rate * s->attack * inlink->ch_layout.nb_channels;
+    s->buffer_size -= s->buffer_size % inlink->ch_layout.nb_channels;
 
     if (s->buffer_size <= 0) {
         av_log(ctx, AV_LOG_ERROR, "Attack is too small.\n");
diff --git a/libavfilter/af_amerge.c b/libavfilter/af_amerge.c
index 9109af22c5..8bcc0ac5be 100644
--- a/libavfilter/af_amerge.c
+++ b/libavfilter/af_amerge.c
@@ -73,7 +73,8 @@  static int query_formats(AVFilterContext *ctx)
         AV_SAMPLE_FMT_NONE
     };
     AMergeContext *s = ctx->priv;
-    int64_t inlayout[SWR_CH_MAX], outlayout = 0;
+    AVChannelLayout *inlayout[SWR_CH_MAX] = { NULL }, outlayout = { 0 };
+    uint64_t outmask = 0;
     AVFilterChannelLayouts *layouts;
     int i, ret, overlap = 0, nb_ch = 0;
 
@@ -84,20 +85,21 @@  static int query_formats(AVFilterContext *ctx)
                    "No channel layout for input %d\n", i + 1);
             return AVERROR(EAGAIN);
         }
-        inlayout[i] = ctx->inputs[i]->incfg.channel_layouts->channel_layouts[0];
+        inlayout[i] = &ctx->inputs[i]->incfg.channel_layouts->channel_layouts[0];
         if (ctx->inputs[i]->incfg.channel_layouts->nb_channel_layouts > 1) {
             char buf[256];
-            av_get_channel_layout_string(buf, sizeof(buf), 0, inlayout[i]);
+            av_channel_layout_describe(inlayout[i], buf, sizeof(buf));
             av_log(ctx, AV_LOG_INFO, "Using \"%s\" for input %d\n", buf, i + 1);
         }
         s->in[i].nb_ch = FF_LAYOUT2COUNT(inlayout[i]);
         if (s->in[i].nb_ch) {
             overlap++;
         } else {
-            s->in[i].nb_ch = av_get_channel_layout_nb_channels(inlayout[i]);
-            if (outlayout & inlayout[i])
+            s->in[i].nb_ch = inlayout[i]->nb_channels;
+            if (av_channel_layout_subset(inlayout[i], outmask))
                 overlap++;
-            outlayout |= inlayout[i];
+            outmask |= inlayout[i]->order == AV_CHANNEL_ORDER_NATIVE ?
+                       inlayout[i]->u.mask : 0;
         }
         nb_ch += s->in[i].nb_ch;
     }
@@ -111,19 +113,20 @@  static int query_formats(AVFilterContext *ctx)
                "output layout will be determined by the number of distinct input channels\n");
         for (i = 0; i < nb_ch; i++)
             s->route[i] = i;
-        outlayout = av_get_default_channel_layout(nb_ch);
-        if (!outlayout && nb_ch)
-            outlayout = 0xFFFFFFFFFFFFFFFFULL >> (64 - nb_ch);
+        av_channel_layout_default(&outlayout, nb_ch);
+        if (!KNOWN(&outlayout) && nb_ch)
+            av_channel_layout_from_mask(&outlayout, 0xFFFFFFFFFFFFFFFFULL >> (64 - nb_ch));
     } else {
         int *route[SWR_CH_MAX];
         int c, out_ch_number = 0;
 
+        av_channel_layout_from_mask(&outlayout, outmask);
         route[0] = s->route;
         for (i = 1; i < s->nb_inputs; i++)
             route[i] = route[i - 1] + s->in[i - 1].nb_ch;
         for (c = 0; c < 64; c++)
             for (i = 0; i < s->nb_inputs; i++)
-                if ((inlayout[i] >> c) & 1)
+                if (av_channel_layout_index_from_channel(inlayout[i], c) >= 0)
                     *(route[i]++) = out_ch_number++;
     }
     if ((ret = ff_set_common_formats_from_list(ctx, packed_sample_fmts)) < 0)
@@ -136,7 +139,7 @@  static int query_formats(AVFilterContext *ctx)
             return ret;
     }
     layouts = NULL;
-    if ((ret = ff_add_channel_layout(&layouts, outlayout)) < 0)
+    if ((ret = ff_add_channel_layout(&layouts, &outlayout)) < 0)
         return ret;
     if ((ret = ff_channel_layouts_ref(layouts, &ctx->outputs[0]->incfg.channel_layouts)) < 0)
         return ret;
@@ -149,6 +152,7 @@  static int config_output(AVFilterLink *outlink)
     AVFilterContext *ctx = outlink->src;
     AMergeContext *s = ctx->priv;
     AVBPrint bp;
+    char buf[128];
     int i;
 
     s->bps = av_get_bytes_per_sample(ctx->outputs[0]->format);
@@ -157,10 +161,12 @@  static int config_output(AVFilterLink *outlink)
     av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC);
     for (i = 0; i < s->nb_inputs; i++) {
         av_bprintf(&bp, "%sin%d:", i ? " + " : "", i);
-        av_bprint_channel_layout(&bp, -1, ctx->inputs[i]->channel_layout);
+        av_channel_layout_describe(&ctx->inputs[i]->ch_layout, buf, sizeof(buf));
+        av_bprintf(&bp, "%s", buf);
     }
     av_bprintf(&bp, " -> out:");
-    av_bprint_channel_layout(&bp, -1, ctx->outputs[0]->channel_layout);
+    av_channel_layout_describe(&ctx->outputs[0]->ch_layout, buf, sizeof(buf));
+    av_bprintf(&bp, "%s", buf);
     av_log(ctx, AV_LOG_VERBOSE, "%s\n", bp.str);
 
     return 0;
@@ -237,8 +243,14 @@  static int try_push_frame(AVFilterContext *ctx, int nb_samples)
     outbuf->pts = inbuf[0]->pts;
 
     outbuf->nb_samples     = nb_samples;
+    if ((ret = av_channel_layout_copy(&outbuf->ch_layout, &outlink->ch_layout)) < 0)
+        return ret;
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
     outbuf->channel_layout = outlink->channel_layout;
-    outbuf->channels       = outlink->channels;
+    outbuf->channels       = outlink->ch_layout.nb_channels;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
 
     while (nb_samples) {
         /* Unroll the most common sample formats: speed +~350% for the loop,
diff --git a/libavfilter/af_amix.c b/libavfilter/af_amix.c
index 3f51d43acd..d7e00ab1f1 100644
--- a/libavfilter/af_amix.c
+++ b/libavfilter/af_amix.c
@@ -261,7 +261,7 @@  static int config_output(AVFilterLink *outlink)
     if (!s->fifos)
         return AVERROR(ENOMEM);
 
-    s->nb_channels = outlink->channels;
+    s->nb_channels = outlink->ch_layout.nb_channels;
     for (i = 0; i < s->nb_inputs; i++) {
         s->fifos[i] = av_audio_fifo_alloc(outlink->format, s->nb_channels, 1024);
         if (!s->fifos[i])
@@ -282,7 +282,7 @@  static int config_output(AVFilterLink *outlink)
         s->scale_norm[i] = s->weight_sum / FFABS(s->weights[i]);
     calculate_scales(s, 0);
 
-    av_get_channel_layout_string(buf, sizeof(buf), -1, outlink->channel_layout);
+    av_channel_layout_describe(&outlink->ch_layout, buf, sizeof(buf));
 
     av_log(ctx, AV_LOG_VERBOSE,
            "inputs:%d fmt:%s srate:%d cl:%s\n", s->nb_inputs,
diff --git a/libavfilter/af_amultiply.c b/libavfilter/af_amultiply.c
index 5de711bade..97728954a5 100644
--- a/libavfilter/af_amultiply.c
+++ b/libavfilter/af_amultiply.c
@@ -128,8 +128,8 @@  static int config_output(AVFilterLink *outlink)
     AudioMultiplyContext *s = ctx->priv;
     AVFilterLink *inlink = ctx->inputs[0];
 
-    s->channels = inlink->channels;
-    s->planes = av_sample_fmt_is_planar(inlink->format) ? inlink->channels : 1;
+    s->channels = inlink->ch_layout.nb_channels;
+    s->planes = av_sample_fmt_is_planar(inlink->format) ? inlink->ch_layout.nb_channels : 1;
     s->samples_align = 16;
 
     return 0;
diff --git a/libavfilter/af_anequalizer.c b/libavfilter/af_anequalizer.c
index 57a9b7634b..c7b9a83d99 100644
--- a/libavfilter/af_anequalizer.c
+++ b/libavfilter/af_anequalizer.c
@@ -103,7 +103,7 @@  static void draw_curves(AVFilterContext *ctx, AVFilterLink *inlink, AVFrame *out
 
     memset(out->data[0], 0, s->h * out->linesize[0]);
 
-    for (ch = 0; ch < inlink->channels; ch++) {
+    for (ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {
         uint8_t fg[4] = { 0xff, 0xff, 0xff, 0xff };
         int prev_v = -1;
         double f;
@@ -577,8 +577,8 @@  static int config_input(AVFilterLink *inlink)
     if (!args)
         return AVERROR(ENOMEM);
 
-    s->nb_allocated = 32 * inlink->channels;
-    s->filters = av_calloc(inlink->channels, 32 * sizeof(*s->filters));
+    s->nb_allocated = 32 * inlink->ch_layout.nb_channels;
+    s->filters = av_calloc(inlink->ch_layout.nb_channels, 32 * sizeof(*s->filters));
     if (!s->filters) {
         s->nb_allocated = 0;
         av_free(args);
@@ -610,7 +610,7 @@  static int config_input(AVFilterLink *inlink)
             s->filters[s->nb_filters].ignore = 1;
 
         if (s->filters[s->nb_filters].channel < 0 ||
-            s->filters[s->nb_filters].channel >= inlink->channels)
+            s->filters[s->nb_filters].channel >= inlink->ch_layout.nb_channels)
             s->filters[s->nb_filters].ignore = 1;
 
         s->filters[s->nb_filters].type = av_clip(s->filters[s->nb_filters].type, 0, NB_TYPES - 1);
@@ -698,8 +698,8 @@  static int filter_channels(AVFilterContext *ctx, void *arg,
 {
     AudioNEqualizerContext *s = ctx->priv;
     AVFrame *buf = arg;
-    const int start = (buf->channels * jobnr) / nb_jobs;
-    const int end = (buf->channels * (jobnr+1)) / nb_jobs;
+    const int start = (buf->ch_layout.nb_channels * jobnr) / nb_jobs;
+    const int end = (buf->ch_layout.nb_channels * (jobnr+1)) / nb_jobs;
 
     for (int i = 0; i < s->nb_filters; i++) {
         EqualizatorFilter *f = &s->filters[i];
@@ -731,7 +731,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
 
     if (!ctx->is_disabled)
         ff_filter_execute(ctx, filter_channels, buf, NULL,
-                          FFMIN(inlink->channels, ff_filter_get_nb_threads(ctx)));
+                          FFMIN(inlink->ch_layout.nb_channels, ff_filter_get_nb_threads(ctx)));
 
     if (s->draw_curves) {
         AVFrame *clone;
diff --git a/libavfilter/af_anlmdn.c b/libavfilter/af_anlmdn.c
index 141e5f398e..6fcf9e9d66 100644
--- a/libavfilter/af_anlmdn.c
+++ b/libavfilter/af_anlmdn.c
@@ -189,7 +189,7 @@  static int config_output(AVFilterLink *outlink)
     if (ret < 0)
         return ret;
 
-    s->fifo = av_audio_fifo_alloc(outlink->format, outlink->channels, s->N);
+    s->fifo = av_audio_fifo_alloc(outlink->format, outlink->ch_layout.nb_channels, s->N);
     if (!s->fifo)
         return AVERROR(ENOMEM);
 
@@ -292,7 +292,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
         if (ret < 0)
             break;
 
-        ff_filter_execute(ctx, filter_channel, out, NULL, inlink->channels);
+        ff_filter_execute(ctx, filter_channel, out, NULL, inlink->ch_layout.nb_channels);
 
         av_audio_fifo_drain(s->fifo, s->H);
 
diff --git a/libavfilter/af_anlms.c b/libavfilter/af_anlms.c
index f20e3c0e82..50bb0c7f42 100644
--- a/libavfilter/af_anlms.c
+++ b/libavfilter/af_anlms.c
@@ -156,8 +156,8 @@  static int process_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_j
 {
     AudioNLMSContext *s = ctx->priv;
     AVFrame *out = arg;
-    const int start = (out->channels * jobnr) / nb_jobs;
-    const int end = (out->channels * (jobnr+1)) / nb_jobs;
+    const int start = (out->ch_layout.nb_channels * jobnr) / nb_jobs;
+    const int end = (out->ch_layout.nb_channels * (jobnr+1)) / nb_jobs;
 
     for (int c = start; c < end; c++) {
         const float *input = (const float *)s->frame[0]->extended_data[c];
@@ -208,7 +208,7 @@  static int activate(AVFilterContext *ctx)
         }
 
         ff_filter_execute(ctx, process_channels, out, NULL,
-                          FFMIN(ctx->outputs[0]->channels, ff_filter_get_nb_threads(ctx)));
+                          FFMIN(ctx->outputs[0]->ch_layout.nb_channels, ff_filter_get_nb_threads(ctx)));
 
         out->pts = s->frame[0]->pts;
 
diff --git a/libavfilter/af_apad.c b/libavfilter/af_apad.c
index ae73f0b6b1..df17c9a531 100644
--- a/libavfilter/af_apad.c
+++ b/libavfilter/af_apad.c
@@ -121,7 +121,7 @@  static int request_frame(AVFilterLink *outlink)
 
         av_samples_set_silence(outsamplesref->extended_data, 0,
                                n_out,
-                               outsamplesref->channels,
+                               outsamplesref->ch_layout.nb_channels,
                                outsamplesref->format);
 
         outsamplesref->pts = s->next_pts;
diff --git a/libavfilter/af_aphaser.c b/libavfilter/af_aphaser.c
index 2d95802677..1f5dcb1f9e 100644
--- a/libavfilter/af_aphaser.c
+++ b/libavfilter/af_aphaser.c
@@ -177,7 +177,7 @@  static int config_output(AVFilterLink *outlink)
         av_log(outlink->src, AV_LOG_ERROR, "delay is too small\n");
         return AVERROR(EINVAL);
     }
-    s->delay_buffer = av_calloc(s->delay_buffer_length, sizeof(*s->delay_buffer) * inlink->channels);
+    s->delay_buffer = av_calloc(s->delay_buffer_length, sizeof(*s->delay_buffer) * inlink->ch_layout.nb_channels);
     s->modulation_buffer_length = inlink->sample_rate / s->speed + 0.5;
     s->modulation_buffer = av_malloc_array(s->modulation_buffer_length, sizeof(*s->modulation_buffer));
 
@@ -223,7 +223,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *inbuf)
     }
 
     s->phaser(s, inbuf->extended_data, outbuf->extended_data,
-              outbuf->nb_samples, outbuf->channels);
+              outbuf->nb_samples, outbuf->ch_layout.nb_channels);
 
     if (inbuf != outbuf)
         av_frame_free(&inbuf);
diff --git a/libavfilter/af_apsyclip.c b/libavfilter/af_apsyclip.c
index dc3a8e97e4..b8b0f0ad46 100644
--- a/libavfilter/af_apsyclip.c
+++ b/libavfilter/af_apsyclip.c
@@ -244,7 +244,7 @@  static int config_input(AVFilterLink *inlink)
 
     generate_spread_table(s);
 
-    s->channels = inlink->channels;
+    s->channels = inlink->ch_layout.nb_channels;
 
     s->tx_ctx = av_calloc(s->channels, sizeof(*s->tx_ctx));
     s->itx_ctx = av_calloc(s->channels, sizeof(*s->itx_ctx));
@@ -533,8 +533,8 @@  static int psy_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
 {
     AudioPsyClipContext *s = ctx->priv;
     AVFrame *out = arg;
-    const int start = (out->channels * jobnr) / nb_jobs;
-    const int end = (out->channels * (jobnr+1)) / nb_jobs;
+    const int start = (out->ch_layout.nb_channels * jobnr) / nb_jobs;
+    const int end = (out->ch_layout.nb_channels * (jobnr+1)) / nb_jobs;
 
     for (int ch = start; ch < end; ch++)
         psy_channel(ctx, s->in, out, ch);
@@ -558,7 +558,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 
     s->in = in;
     ff_filter_execute(ctx, psy_channels, out, NULL,
-                      FFMIN(outlink->channels, ff_filter_get_nb_threads(ctx)));
+                      FFMIN(outlink->ch_layout.nb_channels, ff_filter_get_nb_threads(ctx)));
 
     out->pts = in->pts;
     out->nb_samples = in->nb_samples;
diff --git a/libavfilter/af_apulsator.c b/libavfilter/af_apulsator.c
index c2a8de0e0b..c3ca752035 100644
--- a/libavfilter/af_apulsator.c
+++ b/libavfilter/af_apulsator.c
@@ -192,7 +192,7 @@  static int query_formats(AVFilterContext *ctx)
 
     if ((ret = ff_add_format                 (&formats, AV_SAMPLE_FMT_DBL  )) < 0 ||
         (ret = ff_set_common_formats         (ctx     , formats            )) < 0 ||
-        (ret = ff_add_channel_layout         (&layout , AV_CH_LAYOUT_STEREO)) < 0 ||
+        (ret = ff_add_channel_layout         (&layout , &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO)) < 0 ||
         (ret = ff_set_common_channel_layouts (ctx     , layout             )) < 0)
         return ret;
 
diff --git a/libavfilter/af_aresample.c b/libavfilter/af_aresample.c
index 6e1be5b7eb..e4eccc847b 100644
--- a/libavfilter/af_aresample.c
+++ b/libavfilter/af_aresample.c
@@ -65,7 +65,8 @@  static int query_formats(AVFilterContext *ctx)
 {
     AResampleContext *aresample = ctx->priv;
     enum AVSampleFormat out_format;
-    int64_t out_rate, out_layout;
+    AVChannelLayout out_layout = { 0 };
+    int64_t out_rate;
 
     AVFilterLink *inlink  = ctx->inputs[0];
     AVFilterLink *outlink = ctx->outputs[0];
@@ -79,7 +80,6 @@  static int query_formats(AVFilterContext *ctx)
         av_opt_set_int(aresample->swr, "osr", aresample->sample_rate_arg, 0);
     av_opt_get_sample_fmt(aresample->swr, "osf", 0, &out_format);
     av_opt_get_int(aresample->swr, "osr", 0, &out_rate);
-    av_opt_get_int(aresample->swr, "ocl", 0, &out_layout);
 
     in_formats      = ff_all_formats(AVMEDIA_TYPE_AUDIO);
     if ((ret = ff_formats_ref(in_formats, &inlink->outcfg.formats)) < 0)
@@ -111,11 +111,13 @@  static int query_formats(AVFilterContext *ctx)
     if ((ret = ff_formats_ref(out_formats, &outlink->incfg.formats)) < 0)
         return ret;
 
-    if(out_layout) {
-        int64_t layout_list[] = { out_layout, -1 };
+    av_opt_get_chlayout(aresample->swr, "ochl", 0, &out_layout);
+    if (av_channel_layout_check(&out_layout)) {
+        const AVChannelLayout layout_list[] = { out_layout, { 0 } };
         out_layouts = ff_make_format64_list(layout_list);
     } else
         out_layouts = ff_all_channel_counts();
+    av_channel_layout_uninit(&out_layout);
 
     return ff_channel_layouts_ref(out_layouts, &outlink->incfg.channel_layouts);
 }
@@ -127,42 +129,41 @@  static int config_output(AVFilterLink *outlink)
     AVFilterContext *ctx = outlink->src;
     AVFilterLink *inlink = ctx->inputs[0];
     AResampleContext *aresample = ctx->priv;
-    int64_t out_rate, out_layout;
+    AVChannelLayout out_layout = { 0 };
+    int64_t out_rate;
     enum AVSampleFormat out_format;
     char inchl_buf[128], outchl_buf[128];
 
-    aresample->swr = swr_alloc_set_opts(aresample->swr,
-                                        outlink->channel_layout, outlink->format, outlink->sample_rate,
-                                        inlink->channel_layout, inlink->format, inlink->sample_rate,
-                                        0, ctx);
-    if (!aresample->swr)
-        return AVERROR(ENOMEM);
-    if (!inlink->channel_layout)
-        av_opt_set_int(aresample->swr, "ich", inlink->channels, 0);
-    if (!outlink->channel_layout)
-        av_opt_set_int(aresample->swr, "och", outlink->channels, 0);
+    ret = swr_alloc_set_opts2(&aresample->swr,
+                              &outlink->ch_layout, outlink->format, outlink->sample_rate,
+                              &inlink->ch_layout, inlink->format, inlink->sample_rate,
+                                         0, ctx);
+    if (ret < 0)
+        return ret;
 
     ret = swr_init(aresample->swr);
     if (ret < 0)
         return ret;
 
     av_opt_get_int(aresample->swr, "osr", 0, &out_rate);
-    av_opt_get_int(aresample->swr, "ocl", 0, &out_layout);
+    av_opt_get_chlayout(aresample->swr, "ochl", 0, &out_layout);
     av_opt_get_sample_fmt(aresample->swr, "osf", 0, &out_format);
     outlink->time_base = (AVRational) {1, out_rate};
 
     av_assert0(outlink->sample_rate == out_rate);
-    av_assert0(outlink->channel_layout == out_layout || !outlink->channel_layout);
+    av_assert0(!av_channel_layout_compare(&outlink->ch_layout, &out_layout));
     av_assert0(outlink->format == out_format);
 
+    av_channel_layout_uninit(&out_layout);
+
     aresample->ratio = (double)outlink->sample_rate / inlink->sample_rate;
 
-    av_get_channel_layout_string(inchl_buf,  sizeof(inchl_buf),  inlink ->channels, inlink ->channel_layout);
-    av_get_channel_layout_string(outchl_buf, sizeof(outchl_buf), outlink->channels, outlink->channel_layout);
+    av_channel_layout_describe(&inlink ->ch_layout, inchl_buf,  sizeof(inchl_buf));
+    av_channel_layout_describe(&outlink->ch_layout, outchl_buf, sizeof(outchl_buf));
 
     av_log(ctx, AV_LOG_VERBOSE, "ch:%d chl:%s fmt:%s r:%dHz -> ch:%d chl:%s fmt:%s r:%dHz\n",
-           inlink ->channels, inchl_buf,  av_get_sample_fmt_name(inlink->format),  inlink->sample_rate,
-           outlink->channels, outchl_buf, av_get_sample_fmt_name(outlink->format), outlink->sample_rate);
+           inlink ->ch_layout.nb_channels, inchl_buf,  av_get_sample_fmt_name(inlink->format),  inlink->sample_rate,
+           outlink->ch_layout.nb_channels, outchl_buf, av_get_sample_fmt_name(outlink->format), outlink->sample_rate);
     return 0;
 }
 
@@ -189,8 +190,15 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *insamplesref)
 
     av_frame_copy_props(outsamplesref, insamplesref);
     outsamplesref->format                = outlink->format;
-    outsamplesref->channels              = outlink->channels;
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
+    outsamplesref->channels              = outlink->ch_layout.nb_channels;
     outsamplesref->channel_layout        = outlink->channel_layout;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+    ret = av_channel_layout_copy(&outsamplesref->ch_layout, &outlink->ch_layout);
+    if (ret < 0)
+        return ret;
     outsamplesref->sample_rate           = outlink->sample_rate;
 
     if(insamplesref->pts != AV_NOPTS_VALUE) {
diff --git a/libavfilter/af_arnndn.c b/libavfilter/af_arnndn.c
index 3115c4ae0c..fe562e81a1 100644
--- a/libavfilter/af_arnndn.c
+++ b/libavfilter/af_arnndn.c
@@ -353,7 +353,7 @@  static int config_input(AVFilterLink *inlink)
     AudioRNNContext *s = ctx->priv;
     int ret = 0;
 
-    s->channels = inlink->channels;
+    s->channels = inlink->ch_layout.nb_channels;
 
     if (!s->st)
         s->st = av_calloc(s->channels, sizeof(DenoiseState));
@@ -1413,8 +1413,8 @@  static int rnnoise_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_j
     ThreadData *td = arg;
     AVFrame *in = td->in;
     AVFrame *out = td->out;
-    const int start = (out->channels * jobnr) / nb_jobs;
-    const int end = (out->channels * (jobnr+1)) / nb_jobs;
+    const int start = (out->ch_layout.nb_channels * jobnr) / nb_jobs;
+    const int end = (out->ch_layout.nb_channels * (jobnr+1)) / nb_jobs;
 
     for (int ch = start; ch < end; ch++) {
         rnnoise_channel(s, &s->st[ch],
@@ -1442,7 +1442,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 
     td.in = in; td.out = out;
     ff_filter_execute(ctx, rnnoise_channels, &td, NULL,
-                      FFMIN(outlink->channels, ff_filter_get_nb_threads(ctx)));
+                      FFMIN(outlink->ch_layout.nb_channels, ff_filter_get_nb_threads(ctx)));
 
     av_frame_free(&in);
     return ff_filter_frame(outlink, out);
diff --git a/libavfilter/af_asdr.c b/libavfilter/af_asdr.c
index addfe5f158..a40246f280 100644
--- a/libavfilter/af_asdr.c
+++ b/libavfilter/af_asdr.c
@@ -41,7 +41,7 @@  static void sdr(AVFilterContext *ctx, const AVFrame *u, const AVFrame *v)
 {
     AudioSDRContext *s = ctx->priv;
 
-    for (int ch = 0; ch < u->channels; ch++) {
+    for (int ch = 0; ch < u->ch_layout.nb_channels; ch++) {
         const double *const us = (double *)u->extended_data[ch];
         const double *const vs = (double *)v->extended_data[ch];
         double sum_uv = s->sum_uv[ch];
@@ -117,10 +117,10 @@  static int config_output(AVFilterLink *outlink)
 
     s->pts = AV_NOPTS_VALUE;
 
-    s->channels = inlink->channels;
+    s->channels = inlink->ch_layout.nb_channels;
 
-    s->sum_u  = av_calloc(outlink->channels, sizeof(*s->sum_u));
-    s->sum_uv = av_calloc(outlink->channels, sizeof(*s->sum_uv));
+    s->sum_u  = av_calloc(outlink->ch_layout.nb_channels, sizeof(*s->sum_u));
+    s->sum_uv = av_calloc(outlink->ch_layout.nb_channels, sizeof(*s->sum_uv));
     if (!s->sum_u || !s->sum_uv)
         return AVERROR(ENOMEM);
 
diff --git a/libavfilter/af_asetnsamples.c b/libavfilter/af_asetnsamples.c
index 71788f2a76..6fb646ace4 100644
--- a/libavfilter/af_asetnsamples.c
+++ b/libavfilter/af_asetnsamples.c
@@ -87,9 +87,9 @@  static int activate(AVFilterContext *ctx)
         }
 
         av_samples_copy(pad_frame->extended_data, frame->extended_data,
-                        0, 0, frame->nb_samples, frame->channels, frame->format);
+                        0, 0, frame->nb_samples, frame->ch_layout.nb_channels, frame->format);
         av_samples_set_silence(pad_frame->extended_data, frame->nb_samples,
-                               s->nb_out_samples - frame->nb_samples, frame->channels,
+                               s->nb_out_samples - frame->nb_samples, frame->ch_layout.nb_channels,
                                frame->format);
         av_frame_free(&frame);
         return ff_filter_frame(outlink, pad_frame);
diff --git a/libavfilter/af_ashowinfo.c b/libavfilter/af_ashowinfo.c
index c76756db63..36ba38b478 100644
--- a/libavfilter/af_ashowinfo.c
+++ b/libavfilter/af_ashowinfo.c
@@ -178,9 +178,12 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
 {
     AVFilterContext *ctx = inlink->dst;
     AShowInfoContext *s  = ctx->priv;
+#if FF_API_OLD_CHANNEL_LAYOUT
+    AVChannelLayout layout = { 0 };
+#endif
     char chlayout_str[128];
     uint32_t checksum = 0;
-    int channels    = inlink->channels;
+    int channels    = inlink->ch_layout.nb_channels;
     int planar      = av_sample_fmt_is_planar(buf->format);
     int block_align = av_get_bytes_per_sample(buf->format) * (planar ? 1 : channels);
     int data_size   = buf->nb_samples * block_align;
@@ -200,8 +203,14 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
                        s->plane_checksums[0];
     }
 
-    av_get_channel_layout_string(chlayout_str, sizeof(chlayout_str), buf->channels,
-                                 buf->channel_layout);
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
+    if (av_channel_layout_from_mask(&layout, buf->channel_layout)) {
+        av_channel_layout_describe(&layout, chlayout_str, sizeof(chlayout_str));
+FF_ENABLE_DEPRECATION_WARNINGS
+    } else if (buf->ch_layout.nb_channels)
+#endif
+    av_channel_layout_describe(&buf->ch_layout, chlayout_str, sizeof(chlayout_str));
 
     av_log(ctx, AV_LOG_INFO,
            "n:%"PRId64" pts:%s pts_time:%s pos:%"PRId64" "
@@ -210,7 +219,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
            inlink->frame_count_out,
            av_ts2str(buf->pts), av_ts2timestr(buf->pts, &inlink->time_base),
            buf->pkt_pos,
-           av_get_sample_fmt_name(buf->format), buf->channels, chlayout_str,
+           av_get_sample_fmt_name(buf->format), buf->ch_layout.nb_channels, chlayout_str,
            buf->sample_rate, buf->nb_samples,
            checksum);
 
diff --git a/libavfilter/af_asoftclip.c b/libavfilter/af_asoftclip.c
index 6ffde4431a..6212e1d6fe 100644
--- a/libavfilter/af_asoftclip.c
+++ b/libavfilter/af_asoftclip.c
@@ -440,7 +440,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     }
 
     nb_samples = in->nb_samples;
-    channels = in->channels;
+    channels = in->ch_layout.nb_channels;
 
     td.in = in;
     td.out = out;
diff --git a/libavfilter/af_aspectralstats.c b/libavfilter/af_aspectralstats.c
index da418d22bf..642c1c88ca 100644
--- a/libavfilter/af_aspectralstats.c
+++ b/libavfilter/af_aspectralstats.c
@@ -84,7 +84,7 @@  static int config_output(AVFilterLink *outlink)
     float overlap, scale;
     int ret;
 
-    s->nb_channels = outlink->channels;
+    s->nb_channels = outlink->ch_layout.nb_channels;
     s->fifo = av_audio_fifo_alloc(outlink->format, s->nb_channels, s->win_size);
     if (!s->fifo)
         return AVERROR(ENOMEM);
@@ -474,7 +474,7 @@  static int filter_frame(AVFilterLink *inlink)
 
     metadata = &out->metadata;
     ff_filter_execute(ctx, filter_channel, in, NULL,
-                      FFMIN(inlink->channels, ff_filter_get_nb_threads(ctx)));
+                      FFMIN(inlink->ch_layout.nb_channels, ff_filter_get_nb_threads(ctx)));
 
     set_metadata(s, metadata);
 
diff --git a/libavfilter/af_asr.c b/libavfilter/af_asr.c
index 42250e79e2..b402f5ff26 100644
--- a/libavfilter/af_asr.c
+++ b/libavfilter/af_asr.c
@@ -131,7 +131,7 @@  static int query_formats(AVFilterContext *ctx)
 
     if ((ret = ff_add_format                 (&formats, AV_SAMPLE_FMT_S16                 )) < 0 ||
         (ret = ff_set_common_formats         (ctx     , formats                           )) < 0 ||
-        (ret = ff_add_channel_layout         (&layout , AV_CH_LAYOUT_MONO                 )) < 0 ||
+        (ret = ff_add_channel_layout         (&layout , &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO )) < 0 ||
         (ret = ff_set_common_channel_layouts (ctx     , layout                            )) < 0 ||
         (ret = ff_set_common_samplerates_from_list(ctx, sample_rates     )) < 0)
         return ret;
diff --git a/libavfilter/af_astats.c b/libavfilter/af_astats.c
index 6c79257cb4..d59640a3fd 100644
--- a/libavfilter/af_astats.c
+++ b/libavfilter/af_astats.c
@@ -194,12 +194,12 @@  static int config_output(AVFilterLink *outlink)
 {
     AudioStatsContext *s = outlink->src->priv;
 
-    s->chstats = av_calloc(sizeof(*s->chstats), outlink->channels);
+    s->chstats = av_calloc(sizeof(*s->chstats), outlink->ch_layout.nb_channels);
     if (!s->chstats)
         return AVERROR(ENOMEM);
 
     s->tc_samples = FFMAX(s->time_constant * outlink->sample_rate + .5, 1);
-    s->nb_channels = outlink->channels;
+    s->nb_channels = outlink->ch_layout.nb_channels;
 
     for (int i = 0; i < s->nb_channels; i++) {
         ChannelStats *p = &s->chstats[i];
@@ -584,8 +584,8 @@  static int filter_channel(AVFilterContext *ctx, void *arg, int jobnr, int nb_job
     const uint8_t * const * const data = (const uint8_t * const *)buf->extended_data;
     const int channels = s->nb_channels;
     const int samples = buf->nb_samples;
-    const int start = (buf->channels * jobnr) / nb_jobs;
-    const int end = (buf->channels * (jobnr+1)) / nb_jobs;
+    const int start = (buf->ch_layout.nb_channels * jobnr) / nb_jobs;
+    const int end = (buf->ch_layout.nb_channels * (jobnr+1)) / nb_jobs;
 
     switch (inlink->format) {
     case AV_SAMPLE_FMT_DBLP:
@@ -638,7 +638,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
     }
 
     ff_filter_execute(ctx, filter_channel, buf, NULL,
-                      FFMIN(inlink->channels, ff_filter_get_nb_threads(ctx)));
+                      FFMIN(inlink->ch_layout.nb_channels, ff_filter_get_nb_threads(ctx)));
 
     if (s->metadata)
         set_metadata(s, metadata);
diff --git a/libavfilter/af_asubboost.c b/libavfilter/af_asubboost.c
index da3e68e841..11b0825f97 100644
--- a/libavfilter/af_asubboost.c
+++ b/libavfilter/af_asubboost.c
@@ -76,7 +76,7 @@  static int config_input(AVFilterLink *inlink)
 
     s->buffer = ff_get_audio_buffer(inlink, inlink->sample_rate / 10);
     s->w = ff_get_audio_buffer(inlink, 2);
-    s->write_pos = av_calloc(inlink->channels, sizeof(*s->write_pos));
+    s->write_pos = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->write_pos));
     if (!s->buffer || !s->w || !s->write_pos)
         return AVERROR(ENOMEM);
 
@@ -102,8 +102,8 @@  static int filter_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo
     const double b2 = s->b2;
     const double a1 = -s->a1;
     const double a2 = -s->a2;
-    const int start = (in->channels * jobnr) / nb_jobs;
-    const int end = (in->channels * (jobnr+1)) / nb_jobs;
+    const int start = (in->ch_layout.nb_channels * jobnr) / nb_jobs;
+    const int end = (in->ch_layout.nb_channels * (jobnr+1)) / nb_jobs;
     const int buffer_samples = s->buffer_samples;
 
     for (int ch = start; ch < end; ch++) {
@@ -153,7 +153,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 
     td.in = in; td.out = out;
     ff_filter_execute(ctx, filter_channels, &td, NULL,
-                      FFMIN(inlink->channels, ff_filter_get_nb_threads(ctx)));
+                      FFMIN(inlink->ch_layout.nb_channels, ff_filter_get_nb_threads(ctx)));
 
     if (out != in)
         av_frame_free(&in);
diff --git a/libavfilter/af_asupercut.c b/libavfilter/af_asupercut.c
index a4c2d15154..5c06d559ed 100644
--- a/libavfilter/af_asupercut.c
+++ b/libavfilter/af_asupercut.c
@@ -210,8 +210,8 @@  static int filter_channels_## name(AVFilterContext *ctx, void *arg, \
     ThreadData *td = arg;                                           \
     AVFrame *out = td->out;                                         \
     AVFrame *in = td->in;                                           \
-    const int start = (in->channels * jobnr) / nb_jobs;             \
-    const int end = (in->channels * (jobnr+1)) / nb_jobs;           \
+    const int start = (in->ch_layout.nb_channels * jobnr) / nb_jobs; \
+    const int end = (in->ch_layout.nb_channels * (jobnr+1)) / nb_jobs; \
     const double level = s->level;                                  \
                                                                     \
     for (int ch = start; ch < end; ch++) {                          \
@@ -286,7 +286,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 
     td.in = in; td.out = out;
     ff_filter_execute(ctx, s->filter_channels, &td, NULL,
-                      FFMIN(inlink->channels, ff_filter_get_nb_threads(ctx)));
+                      FFMIN(inlink->ch_layout.nb_channels, ff_filter_get_nb_threads(ctx)));
 
     if (out != in)
         av_frame_free(&in);
diff --git a/libavfilter/af_atempo.c b/libavfilter/af_atempo.c
index e9a6da7970..e06277b804 100644
--- a/libavfilter/af_atempo.c
+++ b/libavfilter/af_atempo.c
@@ -1016,7 +1016,7 @@  static int config_props(AVFilterLink *inlink)
     enum AVSampleFormat format = inlink->format;
     int sample_rate = (int)inlink->sample_rate;
 
-    return yae_reset(atempo, format, sample_rate, inlink->channels);
+    return yae_reset(atempo, format, sample_rate, inlink->ch_layout.nb_channels);
 }
 
 static int push_samples(ATempoContext *atempo,
diff --git a/libavfilter/af_atilt.c b/libavfilter/af_atilt.c
index a6f7782af5..9ece531ea4 100644
--- a/libavfilter/af_atilt.c
+++ b/libavfilter/af_atilt.c
@@ -125,8 +125,8 @@  static int filter_channels_## name(AVFilterContext *ctx, void *arg, \
     ThreadData *td = arg;                                           \
     AVFrame *out = td->out;                                         \
     AVFrame *in = td->in;                                           \
-    const int start = (in->channels * jobnr) / nb_jobs;             \
-    const int end = (in->channels * (jobnr+1)) / nb_jobs;           \
+    const int start = (in->ch_layout.nb_channels * jobnr) / nb_jobs; \
+    const int end = (in->ch_layout.nb_channels * (jobnr+1)) / nb_jobs; \
     const type level = s->level;                                    \
                                                                     \
     for (int ch = start; ch < end; ch++) {                          \
@@ -196,7 +196,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     }
 
     td.in = in; td.out = out;
-    ff_filter_execute(ctx, s->filter_channels, &td, NULL, FFMIN(inlink->channels,
+    ff_filter_execute(ctx, s->filter_channels, &td, NULL, FFMIN(inlink->ch_layout.nb_channels,
                                                                ff_filter_get_nb_threads(ctx)));
 
     if (out != in)
diff --git a/libavfilter/af_axcorrelate.c b/libavfilter/af_axcorrelate.c
index d0a91cd836..9be3f1c921 100644
--- a/libavfilter/af_axcorrelate.c
+++ b/libavfilter/af_axcorrelate.c
@@ -113,7 +113,7 @@  static int xcorrelate_slow_##suffix(AVFilterContext *ctx, \
     const int size = FFMIN(available, s->size);           \
     int used;                                             \
                                                           \
-    for (int ch = 0; ch < out->channels; ch++) {          \
+    for (int ch = 0; ch < out->ch_layout.nb_channels; ch++) {         \
         const type *x = (const type *)s->cache[0]->extended_data[ch]; \
         const type *y = (const type *)s->cache[1]->extended_data[ch]; \
         type *sumx = (type *)s->mean_sum[0]->extended_data[ch];       \
@@ -155,7 +155,7 @@  static int xcorrelate_fast_##suffix(AVFilterContext *ctx, AVFrame *out,        \
     const int size = FFMIN(available, s->size);                                \
     int used;                                                                  \
                                                                                \
-    for (int ch = 0; ch < out->channels; ch++) {                               \
+    for (int ch = 0; ch < out->ch_layout.nb_channels; ch++) {                  \
         const type *x = (const type *)s->cache[0]->extended_data[ch];          \
         const type *y = (const type *)s->cache[1]->extended_data[ch];          \
         type *num_sum = (type *)s->num_sum->extended_data[ch];                 \
@@ -299,8 +299,8 @@  static int config_output(AVFilterLink *outlink)
 
     s->pts = AV_NOPTS_VALUE;
 
-    s->fifo[0] = av_audio_fifo_alloc(outlink->format, outlink->channels, s->size);
-    s->fifo[1] = av_audio_fifo_alloc(outlink->format, outlink->channels, s->size);
+    s->fifo[0] = av_audio_fifo_alloc(outlink->format, outlink->ch_layout.nb_channels, s->size);
+    s->fifo[1] = av_audio_fifo_alloc(outlink->format, outlink->ch_layout.nb_channels, s->size);
     if (!s->fifo[0] || !s->fifo[1])
         return AVERROR(ENOMEM);
 
diff --git a/libavfilter/af_biquads.c b/libavfilter/af_biquads.c
index ee42b2a034..2a0747a037 100644
--- a/libavfilter/af_biquads.c
+++ b/libavfilter/af_biquads.c
@@ -125,7 +125,7 @@  typedef struct BiquadsContext {
     double frequency;
     double width;
     double mix;
-    uint64_t channels;
+    AVChannelLayout ch_layout;
     int normalize;
     int order;
 
@@ -716,11 +716,11 @@  static int config_filter(AVFilterLink *outlink, int reset)
         s->b2 *= factor;
     }
 
-    s->cache = av_realloc_f(s->cache, sizeof(ChanCache), inlink->channels);
+    s->cache = av_realloc_f(s->cache, sizeof(ChanCache), inlink->ch_layout.nb_channels);
     if (!s->cache)
         return AVERROR(ENOMEM);
     if (reset)
-        memset(s->cache, 0, sizeof(ChanCache) * inlink->channels);
+        memset(s->cache, 0, sizeof(ChanCache) * inlink->ch_layout.nb_channels);
 
     switch (s->transform_type) {
     case DI:
@@ -838,12 +838,14 @@  static int filter_channel(AVFilterContext *ctx, void *arg, int jobnr, int nb_job
     AVFrame *buf = td->in;
     AVFrame *out_buf = td->out;
     BiquadsContext *s = ctx->priv;
-    const int start = (buf->channels * jobnr) / nb_jobs;
-    const int end = (buf->channels * (jobnr+1)) / nb_jobs;
+    const int start = (buf->ch_layout.nb_channels * jobnr) / nb_jobs;
+    const int end = (buf->ch_layout.nb_channels * (jobnr+1)) / nb_jobs;
     int ch;
 
     for (ch = start; ch < end; ch++) {
-        if (!((av_channel_layout_extract_channel(inlink->channel_layout, ch) & s->channels))) {
+        if (!(av_channel_layout_channel_from_index(&inlink->ch_layout, ch) >= 0 &&
+              av_channel_layout_channel_from_index(&s->ch_layout, ch) >= 0)) {
+
             if (buf != out_buf)
                 memcpy(out_buf->extended_data[ch], buf->extended_data[ch],
                        buf->nb_samples * s->block_align);
@@ -884,9 +886,9 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
     td.in = buf;
     td.out = out_buf;
     ff_filter_execute(ctx, filter_channel, &td, NULL,
-                      FFMIN(outlink->channels, ff_filter_get_nb_threads(ctx)));
+                      FFMIN(outlink->ch_layout.nb_channels, ff_filter_get_nb_threads(ctx)));
 
-    for (ch = 0; ch < outlink->channels; ch++) {
+    for (ch = 0; ch < outlink->ch_layout.nb_channels; ch++) {
         if (s->cache[ch].clippings > 0)
             av_log(ctx, AV_LOG_WARNING, "Channel %d clipping %d times. Please reduce gain.\n",
                    ch, s->cache[ch].clippings);
@@ -982,8 +984,8 @@  static const AVOption equalizer_options[] = {
     {"g",    "set gain", OFFSET(gain), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -900, 900, FLAGS},
     {"mix", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS},
     {"m",   "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS},
-    {"channels", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS},
-    {"c",        "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS},
+    {"channels", "set channels to filter", OFFSET(ch_layout), AV_OPT_TYPE_CHLAYOUT, {.str="0xFFFFFFFF"}, INT64_MIN, INT64_MAX, FLAGS},
+    {"c",        "set channels to filter", OFFSET(ch_layout), AV_OPT_TYPE_CHLAYOUT, {.str="0xFFFFFFFF"}, INT64_MIN, INT64_MAX, FLAGS},
     {"normalize", "normalize coefficients", OFFSET(normalize), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS},
     {"n",         "normalize coefficients", OFFSET(normalize), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS},
     {"transform", "set transform type", OFFSET(transform_type), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_TTYPE-1, AF, "transform_type"},
@@ -1024,8 +1026,8 @@  static const AVOption bass_lowshelf_options[] = {
     {"p",     "set number of poles", OFFSET(poles), AV_OPT_TYPE_INT, {.i64=2}, 1, 2, AF},
     {"mix", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS},
     {"m",   "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS},
-    {"channels", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS},
-    {"c",        "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS},
+    {"channels", "set channels to filter", OFFSET(ch_layout), AV_OPT_TYPE_CHLAYOUT, {.str="0xFFFFFFFF"}, INT64_MIN, INT64_MAX, FLAGS},
+    {"c",        "set channels to filter", OFFSET(ch_layout), AV_OPT_TYPE_CHLAYOUT, {.str="0xFFFFFFFF"}, INT64_MIN, INT64_MAX, FLAGS},
     {"normalize", "normalize coefficients", OFFSET(normalize), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS},
     {"n",         "normalize coefficients", OFFSET(normalize), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS},
     {"transform", "set transform type", OFFSET(transform_type), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_TTYPE-1, AF, "transform_type"},
@@ -1073,8 +1075,8 @@  static const AVOption treble_highshelf_options[] = {
     {"p",     "set number of poles", OFFSET(poles), AV_OPT_TYPE_INT, {.i64=2}, 1, 2, AF},
     {"mix", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS},
     {"m",   "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS},
-    {"channels", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS},
-    {"c",        "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS},
+    {"channels", "set channels to filter", OFFSET(ch_layout), AV_OPT_TYPE_CHLAYOUT, {.str="0xFFFFFFFF"}, INT64_MIN, INT64_MAX, FLAGS},
+    {"c",        "set channels to filter", OFFSET(ch_layout), AV_OPT_TYPE_CHLAYOUT, {.str="0xFFFFFFFF"}, INT64_MIN, INT64_MAX, FLAGS},
     {"normalize", "normalize coefficients", OFFSET(normalize), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS},
     {"n",         "normalize coefficients", OFFSET(normalize), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS},
     {"transform", "set transform type", OFFSET(transform_type), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_TTYPE-1, AF, "transform_type"},
@@ -1121,8 +1123,8 @@  static const AVOption bandpass_options[] = {
     {"csg",   "use constant skirt gain", OFFSET(csg), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS},
     {"mix", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS},
     {"m",   "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS},
-    {"channels", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS},
-    {"c",        "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS},
+    {"channels", "set channels to filter", OFFSET(ch_layout), AV_OPT_TYPE_CHLAYOUT, {.str="0xFFFFFFFF"}, INT64_MIN, INT64_MAX, FLAGS},
+    {"c",        "set channels to filter", OFFSET(ch_layout), AV_OPT_TYPE_CHLAYOUT, {.str="0xFFFFFFFF"}, INT64_MIN, INT64_MAX, FLAGS},
     {"normalize", "normalize coefficients", OFFSET(normalize), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS},
     {"n",         "normalize coefficients", OFFSET(normalize), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS},
     {"transform", "set transform type", OFFSET(transform_type), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_TTYPE-1, AF, "transform_type"},
@@ -1159,8 +1161,8 @@  static const AVOption bandreject_options[] = {
     {"w",     "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 99999, FLAGS},
     {"mix", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS},
     {"m",   "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS},
-    {"channels", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS},
-    {"c",        "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS},
+    {"channels", "set channels to filter", OFFSET(ch_layout), AV_OPT_TYPE_CHLAYOUT, {.str="0xFFFFFFFF"}, INT64_MIN, INT64_MAX, FLAGS},
+    {"c",        "set channels to filter", OFFSET(ch_layout), AV_OPT_TYPE_CHLAYOUT, {.str="0xFFFFFFFF"}, INT64_MIN, INT64_MAX, FLAGS},
     {"normalize", "normalize coefficients", OFFSET(normalize), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS},
     {"n",         "normalize coefficients", OFFSET(normalize), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS},
     {"transform", "set transform type", OFFSET(transform_type), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_TTYPE-1, AF, "transform_type"},
@@ -1199,8 +1201,8 @@  static const AVOption lowpass_options[] = {
     {"p",     "set number of poles", OFFSET(poles), AV_OPT_TYPE_INT, {.i64=2}, 1, 2, AF},
     {"mix", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS},
     {"m",   "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS},
-    {"channels", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS},
-    {"c",        "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS},
+    {"channels", "set channels to filter", OFFSET(ch_layout), AV_OPT_TYPE_CHLAYOUT, {.str="0xFFFFFFFF"}, INT64_MIN, INT64_MAX, FLAGS},
+    {"c",        "set channels to filter", OFFSET(ch_layout), AV_OPT_TYPE_CHLAYOUT, {.str="0xFFFFFFFF"}, INT64_MIN, INT64_MAX, FLAGS},
     {"normalize", "normalize coefficients", OFFSET(normalize), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS},
     {"n",         "normalize coefficients", OFFSET(normalize), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS},
     {"transform", "set transform type", OFFSET(transform_type), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_TTYPE-1, AF, "transform_type"},
@@ -1239,8 +1241,8 @@  static const AVOption highpass_options[] = {
     {"p",     "set number of poles", OFFSET(poles), AV_OPT_TYPE_INT, {.i64=2}, 1, 2, AF},
     {"mix", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS},
     {"m",   "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS},
-    {"channels", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS},
-    {"c",        "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS},
+    {"channels", "set channels to filter", OFFSET(ch_layout), AV_OPT_TYPE_CHLAYOUT, {.str="0xFFFFFFFF"}, INT64_MIN, INT64_MAX, FLAGS},
+    {"c",        "set channels to filter", OFFSET(ch_layout), AV_OPT_TYPE_CHLAYOUT, {.str="0xFFFFFFFF"}, INT64_MIN, INT64_MAX, FLAGS},
     {"normalize", "normalize coefficients", OFFSET(normalize), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS},
     {"n",         "normalize coefficients", OFFSET(normalize), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS},
     {"transform", "set transform type", OFFSET(transform_type), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_TTYPE-1, AF, "transform_type"},
@@ -1277,8 +1279,8 @@  static const AVOption allpass_options[] = {
     {"w",     "set filter-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=707.1}, 0, 99999, FLAGS},
     {"mix", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS},
     {"m",   "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS},
-    {"channels", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS},
-    {"c",        "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS},
+    {"channels", "set channels to filter", OFFSET(ch_layout), AV_OPT_TYPE_CHLAYOUT, {.str="0xFFFFFFFF"}, INT64_MIN, INT64_MAX, FLAGS},
+    {"c",        "set channels to filter", OFFSET(ch_layout), AV_OPT_TYPE_CHLAYOUT, {.str="0xFFFFFFFF"}, INT64_MIN, INT64_MAX, FLAGS},
     {"normalize", "normalize coefficients", OFFSET(normalize), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS},
     {"n",         "normalize coefficients", OFFSET(normalize), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS},
     {"order", "set filter order", OFFSET(order), AV_OPT_TYPE_INT, {.i64=2}, 1, 2, FLAGS},
@@ -1312,8 +1314,8 @@  static const AVOption biquad_options[] = {
     {"b2", NULL, OFFSET(ob2), AV_OPT_TYPE_DOUBLE, {.dbl=0}, INT32_MIN, INT32_MAX, FLAGS},
     {"mix", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS},
     {"m",   "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS},
-    {"channels", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS},
-    {"c",        "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS},
+    {"channels", "set channels to filter", OFFSET(ch_layout), AV_OPT_TYPE_CHLAYOUT, {.str="0xFFFFFFFF"}, INT64_MIN, INT64_MAX, FLAGS},
+    {"c",        "set channels to filter", OFFSET(ch_layout), AV_OPT_TYPE_CHLAYOUT, {.str="0xFFFFFFFF"}, INT64_MIN, INT64_MAX, FLAGS},
     {"normalize", "normalize coefficients", OFFSET(normalize), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS},
     {"n",         "normalize coefficients", OFFSET(normalize), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS},
     {"transform", "set transform type", OFFSET(transform_type), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_TTYPE-1, AF, "transform_type"},
diff --git a/libavfilter/af_bs2b.c b/libavfilter/af_bs2b.c
index 90ae846d95..20e6d8141a 100644
--- a/libavfilter/af_bs2b.c
+++ b/libavfilter/af_bs2b.c
@@ -104,7 +104,7 @@  static int query_formats(AVFilterContext *ctx)
     };
     int ret;
 
-    if (ff_add_channel_layout(&layouts, AV_CH_LAYOUT_STEREO) != 0)
+    if (ff_add_channel_layout(&layouts, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO) != 0)
         return AVERROR(ENOMEM);
     ret = ff_set_common_channel_layouts(ctx, layouts);
     if (ret < 0)
diff --git a/libavfilter/af_channelmap.c b/libavfilter/af_channelmap.c
index d3ab77920f..9e6cafbc24 100644
--- a/libavfilter/af_channelmap.c
+++ b/libavfilter/af_channelmap.c
@@ -38,8 +38,8 @@ 
 #include "internal.h"
 
 struct ChannelMap {
-    uint64_t in_channel;
-    uint64_t out_channel;
+    int in_channel;
+    int out_channel;
     int in_channel_idx;
     int out_channel_idx;
 };
@@ -59,7 +59,7 @@  typedef struct ChannelMapContext {
     const AVClass *class;
     char *mapping_str;
     char *channel_layout_str;
-    uint64_t output_layout;
+    AVChannelLayout output_layout;
     struct ChannelMap map[MAX_CH];
     int nch;
     enum MappingMode mode;
@@ -105,13 +105,13 @@  static int get_channel_idx(char **map, int *ch, char delim, int max_ch)
     return 0;
 }
 
-static int get_channel(char **map, uint64_t *ch, char delim)
+static int get_channel(char **map, int *ch, char delim)
 {
     char *next = split(*map, delim);
     if (!next && delim == '-')
         return AVERROR(EINVAL);
-    *ch = av_get_channel_layout(*map);
-    if (av_get_channel_layout_nb_channels(*ch) != 1)
+    *ch = av_channel_from_string(*map);
+    if (*ch < 0)
         return AVERROR(EINVAL);
     *map = next;
     return 0;
@@ -167,7 +167,7 @@  static av_cold int channelmap_init(AVFilterContext *ctx)
 
     for (i = 0; i < map_entries; i++) {
         int in_ch_idx = -1, out_ch_idx = -1;
-        uint64_t in_ch = 0, out_ch = 0;
+        int in_ch = 0, out_ch = 0;
         static const char err[] = "Failed to parse channel map\n";
         switch (mode) {
         case MAP_ONE_INT:
@@ -198,13 +198,13 @@  static av_cold int channelmap_init(AVFilterContext *ctx)
         case MAP_PAIR_INT_STR:
             if (get_channel_idx(&mapping, &in_ch_idx, '-', MAX_CH) < 0 ||
                 get_channel(&mapping, &out_ch, separator) < 0 ||
-                out_ch & out_ch_mask) {
+                (1ULL << out_ch) & out_ch_mask) {
                 av_log(ctx, AV_LOG_ERROR, err);
                 return AVERROR(EINVAL);
             }
             s->map[i].in_channel_idx  = in_ch_idx;
             s->map[i].out_channel     = out_ch;
-            out_ch_mask |= out_ch;
+            out_ch_mask |= 1ULL << out_ch;
             break;
         case MAP_PAIR_STR_INT:
             if (get_channel(&mapping, &in_ch, '-') < 0 ||
@@ -218,42 +218,57 @@  static av_cold int channelmap_init(AVFilterContext *ctx)
         case MAP_PAIR_STR_STR:
             if (get_channel(&mapping, &in_ch, '-') < 0 ||
                 get_channel(&mapping, &out_ch, separator) < 0 ||
-                out_ch & out_ch_mask) {
+                (1ULL << out_ch) & out_ch_mask) {
                 av_log(ctx, AV_LOG_ERROR, err);
                 return AVERROR(EINVAL);
             }
             s->map[i].in_channel = in_ch;
             s->map[i].out_channel = out_ch;
-            out_ch_mask |= out_ch;
+            out_ch_mask |= 1ULL << out_ch;
             break;
         }
     }
     s->mode          = mode;
     s->nch           = map_entries;
-    s->output_layout = out_ch_mask ? out_ch_mask :
-                       av_get_default_channel_layout(map_entries);
+    if (out_ch_mask)
+        av_channel_layout_from_mask(&s->output_layout, out_ch_mask);
+    else
+        av_channel_layout_default(&s->output_layout, map_entries);
 
     if (s->channel_layout_str) {
-        uint64_t fmt;
-        if ((fmt = av_get_channel_layout(s->channel_layout_str)) == 0) {
-            av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout: '%s'.\n",
+        AVChannelLayout fmt = { 0 };
+        int ret;
+        if ((ret = av_channel_layout_from_string(&fmt, s->channel_layout_str)) < 0) {
+#if FF_API_OLD_CHANNEL_LAYOUT
+            uint64_t mask;
+FF_DISABLE_DEPRECATION_WARNINGS
+            if ((mask = av_get_channel_layout(s->channel_layout_str)) == 0) {
+#endif
+                av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout: '%s'.\n",
+                       s->channel_layout_str);
+                return AVERROR(EINVAL);
+#if FF_API_OLD_CHANNEL_LAYOUT
+            }
+FF_ENABLE_DEPRECATION_WARNINGS
+            av_log(ctx, AV_LOG_WARNING, "Channel layout '%s' uses a deprecated syntax.\n",
                    s->channel_layout_str);
-            return AVERROR(EINVAL);
+            av_channel_layout_from_mask(&fmt, mask);
+#endif
         }
         if (mode == MAP_NONE) {
             int i;
-            s->nch = av_get_channel_layout_nb_channels(fmt);
+            s->nch = fmt.nb_channels;
             for (i = 0; i < s->nch; i++) {
                 s->map[i].in_channel_idx  = i;
                 s->map[i].out_channel_idx = i;
             }
-        } else if (out_ch_mask && out_ch_mask != fmt) {
-            av_get_channel_layout_string(buf, sizeof(buf), 0, out_ch_mask);
+        } else if (out_ch_mask && av_channel_layout_compare(&s->output_layout, &fmt)) {
+            av_channel_layout_describe(&s->output_layout, buf, sizeof(buf));
             av_log(ctx, AV_LOG_ERROR,
                    "Output channel layout '%s' does not match the list of channel mapped: '%s'.\n",
                    s->channel_layout_str, buf);
             return AVERROR(EINVAL);
-        } else if (s->nch != av_get_channel_layout_nb_channels(fmt)) {
+        } else if (s->nch != fmt.nb_channels) {
             av_log(ctx, AV_LOG_ERROR,
                    "Output channel layout %s does not match the number of channels mapped %d.\n",
                    s->channel_layout_str, s->nch);
@@ -261,7 +276,7 @@  static av_cold int channelmap_init(AVFilterContext *ctx)
         }
         s->output_layout = fmt;
     }
-    if (!s->output_layout) {
+    if (!s->output_layout.nb_channels) {
         av_log(ctx, AV_LOG_ERROR, "Output channel layout is not set and "
                "cannot be guessed from the maps.\n");
         return AVERROR(EINVAL);
@@ -269,8 +284,8 @@  static av_cold int channelmap_init(AVFilterContext *ctx)
 
     if (mode == MAP_PAIR_INT_STR || mode == MAP_PAIR_STR_STR) {
         for (i = 0; i < s->nch; i++) {
-            s->map[i].out_channel_idx = av_get_channel_layout_channel_index(
-                s->output_layout, s->map[i].out_channel);
+            s->map[i].out_channel_idx = av_channel_layout_index_from_channel(
+                &s->output_layout, s->map[i].out_channel);
         }
     }
 
@@ -285,7 +300,7 @@  static int channelmap_query_formats(AVFilterContext *ctx)
 
     if ((ret = ff_set_common_formats    (ctx,  ff_planar_sample_fmts()))  < 0 ||
         (ret = ff_set_common_all_samplerates(ctx                              )) < 0 ||
-        (ret = ff_add_channel_layout(&channel_layouts, s->output_layout)) < 0 ||
+        (ret = ff_add_channel_layout(&channel_layouts, &s->output_layout)) < 0 ||
         (ret = ff_channel_layouts_ref(channel_layouts,
                                       &ctx->outputs[0]->incfg.channel_layouts)) < 0)
         return ret;
@@ -299,9 +314,9 @@  static int channelmap_filter_frame(AVFilterLink *inlink, AVFrame *buf)
     AVFilterContext  *ctx = inlink->dst;
     AVFilterLink *outlink = ctx->outputs[0];
     const ChannelMapContext *s = ctx->priv;
-    const int nch_in = inlink->channels;
+    const int nch_in = inlink->ch_layout.nb_channels;
     const int nch_out = s->nch;
-    int ch;
+    int ch, ret;
     uint8_t *source_planes[MAX_CH];
 
     memcpy(source_planes, buf->extended_data,
@@ -336,8 +351,14 @@  static int channelmap_filter_frame(AVFilterLink *inlink, AVFrame *buf)
         memcpy(buf->data, buf->extended_data,
            FFMIN(FF_ARRAY_ELEMS(buf->data), nch_out) * sizeof(buf->data[0]));
 
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
+    buf->ch_layout.nb_channels = outlink->ch_layout.nb_channels;
     buf->channel_layout = outlink->channel_layout;
-    buf->channels       = outlink->channels;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+    if ((ret = av_channel_layout_copy(&buf->ch_layout, &outlink->ch_layout)) < 0)
+        return ret;
 
     return ff_filter_frame(outlink, buf);
 }
@@ -346,24 +367,23 @@  static int channelmap_config_input(AVFilterLink *inlink)
 {
     AVFilterContext *ctx = inlink->dst;
     ChannelMapContext *s = ctx->priv;
-    int nb_channels = inlink->channels;
+    int nb_channels = inlink->ch_layout.nb_channels;
     int i, err = 0;
-    const char *channel_name;
+    char channel_name[64];
     char layout_name[256];
 
     for (i = 0; i < s->nch; i++) {
         struct ChannelMap *m = &s->map[i];
 
         if (s->mode == MAP_PAIR_STR_INT || s->mode == MAP_PAIR_STR_STR) {
-            m->in_channel_idx = av_get_channel_layout_channel_index(
-                inlink->channel_layout, m->in_channel);
+            m->in_channel_idx = av_channel_layout_index_from_channel(
+                &inlink->ch_layout, m->in_channel);
         }
 
         if (m->in_channel_idx < 0 || m->in_channel_idx >= nb_channels) {
-            av_get_channel_layout_string(layout_name, sizeof(layout_name),
-                                         nb_channels, inlink->channel_layout);
+            av_channel_layout_describe(&inlink->ch_layout, layout_name, sizeof(layout_name));
             if (m->in_channel) {
-                channel_name = av_get_channel_name(m->in_channel);
+                av_channel_name(channel_name, sizeof(channel_name), m->in_channel);
                 av_log(ctx, AV_LOG_ERROR,
                        "input channel '%s' not available from input layout '%s'\n",
                        channel_name, layout_name);
diff --git a/libavfilter/af_channelsplit.c b/libavfilter/af_channelsplit.c
index 1a2519dd32..31453823c5 100644
--- a/libavfilter/af_channelsplit.c
+++ b/libavfilter/af_channelsplit.c
@@ -36,7 +36,7 @@ 
 typedef struct ChannelSplitContext {
     const AVClass *class;
 
-    uint64_t channel_layout;
+    AVChannelLayout channel_layout;
     char    *channel_layout_str;
     char    *channels_str;
 
@@ -57,11 +57,11 @@  AVFILTER_DEFINE_CLASS(channelsplit);
 static av_cold int init(AVFilterContext *ctx)
 {
     ChannelSplitContext *s = ctx->priv;
-    uint64_t channel_layout;
+    AVChannelLayout channel_layout = { 0 };
     int nb_channels;
     int all = 0, ret = 0, i;
 
-    if (!(s->channel_layout = av_get_channel_layout(s->channel_layout_str))) {
+    if ((ret = av_channel_layout_from_string(&s->channel_layout, s->channel_layout_str)) < 0) {
         av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout '%s'.\n",
                s->channel_layout_str);
         ret = AVERROR(EINVAL);
@@ -70,27 +70,32 @@  static av_cold int init(AVFilterContext *ctx)
 
 
     if (!strcmp(s->channels_str, "all")) {
-        nb_channels = av_get_channel_layout_nb_channels(s->channel_layout);
+        nb_channels = s->channel_layout.nb_channels;
         channel_layout = s->channel_layout;
         all = 1;
     } else {
-        if ((ret = av_get_extended_channel_layout(s->channels_str, &channel_layout, &nb_channels)) < 0)
+        if ((ret = av_channel_layout_from_string(&channel_layout, s->channels_str)) < 0)
             return ret;
     }
 
     for (i = 0; i < nb_channels; i++) {
-        uint64_t channel = av_channel_layout_extract_channel(channel_layout, i);
-        AVFilterPad pad  = { 0 };
+        int channel = av_channel_layout_channel_from_index(&channel_layout, i);
+        char buf[64];
+        AVFilterPad pad = { .flags = AVFILTERPAD_FLAG_FREE_NAME };
 
+        av_channel_name(buf, sizeof(buf), channel);
         pad.type = AVMEDIA_TYPE_AUDIO;
-        pad.name = av_get_channel_name(channel);
+        pad.name = av_strdup(buf);
+        if (!pad.name)
+            return AVERROR(ENOMEM);
 
         if (all) {
             s->map[i] = i;
         } else {
-            if ((ret = av_get_channel_layout_channel_index(s->channel_layout, channel)) < 0) {
+            if ((ret = av_channel_layout_index_from_channel(&s->channel_layout, channel)) < 0) {
                 av_log(ctx, AV_LOG_ERROR, "Channel name '%s' not present in channel layout '%s'.\n",
-                       av_get_channel_name(channel), s->channel_layout_str);
+                       pad.name, s->channel_layout_str);
+                av_freep(&pad.name);
                 return ret;
             }
 
@@ -115,15 +120,18 @@  static int query_formats(AVFilterContext *ctx)
         (ret = ff_set_common_all_samplerates(ctx)) < 0)
         return ret;
 
-    if ((ret = ff_add_channel_layout(&in_layouts, s->channel_layout)) < 0 ||
+    if ((ret = ff_add_channel_layout(&in_layouts, &s->channel_layout)) < 0 ||
         (ret = ff_channel_layouts_ref(in_layouts, &ctx->inputs[0]->outcfg.channel_layouts)) < 0)
         return ret;
 
     for (i = 0; i < ctx->nb_outputs; i++) {
+        AVChannelLayout channel_layout = { 0 };
         AVFilterChannelLayouts *out_layouts = NULL;
-        uint64_t channel = av_channel_layout_extract_channel(s->channel_layout, s->map[i]);
+        int channel = av_channel_layout_channel_from_index(&s->channel_layout, s->map[i]);
 
-        if ((ret = ff_add_channel_layout(&out_layouts, channel)) < 0 ||
+        if ((channel < 0) ||
+            (ret = av_channel_layout_from_mask(&channel_layout, 1ULL << channel)) < 0 ||
+            (ret = ff_add_channel_layout(&out_layouts, &channel_layout)) < 0 ||
             (ret = ff_channel_layouts_ref(out_layouts, &ctx->outputs[i]->incfg.channel_layouts)) < 0)
             return ret;
     }
@@ -139,6 +147,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
 
     for (i = 0; i < ctx->nb_outputs; i++) {
         AVFrame *buf_out = av_frame_clone(buf);
+        int channel = av_channel_layout_channel_from_index(&buf->ch_layout, s->map[i]);
 
         if (!buf_out) {
             ret = AVERROR(ENOMEM);
@@ -146,9 +155,16 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
         }
 
         buf_out->data[0] = buf_out->extended_data[0] = buf_out->extended_data[s->map[i]];
+        ret = av_channel_layout_from_mask(&buf_out->ch_layout, 1ULL << channel);
+        if (ret < 0)
+            break;
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
         buf_out->channel_layout =
             av_channel_layout_extract_channel(buf->channel_layout, s->map[i]);
         buf_out->channels = 1;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
 
         ret = ff_filter_frame(ctx->outputs[i], buf_out);
         if (ret < 0)
diff --git a/libavfilter/af_chorus.c b/libavfilter/af_chorus.c
index 68de692c4b..19826cfb15 100644
--- a/libavfilter/af_chorus.c
+++ b/libavfilter/af_chorus.c
@@ -161,7 +161,7 @@  static int config_output(AVFilterLink *outlink)
     float sum_in_volume = 1.0;
     int n;
 
-    s->channels = outlink->channels;
+    s->channels = outlink->ch_layout.nb_channels;
 
     for (n = 0; n < s->num_chorus; n++) {
         int samples = (int) ((s->delays[n] + s->depths[n]) * outlink->sample_rate / 1000.0);
@@ -184,15 +184,15 @@  static int config_output(AVFilterLink *outlink)
     if (s->in_gain * (sum_in_volume) > 1.0 / s->out_gain)
         av_log(ctx, AV_LOG_WARNING, "output gain can cause saturation or clipping of output\n");
 
-    s->counter = av_calloc(outlink->channels, sizeof(*s->counter));
+    s->counter = av_calloc(outlink->ch_layout.nb_channels, sizeof(*s->counter));
     if (!s->counter)
         return AVERROR(ENOMEM);
 
-    s->phase = av_calloc(outlink->channels, sizeof(*s->phase));
+    s->phase = av_calloc(outlink->ch_layout.nb_channels, sizeof(*s->phase));
     if (!s->phase)
         return AVERROR(ENOMEM);
 
-    for (n = 0; n < outlink->channels; n++) {
+    for (n = 0; n < outlink->ch_layout.nb_channels; n++) {
         s->phase[n] = av_calloc(s->num_chorus, sizeof(int));
         if (!s->phase[n])
             return AVERROR(ENOMEM);
@@ -201,7 +201,7 @@  static int config_output(AVFilterLink *outlink)
     s->fade_out = s->max_samples;
 
     return av_samples_alloc_array_and_samples(&s->chorusbuf, NULL,
-                                              outlink->channels,
+                                              outlink->ch_layout.nb_channels,
                                               s->max_samples,
                                               outlink->format, 0);
 }
@@ -226,7 +226,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
         av_frame_copy_props(out_frame, frame);
     }
 
-    for (c = 0; c < inlink->channels; c++) {
+    for (c = 0; c < inlink->ch_layout.nb_channels; c++) {
         const float *src = (const float *)frame->extended_data[c];
         float *dst = (float *)out_frame->extended_data[c];
         float *chorusbuf = (float *)s->chorusbuf[c];
@@ -280,7 +280,7 @@  static int request_frame(AVFilterLink *outlink)
 
         av_samples_set_silence(frame->extended_data, 0,
                                frame->nb_samples,
-                               outlink->channels,
+                               outlink->ch_layout.nb_channels,
                                frame->format);
 
         frame->pts = s->next_pts;
diff --git a/libavfilter/af_compand.c b/libavfilter/af_compand.c
index 2f8a580279..ba90d21ced 100644
--- a/libavfilter/af_compand.c
+++ b/libavfilter/af_compand.c
@@ -146,7 +146,7 @@  static int compand_nodelay(AVFilterContext *ctx, AVFrame *frame)
 {
     CompandContext *s    = ctx->priv;
     AVFilterLink *inlink = ctx->inputs[0];
-    const int channels   = inlink->channels;
+    const int channels   = inlink->ch_layout.nb_channels;
     const int nb_samples = frame->nb_samples;
     AVFrame *out_frame;
     int chan, i;
@@ -192,7 +192,7 @@  static int compand_delay(AVFilterContext *ctx, AVFrame *frame)
 {
     CompandContext *s    = ctx->priv;
     AVFilterLink *inlink = ctx->inputs[0];
-    const int channels = inlink->channels;
+    const int channels = inlink->ch_layout.nb_channels;
     const int nb_samples = frame->nb_samples;
     int chan, i, av_uninit(dindex), oindex, av_uninit(count);
     AVFrame *out_frame   = NULL;
@@ -264,7 +264,7 @@  static int compand_drain(AVFilterLink *outlink)
 {
     AVFilterContext *ctx = outlink->src;
     CompandContext *s    = ctx->priv;
-    const int channels   = outlink->channels;
+    const int channels   = outlink->ch_layout.nb_channels;
     AVFrame *frame       = NULL;
     int chan, i, dindex;
 
@@ -302,7 +302,7 @@  static int config_output(AVFilterLink *outlink)
     const int sample_rate = outlink->sample_rate;
     double radius         = s->curve_dB * M_LN10 / 20.0;
     char *p, *saveptr     = NULL;
-    const int channels    = outlink->channels;
+    const int channels    = outlink->ch_layout.nb_channels;
     int nb_attacks, nb_decays, nb_points;
     int new_nb_items, num;
     int i;
@@ -503,7 +503,13 @@  static int config_output(AVFilterLink *outlink)
 
     s->delay_frame->format         = outlink->format;
     s->delay_frame->nb_samples     = s->delay_samples;
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
     s->delay_frame->channel_layout = outlink->channel_layout;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+    if ((err = av_channel_layout_copy(&s->delay_frame->ch_layout, &outlink->ch_layout)) < 0)
+        return err;
 
     err = av_frame_get_buffer(s->delay_frame, 0);
     if (err)
diff --git a/libavfilter/af_compensationdelay.c b/libavfilter/af_compensationdelay.c
index 6a58fd21bd..ac5a342ddb 100644
--- a/libavfilter/af_compensationdelay.c
+++ b/libavfilter/af_compensationdelay.c
@@ -68,6 +68,7 @@  static int config_input(AVFilterLink *inlink)
     AVFilterContext *ctx = inlink->dst;
     CompensationDelayContext *s = ctx->priv;
     unsigned min_size, new_size = 1;
+    int ret;
 
     s->delay = (s->distance_m * 100. + s->distance_cm * 1. + s->distance_mm * .1) *
                COMP_DELAY_SOUND_FRONT_DELAY(s->temp) * inlink->sample_rate;
@@ -83,7 +84,13 @@  static int config_input(AVFilterLink *inlink)
     s->buf_size                    = new_size;
     s->delay_frame->format         = inlink->format;
     s->delay_frame->nb_samples     = new_size;
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
     s->delay_frame->channel_layout = inlink->channel_layout;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+    if ((ret = av_channel_layout_copy(&s->delay_frame->ch_layout, &inlink->ch_layout)) < 0)
+        return ret;
 
     return av_frame_get_buffer(s->delay_frame, 0);
 }
@@ -108,7 +115,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     }
     av_frame_copy_props(out, in);
 
-    for (ch = 0; ch < inlink->channels; ch++) {
+    for (ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {
         const double *src = (const double *)in->extended_data[ch];
         double *dst = (double *)out->extended_data[ch];
         double *buffer = (double *)s->delay_frame->extended_data[ch];
diff --git a/libavfilter/af_crossfeed.c b/libavfilter/af_crossfeed.c
index ecfbb978d4..15990703e1 100644
--- a/libavfilter/af_crossfeed.c
+++ b/libavfilter/af_crossfeed.c
@@ -46,7 +46,7 @@  static int query_formats(AVFilterContext *ctx)
 
     if ((ret = ff_add_format                 (&formats, AV_SAMPLE_FMT_DBL  )) < 0 ||
         (ret = ff_set_common_formats         (ctx     , formats            )) < 0 ||
-        (ret = ff_add_channel_layout         (&layout , AV_CH_LAYOUT_STEREO)) < 0 ||
+        (ret = ff_add_channel_layout         (&layout , &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO)) < 0 ||
         (ret = ff_set_common_channel_layouts (ctx     , layout             )) < 0 ||
         (ret = ff_set_common_all_samplerates (ctx                          )) < 0)
         return ret;
diff --git a/libavfilter/af_crystalizer.c b/libavfilter/af_crystalizer.c
index 8d967fd629..2d0ec50f21 100644
--- a/libavfilter/af_crystalizer.c
+++ b/libavfilter/af_crystalizer.c
@@ -312,10 +312,10 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     td.s = (const void **)in->extended_data;
     td.p = (void **)s->prev->extended_data;
     td.nb_samples = in->nb_samples;
-    td.channels = in->channels;
+    td.channels = in->ch_layout.nb_channels;
     td.mult = ctx->is_disabled ? 0.f : s->mult;
     ff_filter_execute(ctx, s->filter[td.mult >= 0.f][s->clip], &td, NULL,
-                      FFMIN(inlink->channels, ff_filter_get_nb_threads(ctx)));
+                      FFMIN(inlink->ch_layout.nb_channels, ff_filter_get_nb_threads(ctx)));
 
     if (out != in)
         av_frame_free(&in);
diff --git a/libavfilter/af_dcshift.c b/libavfilter/af_dcshift.c
index da7c16550a..480f01f4a3 100644
--- a/libavfilter/af_dcshift.c
+++ b/libavfilter/af_dcshift.c
@@ -73,7 +73,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     }
 
     if (s->limitergain > 0) {
-        for (i = 0; i < inlink->channels; i++) {
+        for (i = 0; i < inlink->ch_layout.nb_channels; i++) {
             const int32_t *src = (int32_t *)in->extended_data[i];
             int32_t *dst = (int32_t *)out->extended_data[i];
 
@@ -98,7 +98,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
             }
         }
     } else {
-        for (i = 0; i < inlink->channels; i++) {
+        for (i = 0; i < inlink->ch_layout.nb_channels; i++) {
             const int32_t *src = (int32_t *)in->extended_data[i];
             int32_t *dst = (int32_t *)out->extended_data[i];
 
diff --git a/libavfilter/af_deesser.c b/libavfilter/af_deesser.c
index 1093e242d7..cdef837155 100644
--- a/libavfilter/af_deesser.c
+++ b/libavfilter/af_deesser.c
@@ -73,11 +73,11 @@  static int config_input(AVFilterLink *inlink)
     AVFilterContext *ctx = inlink->dst;
     DeesserContext *s = ctx->priv;
 
-    s->chan = av_calloc(inlink->channels, sizeof(*s->chan));
+    s->chan = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->chan));
     if (!s->chan)
         return AVERROR(ENOMEM);
 
-    for (int i = 0; i < inlink->channels; i++) {
+    for (int i = 0; i < inlink->ch_layout.nb_channels; i++) {
         DeesserChannel *chan = &s->chan[i];
 
         chan->ratioA = chan->ratioB = 1.0;
@@ -104,7 +104,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
         av_frame_copy_props(out, in);
     }
 
-    for (int ch = 0; ch < inlink->channels; ch++) {
+    for (int ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {
         DeesserChannel *dec = &s->chan[ch];
         double *src = (double *)in->extended_data[ch];
         double *dst = (double *)out->extended_data[ch];
diff --git a/libavfilter/af_drmeter.c b/libavfilter/af_drmeter.c
index 2021cab143..3e80691339 100644
--- a/libavfilter/af_drmeter.c
+++ b/libavfilter/af_drmeter.c
@@ -59,10 +59,10 @@  static int config_output(AVFilterLink *outlink)
 {
     DRMeterContext *s = outlink->src->priv;
 
-    s->chstats = av_calloc(sizeof(*s->chstats), outlink->channels);
+    s->chstats = av_calloc(sizeof(*s->chstats), outlink->ch_layout.nb_channels);
     if (!s->chstats)
         return AVERROR(ENOMEM);
-    s->nb_channels = outlink->channels;
+    s->nb_channels = outlink->ch_layout.nb_channels;
     s->tc_samples = s->time_constant * outlink->sample_rate + .5;
 
     return 0;
diff --git a/libavfilter/af_dynaudnorm.c b/libavfilter/af_dynaudnorm.c
index 783266f8c1..f154f54134 100644
--- a/libavfilter/af_dynaudnorm.c
+++ b/libavfilter/af_dynaudnorm.c
@@ -301,17 +301,17 @@  static int config_input(AVFilterLink *inlink)
 
     uninit(ctx);
 
-    s->channels = inlink->channels;
+    s->channels = inlink->ch_layout.nb_channels;
     s->frame_len = frame_size(inlink->sample_rate, s->frame_len_msec);
     av_log(ctx, AV_LOG_DEBUG, "frame len %d\n", s->frame_len);
 
-    s->prev_amplification_factor = av_malloc_array(inlink->channels, sizeof(*s->prev_amplification_factor));
-    s->dc_correction_value = av_calloc(inlink->channels, sizeof(*s->dc_correction_value));
-    s->compress_threshold = av_calloc(inlink->channels, sizeof(*s->compress_threshold));
-    s->gain_history_original = av_calloc(inlink->channels, sizeof(*s->gain_history_original));
-    s->gain_history_minimum = av_calloc(inlink->channels, sizeof(*s->gain_history_minimum));
-    s->gain_history_smoothed = av_calloc(inlink->channels, sizeof(*s->gain_history_smoothed));
-    s->threshold_history = av_calloc(inlink->channels, sizeof(*s->threshold_history));
+    s->prev_amplification_factor = av_malloc_array(inlink->ch_layout.nb_channels, sizeof(*s->prev_amplification_factor));
+    s->dc_correction_value = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->dc_correction_value));
+    s->compress_threshold = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->compress_threshold));
+    s->gain_history_original = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->gain_history_original));
+    s->gain_history_minimum = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->gain_history_minimum));
+    s->gain_history_smoothed = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->gain_history_smoothed));
+    s->threshold_history = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->threshold_history));
     s->weights = av_malloc_array(MAX_FILTER_SIZE, sizeof(*s->weights));
     s->is_enabled = cqueue_create(s->filter_size, MAX_FILTER_SIZE);
     if (!s->prev_amplification_factor || !s->dc_correction_value ||
@@ -321,7 +321,7 @@  static int config_input(AVFilterLink *inlink)
         !s->is_enabled || !s->weights)
         return AVERROR(ENOMEM);
 
-    for (c = 0; c < inlink->channels; c++) {
+    for (c = 0; c < inlink->ch_layout.nb_channels; c++) {
         s->prev_amplification_factor[c] = 1.0;
 
         s->gain_history_original[c] = cqueue_create(s->filter_size, MAX_FILTER_SIZE);
@@ -364,7 +364,7 @@  static double find_peak_magnitude(AVFrame *frame, int channel)
     int c, i;
 
     if (channel == -1) {
-        for (c = 0; c < frame->channels; c++) {
+        for (c = 0; c < frame->ch_layout.nb_channels; c++) {
             double *data_ptr = (double *)frame->extended_data[c];
 
             for (i = 0; i < frame->nb_samples; i++)
@@ -386,7 +386,7 @@  static double compute_frame_rms(AVFrame *frame, int channel)
     int c, i;
 
     if (channel == -1) {
-        for (c = 0; c < frame->channels; c++) {
+        for (c = 0; c < frame->ch_layout.nb_channels; c++) {
             const double *data_ptr = (double *)frame->extended_data[c];
 
             for (i = 0; i < frame->nb_samples; i++) {
@@ -394,7 +394,7 @@  static double compute_frame_rms(AVFrame *frame, int channel)
             }
         }
 
-        rms_value /= frame->nb_samples * frame->channels;
+        rms_value /= frame->nb_samples * frame->ch_layout.nb_channels;
     } else {
         const double *data_ptr = (double *)frame->extended_data[channel];
         for (i = 0; i < frame->nb_samples; i++) {
diff --git a/libavfilter/af_earwax.c b/libavfilter/af_earwax.c
index fa0162abb2..f420a5ac55 100644
--- a/libavfilter/af_earwax.c
+++ b/libavfilter/af_earwax.c
@@ -88,7 +88,7 @@  static int query_formats(AVFilterContext *ctx)
 
     if ((ret = ff_add_format                 (&formats, AV_SAMPLE_FMT_S16P                )) < 0 ||
         (ret = ff_set_common_formats         (ctx     , formats                           )) < 0 ||
-        (ret = ff_add_channel_layout         (&layout , AV_CH_LAYOUT_STEREO               )) < 0 ||
+        (ret = ff_add_channel_layout         (&layout , &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO)) < 0 ||
         (ret = ff_set_common_channel_layouts (ctx     , layout                            )) < 0 ||
         (ret = ff_set_common_samplerates_from_list(ctx, sample_rates)) < 0)
         return ret;
diff --git a/libavfilter/af_extrastereo.c b/libavfilter/af_extrastereo.c
index 1645ccb944..6f1d691d8e 100644
--- a/libavfilter/af_extrastereo.c
+++ b/libavfilter/af_extrastereo.c
@@ -49,7 +49,7 @@  static int query_formats(AVFilterContext *ctx)
 
     if ((ret = ff_add_format                 (&formats, AV_SAMPLE_FMT_FLT  )) < 0 ||
         (ret = ff_set_common_formats         (ctx     , formats            )) < 0 ||
-        (ret = ff_add_channel_layout         (&layout , AV_CH_LAYOUT_STEREO)) < 0 ||
+        (ret = ff_add_channel_layout         (&layout , &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO)) < 0 ||
         (ret = ff_set_common_channel_layouts (ctx     , layout             )) < 0)
         return ret;
 
diff --git a/libavfilter/af_firequalizer.c b/libavfilter/af_firequalizer.c
index 568b78117a..c19a2fe122 100644
--- a/libavfilter/af_firequalizer.c
+++ b/libavfilter/af_firequalizer.c
@@ -607,14 +607,15 @@  static int generate_kernel(AVFilterContext *ctx, const char *gain, const char *g
     if (s->dumpfile && (!s->dump_buf || !s->analysis_rdft || !(dump_fp = fopen(s->dumpfile, "w"))))
         av_log(ctx, AV_LOG_WARNING, "dumping failed.\n");
 
-    vars[VAR_CHS] = inlink->channels;
-    vars[VAR_CHLAYOUT] = inlink->channel_layout;
+    vars[VAR_CHS] = inlink->ch_layout.nb_channels;
+    vars[VAR_CHLAYOUT] = inlink->ch_layout.order == AV_CHANNEL_ORDER_NATIVE ?
+                         inlink->ch_layout.u.mask : 0;
     vars[VAR_SR] = inlink->sample_rate;
-    for (ch = 0; ch < inlink->channels; ch++) {
+    for (ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {
         float *rdft_buf = s->kernel_tmp_buf + ch * s->rdft_len;
         double result;
         vars[VAR_CH] = ch;
-        vars[VAR_CHID] = av_channel_layout_extract_channel(inlink->channel_layout, ch);
+        vars[VAR_CHID] = av_channel_layout_channel_from_index(&inlink->ch_layout, ch);
         vars[VAR_F] = 0.0;
         if (xlog)
             vars[VAR_F] = log2(0.05 * vars[VAR_F]);
@@ -715,7 +716,7 @@  static int generate_kernel(AVFilterContext *ctx, const char *gain, const char *g
             break;
     }
 
-    memcpy(s->kernel_buf, s->kernel_tmp_buf, (s->multi ? inlink->channels : 1) * s->rdft_len * sizeof(*s->kernel_buf));
+    memcpy(s->kernel_buf, s->kernel_tmp_buf, (s->multi ? inlink->ch_layout.nb_channels : 1) * s->rdft_len * sizeof(*s->kernel_buf));
     av_expr_free(gain_expr);
     if (dump_fp)
         fclose(dump_fp);
@@ -754,7 +755,7 @@  static int config_input(AVFilterLink *inlink)
     if (!(s->rdft = av_rdft_init(rdft_bits, DFT_R2C)) || !(s->irdft = av_rdft_init(rdft_bits, IDFT_C2R)))
         return AVERROR(ENOMEM);
 
-    if (s->fft2 && !s->multi && inlink->channels > 1 && !(s->fft_ctx = av_fft_init(rdft_bits, 0)))
+    if (s->fft2 && !s->multi && inlink->ch_layout.nb_channels > 1 && !(s->fft_ctx = av_fft_init(rdft_bits, 0)))
         return AVERROR(ENOMEM);
 
     if (s->min_phase) {
@@ -796,15 +797,15 @@  static int config_input(AVFilterLink *inlink)
     }
 
     s->analysis_buf = av_malloc_array(s->analysis_rdft_len, sizeof(*s->analysis_buf));
-    s->kernel_tmp_buf = av_malloc_array(s->rdft_len * (s->multi ? inlink->channels : 1), sizeof(*s->kernel_tmp_buf));
-    s->kernel_buf = av_malloc_array(s->rdft_len * (s->multi ? inlink->channels : 1), sizeof(*s->kernel_buf));
-    s->conv_buf   = av_calloc(2 * s->rdft_len * inlink->channels, sizeof(*s->conv_buf));
-    s->conv_idx   = av_calloc(inlink->channels, sizeof(*s->conv_idx));
+    s->kernel_tmp_buf = av_malloc_array(s->rdft_len * (s->multi ? inlink->ch_layout.nb_channels : 1), sizeof(*s->kernel_tmp_buf));
+    s->kernel_buf = av_malloc_array(s->rdft_len * (s->multi ? inlink->ch_layout.nb_channels : 1), sizeof(*s->kernel_buf));
+    s->conv_buf   = av_calloc(2 * s->rdft_len * inlink->ch_layout.nb_channels, sizeof(*s->conv_buf));
+    s->conv_idx   = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->conv_idx));
     if (!s->analysis_buf || !s->kernel_tmp_buf || !s->kernel_buf || !s->conv_buf || !s->conv_idx)
         return AVERROR(ENOMEM);
 
     av_log(ctx, AV_LOG_DEBUG, "sample_rate = %d, channels = %d, analysis_rdft_len = %d, rdft_len = %d, fir_len = %d, nsamples_max = %d.\n",
-           inlink->sample_rate, inlink->channels, s->analysis_rdft_len, s->rdft_len, s->fir_len, s->nsamples_max);
+           inlink->sample_rate, inlink->ch_layout.nb_channels, s->analysis_rdft_len, s->rdft_len, s->fir_len, s->nsamples_max);
 
     if (s->fixed)
         inlink->min_samples = inlink->max_samples = s->nsamples_max;
@@ -819,19 +820,19 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
     int ch;
 
     if (!s->min_phase) {
-        for (ch = 0; ch + 1 < inlink->channels && s->fft_ctx; ch += 2) {
+        for (ch = 0; ch + 1 < inlink->ch_layout.nb_channels && s->fft_ctx; ch += 2) {
             fast_convolute2(s, s->kernel_buf, (FFTComplex *)(s->conv_buf + 2 * ch * s->rdft_len),
                             s->conv_idx + ch, (float *) frame->extended_data[ch],
                             (float *) frame->extended_data[ch+1], frame->nb_samples);
         }
 
-        for ( ; ch < inlink->channels; ch++) {
+        for ( ; ch < inlink->ch_layout.nb_channels; ch++) {
             fast_convolute(s, s->kernel_buf + (s->multi ? ch * s->rdft_len : 0),
                         s->conv_buf + 2 * ch * s->rdft_len, s->conv_idx + ch,
                         (float *) frame->extended_data[ch], frame->nb_samples);
         }
     } else {
-        for (ch = 0; ch < inlink->channels; ch++) {
+        for (ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {
             fast_convolute_nonlinear(s, s->kernel_buf + (s->multi ? ch * s->rdft_len : 0),
                                      s->conv_buf + 2 * ch * s->rdft_len, s->conv_idx + ch,
                                      (float *) frame->extended_data[ch], frame->nb_samples);
@@ -861,7 +862,7 @@  static int request_frame(AVFilterLink *outlink)
         if (!frame)
             return AVERROR(ENOMEM);
 
-        av_samples_set_silence(frame->extended_data, 0, frame->nb_samples, outlink->channels, frame->format);
+        av_samples_set_silence(frame->extended_data, 0, frame->nb_samples, outlink->ch_layout.nb_channels, frame->format);
         frame->pts = s->next_pts;
         s->remaining -= frame->nb_samples;
         ret = filter_frame(ctx->inputs[0], frame);
diff --git a/libavfilter/af_flanger.c b/libavfilter/af_flanger.c
index ba8d033ce8..452436a4b6 100644
--- a/libavfilter/af_flanger.c
+++ b/libavfilter/af_flanger.c
@@ -95,7 +95,7 @@  static int config_input(AVFilterLink *inlink)
 
     s->max_samples = (s->delay_min + s->delay_depth) * inlink->sample_rate + 2.5;
     s->lfo_length  = inlink->sample_rate / s->speed;
-    s->delay_last  = av_calloc(inlink->channels, sizeof(*s->delay_last));
+    s->delay_last  = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->delay_last));
     s->lfo         = av_calloc(s->lfo_length, sizeof(*s->lfo));
     if (!s->lfo || !s->delay_last)
         return AVERROR(ENOMEM);
@@ -105,7 +105,7 @@  static int config_input(AVFilterLink *inlink)
                            s->max_samples - 2., 3 * M_PI_2);
 
     return av_samples_alloc_array_and_samples(&s->delay_buffer, NULL,
-                                              inlink->channels, s->max_samples,
+                                              inlink->ch_layout.nb_channels, s->max_samples,
                                               inlink->format, 0);
 }
 
@@ -131,7 +131,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
 
         s->delay_buf_pos = (s->delay_buf_pos + s->max_samples - 1) % s->max_samples;
 
-        for (chan = 0; chan < inlink->channels; chan++) {
+        for (chan = 0; chan < inlink->ch_layout.nb_channels; chan++) {
             double *src = (double *)frame->extended_data[chan];
             double *dst = (double *)out_frame->extended_data[chan];
             double delayed_0, delayed_1;
diff --git a/libavfilter/af_haas.c b/libavfilter/af_haas.c
index 281ec276f9..d283da7261 100644
--- a/libavfilter/af_haas.c
+++ b/libavfilter/af_haas.c
@@ -87,7 +87,7 @@  static int query_formats(AVFilterContext *ctx)
 
     if ((ret = ff_add_format                 (&formats, AV_SAMPLE_FMT_DBL  )) < 0 ||
         (ret = ff_set_common_formats         (ctx     , formats            )) < 0 ||
-        (ret = ff_add_channel_layout         (&layout , AV_CH_LAYOUT_STEREO)) < 0 ||
+        (ret = ff_add_channel_layout         (&layout , &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO)) < 0 ||
         (ret = ff_set_common_channel_layouts (ctx     , layout             )) < 0)
         return ret;
 
diff --git a/libavfilter/af_hdcd.c b/libavfilter/af_hdcd.c
index 494642106d..49bfa1bfa8 100644
--- a/libavfilter/af_hdcd.c
+++ b/libavfilter/af_hdcd.c
@@ -1554,27 +1554,27 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     switch (inlink->format) {
         case AV_SAMPLE_FMT_S16P:
             for (n = 0; n < in->nb_samples; n++)
-                for (c = 0; c < in->channels; c++) {
+                for (c = 0; c < in->ch_layout.nb_channels; c++) {
                     in_data = (int16_t*)in->extended_data[c];
-                    out_data[(n * in->channels) + c] = in_data[n];
+                    out_data[(n * in->ch_layout.nb_channels) + c] = in_data[n];
                 }
             break;
         case AV_SAMPLE_FMT_S16:
             in_data  = (int16_t*)in->data[0];
-            for (n = 0; n < in->nb_samples * in->channels; n++)
+            for (n = 0; n < in->nb_samples * in->ch_layout.nb_channels; n++)
                 out_data[n] = in_data[n];
             break;
 
         case AV_SAMPLE_FMT_S32P:
             for (n = 0; n < in->nb_samples; n++)
-                for (c = 0; c < in->channels; c++) {
+                for (c = 0; c < in->ch_layout.nb_channels; c++) {
                     in_data32 = (int32_t*)in->extended_data[c];
-                    out_data[(n * in->channels) + c] = in_data32[n] >> a;
+                    out_data[(n * in->ch_layout.nb_channels) + c] = in_data32[n] >> a;
                 }
             break;
         case AV_SAMPLE_FMT_S32:
             in_data32  = (int32_t*)in->data[0];
-            for (n = 0; n < in->nb_samples * in->channels; n++)
+            for (n = 0; n < in->nb_samples * in->ch_layout.nb_channels; n++)
                 out_data[n] = in_data32[n] >> a;
             break;
     }
@@ -1587,14 +1587,14 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
         hdcd_detect_end(&s->detect, 2);
     } else {
         hdcd_detect_start(&s->detect);
-        for (c = 0; c < in->channels; c++) {
-            hdcd_process(s, &s->state[c], out_data + c, in->nb_samples, in->channels);
+        for (c = 0; c < in->ch_layout.nb_channels; c++) {
+            hdcd_process(s, &s->state[c], out_data + c, in->nb_samples, in->ch_layout.nb_channels);
             hdcd_detect_onech(&s->state[c], &s->detect);
         }
-        hdcd_detect_end(&s->detect, in->channels);
+        hdcd_detect_end(&s->detect, in->ch_layout.nb_channels);
     }
 
-    s->sample_count += in->nb_samples * in->channels;
+    s->sample_count += in->nb_samples * in->ch_layout.nb_channels;
 
     av_frame_free(&in);
     return ff_filter_frame(outlink, out);
@@ -1627,10 +1627,10 @@  static int query_formats(AVFilterContext *ctx)
     };
     int ret;
 
-    ret = ff_add_channel_layout(&layouts, AV_CH_LAYOUT_MONO);
+    ret = ff_add_channel_layout(&layouts, &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO);
     if (ret < 0)
         return ret;
-    ret = ff_add_channel_layout(&layouts, AV_CH_LAYOUT_STEREO);
+    ret = ff_add_channel_layout(&layouts, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO);
     if (ret < 0)
         return ret;
 
@@ -1739,8 +1739,8 @@  static int config_input(AVFilterLink *inlink) {
     av_log(ctx, AV_LOG_VERBOSE, "CDT period: %dms (%u samples @44100Hz)\n",
         s->cdt_ms, s->state[0].sustain_reset );
 
-    if (inlink->channels != 2 && s->process_stereo) {
-        av_log(ctx, AV_LOG_WARNING, "process_stereo disabled (channels = %d)\n", inlink->channels);
+    if (inlink->ch_layout.nb_channels != 2 && s->process_stereo) {
+        av_log(ctx, AV_LOG_WARNING, "process_stereo disabled (channels = %d)\n", inlink->ch_layout.nb_channels);
         s->process_stereo = 0;
     }
     av_log(ctx, AV_LOG_VERBOSE, "Process mode: %s\n",
diff --git a/libavfilter/af_headphone.c b/libavfilter/af_headphone.c
index b2030dbbbb..2fe36368c1 100644
--- a/libavfilter/af_headphone.c
+++ b/libavfilter/af_headphone.c
@@ -85,13 +85,13 @@  typedef struct HeadphoneContext {
     uint64_t mapping[64];
 } HeadphoneContext;
 
-static int parse_channel_name(const char *arg, uint64_t *rchannel)
+static int parse_channel_name(const char *arg, int *rchannel)
 {
-    uint64_t layout = av_get_channel_layout(arg);
+    int channel = av_channel_from_string(arg);
 
-    if (av_get_channel_layout_nb_channels(layout) != 1)
+    if (channel < 0)
         return AVERROR(EINVAL);
-    *rchannel = layout;
+    *rchannel = channel;
     return 0;
 }
 
@@ -103,14 +103,14 @@  static void parse_map(AVFilterContext *ctx)
 
     p = s->map;
     while ((arg = av_strtok(p, "|", &tokenizer))) {
-        uint64_t out_channel;
+        int out_channel;
 
         p = NULL;
         if (parse_channel_name(arg, &out_channel)) {
             av_log(ctx, AV_LOG_WARNING, "Failed to parse \'%s\' as channel name.\n", arg);
             continue;
         }
-        if (used_channels & out_channel) {
+        if (used_channels & (1ULL << out_channel)) {
             av_log(ctx, AV_LOG_WARNING, "Ignoring duplicate channel '%s'.\n", arg);
             continue;
         }
@@ -152,7 +152,7 @@  static int headphone_convolute(AVFilterContext *ctx, void *arg, int jobnr, int n
     const int air_len = s->air_len;
     const float *src = (const float *)in->data[0];
     float *dst = (float *)out->data[0];
-    const int in_channels = in->channels;
+    const int in_channels = in->ch_layout.nb_channels;
     const int buffer_length = s->buffer_length;
     const uint32_t modulo = (uint32_t)buffer_length - 1;
     float *buffer[64];
@@ -221,7 +221,7 @@  static int headphone_fast_convolute(AVFilterContext *ctx, void *arg, int jobnr,
     const int ir_len = s->ir_len;
     const float *src = (const float *)in->data[0];
     float *dst = (float *)out->data[0];
-    const int in_channels = in->channels;
+    const int in_channels = in->ch_layout.nb_channels;
     const int buffer_length = s->buffer_length;
     const uint32_t modulo = (uint32_t)buffer_length - 1;
     AVComplexFloat *fft_out = s->out_fft[jobnr];
@@ -360,7 +360,7 @@  static int convert_coeffs(AVFilterContext *ctx, AVFilterLink *inlink)
 {
     struct HeadphoneContext *s = ctx->priv;
     const int ir_len = s->ir_len;
-    int nb_input_channels = ctx->inputs[0]->channels;
+    int nb_input_channels = ctx->inputs[0]->ch_layout.nb_channels;
     float gain_lin = expf((s->gain - 3 * nb_input_channels) / 20 * M_LN10);
     AVFrame *frame;
     int ret = 0;
@@ -451,7 +451,7 @@  static int convert_coeffs(AVFilterContext *ctx, AVFilterLink *inlink)
         ptr = (float *)frame->extended_data[0];
 
         if (s->hrir_fmt == HRIR_STEREO) {
-            int idx = av_get_channel_layout_channel_index(inlink->channel_layout,
+            int idx = av_channel_layout_index_from_channel(&inlink->ch_layout,
                                                           s->mapping[i]);
             if (idx < 0)
                 continue;
@@ -478,10 +478,10 @@  static int convert_coeffs(AVFilterContext *ctx, AVFilterLink *inlink)
                 s->tx_fn[0](s->fft[0], fft_out_r, fft_in_r, sizeof(float));
             }
         } else {
-            int I, N = ctx->inputs[1]->channels;
+            int I, N = ctx->inputs[1]->ch_layout.nb_channels;
 
             for (k = 0; k < N / 2; k++) {
-                int idx = av_get_channel_layout_channel_index(inlink->channel_layout,
+                int idx = av_channel_layout_index_from_channel(&inlink->ch_layout,
                                                               s->mapping[k]);
                 if (idx < 0)
                     continue;
@@ -602,7 +602,7 @@  static int query_formats(AVFilterContext *ctx)
     if (ret)
         return ret;
 
-    ret = ff_add_channel_layout(&stereo_layout, AV_CH_LAYOUT_STEREO);
+    ret = ff_add_channel_layout(&stereo_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO);
     if (ret)
         return ret;
     ret = ff_channel_layouts_ref(stereo_layout, &ctx->outputs[0]->incfg.channel_layouts);
@@ -632,13 +632,13 @@  static int config_input(AVFilterLink *inlink)
     AVFilterContext *ctx = inlink->dst;
     HeadphoneContext *s = ctx->priv;
 
-    if (s->nb_irs < inlink->channels) {
-        av_log(ctx, AV_LOG_ERROR, "Number of HRIRs must be >= %d.\n", inlink->channels);
+    if (s->nb_irs < inlink->ch_layout.nb_channels) {
+        av_log(ctx, AV_LOG_ERROR, "Number of HRIRs must be >= %d.\n", inlink->ch_layout.nb_channels);
         return AVERROR(EINVAL);
     }
 
-    s->lfe_channel = av_get_channel_layout_channel_index(inlink->channel_layout,
-                                                         AV_CH_LOW_FREQUENCY);
+    s->lfe_channel = av_channel_layout_index_from_channel(&inlink->ch_layout,
+                                                          AV_CHAN_LOW_FREQUENCY);
     return 0;
 }
 
@@ -694,13 +694,13 @@  static int config_output(AVFilterLink *outlink)
     if (s->hrir_fmt == HRIR_MULTI) {
         AVFilterLink *hrir_link = ctx->inputs[1];
 
-        if (hrir_link->channels < inlink->channels * 2) {
-            av_log(ctx, AV_LOG_ERROR, "Number of channels in HRIR stream must be >= %d.\n", inlink->channels * 2);
+        if (hrir_link->ch_layout.nb_channels < inlink->ch_layout.nb_channels * 2) {
+            av_log(ctx, AV_LOG_ERROR, "Number of channels in HRIR stream must be >= %d.\n", inlink->ch_layout.nb_channels * 2);
             return AVERROR(EINVAL);
         }
     }
 
-    s->gain_lfe = expf((s->gain - 3 * inlink->channels + s->lfe_gain) / 20 * M_LN10);
+    s->gain_lfe = expf((s->gain - 3 * inlink->ch_layout.nb_channels + s->lfe_gain) / 20 * M_LN10);
 
     return 0;
 }
diff --git a/libavfilter/af_join.c b/libavfilter/af_join.c
index 6cc21f465c..3e272d9161 100644
--- a/libavfilter/af_join.c
+++ b/libavfilter/af_join.c
@@ -24,6 +24,7 @@ 
  * a single output
  */
 
+#include "libavutil/avassert.h"
 #include "libavutil/avstring.h"
 #include "libavutil/channel_layout.h"
 #include "libavutil/common.h"
@@ -36,10 +37,10 @@ 
 #include "internal.h"
 
 typedef struct ChannelMap {
-    int input;                ///< input stream index
-    int       in_channel_idx; ///< index of in_channel in the input stream data
-    uint64_t  in_channel;     ///< layout describing the input channel
-    uint64_t out_channel;     ///< layout describing the output channel
+    int input;                     ///< input stream index
+    int            in_channel_idx; ///< index of in_channel in the input stream data
+    enum AVChannel in_channel;
+    enum AVChannel out_channel;
 } ChannelMap;
 
 typedef struct JoinContext {
@@ -48,11 +49,10 @@  typedef struct JoinContext {
     int inputs;
     char *map;
     char    *channel_layout_str;
-    uint64_t channel_layout;
+    AVChannelLayout ch_layout;
 
     int64_t  eof_pts;
 
-    int      nb_channels;
     ChannelMap *channels;
 
     /**
@@ -79,20 +79,21 @@  static const AVOption join_options[] = {
     { NULL }
 };
 
+#define MAP_SEPARATOR '|'
+
 AVFILTER_DEFINE_CLASS(join);
 
 static int parse_maps(AVFilterContext *ctx)
 {
     JoinContext *s = ctx->priv;
-    char separator = '|';
     char *cur      = s->map;
 
     while (cur && *cur) {
+        ChannelMap *map;
         char *sep, *next, *p;
-        uint64_t in_channel = 0, out_channel = 0;
-        int input_idx, out_ch_idx, in_ch_idx;
+        int input_idx, out_ch_idx;
 
-        next = strchr(cur, separator);
+        next = strchr(cur, MAP_SEPARATOR);
         if (next)
             *next++ = 0;
 
@@ -104,28 +105,16 @@  static int parse_maps(AVFilterContext *ctx)
         }
         *sep++ = 0;
 
-#define PARSE_CHANNEL(str, var, inout)                                         \
-        if (!(var = av_get_channel_layout(str))) {                             \
-            av_log(ctx, AV_LOG_ERROR, "Invalid " inout " channel: %s.\n", str);\
-            return AVERROR(EINVAL);                                            \
-        }                                                                      \
-        if (av_get_channel_layout_nb_channels(var) != 1) {                     \
-            av_log(ctx, AV_LOG_ERROR, "Channel map describes more than one "   \
-                   inout " channel.\n");                                       \
-            return AVERROR(EINVAL);                                            \
-        }
-
         /* parse output channel */
-        PARSE_CHANNEL(sep, out_channel, "output");
-        if (!(out_channel & s->channel_layout)) {
-            av_log(ctx, AV_LOG_ERROR, "Output channel '%s' is not present in "
-                   "requested channel layout.\n", sep);
+        out_ch_idx = av_channel_layout_index_from_string(&s->ch_layout, sep);
+        if (out_ch_idx < 0) {
+            av_log(ctx, AV_LOG_ERROR, "Invalid output channel: %s.\n", sep);
             return AVERROR(EINVAL);
         }
 
-        out_ch_idx = av_get_channel_layout_channel_index(s->channel_layout,
-                                                         out_channel);
-        if (s->channels[out_ch_idx].input >= 0) {
+        map = &s->channels[out_ch_idx];
+
+        if (map->input >= 0) {
             av_log(ctx, AV_LOG_ERROR, "Multiple maps for output channel "
                    "'%s'.\n", sep);
             return AVERROR(EINVAL);
@@ -142,19 +131,21 @@  static int parse_maps(AVFilterContext *ctx)
         if (*cur)
             cur++;
 
-        in_ch_idx = strtol(cur, &p, 0);
+        map->input          = input_idx;
+        map->in_channel     = AV_CHAN_NONE;
+        map->in_channel_idx = strtol(cur, &p, 0);
         if (p == cur) {
-            /* channel specifier is not a number,
-             * try to parse as channel name */
-            PARSE_CHANNEL(cur, in_channel, "input");
+            /* channel specifier is not a number, handle as channel name */
+            map->in_channel = av_channel_from_string(cur);
+            if (map->in_channel < 0) {
+                av_log(ctx, AV_LOG_ERROR, "Invalid input channel: %s.\n", cur);
+                return AVERROR(EINVAL);
+            }
+        } else if (map->in_channel_idx < 0) {
+            av_log(ctx, AV_LOG_ERROR, "Invalid input channel index: %d\n", map->in_channel_idx);
+            return AVERROR(EINVAL);
         }
 
-        s->channels[out_ch_idx].input      = input_idx;
-        if (in_channel)
-            s->channels[out_ch_idx].in_channel = in_channel;
-        else
-            s->channels[out_ch_idx].in_channel_idx = in_ch_idx;
-
         cur = next;
     }
     return 0;
@@ -165,22 +156,37 @@  static av_cold int join_init(AVFilterContext *ctx)
     JoinContext *s = ctx->priv;
     int ret, i;
 
-    if (!(s->channel_layout = av_get_channel_layout(s->channel_layout_str))) {
-        av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout '%s'.\n",
+    ret = av_channel_layout_from_string(&s->ch_layout, s->channel_layout_str);
+    if (ret < 0) {
+#if FF_API_OLD_CHANNEL_LAYOUT
+        uint64_t mask;
+FF_DISABLE_DEPRECATION_WARNINGS
+        mask = av_get_channel_layout(s->channel_layout_str);
+        if (!mask) {
+#endif
+            av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout '%s'.\n",
+                   s->channel_layout_str);
+            return AVERROR(EINVAL);
+#if FF_API_OLD_CHANNEL_LAYOUT
+        }
+FF_ENABLE_DEPRECATION_WARNINGS
+        av_log(ctx, AV_LOG_WARNING, "Channel layout '%s' uses a deprecated syntax.\n",
                s->channel_layout_str);
-        return AVERROR(EINVAL);
+        av_channel_layout_from_mask(&s->ch_layout, mask);
+#endif
     }
 
-    s->nb_channels  = av_get_channel_layout_nb_channels(s->channel_layout);
-    s->channels     = av_calloc(s->nb_channels, sizeof(*s->channels));
-    s->buffers      = av_calloc(s->nb_channels, sizeof(*s->buffers));
+    s->channels     = av_calloc(s->ch_layout.nb_channels, sizeof(*s->channels));
+    s->buffers      = av_calloc(s->ch_layout.nb_channels, sizeof(*s->buffers));
     s->input_frames = av_calloc(s->inputs, sizeof(*s->input_frames));
     if (!s->channels || !s->buffers|| !s->input_frames)
         return AVERROR(ENOMEM);
 
-    for (i = 0; i < s->nb_channels; i++) {
-        s->channels[i].out_channel = av_channel_layout_extract_channel(s->channel_layout, i);
-        s->channels[i].input       = -1;
+    for (i = 0; i < s->ch_layout.nb_channels; i++) {
+        s->channels[i].out_channel    = av_channel_layout_channel_from_index(&s->ch_layout, i);
+        s->channels[i].input          = -1;
+        s->channels[i].in_channel_idx = -1;
+        s->channels[i].in_channel     = AV_CHAN_NONE;
     }
 
     if ((ret = parse_maps(ctx)) < 0)
@@ -221,7 +227,7 @@  static int join_query_formats(AVFilterContext *ctx)
     AVFilterChannelLayouts *layouts = NULL;
     int i, ret;
 
-    if ((ret = ff_add_channel_layout(&layouts, s->channel_layout)) < 0 ||
+    if ((ret = ff_add_channel_layout(&layouts, &s->ch_layout)) < 0 ||
         (ret = ff_channel_layouts_ref(layouts, &ctx->outputs[0]->incfg.channel_layouts)) < 0)
         return ret;
 
@@ -238,38 +244,55 @@  static int join_query_formats(AVFilterContext *ctx)
     return 0;
 }
 
+typedef struct ChannelList {
+    enum AVChannel *ch;
+    int          nb_ch;
+} ChannelList;
+
+static enum AVChannel channel_list_pop(ChannelList *chl, int idx)
+{
+    enum AVChannel ret = chl->ch[idx];
+    memcpy(chl->ch + idx, chl->ch + idx + 1,
+           (chl->nb_ch - idx - 1) * sizeof(*chl->ch));
+    chl->nb_ch--;
+    return ret;
+}
+
+/*
+ * If ch is present in chl, remove it from the list and return it.
+ * Otherwise return AV_CHAN_NONE.
+ */
+static enum AVChannel channel_list_pop_ch(ChannelList *chl, enum AVChannel ch)
+{
+    for (int i = 0; i < chl->nb_ch; i++)
+        if (chl->ch[i] == ch)
+            return channel_list_pop(chl, i);
+    return AV_CHAN_NONE;
+}
+
 static void guess_map_matching(AVFilterContext *ctx, ChannelMap *ch,
-                               uint64_t *inputs)
+                               ChannelList *inputs)
 {
     int i;
 
     for (i = 0; i < ctx->nb_inputs; i++) {
-        AVFilterLink *link = ctx->inputs[i];
-
-        if (ch->out_channel & link->channel_layout &&
-            !(ch->out_channel & inputs[i])) {
+        if (channel_list_pop_ch(&inputs[i], ch->out_channel) != AV_CHAN_NONE) {
             ch->input      = i;
             ch->in_channel = ch->out_channel;
-            inputs[i]     |= ch->out_channel;
             return;
         }
     }
 }
 
 static void guess_map_any(AVFilterContext *ctx, ChannelMap *ch,
-                          uint64_t *inputs)
+                          ChannelList *inputs)
 {
     int i;
 
     for (i = 0; i < ctx->nb_inputs; i++) {
-        AVFilterLink *link = ctx->inputs[i];
-
-        if ((inputs[i] & link->channel_layout) != link->channel_layout) {
-            uint64_t unused = link->channel_layout & ~inputs[i];
-
+        if (inputs[i].nb_ch) {
             ch->input      = i;
-            ch->in_channel = av_channel_layout_extract_channel(unused, 0);
-            inputs[i]     |= ch->in_channel;
+            ch->in_channel = channel_list_pop(&inputs[i], 0);
             return;
         }
     }
@@ -279,81 +302,136 @@  static int join_config_output(AVFilterLink *outlink)
 {
     AVFilterContext *ctx = outlink->src;
     JoinContext       *s = ctx->priv;
-    uint64_t *inputs;   // nth element tracks which channels are used from nth input
+    // unused channels from each input
+    ChannelList *inputs_unused;
+    char inbuf[64], outbuf[64];
     int i, ret = 0;
 
-    /* initialize inputs to user-specified mappings */
-    if (!(inputs = av_calloc(ctx->nb_inputs, sizeof(*inputs))))
+    /* initialize unused channel list for each input */
+    inputs_unused = av_calloc(ctx->nb_inputs, sizeof(*inputs_unused));
+    if (!inputs_unused)
         return AVERROR(ENOMEM);
-    for (i = 0; i < s->nb_channels; i++) {
+    for (i = 0; i < ctx->nb_inputs; i++) {
+        AVFilterLink *inlink = ctx->inputs[i];
+        AVChannelLayout *chl = &inlink->ch_layout;
+        ChannelList      *iu = &inputs_unused[i];
+
+        iu->nb_ch = chl->nb_channels;
+        iu->ch    = av_malloc_array(iu->nb_ch, sizeof(*iu->ch));
+        if (!iu->ch) {
+            ret = AVERROR(ENOMEM);
+            goto fail;
+        }
+
+        for (int ch_idx = 0; ch_idx < iu->nb_ch; ch_idx++) {
+            iu->ch[ch_idx] = av_channel_layout_channel_from_index(chl, ch_idx);
+            if (iu->ch[ch_idx] < 0) {
+                /* no channel ordering information in this input,
+                 * so don't auto-map from it */
+                iu->nb_ch = 0;
+                break;
+            }
+        }
+    }
+
+    /* process user-specified maps */
+    for (i = 0; i < s->ch_layout.nb_channels; i++) {
         ChannelMap *ch = &s->channels[i];
         AVFilterLink *inlink;
+        AVChannelLayout *ichl;
+        ChannelList     *iu;
 
         if (ch->input < 0)
             continue;
 
         inlink = ctx->inputs[ch->input];
+        ichl   = &inlink->ch_layout;
+        iu     = &inputs_unused[ch->input];
+
+        /* get the index for the channels defined by name */
+        if (ch->in_channel != AV_CHAN_NONE) {
+            ch->in_channel_idx = av_channel_layout_index_from_channel(ichl, ch->in_channel);
+            if (ch->in_channel_idx < 0) {
+                av_channel_name(inbuf, sizeof(inbuf), ch->in_channel);
+                av_log(ctx, AV_LOG_ERROR, "Requested channel %s is not present in "
+                       "input stream #%d.\n", inbuf,
+                       ch->input);
+                ret = AVERROR(EINVAL);
+                goto fail;
+            }
+        }
 
-        if (!ch->in_channel)
-            ch->in_channel = av_channel_layout_extract_channel(inlink->channel_layout,
-                                                               ch->in_channel_idx);
-
-        if (!(ch->in_channel & inlink->channel_layout)) {
-            av_log(ctx, AV_LOG_ERROR, "Requested channel %s is not present in "
-                   "input stream #%d.\n", av_get_channel_name(ch->in_channel),
-                   ch->input);
+        /* make sure channels specified by index actually exist */
+        if (ch->in_channel_idx >= ichl->nb_channels) {
+            av_log(ctx, AV_LOG_ERROR, "Requested channel with index %d is not "
+                   "present in input stream #%d.\n", ch->in_channel_idx, ch->input);
             ret = AVERROR(EINVAL);
             goto fail;
         }
 
-        inputs[ch->input] |= ch->in_channel;
+        channel_list_pop_ch(iu, av_channel_layout_channel_from_index(ichl, ch->in_channel_idx));
     }
 
     /* guess channel maps when not explicitly defined */
     /* first try unused matching channels */
-    for (i = 0; i < s->nb_channels; i++) {
+    for (i = 0; i < s->ch_layout.nb_channels; i++) {
         ChannelMap *ch = &s->channels[i];
 
         if (ch->input < 0)
-            guess_map_matching(ctx, ch, inputs);
+            guess_map_matching(ctx, ch, inputs_unused);
     }
 
     /* if the above failed, try to find _any_ unused input channel */
-    for (i = 0; i < s->nb_channels; i++) {
+    for (i = 0; i < s->ch_layout.nb_channels; i++) {
         ChannelMap *ch = &s->channels[i];
 
         if (ch->input < 0)
-            guess_map_any(ctx, ch, inputs);
+            guess_map_any(ctx, ch, inputs_unused);
 
         if (ch->input < 0) {
+            av_channel_name(outbuf, sizeof(outbuf), ch->out_channel);
             av_log(ctx, AV_LOG_ERROR, "Could not find input channel for "
                    "output channel '%s'.\n",
-                   av_get_channel_name(ch->out_channel));
+                   outbuf);
+            ret = AVERROR(EINVAL);
             goto fail;
         }
 
-        ch->in_channel_idx = av_get_channel_layout_channel_index(ctx->inputs[ch->input]->channel_layout,
-                                                                 ch->in_channel);
+        if (ch->in_channel != AV_CHAN_NONE) {
+            ch->in_channel_idx = av_channel_layout_index_from_channel(
+                &ctx->inputs[ch->input]->ch_layout, ch->in_channel);
+        }
+
+        av_assert0(ch->in_channel_idx >= 0);
     }
 
     /* print mappings */
     av_log(ctx, AV_LOG_VERBOSE, "mappings: ");
-    for (i = 0; i < s->nb_channels; i++) {
+    for (i = 0; i < s->ch_layout.nb_channels; i++) {
         ChannelMap *ch = &s->channels[i];
-        av_log(ctx, AV_LOG_VERBOSE, "%d.%s => %s ", ch->input,
-               av_get_channel_name(ch->in_channel),
-               av_get_channel_name(ch->out_channel));
+        AVFilterLink  *inlink = ctx->inputs[ch->input];
+        AVChannelLayout *ichl = &inlink->ch_layout;
+        enum AVChannel  in_ch = av_channel_layout_channel_from_index(
+                                    ichl, ch->in_channel_idx);
+
+        av_channel_name(inbuf, sizeof(inbuf), in_ch);
+        av_channel_name(outbuf, sizeof(outbuf), ch->out_channel);
+        av_log(ctx, AV_LOG_VERBOSE, "%d.%s(%d) => %s(%d) ", ch->input,
+               inbuf, ch->in_channel_idx,
+               outbuf, i);
     }
     av_log(ctx, AV_LOG_VERBOSE, "\n");
 
     for (i = 0; i < ctx->nb_inputs; i++) {
-        if (!inputs[i])
+        if (inputs_unused[i].nb_ch == ctx->inputs[i]->ch_layout.nb_channels)
             av_log(ctx, AV_LOG_WARNING, "No channels are used from input "
                    "stream %d.\n", i);
     }
 
 fail:
-    av_freep(&inputs);
+    for (i = 0; i < ctx->nb_inputs; i++)
+        av_freep(&inputs_unused[i].ch);
+    av_freep(&inputs_unused);
     return ret;
 }
 
@@ -382,8 +460,8 @@  static int try_push_frame(AVFilterContext *ctx)
     frame = av_frame_alloc();
     if (!frame)
         return AVERROR(ENOMEM);
-    if (s->nb_channels > FF_ARRAY_ELEMS(frame->data)) {
-        frame->extended_data = av_calloc(s->nb_channels,
+    if (s->ch_layout.nb_channels > FF_ARRAY_ELEMS(frame->data)) {
+        frame->extended_data = av_calloc(s->ch_layout.nb_channels,
                                           sizeof(*frame->extended_data));
         if (!frame->extended_data) {
             ret = AVERROR(ENOMEM);
@@ -392,7 +470,7 @@  static int try_push_frame(AVFilterContext *ctx)
     }
 
     /* copy the data pointers */
-    for (i = 0; i < s->nb_channels; i++) {
+    for (i = 0; i < s->ch_layout.nb_channels; i++) {
         ChannelMap *ch = &s->channels[i];
         AVFrame *cur   = s->input_frames[ch->input];
         AVBufferRef *buf;
@@ -442,15 +520,21 @@  static int try_push_frame(AVFilterContext *ctx)
     }
 
     frame->nb_samples     = nb_samples;
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
     frame->channel_layout = outlink->channel_layout;
-    frame->channels       = outlink->channels;
+    frame->channels       = outlink->ch_layout.nb_channels;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+    if ((ret = av_channel_layout_copy(&frame->ch_layout, &outlink->ch_layout)) < 0)
+        return ret;
     frame->sample_rate    = outlink->sample_rate;
     frame->format         = outlink->format;
     frame->pts            = s->input_frames[0]->pts;
     frame->linesize[0]    = linesize;
     if (frame->data != frame->extended_data) {
         memcpy(frame->data, frame->extended_data, sizeof(*frame->data) *
-               FFMIN(FF_ARRAY_ELEMS(frame->data), s->nb_channels));
+               FFMIN(FF_ARRAY_ELEMS(frame->data), s->ch_layout.nb_channels));
     }
 
     s->eof_pts = frame->pts + av_rescale_q(frame->nb_samples,
diff --git a/libavfilter/af_ladspa.c b/libavfilter/af_ladspa.c
index ff16388a56..46f85943e0 100644
--- a/libavfilter/af_ladspa.c
+++ b/libavfilter/af_ladspa.c
@@ -366,8 +366,14 @@  static int config_output(AVFilterLink *outlink)
         outlink->format      = inlink->format;
         outlink->sample_rate = inlink->sample_rate;
         if (s->nb_inputs == s->nb_outputs) {
+            if ((ret = av_channel_layout_copy(&outlink->ch_layout, &inlink->ch_layout)) < 0)
+                return ret;
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
             outlink->channel_layout = inlink->channel_layout;
-            outlink->channels = inlink->channels;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+            outlink->ch_layout.nb_channels = inlink->ch_layout.nb_channels;
         }
 
         ret = 0;
@@ -681,7 +687,7 @@  static int query_formats(AVFilterContext *ctx)
             return ret;
     } else if (s->nb_inputs == 2 && s->nb_outputs == 2) {
         layouts = NULL;
-        ret = ff_add_channel_layout(&layouts, AV_CH_LAYOUT_STEREO);
+        ret = ff_add_channel_layout(&layouts, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO);
         if (ret < 0)
             return ret;
         ret = ff_set_common_channel_layouts(ctx, layouts);
@@ -692,10 +698,10 @@  static int query_formats(AVFilterContext *ctx)
 
         if (s->nb_inputs >= 1) {
             AVFilterLink *inlink = ctx->inputs[0];
-            uint64_t inlayout = FF_COUNT2LAYOUT(s->nb_inputs);
+            AVChannelLayout inlayout = FF_COUNT2LAYOUT(s->nb_inputs);
 
             layouts = NULL;
-            ret = ff_add_channel_layout(&layouts, inlayout);
+            ret = ff_add_channel_layout(&layouts, &inlayout);
             if (ret < 0)
                 return ret;
             ret = ff_channel_layouts_ref(layouts, &inlink->outcfg.channel_layouts);
@@ -710,10 +716,10 @@  static int query_formats(AVFilterContext *ctx)
         }
 
         if (s->nb_outputs >= 1) {
-            uint64_t outlayout = FF_COUNT2LAYOUT(s->nb_outputs);
+            AVChannelLayout outlayout = FF_COUNT2LAYOUT(s->nb_outputs);
 
             layouts = NULL;
-            ret = ff_add_channel_layout(&layouts, outlayout);
+            ret = ff_add_channel_layout(&layouts, &outlayout);
             if (ret < 0)
                 return ret;
             ret = ff_channel_layouts_ref(layouts, &outlink->incfg.channel_layouts);
diff --git a/libavfilter/af_loudnorm.c b/libavfilter/af_loudnorm.c
index dbe7fba986..ac3cb2021d 100644
--- a/libavfilter/af_loudnorm.c
+++ b/libavfilter/af_loudnorm.c
@@ -446,7 +446,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
         double offset, offset_tp, true_peak;
 
         ff_ebur128_loudness_global(s->r128_in, &global);
-        for (c = 0; c < inlink->channels; c++) {
+        for (c = 0; c < inlink->ch_layout.nb_channels; c++) {
             double tmp;
             ff_ebur128_sample_peak(s->r128_in, c, &tmp);
             if (c == 0 || tmp > true_peak)
@@ -462,11 +462,11 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     switch (s->frame_type) {
     case FIRST_FRAME:
         for (n = 0; n < in->nb_samples; n++) {
-            for (c = 0; c < inlink->channels; c++) {
+            for (c = 0; c < inlink->ch_layout.nb_channels; c++) {
                 buf[s->buf_index + c] = src[c];
             }
-            src += inlink->channels;
-            s->buf_index += inlink->channels;
+            src += inlink->ch_layout.nb_channels;
+            s->buf_index += inlink->ch_layout.nb_channels;
         }
 
         ff_ebur128_loudness_shortterm(s->r128_in, &shortterm);
@@ -486,19 +486,19 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
         s->buf_index =
         s->limiter_buf_index = 0;
 
-        for (n = 0; n < (s->limiter_buf_size / inlink->channels); n++) {
-            for (c = 0; c < inlink->channels; c++) {
+        for (n = 0; n < (s->limiter_buf_size / inlink->ch_layout.nb_channels); n++) {
+            for (c = 0; c < inlink->ch_layout.nb_channels; c++) {
                 limiter_buf[s->limiter_buf_index + c] = buf[s->buf_index + c] * s->delta[s->index] * s->offset;
             }
-            s->limiter_buf_index += inlink->channels;
+            s->limiter_buf_index += inlink->ch_layout.nb_channels;
             if (s->limiter_buf_index >= s->limiter_buf_size)
                 s->limiter_buf_index -= s->limiter_buf_size;
 
-            s->buf_index += inlink->channels;
+            s->buf_index += inlink->ch_layout.nb_channels;
         }
 
         subframe_length = frame_size(inlink->sample_rate, 100);
-        true_peak_limiter(s, dst, subframe_length, inlink->channels);
+        true_peak_limiter(s, dst, subframe_length, inlink->ch_layout.nb_channels);
         ff_ebur128_add_frames_double(s->r128_out, dst, subframe_length);
 
         s->pts +=
@@ -514,29 +514,29 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
         gain_next = gaussian_filter(s, s->index + 11 < 30 ? s->index + 11 : s->index + 11 - 30);
 
         for (n = 0; n < in->nb_samples; n++) {
-            for (c = 0; c < inlink->channels; c++) {
+            for (c = 0; c < inlink->ch_layout.nb_channels; c++) {
                 buf[s->prev_buf_index + c] = src[c];
                 limiter_buf[s->limiter_buf_index + c] = buf[s->buf_index + c] * (gain + (((double) n / in->nb_samples) * (gain_next - gain))) * s->offset;
             }
-            src += inlink->channels;
+            src += inlink->ch_layout.nb_channels;
 
-            s->limiter_buf_index += inlink->channels;
+            s->limiter_buf_index += inlink->ch_layout.nb_channels;
             if (s->limiter_buf_index >= s->limiter_buf_size)
                 s->limiter_buf_index -= s->limiter_buf_size;
 
-            s->prev_buf_index += inlink->channels;
+            s->prev_buf_index += inlink->ch_layout.nb_channels;
             if (s->prev_buf_index >= s->buf_size)
                 s->prev_buf_index -= s->buf_size;
 
-            s->buf_index += inlink->channels;
+            s->buf_index += inlink->ch_layout.nb_channels;
             if (s->buf_index >= s->buf_size)
                 s->buf_index -= s->buf_size;
         }
 
-        subframe_length = (frame_size(inlink->sample_rate, 100) - in->nb_samples) * inlink->channels;
+        subframe_length = (frame_size(inlink->sample_rate, 100) - in->nb_samples) * inlink->ch_layout.nb_channels;
         s->limiter_buf_index = s->limiter_buf_index + subframe_length < s->limiter_buf_size ? s->limiter_buf_index + subframe_length : s->limiter_buf_index + subframe_length - s->limiter_buf_size;
 
-        true_peak_limiter(s, dst, in->nb_samples, inlink->channels);
+        true_peak_limiter(s, dst, in->nb_samples, inlink->ch_layout.nb_channels);
         ff_ebur128_add_frames_double(s->r128_out, dst, in->nb_samples);
 
         ff_ebur128_loudness_range(s->r128_in, &lra);
@@ -576,39 +576,39 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
         s->limiter_buf_index = 0;
         src_index = 0;
 
-        for (n = 0; n < s->limiter_buf_size / inlink->channels; n++) {
-            for (c = 0; c < inlink->channels; c++) {
+        for (n = 0; n < s->limiter_buf_size / inlink->ch_layout.nb_channels; n++) {
+            for (c = 0; c < inlink->ch_layout.nb_channels; c++) {
                 s->limiter_buf[s->limiter_buf_index + c] = src[src_index + c] * gain * s->offset;
             }
-            src_index += inlink->channels;
+            src_index += inlink->ch_layout.nb_channels;
 
-            s->limiter_buf_index += inlink->channels;
+            s->limiter_buf_index += inlink->ch_layout.nb_channels;
             if (s->limiter_buf_index >= s->limiter_buf_size)
                 s->limiter_buf_index -= s->limiter_buf_size;
         }
 
         subframe_length = frame_size(inlink->sample_rate, 100);
         for (i = 0; i < in->nb_samples / subframe_length; i++) {
-            true_peak_limiter(s, dst, subframe_length, inlink->channels);
+            true_peak_limiter(s, dst, subframe_length, inlink->ch_layout.nb_channels);
 
             for (n = 0; n < subframe_length; n++) {
-                for (c = 0; c < inlink->channels; c++) {
-                    if (src_index < (in->nb_samples * inlink->channels)) {
+                for (c = 0; c < inlink->ch_layout.nb_channels; c++) {
+                    if (src_index < (in->nb_samples * inlink->ch_layout.nb_channels)) {
                         limiter_buf[s->limiter_buf_index + c] = src[src_index + c] * gain * s->offset;
                     } else {
                         limiter_buf[s->limiter_buf_index + c] = 0.;
                     }
                 }
 
-                if (src_index < (in->nb_samples * inlink->channels))
-                    src_index += inlink->channels;
+                if (src_index < (in->nb_samples * inlink->ch_layout.nb_channels))
+                    src_index += inlink->ch_layout.nb_channels;
 
-                s->limiter_buf_index += inlink->channels;
+                s->limiter_buf_index += inlink->ch_layout.nb_channels;
                 if (s->limiter_buf_index >= s->limiter_buf_size)
                     s->limiter_buf_index -= s->limiter_buf_size;
             }
 
-            dst += (subframe_length * inlink->channels);
+            dst += (subframe_length * inlink->ch_layout.nb_channels);
         }
 
         dst = (double *)out->data[0];
@@ -617,11 +617,11 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 
     case LINEAR_MODE:
         for (n = 0; n < in->nb_samples; n++) {
-            for (c = 0; c < inlink->channels; c++) {
+            for (c = 0; c < inlink->ch_layout.nb_channels; c++) {
                 dst[c] = src[c] * s->offset;
             }
-            src += inlink->channels;
-            dst += inlink->channels;
+            src += inlink->ch_layout.nb_channels;
+            dst += inlink->ch_layout.nb_channels;
         }
 
         dst = (double *)out->data[0];
@@ -650,7 +650,7 @@  static int request_frame(AVFilterLink *outlink)
         int nb_samples, n, c, offset;
         AVFrame *frame;
 
-        nb_samples  = (s->buf_size / inlink->channels) - s->prev_nb_samples;
+        nb_samples  = (s->buf_size / inlink->ch_layout.nb_channels) - s->prev_nb_samples;
         nb_samples -= (frame_size(inlink->sample_rate, 100) - s->prev_nb_samples);
 
         frame = ff_get_audio_buffer(outlink, nb_samples);
@@ -661,16 +661,16 @@  static int request_frame(AVFilterLink *outlink)
         buf = s->buf;
         src = (double *)frame->data[0];
 
-        offset  = ((s->limiter_buf_size / inlink->channels) - s->prev_nb_samples) * inlink->channels;
-        offset -= (frame_size(inlink->sample_rate, 100) - s->prev_nb_samples) * inlink->channels;
+        offset  = ((s->limiter_buf_size / inlink->ch_layout.nb_channels) - s->prev_nb_samples) * inlink->ch_layout.nb_channels;
+        offset -= (frame_size(inlink->sample_rate, 100) - s->prev_nb_samples) * inlink->ch_layout.nb_channels;
         s->buf_index = s->buf_index - offset < 0 ? s->buf_index - offset + s->buf_size : s->buf_index - offset;
 
         for (n = 0; n < nb_samples; n++) {
-            for (c = 0; c < inlink->channels; c++) {
+            for (c = 0; c < inlink->ch_layout.nb_channels; c++) {
                 src[c] = buf[s->buf_index + c];
             }
-            src += inlink->channels;
-            s->buf_index += inlink->channels;
+            src += inlink->ch_layout.nb_channels;
+            s->buf_index += inlink->ch_layout.nb_channels;
             if (s->buf_index >= s->buf_size)
                 s->buf_index -= s->buf_size;
         }
@@ -720,30 +720,30 @@  static int config_input(AVFilterLink *inlink)
     AVFilterContext *ctx = inlink->dst;
     LoudNormContext *s = ctx->priv;
 
-    s->r128_in = ff_ebur128_init(inlink->channels, inlink->sample_rate, 0, FF_EBUR128_MODE_I | FF_EBUR128_MODE_S | FF_EBUR128_MODE_LRA | FF_EBUR128_MODE_SAMPLE_PEAK);
+    s->r128_in = ff_ebur128_init(inlink->ch_layout.nb_channels, inlink->sample_rate, 0, FF_EBUR128_MODE_I | FF_EBUR128_MODE_S | FF_EBUR128_MODE_LRA | FF_EBUR128_MODE_SAMPLE_PEAK);
     if (!s->r128_in)
         return AVERROR(ENOMEM);
 
-    s->r128_out = ff_ebur128_init(inlink->channels, inlink->sample_rate, 0, FF_EBUR128_MODE_I | FF_EBUR128_MODE_S | FF_EBUR128_MODE_LRA | FF_EBUR128_MODE_SAMPLE_PEAK);
+    s->r128_out = ff_ebur128_init(inlink->ch_layout.nb_channels, inlink->sample_rate, 0, FF_EBUR128_MODE_I | FF_EBUR128_MODE_S | FF_EBUR128_MODE_LRA | FF_EBUR128_MODE_SAMPLE_PEAK);
     if (!s->r128_out)
         return AVERROR(ENOMEM);
 
-    if (inlink->channels == 1 && s->dual_mono) {
+    if (inlink->ch_layout.nb_channels == 1 && s->dual_mono) {
         ff_ebur128_set_channel(s->r128_in,  0, FF_EBUR128_DUAL_MONO);
         ff_ebur128_set_channel(s->r128_out, 0, FF_EBUR128_DUAL_MONO);
     }
 
-    s->buf_size = frame_size(inlink->sample_rate, 3000) * inlink->channels;
+    s->buf_size = frame_size(inlink->sample_rate, 3000) * inlink->ch_layout.nb_channels;
     s->buf = av_malloc_array(s->buf_size, sizeof(*s->buf));
     if (!s->buf)
         return AVERROR(ENOMEM);
 
-    s->limiter_buf_size = frame_size(inlink->sample_rate, 210) * inlink->channels;
+    s->limiter_buf_size = frame_size(inlink->sample_rate, 210) * inlink->ch_layout.nb_channels;
     s->limiter_buf = av_malloc_array(s->buf_size, sizeof(*s->limiter_buf));
     if (!s->limiter_buf)
         return AVERROR(ENOMEM);
 
-    s->prev_smp = av_malloc_array(inlink->channels, sizeof(*s->prev_smp));
+    s->prev_smp = av_malloc_array(inlink->ch_layout.nb_channels, sizeof(*s->prev_smp));
     if (!s->prev_smp)
         return AVERROR(ENOMEM);
 
@@ -758,7 +758,7 @@  static int config_input(AVFilterLink *inlink)
     s->buf_index =
     s->prev_buf_index =
     s->limiter_buf_index = 0;
-    s->channels = inlink->channels;
+    s->channels = inlink->ch_layout.nb_channels;
     s->index = 1;
     s->limiter_state = OUT;
     s->offset = pow(10., s->offset / 20.);
diff --git a/libavfilter/af_lv2.c b/libavfilter/af_lv2.c
index 0f0c797989..4d96b380ff 100644
--- a/libavfilter/af_lv2.c
+++ b/libavfilter/af_lv2.c
@@ -288,8 +288,15 @@  static int config_output(AVFilterLink *outlink)
         outlink->format      = inlink->format;
         outlink->sample_rate = sample_rate = inlink->sample_rate;
         if (s->nb_inputs == s->nb_outputs) {
+            int ret;
+            if ((ret = av_channel_layout_copy(&outlink->ch_layout, &inlink->ch_layout)) < 0)
+                return ret;
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
             outlink->channel_layout = inlink->channel_layout;
-            outlink->channels = inlink->channels;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+            outlink->ch_layout.nb_channels = inlink->ch_layout.nb_channels;
         }
 
     } else {
@@ -496,7 +503,7 @@  static int query_formats(AVFilterContext *ctx)
 
     if (s->nb_inputs == 2 && s->nb_outputs == 2) {
         layouts = NULL;
-        ret = ff_add_channel_layout(&layouts, AV_CH_LAYOUT_STEREO);
+        ret = ff_add_channel_layout(&layouts, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO);
         if (ret < 0)
             return ret;
         ret = ff_set_common_channel_layouts(ctx, layouts);
@@ -505,10 +512,10 @@  static int query_formats(AVFilterContext *ctx)
     } else {
         if (s->nb_inputs >= 1) {
             AVFilterLink *inlink = ctx->inputs[0];
-            uint64_t inlayout = FF_COUNT2LAYOUT(s->nb_inputs);
+            AVChannelLayout inlayout = FF_COUNT2LAYOUT(s->nb_inputs);
 
             layouts = NULL;
-            ret = ff_add_channel_layout(&layouts, inlayout);
+            ret = ff_add_channel_layout(&layouts, &inlayout);
             if (ret < 0)
                 return ret;
             ret = ff_channel_layouts_ref(layouts, &inlink->outcfg.channel_layouts);
@@ -523,10 +530,10 @@  static int query_formats(AVFilterContext *ctx)
         }
 
         if (s->nb_outputs >= 1) {
-            uint64_t outlayout = FF_COUNT2LAYOUT(s->nb_outputs);
+            AVChannelLayout outlayout = FF_COUNT2LAYOUT(s->nb_outputs);
 
             layouts = NULL;
-            ret = ff_add_channel_layout(&layouts, outlayout);
+            ret = ff_add_channel_layout(&layouts, &outlayout);
             if (ret < 0)
                 return ret;
             ret = ff_channel_layouts_ref(layouts, &outlink->incfg.channel_layouts);
diff --git a/libavfilter/af_mcompand.c b/libavfilter/af_mcompand.c
index 90cfda38c9..1267cd9f34 100644
--- a/libavfilter/af_mcompand.c
+++ b/libavfilter/af_mcompand.c
@@ -302,7 +302,7 @@  static int crossover_setup(AVFilterLink *outlink, Crossover *p, double frequency
     square_quadratic(x + 3, p->coefs + 5);
     square_quadratic(x + 6, p->coefs + 10);
 
-    p->previous = av_calloc(outlink->channels, sizeof(*p->previous));
+    p->previous = av_calloc(outlink->ch_layout.nb_channels, sizeof(*p->previous));
     if (!p->previous)
         return AVERROR(ENOMEM);
 
@@ -350,13 +350,13 @@  static int config_output(AVFilterLink *outlink)
             return AVERROR(EINVAL);
         }
 
-        s->bands[i].attack_rate = av_calloc(outlink->channels, sizeof(double));
-        s->bands[i].decay_rate = av_calloc(outlink->channels, sizeof(double));
-        s->bands[i].volume = av_calloc(outlink->channels, sizeof(double));
+        s->bands[i].attack_rate = av_calloc(outlink->ch_layout.nb_channels, sizeof(double));
+        s->bands[i].decay_rate = av_calloc(outlink->ch_layout.nb_channels, sizeof(double));
+        s->bands[i].volume = av_calloc(outlink->ch_layout.nb_channels, sizeof(double));
         if (!s->bands[i].attack_rate || !s->bands[i].decay_rate || !s->bands[i].volume)
             return AVERROR(ENOMEM);
 
-        for (k = 0; k < FFMIN(nb_attacks / 2, outlink->channels); k++) {
+        for (k = 0; k < FFMIN(nb_attacks / 2, outlink->ch_layout.nb_channels); k++) {
             char *tstr3 = av_strtok(p3, ",", &saveptr3);
 
             p3 = NULL;
@@ -377,7 +377,7 @@  static int config_output(AVFilterLink *outlink)
             }
         }
 
-        for (ch = k; ch < outlink->channels; ch++) {
+        for (ch = k; ch < outlink->ch_layout.nb_channels; ch++) {
             s->bands[i].attack_rate[ch] = s->bands[i].attack_rate[k - 1];
             s->bands[i].decay_rate[ch]  = s->bands[i].decay_rate[k - 1];
         }
@@ -440,7 +440,7 @@  static int config_output(AVFilterLink *outlink)
                 sscanf(tstr2, "%lf", &initial_volume);
                 initial_volume = pow(10.0, initial_volume / 20);
 
-                for (k = 0; k < outlink->channels; k++) {
+                for (k = 0; k < outlink->ch_layout.nb_channels; k++) {
                     s->bands[i].volume[k] = initial_volume;
                 }
 
@@ -574,7 +574,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
         s->band_samples = in->nb_samples;
     }
 
-    for (ch = 0; ch < outlink->channels; ch++) {
+    for (ch = 0; ch < outlink->ch_layout.nb_channels; ch++) {
         double *a, *dst = (double *)out->extended_data[ch];
 
         for (band = 0, abuf = in, bbuf = s->band_buf2, cbuf = s->band_buf1; band < s->nb_bands; band++) {
diff --git a/libavfilter/af_pan.c b/libavfilter/af_pan.c
index a8a18960c4..067f646805 100644
--- a/libavfilter/af_pan.c
+++ b/libavfilter/af_pan.c
@@ -42,7 +42,7 @@ 
 typedef struct PanContext {
     const AVClass *class;
     char *args;
-    int64_t out_channel_layout;
+    AVChannelLayout out_channel_layout;
     double gain[MAX_CHANNELS][MAX_CHANNELS];
     int64_t need_renorm;
     int need_renumber;
@@ -65,23 +65,15 @@  static void skip_spaces(char **arg)
 static int parse_channel_name(char **arg, int *rchannel, int *rnamed)
 {
     char buf[8];
-    int len, i, channel_id = 0;
-    int64_t layout, layout0;
+    int len, channel_id = 0;
 
     skip_spaces(arg);
     /* try to parse a channel name, e.g. "FL" */
     if (sscanf(*arg, "%7[A-Z]%n", buf, &len)) {
-        layout0 = layout = av_get_channel_layout(buf);
-        /* channel_id <- first set bit in layout */
-        for (i = 32; i > 0; i >>= 1) {
-            if (layout >= (int64_t)1 << i) {
-                channel_id += i;
-                layout >>= i;
-            }
-        }
-        /* reject layouts that are not a single channel */
-        if (channel_id >= MAX_CHANNELS || layout0 != (int64_t)1 << channel_id)
-            return AVERROR(EINVAL);
+        channel_id = av_channel_from_string(buf);
+        if (channel_id < 0)
+            return channel_id;
+
         *rchannel = channel_id;
         *rnamed = 1;
         *arg += len;
@@ -137,17 +129,12 @@  static av_cold int init(AVFilterContext *ctx)
             goto fail;
         }
         if (named) {
-            if (!((pan->out_channel_layout >> out_ch_id) & 1)) {
+            if ((out_ch_id = av_channel_layout_index_from_channel(&pan->out_channel_layout, out_ch_id)) < 0) {
                 av_log(ctx, AV_LOG_ERROR,
                        "Channel \"%.8s\" does not exist in the chosen layout\n", arg0);
                 ret = AVERROR(EINVAL);
                 goto fail;
             }
-            /* get the channel number in the output channel layout:
-             * out_channel_layout & ((1 << out_ch_id) - 1) are all the
-             * channels that come before out_ch_id,
-             * so their count is the index of out_ch_id */
-            out_ch_id = av_get_channel_layout_nb_channels(pan->out_channel_layout & (((int64_t)1 << out_ch_id) - 1));
         }
         if (out_ch_id < 0 || out_ch_id >= pan->nb_output_channels) {
             av_log(ctx, AV_LOG_ERROR,
@@ -269,9 +256,7 @@  static int query_formats(AVFilterContext *ctx)
 
     // outlink supports only requested output channel layout
     layouts = NULL;
-    if ((ret = ff_add_channel_layout(&layouts,
-                          pan->out_channel_layout ? pan->out_channel_layout :
-                          FF_COUNT2LAYOUT(pan->nb_output_channels))) < 0)
+    if ((ret = ff_add_channel_layout(&layouts, &pan->out_channel_layout)) < 0)
         return ret;
     return ff_channel_layouts_ref(layouts, &outlink->incfg.channel_layouts);
 }
@@ -281,13 +266,13 @@  static int config_props(AVFilterLink *link)
     AVFilterContext *ctx = link->dst;
     PanContext *pan = ctx->priv;
     char buf[1024], *cur;
-    int i, j, k, r;
+    int i, j, k, r, ret;
     double t;
 
     if (pan->need_renumber) {
         // input channels were given by their name: renumber them
         for (i = j = 0; i < MAX_CHANNELS; i++) {
-            if ((link->channel_layout >> i) & 1) {
+            if (av_channel_layout_index_from_channel(&link->ch_layout, i) >= 0) {
                 for (k = 0; k < pan->nb_output_channels; k++)
                     pan->gain[k][j] = pan->gain[k][i];
                 j++;
@@ -297,7 +282,7 @@  static int config_props(AVFilterLink *link)
 
     // sanity check; can't be done in query_formats since the inlink
     // channel layout is unknown at that time
-    if (link->channels > MAX_CHANNELS ||
+    if (link->ch_layout.nb_channels > MAX_CHANNELS ||
         pan->nb_output_channels > MAX_CHANNELS) {
         av_log(ctx, AV_LOG_ERROR,
                "af_pan supports a maximum of %d channels. "
@@ -306,20 +291,12 @@  static int config_props(AVFilterLink *link)
     }
 
     // init libswresample context
-    pan->swr = swr_alloc_set_opts(pan->swr,
-                                  pan->out_channel_layout, link->format, link->sample_rate,
-                                  link->channel_layout,    link->format, link->sample_rate,
-                                  0, ctx);
-    if (!pan->swr)
+    ret = swr_alloc_set_opts2(&pan->swr,
+                              &pan->out_channel_layout, link->format, link->sample_rate,
+                              &link->ch_layout, link->format, link->sample_rate,
+                              0, ctx);
+    if (ret < 0)
         return AVERROR(ENOMEM);
-    if (!link->channel_layout) {
-        if (av_opt_set_int(pan->swr, "ich", link->channels, 0) < 0)
-            return AVERROR(EINVAL);
-    }
-    if (!pan->out_channel_layout) {
-        if (av_opt_set_int(pan->swr, "och", pan->nb_output_channels, 0) < 0)
-            return AVERROR(EINVAL);
-    }
 
     // gains are pure, init the channel mapping
     if (pan->pure_gains) {
@@ -327,7 +304,7 @@  static int config_props(AVFilterLink *link)
         // get channel map from the pure gains
         for (i = 0; i < pan->nb_output_channels; i++) {
             int ch_id = -1;
-            for (j = 0; j < link->channels; j++) {
+            for (j = 0; j < link->ch_layout.nb_channels; j++) {
                 if (pan->gain[i][j]) {
                     ch_id = j;
                     break;
@@ -336,7 +313,6 @@  static int config_props(AVFilterLink *link)
             pan->channel_map[i] = ch_id;
         }
 
-        av_opt_set_int(pan->swr, "icl", pan->out_channel_layout, 0);
         av_opt_set_int(pan->swr, "uch", pan->nb_output_channels, 0);
         swr_set_channel_mapping(pan->swr, pan->channel_map);
     } else {
@@ -345,7 +321,7 @@  static int config_props(AVFilterLink *link)
             if (!((pan->need_renorm >> i) & 1))
                 continue;
             t = 0;
-            for (j = 0; j < link->channels; j++)
+            for (j = 0; j < link->ch_layout.nb_channels; j++)
                 t += fabs(pan->gain[i][j]);
             if (t > -1E-5 && t < 1E-5) {
                 // t is almost 0 but not exactly, this is probably a mistake
@@ -354,11 +330,9 @@  static int config_props(AVFilterLink *link)
                            "Degenerate coefficients while renormalizing\n");
                 continue;
             }
-            for (j = 0; j < link->channels; j++)
+            for (j = 0; j < link->ch_layout.nb_channels; j++)
                 pan->gain[i][j] /= t;
         }
-        av_opt_set_int(pan->swr, "icl", link->channel_layout, 0);
-        av_opt_set_int(pan->swr, "ocl", pan->out_channel_layout, 0);
         swr_set_matrix(pan->swr, pan->gain[0], pan->gain[1] - pan->gain[0]);
     }
 
@@ -369,7 +343,7 @@  static int config_props(AVFilterLink *link)
     // summary
     for (i = 0; i < pan->nb_output_channels; i++) {
         cur = buf;
-        for (j = 0; j < link->channels; j++) {
+        for (j = 0; j < link->ch_layout.nb_channels; j++) {
             r = snprintf(cur, buf + sizeof(buf) - cur, "%s%.3g i%d",
                          j ? " + " : "", pan->gain[i][j], j);
             cur += FFMIN(buf + sizeof(buf) - cur, r);
@@ -405,8 +379,14 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
     swr_convert(pan->swr, outsamples->extended_data, n,
                 (void *)insamples->extended_data, n);
     av_frame_copy_props(outsamples, insamples);
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
     outsamples->channel_layout = outlink->channel_layout;
-    outsamples->channels = outlink->channels;
+    outsamples->channels = outlink->ch_layout.nb_channels;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+    if ((ret = av_channel_layout_copy(&outsamples->ch_layout, &outlink->ch_layout)) < 0)
+        return ret;
 
     ret = ff_filter_frame(outlink, outsamples);
     av_frame_free(&insamples);
diff --git a/libavfilter/af_replaygain.c b/libavfilter/af_replaygain.c
index e9bfc5676c..53852ac8bc 100644
--- a/libavfilter/af_replaygain.c
+++ b/libavfilter/af_replaygain.c
@@ -327,7 +327,7 @@  static int query_formats(AVFilterContext *ctx)
 
     if ((ret = ff_add_format                 (&formats, AV_SAMPLE_FMT_FLT  )) < 0 ||
         (ret = ff_set_common_formats         (ctx     , formats            )) < 0 ||
-        (ret = ff_add_channel_layout         (&layout , AV_CH_LAYOUT_STEREO)) < 0 ||
+        (ret = ff_add_channel_layout         (&layout , &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO)) < 0 ||
         (ret = ff_set_common_channel_layouts (ctx     , layout             )) < 0)
         return ret;
 
diff --git a/libavfilter/af_rubberband.c b/libavfilter/af_rubberband.c
index 4a42aa8a1f..34a1605667 100644
--- a/libavfilter/af_rubberband.c
+++ b/libavfilter/af_rubberband.c
@@ -135,7 +135,7 @@  static int config_input(AVFilterLink *inlink)
 
     if (s->rbs)
         rubberband_delete(s->rbs);
-    s->rbs = rubberband_new(inlink->sample_rate, inlink->channels, opts, 1. / s->tempo, s->pitch);
+    s->rbs = rubberband_new(inlink->sample_rate, inlink->ch_layout.nb_channels, opts, 1. / s->tempo, s->pitch);
     if (!s->rbs)
         return AVERROR(ENOMEM);
 
diff --git a/libavfilter/af_sidechaincompress.c b/libavfilter/af_sidechaincompress.c
index c0ce82066b..90d2a2c726 100644
--- a/libavfilter/af_sidechaincompress.c
+++ b/libavfilter/af_sidechaincompress.c
@@ -177,13 +177,13 @@  static void compressor(SidechainCompressContext *s,
         abs_sample = fabs(scsrc[0] * level_sc);
 
         if (s->link == 1) {
-            for (c = 1; c < sclink->channels; c++)
+            for (c = 1; c < sclink->ch_layout.nb_channels; c++)
                 abs_sample = FFMAX(fabs(scsrc[c] * level_sc), abs_sample);
         } else {
-            for (c = 1; c < sclink->channels; c++)
+            for (c = 1; c < sclink->ch_layout.nb_channels; c++)
                 abs_sample += fabs(scsrc[c] * level_sc);
 
-            abs_sample /= sclink->channels;
+            abs_sample /= sclink->ch_layout.nb_channels;
         }
 
         if (s->detection)
@@ -206,12 +206,12 @@  static void compressor(SidechainCompressContext *s,
                                s->compressed_knee_stop,
                                s->detection, s->mode);
 
-        for (c = 0; c < inlink->channels; c++)
+        for (c = 0; c < inlink->ch_layout.nb_channels; c++)
             dst[c] = src[c] * level_in * (gain * makeup * mix + (1. - mix));
 
-        src += inlink->channels;
-        dst += inlink->channels;
-        scsrc += sclink->channels;
+        src += inlink->ch_layout.nb_channels;
+        dst += inlink->ch_layout.nb_channels;
+        scsrc += sclink->ch_layout.nb_channels;
     }
 }
 
@@ -325,8 +325,8 @@  static int config_output(AVFilterLink *outlink)
 
     outlink->time_base   = ctx->inputs[0]->time_base;
 
-    s->fifo[0] = av_audio_fifo_alloc(ctx->inputs[0]->format, ctx->inputs[0]->channels, 1024);
-    s->fifo[1] = av_audio_fifo_alloc(ctx->inputs[1]->format, ctx->inputs[1]->channels, 1024);
+    s->fifo[0] = av_audio_fifo_alloc(ctx->inputs[0]->format, ctx->inputs[0]->ch_layout.nb_channels, 1024);
+    s->fifo[1] = av_audio_fifo_alloc(ctx->inputs[1]->format, ctx->inputs[1]->ch_layout.nb_channels, 1024);
     if (!s->fifo[0] || !s->fifo[1])
         return AVERROR(ENOMEM);
 
diff --git a/libavfilter/af_silencedetect.c b/libavfilter/af_silencedetect.c
index 0ba76469de..6518283d9f 100644
--- a/libavfilter/af_silencedetect.c
+++ b/libavfilter/af_silencedetect.c
@@ -136,12 +136,12 @@  static void silencedetect_##name(SilenceDetectContext *s, AVFrame *insamples,
                                  int nb_samples, int64_t nb_samples_notify,      \
                                  AVRational time_base)                           \
 {                                                                                \
-    const int channels = insamples->channels;                                    \
+    const int channels = insamples->ch_layout.nb_channels;                       \
     const type noise = s->noise;                                                 \
                                                                                  \
     nb_samples /= channels;                                                      \
     for (int i = 0; i < nb_samples; i++) {                                       \
-        for (int ch = 0; ch < insamples->channels; ch++) {                       \
+        for (int ch = 0; ch < insamples->ch_layout.nb_channels; ch++) {          \
             const type *p = (const type *)insamples->extended_data[ch];          \
             update(s, insamples, p[i] < noise && p[i] > -noise,                  \
                    channels * i + ch,                                            \
@@ -166,7 +166,7 @@  static int config_input(AVFilterLink *inlink)
     SilenceDetectContext *s = ctx->priv;
     int c;
 
-    s->channels = inlink->channels;
+    s->channels = inlink->ch_layout.nb_channels;
     s->duration = av_rescale(s->duration, inlink->sample_rate, AV_TIME_BASE);
     s->independent_channels = s->mono ? s->channels : 1;
     s->nb_null_samples = av_calloc(s->independent_channels,
@@ -210,7 +210,7 @@  static int config_input(AVFilterLink *inlink)
 static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
 {
     SilenceDetectContext *s         = inlink->dst->priv;
-    const int nb_channels           = inlink->channels;
+    const int nb_channels           = inlink->ch_layout.nb_channels;
     const int srate                 = inlink->sample_rate;
     const int nb_samples            = insamples->nb_samples     * nb_channels;
     const int64_t nb_samples_notify = s->duration * (s->mono ? 1 : nb_channels);
diff --git a/libavfilter/af_silenceremove.c b/libavfilter/af_silenceremove.c
index a02e1de783..a6db9be9d5 100644
--- a/libavfilter/af_silenceremove.c
+++ b/libavfilter/af_silenceremove.c
@@ -136,10 +136,10 @@  static void copy_double(SilenceRemoveContext *s, AVFrame *out, AVFrame *in,
                         int ch, int out_offset, int in_offset)
 {
     const double *srcp = (const double *)in->data[0];
-    const double src = srcp[in->channels * in_offset + ch];
+    const double src = srcp[in->ch_layout.nb_channels * in_offset + ch];
     double *dstp = (double *)out->data[0];
 
-    dstp[out->channels * out_offset + ch] = src;
+    dstp[out->ch_layout.nb_channels * out_offset + ch] = src;
 }
 
 static void copy_doublep(SilenceRemoveContext *s, AVFrame *out, AVFrame *in,
@@ -156,10 +156,10 @@  static void copy_float(SilenceRemoveContext *s, AVFrame *out, AVFrame *in,
                        int ch, int out_offset, int in_offset)
 {
     const float *srcp = (const float *)in->data[0];
-    const float src = srcp[in->channels * in_offset + ch];
+    const float src = srcp[in->ch_layout.nb_channels * in_offset + ch];
     float *dstp = (float *)out->data[0];
 
-    dstp[out->channels * out_offset + ch] = src;
+    dstp[out->ch_layout.nb_channels * out_offset + ch] = src;
 }
 
 static void copy_floatp(SilenceRemoveContext *s, AVFrame *out, AVFrame *in,
@@ -176,8 +176,8 @@  static double compute_peak_double(SilenceRemoveContext *s, AVFrame *frame, int c
 {
     const double *samples = (const double *)frame->data[0];
     const double *wsamples = (const double *)s->window->data[0];
-    double sample = samples[frame->channels * offset + ch];
-    double wsample = wsamples[frame->channels * s->window_offset + ch];
+    double sample = samples[frame->ch_layout.nb_channels * offset + ch];
+    double wsample = wsamples[frame->ch_layout.nb_channels * s->window_offset + ch];
     double new_sum;
 
     new_sum  = s->sum;
@@ -192,8 +192,8 @@  static void update_peak_double(SilenceRemoveContext *s, AVFrame *frame, int ch,
 {
     const double *samples = (const double *)frame->data[0];
     double *wsamples = (double *)s->window->data[0];
-    double sample = samples[frame->channels * offset + ch];
-    double *wsample = &wsamples[frame->channels * s->window_offset + ch];
+    double sample = samples[frame->ch_layout.nb_channels * offset + ch];
+    double *wsample = &wsamples[frame->ch_layout.nb_channels * s->window_offset + ch];
 
     s->sum -= *wsample;
     s->sum  = fmax(s->sum, 0.);
@@ -205,8 +205,8 @@  static double compute_peak_float(SilenceRemoveContext *s, AVFrame *frame, int ch
 {
     const float *samples = (const float *)frame->data[0];
     const float *wsamples = (const float *)s->window->data[0];
-    float sample = samples[frame->channels * offset + ch];
-    float wsample = wsamples[frame->channels * s->window_offset + ch];
+    float sample = samples[frame->ch_layout.nb_channels * offset + ch];
+    float wsample = wsamples[frame->ch_layout.nb_channels * s->window_offset + ch];
     float new_sum;
 
     new_sum  = s->sum;
@@ -221,8 +221,8 @@  static void update_peak_float(SilenceRemoveContext *s, AVFrame *frame, int ch, i
 {
     const float *samples = (const float *)frame->data[0];
     float *wsamples = (float *)s->window->data[0];
-    float sample = samples[frame->channels * offset + ch];
-    float *wsample = &wsamples[frame->channels * s->window_offset + ch];
+    float sample = samples[frame->ch_layout.nb_channels * offset + ch];
+    float *wsample = &wsamples[frame->ch_layout.nb_channels * s->window_offset + ch];
 
     s->sum -= *wsample;
     s->sum  = fmaxf(s->sum, 0.f);
@@ -234,8 +234,8 @@  static double compute_rms_double(SilenceRemoveContext *s, AVFrame *frame, int ch
 {
     const double *samples = (const double *)frame->data[0];
     const double *wsamples = (const double *)s->window->data[0];
-    double sample = samples[frame->channels * offset + ch];
-    double wsample = wsamples[frame->channels * s->window_offset + ch];
+    double sample = samples[frame->ch_layout.nb_channels * offset + ch];
+    double wsample = wsamples[frame->ch_layout.nb_channels * s->window_offset + ch];
     double new_sum;
 
     new_sum  = s->sum;
@@ -251,8 +251,8 @@  static void update_rms_double(SilenceRemoveContext *s, AVFrame *frame, int ch, i
 {
     const double *samples = (const double *)frame->data[0];
     double *wsamples = (double *)s->window->data[0];
-    double sample = samples[frame->channels * offset + ch];
-    double *wsample = &wsamples[frame->channels * s->window_offset + ch];
+    double sample = samples[frame->ch_layout.nb_channels * offset + ch];
+    double *wsample = &wsamples[frame->ch_layout.nb_channels * s->window_offset + ch];
 
     s->sum -= *wsample;
     s->sum  = fmax(s->sum, 0.);
@@ -264,8 +264,8 @@  static double compute_rms_float(SilenceRemoveContext *s, AVFrame *frame, int ch,
 {
     const float *samples = (const float *)frame->data[0];
     const float *wsamples = (const float *)s->window->data[0];
-    float sample = samples[frame->channels * offset + ch];
-    float wsample = wsamples[frame->channels * s->window_offset + ch];
+    float sample = samples[frame->ch_layout.nb_channels * offset + ch];
+    float wsample = wsamples[frame->ch_layout.nb_channels * s->window_offset + ch];
     float new_sum;
 
     new_sum  = s->sum;
@@ -280,9 +280,9 @@  static double compute_rms_float(SilenceRemoveContext *s, AVFrame *frame, int ch,
 static void update_rms_float(SilenceRemoveContext *s, AVFrame *frame, int ch, int offset)
 {
     const float *samples = (const float *)frame->data[0];
-    float sample = samples[frame->channels * offset + ch];
+    float sample = samples[frame->ch_layout.nb_channels * offset + ch];
     float *wsamples = (float *)s->window->data[0];
-    float *wsample = &wsamples[frame->channels * s->window_offset + ch];
+    float *wsample = &wsamples[frame->ch_layout.nb_channels * s->window_offset + ch];
 
     s->sum -= *wsample;
     s->sum  = fmaxf(s->sum, 0.f);
@@ -423,7 +423,7 @@  static av_cold int init(AVFilterContext *ctx)
 static void clear_window(SilenceRemoveContext *s)
 {
     av_samples_set_silence(s->window->extended_data, 0, s->window_duration,
-                           s->window->channels, s->window->format);
+                           s->window->ch_layout.nb_channels, s->window->format);
 
     s->window_offset = 0;
     s->sum = 0;
@@ -543,7 +543,7 @@  static int config_input(AVFilterLink *inlink)
         return AVERROR_BUG;
     }
 
-    s->fifo = av_audio_fifo_alloc(inlink->format, inlink->channels, 1024);
+    s->fifo = av_audio_fifo_alloc(inlink->format, inlink->ch_layout.nb_channels, 1024);
     if (!s->fifo)
         return AVERROR(ENOMEM);
 
@@ -576,14 +576,14 @@  static void flush(SilenceRemoveContext *s,
         av_samples_copy(silence->extended_data, s->stop_silence_hold->extended_data, 0,
                         s->stop_silence_offset,
                         s->stop_silence_end - s->stop_silence_offset,
-                        outlink->channels, outlink->format);
+                        outlink->ch_layout.nb_channels, outlink->format);
     }
 
     if (s->stop_silence_offset > 0) {
         av_samples_copy(silence->extended_data, s->stop_silence_hold->extended_data,
                         s->stop_silence_end - s->stop_silence_offset,
                         0, s->stop_silence_offset,
-                        outlink->channels, outlink->format);
+                        outlink->ch_layout.nb_channels, outlink->format);
     }
 
     s->stop_silence_offset = 0;
@@ -617,18 +617,18 @@  silence_trim:
         for (i = 0; i < nbs; i++) {
             if (s->start_mode == T_ANY) {
                 threshold = 0;
-                for (j = 0; j < outlink->channels; j++) {
+                for (j = 0; j < outlink->ch_layout.nb_channels; j++) {
                     threshold |= s->compute(s, in, j, nb_samples_read) > s->start_threshold;
                 }
             } else {
                 threshold = 1;
-                for (j = 0; j < outlink->channels; j++) {
+                for (j = 0; j < outlink->ch_layout.nb_channels; j++) {
                     threshold &= s->compute(s, in, j, nb_samples_read) > s->start_threshold;
                 }
             }
 
             if (threshold) {
-                for (j = 0; j < outlink->channels; j++) {
+                for (j = 0; j < outlink->ch_layout.nb_channels; j++) {
                     s->update(s, in, j, nb_samples_read);
                     s->copy(s, s->start_holdoff, in, j, s->start_holdoff_end, nb_samples_read);
                 }
@@ -656,7 +656,7 @@  silence_trim:
                 s->start_holdoff_end = 0;
                 s->one_period++;
 
-                for (j = 0; j < outlink->channels; j++) {
+                for (j = 0; j < outlink->ch_layout.nb_channels; j++) {
                     s->update(s, in, j, nb_samples_read);
                     if (s->start_silence)
                         s->copy(s, s->start_silence_hold, in, j, s->start_silence_offset, nb_samples_read);
@@ -694,21 +694,21 @@  silence_trim_flush:
                 av_samples_copy(out->extended_data, s->start_silence_hold->extended_data, 0,
                                 s->start_silence_offset,
                                 s->start_silence_end - s->start_silence_offset,
-                                outlink->channels, outlink->format);
+                                outlink->ch_layout.nb_channels, outlink->format);
             }
 
             if (s->start_silence_offset > 0) {
                 av_samples_copy(out->extended_data, s->start_silence_hold->extended_data,
                                 s->start_silence_end - s->start_silence_offset,
                                 0, s->start_silence_offset,
-                                outlink->channels, outlink->format);
+                                outlink->ch_layout.nb_channels, outlink->format);
             }
         }
 
         av_samples_copy(out->extended_data, s->start_holdoff->extended_data,
                         s->start_silence_end,
                         s->start_holdoff_offset, nbs,
-                        outlink->channels, outlink->format);
+                        outlink->ch_layout.nb_channels, outlink->format);
 
         s->start_holdoff_offset += nbs;
 
@@ -741,12 +741,12 @@  silence_copy:
             for (i = 0; i < nbs; i++) {
                 if (s->stop_mode == T_ANY) {
                     threshold = 0;
-                    for (j = 0; j < outlink->channels; j++) {
+                    for (j = 0; j < outlink->ch_layout.nb_channels; j++) {
                         threshold |= s->compute(s, in, j, nb_samples_read) > s->stop_threshold;
                     }
                 } else {
                     threshold = 1;
-                    for (j = 0; j < outlink->channels; j++) {
+                    for (j = 0; j < outlink->ch_layout.nb_channels; j++) {
                         threshold &= s->compute(s, in, j, nb_samples_read) > s->stop_threshold;
                     }
                 }
@@ -757,7 +757,7 @@  silence_copy:
                     s->one_period++;
                     goto silence_copy_flush;
                 } else if (threshold) {
-                    for (j = 0; j < outlink->channels; j++) {
+                    for (j = 0; j < outlink->ch_layout.nb_channels; j++) {
                         s->update(s, in, j, nb_samples_read);
                         s->copy(s, out, in, j, nb_samples_written, nb_samples_read);
                     }
@@ -769,7 +769,7 @@  silence_copy:
                     nb_samples_written++;
                     s->one_period++;
                 } else if (!threshold) {
-                    for (j = 0; j < outlink->channels; j++) {
+                    for (j = 0; j < outlink->ch_layout.nb_channels; j++) {
                         s->update(s, in, j, nb_samples_read);
                         if (s->stop_silence)
                             s->copy(s, s->stop_silence_hold, in, j, s->stop_silence_offset, nb_samples_read);
@@ -827,7 +827,7 @@  silence_copy:
             av_samples_copy(out->extended_data, in->extended_data,
                             nb_samples_written,
                             nb_samples_read, nbs,
-                            outlink->channels, outlink->format);
+                            outlink->ch_layout.nb_channels, outlink->format);
 
             av_audio_fifo_write(s->fifo, (void **)out->extended_data, out->nb_samples);
             av_frame_free(&out);
@@ -848,7 +848,7 @@  silence_copy_flush:
 
         av_samples_copy(out->extended_data, s->stop_holdoff->extended_data, 0,
                         s->stop_holdoff_offset, nbs,
-                        outlink->channels, outlink->format);
+                        outlink->ch_layout.nb_channels, outlink->format);
 
         s->stop_holdoff_offset += nbs;
 
@@ -909,7 +909,7 @@  static int request_frame(AVFilterLink *outlink)
 
             av_samples_copy(frame->extended_data, s->stop_holdoff->extended_data, 0,
                             s->stop_holdoff_offset, nbs,
-                            outlink->channels, outlink->format);
+                            outlink->ch_layout.nb_channels, outlink->format);
 
             frame->pts = s->next_pts;
             s->next_pts += av_rescale_q(frame->nb_samples,
diff --git a/libavfilter/af_sofalizer.c b/libavfilter/af_sofalizer.c
index 20b717bdf8..246ddeffb9 100644
--- a/libavfilter/af_sofalizer.c
+++ b/libavfilter/af_sofalizer.c
@@ -187,25 +187,15 @@  static int preload_sofa(AVFilterContext *ctx, char *filename, int *samplingrate)
 
 static int parse_channel_name(AVFilterContext *ctx, char **arg, int *rchannel)
 {
-    int len, i, channel_id = 0;
-    int64_t layout, layout0;
+    int len, channel_id = 0;
     char buf[8] = {0};
 
     /* try to parse a channel name, e.g. "FL" */
     if (av_sscanf(*arg, "%7[A-Z]%n", buf, &len)) {
-        layout0 = layout = av_get_channel_layout(buf);
-        /* channel_id <- first set bit in layout */
-        for (i = 32; i > 0; i >>= 1) {
-            if (layout >= 1LL << i) {
-                channel_id += i;
-                layout >>= i;
-            }
-        }
-        /* reject layouts that are not a single channel */
-        if (channel_id >= 64 || layout0 != 1LL << channel_id) {
-            av_log(ctx, AV_LOG_WARNING, "Failed to parse \'%s\' as channel name.\n", buf);
-            return AVERROR(EINVAL);
-        }
+        channel_id = av_channel_from_string(buf);
+        if (channel_id < 0)
+            return channel_id;
+
         *rchannel = channel_id;
         *arg += len;
         return 0;
@@ -221,7 +211,7 @@  static int parse_channel_name(AVFilterContext *ctx, char **arg, int *rchannel)
     return AVERROR(EINVAL);
 }
 
-static void parse_speaker_pos(AVFilterContext *ctx, int64_t in_channel_layout)
+static void parse_speaker_pos(AVFilterContext *ctx)
 {
     SOFAlizerContext *s = ctx->priv;
     char *arg, *tokenizer, *p, *args = av_strdup(s->speakers_pos);
@@ -256,10 +246,10 @@  static int get_speaker_pos(AVFilterContext *ctx,
                            float *speaker_azim, float *speaker_elev)
 {
     struct SOFAlizerContext *s = ctx->priv;
-    uint64_t channels_layout = ctx->inputs[0]->channel_layout;
+    AVChannelLayout *channel_layout = &ctx->inputs[0]->ch_layout;
     float azim[64] = { 0 };
     float elev[64] = { 0 };
-    int m, ch, n_conv = ctx->inputs[0]->channels; /* get no. input channels */
+    int m, ch, n_conv = ctx->inputs[0]->ch_layout.nb_channels; /* get no. input channels */
 
     if (n_conv < 0 || n_conv > 64)
         return AVERROR(EINVAL);
@@ -267,45 +257,45 @@  static int get_speaker_pos(AVFilterContext *ctx,
     s->lfe_channel = -1;
 
     if (s->speakers_pos)
-        parse_speaker_pos(ctx, channels_layout);
+        parse_speaker_pos(ctx);
 
     /* set speaker positions according to input channel configuration: */
     for (m = 0, ch = 0; ch < n_conv && m < 64; m++) {
-        uint64_t mask = channels_layout & (1ULL << m);
-
-        switch (mask) {
-        case AV_CH_FRONT_LEFT:            azim[ch] =  30;      break;
-        case AV_CH_FRONT_RIGHT:           azim[ch] = 330;      break;
-        case AV_CH_FRONT_CENTER:          azim[ch] =   0;      break;
-        case AV_CH_LOW_FREQUENCY:
-        case AV_CH_LOW_FREQUENCY_2:       s->lfe_channel = ch; break;
-        case AV_CH_BACK_LEFT:             azim[ch] = 150;      break;
-        case AV_CH_BACK_RIGHT:            azim[ch] = 210;      break;
-        case AV_CH_BACK_CENTER:           azim[ch] = 180;      break;
-        case AV_CH_SIDE_LEFT:             azim[ch] =  90;      break;
-        case AV_CH_SIDE_RIGHT:            azim[ch] = 270;      break;
-        case AV_CH_FRONT_LEFT_OF_CENTER:  azim[ch] =  15;      break;
-        case AV_CH_FRONT_RIGHT_OF_CENTER: azim[ch] = 345;      break;
-        case AV_CH_TOP_CENTER:            azim[ch] =   0;
+        int chan = av_channel_layout_channel_from_index(channel_layout, m);
+
+        switch (chan) {
+        case AV_CHAN_FRONT_LEFT:          azim[ch] =  30;      break;
+        case AV_CHAN_FRONT_RIGHT:         azim[ch] = 330;      break;
+        case AV_CHAN_FRONT_CENTER:        azim[ch] =   0;      break;
+        case AV_CHAN_LOW_FREQUENCY:
+        case AV_CHAN_LOW_FREQUENCY_2:     s->lfe_channel = ch; break;
+        case AV_CHAN_BACK_LEFT:           azim[ch] = 150;      break;
+        case AV_CHAN_BACK_RIGHT:          azim[ch] = 210;      break;
+        case AV_CHAN_BACK_CENTER:         azim[ch] = 180;      break;
+        case AV_CHAN_SIDE_LEFT:           azim[ch] =  90;      break;
+        case AV_CHAN_SIDE_RIGHT:          azim[ch] = 270;      break;
+        case AV_CHAN_FRONT_LEFT_OF_CENTER:  azim[ch] =  15;    break;
+        case AV_CHAN_FRONT_RIGHT_OF_CENTER: azim[ch] = 345;    break;
+        case AV_CHAN_TOP_CENTER:          azim[ch] =   0;
                                           elev[ch] =  90;      break;
-        case AV_CH_TOP_FRONT_LEFT:        azim[ch] =  30;
+        case AV_CHAN_TOP_FRONT_LEFT:      azim[ch] =  30;
                                           elev[ch] =  45;      break;
-        case AV_CH_TOP_FRONT_CENTER:      azim[ch] =   0;
+        case AV_CHAN_TOP_FRONT_CENTER:    azim[ch] =   0;
                                           elev[ch] =  45;      break;
-        case AV_CH_TOP_FRONT_RIGHT:       azim[ch] = 330;
+        case AV_CHAN_TOP_FRONT_RIGHT:     azim[ch] = 330;
                                           elev[ch] =  45;      break;
-        case AV_CH_TOP_BACK_LEFT:         azim[ch] = 150;
+        case AV_CHAN_TOP_BACK_LEFT:       azim[ch] = 150;
                                           elev[ch] =  45;      break;
-        case AV_CH_TOP_BACK_RIGHT:        azim[ch] = 210;
+        case AV_CHAN_TOP_BACK_RIGHT:      azim[ch] = 210;
                                           elev[ch] =  45;      break;
-        case AV_CH_TOP_BACK_CENTER:       azim[ch] = 180;
+        case AV_CHAN_TOP_BACK_CENTER:     azim[ch] = 180;
                                           elev[ch] =  45;      break;
-        case AV_CH_WIDE_LEFT:             azim[ch] =  90;      break;
-        case AV_CH_WIDE_RIGHT:            azim[ch] = 270;      break;
-        case AV_CH_SURROUND_DIRECT_LEFT:  azim[ch] =  90;      break;
-        case AV_CH_SURROUND_DIRECT_RIGHT: azim[ch] = 270;      break;
-        case AV_CH_STEREO_LEFT:           azim[ch] =  90;      break;
-        case AV_CH_STEREO_RIGHT:          azim[ch] = 270;      break;
+        case AV_CHAN_WIDE_LEFT:           azim[ch] =  90;      break;
+        case AV_CHAN_WIDE_RIGHT:          azim[ch] = 270;      break;
+        case AV_CHAN_SURROUND_DIRECT_LEFT:  azim[ch] =  90;    break;
+        case AV_CHAN_SURROUND_DIRECT_RIGHT: azim[ch] = 270;    break;
+        case AV_CHAN_STEREO_LEFT:         azim[ch] =  90;      break;
+        case AV_CHAN_STEREO_RIGHT:        azim[ch] = 270;      break;
         case 0:                                                break;
         default:
             return AVERROR(EINVAL);
@@ -316,7 +306,7 @@  static int get_speaker_pos(AVFilterContext *ctx,
             elev[ch] = s->vspkrpos[m].elev;
         }
 
-        if (mask)
+        if (chan)
             ch++;
     }
 
@@ -668,7 +658,7 @@  static int query_formats(AVFilterContext *ctx)
         return ret;
 
     layouts = NULL;
-    ret = ff_add_channel_layout(&layouts, AV_CH_LAYOUT_STEREO);
+    ret = ff_add_channel_layout(&layouts, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO);
     if (ret)
         return ret;
 
@@ -733,7 +723,7 @@  static int load_data(AVFilterContext *ctx, int azim, int elev, float radius, int
     int n_fft;
     float delay_l; /* broadband delay for each IR */
     float delay_r;
-    int nb_input_channels = ctx->inputs[0]->channels; /* no. input channels */
+    int nb_input_channels = ctx->inputs[0]->ch_layout.nb_channels; /* no. input channels */
     float gain_lin = expf((s->gain - 3 * nb_input_channels) / 20 * M_LN10); /* gain - 3dB/channel */
     AVComplexFloat *data_hrtf_l = NULL;
     AVComplexFloat *data_hrtf_r = NULL;
@@ -1016,16 +1006,16 @@  static int config_input(AVFilterLink *inlink)
         s->nb_samples = s->framesize;
 
     /* gain -3 dB per channel */
-    s->gain_lfe = expf((s->gain - 3 * inlink->channels + s->lfe_gain) / 20 * M_LN10);
+    s->gain_lfe = expf((s->gain - 3 * inlink->ch_layout.nb_channels + s->lfe_gain) / 20 * M_LN10);
 
-    s->n_conv = inlink->channels;
+    s->n_conv = inlink->ch_layout.nb_channels;
 
     /* load IRs to data_ir[0] and data_ir[1] for required directions */
     if ((ret = load_data(ctx, s->rotation, s->elevation, s->radius, inlink->sample_rate)) < 0)
         return ret;
 
     av_log(ctx, AV_LOG_DEBUG, "Samplerate: %d Channels to convolute: %d, Length of ringbuffer: %d x %d\n",
-        inlink->sample_rate, s->n_conv, inlink->channels, s->buffer_length);
+        inlink->sample_rate, s->n_conv, inlink->ch_layout.nb_channels, s->buffer_length);
 
     return 0;
 }
diff --git a/libavfilter/af_speechnorm.c b/libavfilter/af_speechnorm.c
index 212a926f36..a40abc025d 100644
--- a/libavfilter/af_speechnorm.c
+++ b/libavfilter/af_speechnorm.c
@@ -68,7 +68,7 @@  typedef struct SpeechNormalizerContext {
     double threshold_value;
     double raise_amount;
     double fall_amount;
-    uint64_t channels;
+    AVChannelLayout ch_layout;
     int invert;
     int link;
 
@@ -103,8 +103,8 @@  static const AVOption speechnorm_options[] = {
     { "r",     "set the expansion raising amount", OFFSET(raise_amount), AV_OPT_TYPE_DOUBLE, {.dbl=0.001}, 0.0, 1.0, FLAGS },
     { "fall", "set the compression raising amount", OFFSET(fall_amount), AV_OPT_TYPE_DOUBLE, {.dbl=0.001}, 0.0, 1.0, FLAGS },
     { "f",    "set the compression raising amount", OFFSET(fall_amount), AV_OPT_TYPE_DOUBLE, {.dbl=0.001}, 0.0, 1.0, FLAGS },
-    { "channels", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS },
-    { "h",        "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS },
+    { "channels", "set channels to filter", OFFSET(ch_layout), AV_OPT_TYPE_CHLAYOUT, {.str="0xFFFFFFFF"}, INT64_MIN, INT64_MAX, FLAGS },
+    { "h",        "set channels to filter", OFFSET(ch_layout), AV_OPT_TYPE_CHLAYOUT, {.str="0xFFFFFFFF"}, INT64_MIN, INT64_MAX, FLAGS },
     { "invert", "set inverted filtering", OFFSET(invert), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
     { "i",      "set inverted filtering", OFFSET(invert), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
     { "link", "set linked channels filtering", OFFSET(link), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
@@ -142,7 +142,7 @@  static int available_samples(AVFilterContext *ctx)
     int min_pi_nb_samples;
 
     min_pi_nb_samples = get_pi_samples(s->cc[0].pi, s->cc[0].pi_start, s->cc[0].pi_end, s->cc[0].pi_size);
-    for (int ch = 1; ch < inlink->channels && min_pi_nb_samples > 0; ch++) {
+    for (int ch = 1; ch < inlink->ch_layout.nb_channels && min_pi_nb_samples > 0; ch++) {
         ChannelContext *cc = &s->cc[ch];
 
         min_pi_nb_samples = FFMIN(min_pi_nb_samples, get_pi_samples(cc->pi, cc->pi_start, cc->pi_end, cc->pi_size));
@@ -283,11 +283,12 @@  static void filter_channels_## name (AVFilterContext *ctx,
     SpeechNormalizerContext *s = ctx->priv;                                     \
     AVFilterLink *inlink = ctx->inputs[0];                                      \
                                                                                 \
-    for (int ch = 0; ch < inlink->channels; ch++) {                             \
+    for (int ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {                             \
         ChannelContext *cc = &s->cc[ch];                                        \
         const ptype *src = (const ptype *)in->extended_data[ch];                \
         ptype *dst = (ptype *)out->extended_data[ch];                           \
-        const int bypass = !(av_channel_layout_extract_channel(inlink->channel_layout, ch) & s->channels); \
+        const int bypass = !(av_channel_layout_channel_from_index(&inlink->ch_layout, ch) >= 0 && \
+                             av_channel_layout_channel_from_index(&s->ch_layout, ch) >= 0); \
         int n = 0;                                                              \
                                                                                 \
         while (n < nb_samples) {                                                \
@@ -333,10 +334,11 @@  static void filter_link_channels_## name (AVFilterContext *ctx,
         int max_size = 1;                                                       \
         ptype gain = s->max_expansion;                                          \
                                                                                 \
-        for (int ch = 0; ch < inlink->channels; ch++) {                         \
+        for (int ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {                         \
             ChannelContext *cc = &s->cc[ch];                                    \
                                                                                 \
-            cc->bypass = !(av_channel_layout_extract_channel(inlink->channel_layout, ch) & s->channels); \
+            cc->bypass = !(av_channel_layout_channel_from_index(&inlink->ch_layout, ch) >= 0 && \
+                             av_channel_layout_channel_from_index(&s->ch_layout, ch) >= 0); \
                                                                                 \
             next_pi(ctx, cc, cc->bypass);                                       \
             min_size = FFMIN(min_size, cc->pi_size);                            \
@@ -344,7 +346,7 @@  static void filter_link_channels_## name (AVFilterContext *ctx,
         }                                                                       \
                                                                                 \
         av_assert0(min_size > 0);                                               \
-        for (int ch = 0; ch < inlink->channels; ch++) {                         \
+        for (int ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {                         \
             ChannelContext *cc = &s->cc[ch];                                    \
                                                                                 \
             if (cc->bypass)                                                     \
@@ -352,7 +354,7 @@  static void filter_link_channels_## name (AVFilterContext *ctx,
             gain = FFMIN(gain, min_gain(ctx, cc, max_size));                    \
         }                                                                       \
                                                                                 \
-        for (int ch = 0; ch < inlink->channels; ch++) {                         \
+        for (int ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {                         \
             ChannelContext *cc = &s->cc[ch];                                    \
             const ptype *src = (const ptype *)in->extended_data[ch];            \
             ptype *dst = (ptype *)out->extended_data[ch];                       \
@@ -428,7 +430,7 @@  static int filter_frame(AVFilterContext *ctx)
 
         ff_bufqueue_add(ctx, &s->queue, in);
 
-        for (int ch = 0; ch < inlink->channels; ch++) {
+        for (int ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {
             ChannelContext *cc = &s->cc[ch];
 
             s->analyze_channel(ctx, cc, in->extended_data[ch], in->nb_samples);
@@ -486,11 +488,11 @@  static int config_input(AVFilterLink *inlink)
     s->max_period = inlink->sample_rate / 10;
 
     s->prev_gain = 1.;
-    s->cc = av_calloc(inlink->channels, sizeof(*s->cc));
+    s->cc = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->cc));
     if (!s->cc)
         return AVERROR(ENOMEM);
 
-    for (int ch = 0; ch < inlink->channels; ch++) {
+    for (int ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {
         ChannelContext *cc = &s->cc[ch];
 
         cc->state = -1;
diff --git a/libavfilter/af_stereotools.c b/libavfilter/af_stereotools.c
index 27ec4a2e4a..eedc7c68bd 100644
--- a/libavfilter/af_stereotools.c
+++ b/libavfilter/af_stereotools.c
@@ -107,7 +107,7 @@  static int query_formats(AVFilterContext *ctx)
 
     if ((ret = ff_add_format                 (&formats, AV_SAMPLE_FMT_DBL  )) < 0 ||
         (ret = ff_set_common_formats         (ctx     , formats            )) < 0 ||
-        (ret = ff_add_channel_layout         (&layout , AV_CH_LAYOUT_STEREO)) < 0 ||
+        (ret = ff_add_channel_layout         (&layout , &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO)) < 0 ||
         (ret = ff_set_common_channel_layouts (ctx     , layout             )) < 0)
         return ret;
 
diff --git a/libavfilter/af_stereowiden.c b/libavfilter/af_stereowiden.c
index 7cce1a8f28..a91ea03957 100644
--- a/libavfilter/af_stereowiden.c
+++ b/libavfilter/af_stereowiden.c
@@ -60,7 +60,7 @@  static int query_formats(AVFilterContext *ctx)
 
     if ((ret = ff_add_format                 (&formats, AV_SAMPLE_FMT_FLT  )) < 0 ||
         (ret = ff_set_common_formats         (ctx     , formats            )) < 0 ||
-        (ret = ff_add_channel_layout         (&layout , AV_CH_LAYOUT_STEREO)) < 0 ||
+        (ret = ff_add_channel_layout         (&layout , &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO)) < 0 ||
         (ret = ff_set_common_channel_layouts (ctx     , layout             )) < 0)
         return ret;
 
diff --git a/libavfilter/af_superequalizer.c b/libavfilter/af_superequalizer.c
index aa73e92039..6df8d36d0f 100644
--- a/libavfilter/af_superequalizer.c
+++ b/libavfilter/af_superequalizer.c
@@ -199,7 +199,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
         return AVERROR(ENOMEM);
     }
 
-    for (ch = 0; ch < in->channels; ch++) {
+    for (ch = 0; ch < in->ch_layout.nb_channels; ch++) {
         ptr = (float *)out->extended_data[ch];
         dst = (float *)s->out->extended_data[ch];
         src = (float *)in->extended_data[ch];
diff --git a/libavfilter/af_surround.c b/libavfilter/af_surround.c
index ccd85148e9..71d713e4ed 100644
--- a/libavfilter/af_surround.c
+++ b/libavfilter/af_surround.c
@@ -92,8 +92,8 @@  typedef struct AudioSurroundContext {
     float lowcut;
     float highcut;
 
-    uint64_t out_channel_layout;
-    uint64_t in_channel_layout;
+    AVChannelLayout out_channel_layout;
+    AVChannelLayout in_channel_layout;
     int nb_in_channels;
     int nb_out_channels;
 
@@ -171,7 +171,7 @@  static int query_formats(AVFilterContext *ctx)
         return ret;
 
     layouts = NULL;
-    ret = ff_add_channel_layout(&layouts, s->out_channel_layout);
+    ret = ff_add_channel_layout(&layouts, &s->out_channel_layout);
     if (ret)
         return ret;
 
@@ -180,7 +180,7 @@  static int query_formats(AVFilterContext *ctx)
         return ret;
 
     layouts = NULL;
-    ret = ff_add_channel_layout(&layouts, s->in_channel_layout);
+    ret = ff_add_channel_layout(&layouts, &s->in_channel_layout);
     if (ret)
         return ret;
 
@@ -197,12 +197,12 @@  static int config_input(AVFilterLink *inlink)
     AudioSurroundContext *s = ctx->priv;
     int ch;
 
-    s->rdft = av_calloc(inlink->channels, sizeof(*s->rdft));
+    s->rdft = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->rdft));
     if (!s->rdft)
         return AVERROR(ENOMEM);
-    s->nb_in_channels = inlink->channels;
+    s->nb_in_channels = inlink->ch_layout.nb_channels;
 
-    for (ch = 0; ch < inlink->channels; ch++) {
+    for (ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {
         s->rdft[ch]  = av_rdft_init(ff_log2(s->buf_size), DFT_R2C);
         if (!s->rdft[ch])
             return AVERROR(ENOMEM);
@@ -212,31 +212,31 @@  static int config_input(AVFilterLink *inlink)
         return AVERROR(ENOMEM);
     for (ch = 0;  ch < s->nb_in_channels; ch++)
         s->input_levels[ch] = s->level_in;
-    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_FRONT_CENTER);
+    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_FRONT_CENTER);
     if (ch >= 0)
         s->input_levels[ch] *= s->fc_in;
-    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_FRONT_LEFT);
+    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_FRONT_LEFT);
     if (ch >= 0)
         s->input_levels[ch] *= s->fl_in;
-    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_FRONT_RIGHT);
+    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_FRONT_RIGHT);
     if (ch >= 0)
         s->input_levels[ch] *= s->fr_in;
-    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_SIDE_LEFT);
+    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_SIDE_LEFT);
     if (ch >= 0)
         s->input_levels[ch] *= s->sl_in;
-    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_SIDE_RIGHT);
+    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_SIDE_RIGHT);
     if (ch >= 0)
         s->input_levels[ch] *= s->sr_in;
-    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_BACK_LEFT);
+    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_BACK_LEFT);
     if (ch >= 0)
         s->input_levels[ch] *= s->bl_in;
-    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_BACK_RIGHT);
+    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_BACK_RIGHT);
     if (ch >= 0)
         s->input_levels[ch] *= s->br_in;
-    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_BACK_CENTER);
+    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_BACK_CENTER);
     if (ch >= 0)
         s->input_levels[ch] *= s->bc_in;
-    ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_LOW_FREQUENCY);
+    ch = av_channel_layout_index_from_channel(&inlink->ch_layout, AV_CHAN_LOW_FREQUENCY);
     if (ch >= 0)
         s->input_levels[ch] *= s->lfe_in;
 
@@ -244,7 +244,7 @@  static int config_input(AVFilterLink *inlink)
     if (!s->input)
         return AVERROR(ENOMEM);
 
-    s->fifo = av_audio_fifo_alloc(inlink->format, inlink->channels, s->buf_size);
+    s->fifo = av_audio_fifo_alloc(inlink->format, inlink->ch_layout.nb_channels, s->buf_size);
     if (!s->fifo)
         return AVERROR(ENOMEM);
 
@@ -260,12 +260,12 @@  static int config_output(AVFilterLink *outlink)
     AudioSurroundContext *s = ctx->priv;
     int ch;
 
-    s->irdft = av_calloc(outlink->channels, sizeof(*s->irdft));
+    s->irdft = av_calloc(outlink->ch_layout.nb_channels, sizeof(*s->irdft));
     if (!s->irdft)
         return AVERROR(ENOMEM);
-    s->nb_out_channels = outlink->channels;
+    s->nb_out_channels = outlink->ch_layout.nb_channels;
 
-    for (ch = 0; ch < outlink->channels; ch++) {
+    for (ch = 0; ch < outlink->ch_layout.nb_channels; ch++) {
         s->irdft[ch] = av_rdft_init(ff_log2(s->buf_size), IDFT_C2R);
         if (!s->irdft[ch])
             return AVERROR(ENOMEM);
@@ -275,31 +275,31 @@  static int config_output(AVFilterLink *outlink)
         return AVERROR(ENOMEM);
     for (ch = 0;  ch < s->nb_out_channels; ch++)
         s->output_levels[ch] = s->level_out;
-    ch = av_get_channel_layout_channel_index(outlink->channel_layout, AV_CH_FRONT_CENTER);
+    ch = av_channel_layout_index_from_channel(&outlink->ch_layout, AV_CHAN_FRONT_CENTER);
     if (ch >= 0)
         s->output_levels[ch] *= s->fc_out;
-    ch = av_get_channel_layout_channel_index(outlink->channel_layout, AV_CH_FRONT_LEFT);
+    ch = av_channel_layout_index_from_channel(&outlink->ch_layout, AV_CHAN_FRONT_LEFT);
     if (ch >= 0)
         s->output_levels[ch] *= s->fl_out;
-    ch = av_get_channel_layout_channel_index(outlink->channel_layout, AV_CH_FRONT_RIGHT);
+    ch = av_channel_layout_index_from_channel(&outlink->ch_layout, AV_CHAN_FRONT_RIGHT);
     if (ch >= 0)
         s->output_levels[ch] *= s->fr_out;
-    ch = av_get_channel_layout_channel_index(outlink->channel_layout, AV_CH_SIDE_LEFT);
+    ch = av_channel_layout_index_from_channel(&outlink->ch_layout, AV_CHAN_SIDE_LEFT);
     if (ch >= 0)
         s->output_levels[ch] *= s->sl_out;
-    ch = av_get_channel_layout_channel_index(outlink->channel_layout, AV_CH_SIDE_RIGHT);
+    ch = av_channel_layout_index_from_channel(&outlink->ch_layout, AV_CHAN_SIDE_RIGHT);
     if (ch >= 0)
         s->output_levels[ch] *= s->sr_out;
-    ch = av_get_channel_layout_channel_index(outlink->channel_layout, AV_CH_BACK_LEFT);
+    ch = av_channel_layout_index_from_channel(&outlink->ch_layout, AV_CHAN_BACK_LEFT);
     if (ch >= 0)
         s->output_levels[ch] *= s->bl_out;
-    ch = av_get_channel_layout_channel_index(outlink->channel_layout, AV_CH_BACK_RIGHT);
+    ch = av_channel_layout_index_from_channel(&outlink->ch_layout, AV_CHAN_BACK_RIGHT);
     if (ch >= 0)
         s->output_levels[ch] *= s->br_out;
-    ch = av_get_channel_layout_channel_index(outlink->channel_layout, AV_CH_BACK_CENTER);
+    ch = av_channel_layout_index_from_channel(&outlink->ch_layout, AV_CHAN_BACK_CENTER);
     if (ch >= 0)
         s->output_levels[ch] *= s->bc_out;
-    ch = av_get_channel_layout_channel_index(outlink->channel_layout, AV_CH_LOW_FREQUENCY);
+    ch = av_channel_layout_index_from_channel(&outlink->ch_layout, AV_CHAN_LOW_FREQUENCY);
     if (ch >= 0)
         s->output_levels[ch] *= s->lfe_out;
 
@@ -1373,15 +1373,16 @@  static av_cold int init(AVFilterContext *ctx)
 {
     AudioSurroundContext *s = ctx->priv;
     float overlap;
-    int i;
+    int64_t in_channel_layout, out_channel_layout;
+    int i, ret;
 
-    if (!(s->out_channel_layout = av_get_channel_layout(s->out_channel_layout_str))) {
+    if ((ret = av_channel_layout_from_string(&s->out_channel_layout, s->out_channel_layout_str)) < 0) {
         av_log(ctx, AV_LOG_ERROR, "Error parsing output channel layout '%s'.\n",
                s->out_channel_layout_str);
-        return AVERROR(EINVAL);
+        return ret;
     }
 
-    if (!(s->in_channel_layout = av_get_channel_layout(s->in_channel_layout_str))) {
+    if ((ret = av_channel_layout_from_string(&s->in_channel_layout, s->in_channel_layout_str)) < 0) {
         av_log(ctx, AV_LOG_ERROR, "Error parsing input channel layout '%s'.\n",
                s->in_channel_layout_str);
         return AVERROR(EINVAL);
@@ -1393,10 +1394,15 @@  static av_cold int init(AVFilterContext *ctx)
         return AVERROR(EINVAL);
     }
 
-    switch (s->in_channel_layout) {
+    in_channel_layout  = s->in_channel_layout.order == AV_CHANNEL_ORDER_NATIVE ?
+                         s->in_channel_layout.u.mask : 0;
+    out_channel_layout = s->out_channel_layout.order == AV_CHANNEL_ORDER_NATIVE ?
+                         s->out_channel_layout.u.mask : 0;
+
+    switch (in_channel_layout) {
     case AV_CH_LAYOUT_STEREO:
         s->filter = filter_stereo;
-        switch (s->out_channel_layout) {
+        switch (out_channel_layout) {
         case AV_CH_LAYOUT_MONO:
             s->upmix_stereo = upmix_1_0;
             break;
@@ -1442,7 +1448,7 @@  static av_cold int init(AVFilterContext *ctx)
         break;
     case AV_CH_LAYOUT_2POINT1:
         s->filter = filter_2_1;
-        switch (s->out_channel_layout) {
+        switch (out_channel_layout) {
         case AV_CH_LAYOUT_5POINT1_BACK:
             s->upmix_2_1 = upmix_5_1_back_2_1;
             break;
@@ -1452,7 +1458,7 @@  static av_cold int init(AVFilterContext *ctx)
         break;
     case AV_CH_LAYOUT_SURROUND:
         s->filter = filter_surround;
-        switch (s->out_channel_layout) {
+        switch (out_channel_layout) {
         case AV_CH_LAYOUT_3POINT1:
             s->upmix_3_0 = upmix_3_1_surround;
             break;
@@ -1465,7 +1471,7 @@  static av_cold int init(AVFilterContext *ctx)
         break;
     case AV_CH_LAYOUT_5POINT0:
         s->filter = filter_5_0_side;
-        switch (s->out_channel_layout) {
+        switch (out_channel_layout) {
         case AV_CH_LAYOUT_7POINT1:
             s->upmix_5_0 = upmix_7_1_5_0_side;
             break;
@@ -1475,7 +1481,7 @@  static av_cold int init(AVFilterContext *ctx)
         break;
     case AV_CH_LAYOUT_5POINT1:
         s->filter = filter_5_1_side;
-        switch (s->out_channel_layout) {
+        switch (out_channel_layout) {
         case AV_CH_LAYOUT_7POINT1:
             s->upmix_5_1 = upmix_7_1_5_1;
             break;
@@ -1485,7 +1491,7 @@  static av_cold int init(AVFilterContext *ctx)
         break;
     case AV_CH_LAYOUT_5POINT1_BACK:
         s->filter = filter_5_1_back;
-        switch (s->out_channel_layout) {
+        switch (out_channel_layout) {
         case AV_CH_LAYOUT_7POINT1:
             s->upmix_5_1 = upmix_7_1_5_1;
             break;
@@ -1586,7 +1592,7 @@  static int filter_frame(AVFilterLink *inlink)
     if (ret < 0)
         return ret;
 
-    ff_filter_execute(ctx, fft_channel, NULL, NULL, inlink->channels);
+    ff_filter_execute(ctx, fft_channel, NULL, NULL, inlink->ch_layout.nb_channels);
 
     s->filter(ctx);
 
@@ -1594,7 +1600,7 @@  static int filter_frame(AVFilterLink *inlink)
     if (!out)
         return AVERROR(ENOMEM);
 
-    ff_filter_execute(ctx, ifft_channel, out, NULL, outlink->channels);
+    ff_filter_execute(ctx, ifft_channel, out, NULL, outlink->ch_layout.nb_channels);
 
     out->pts = s->pts;
     if (s->pts != AV_NOPTS_VALUE)
diff --git a/libavfilter/af_tremolo.c b/libavfilter/af_tremolo.c
index b34a7b79f7..400549a58c 100644
--- a/libavfilter/af_tremolo.c
+++ b/libavfilter/af_tremolo.c
@@ -49,7 +49,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     AVFilterLink *outlink = ctx->outputs[0];
     TremoloContext *s = ctx->priv;
     const double *src = (const double *)in->data[0];
-    const int channels = inlink->channels;
+    const int channels = inlink->ch_layout.nb_channels;
     const int nb_samples = in->nb_samples;
     AVFrame *out;
     double *dst;
diff --git a/libavfilter/af_vibrato.c b/libavfilter/af_vibrato.c
index 2cf1364273..900f63e397 100644
--- a/libavfilter/af_vibrato.c
+++ b/libavfilter/af_vibrato.c
@@ -80,7 +80,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
         if (s->wave_table_index >= s->wave_table_size)
             s->wave_table_index -= s->wave_table_size;
 
-        for (c = 0; c < inlink->channels; c++) {
+        for (c = 0; c < inlink->ch_layout.nb_channels; c++) {
             int samp1_index, samp2_index;
             double *buf;
             double this_samp;
@@ -128,10 +128,10 @@  static int config_input(AVFilterLink *inlink)
     AVFilterContext *ctx = inlink->dst;
     VibratoContext *s = ctx->priv;
 
-    s->buf = av_calloc(inlink->channels, sizeof(*s->buf));
+    s->buf = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->buf));
     if (!s->buf)
         return AVERROR(ENOMEM);
-    s->channels = inlink->channels;
+    s->channels = inlink->ch_layout.nb_channels;
     s->buf_size = lrint(inlink->sample_rate * 0.005 + 0.5);
     for (c = 0; c < s->channels; c++) {
         s->buf[c] = av_malloc_array(s->buf_size, sizeof(*s->buf[c]));
diff --git a/libavfilter/af_volume.c b/libavfilter/af_volume.c
index 76ccddc316..4c9b96f17e 100644
--- a/libavfilter/af_volume.c
+++ b/libavfilter/af_volume.c
@@ -281,7 +281,7 @@  static int config_output(AVFilterLink *outlink)
     AVFilterLink *inlink = ctx->inputs[0];
 
     vol->sample_fmt = inlink->format;
-    vol->channels   = inlink->channels;
+    vol->channels   = inlink->ch_layout.nb_channels;
     vol->planes     = av_sample_fmt_is_planar(inlink->format) ? vol->channels : 1;
 
     vol->var_values[VAR_N] =
@@ -294,7 +294,7 @@  static int config_output(AVFilterLink *outlink)
     vol->var_values[VAR_T] =
     vol->var_values[VAR_VOLUME] = NAN;
 
-    vol->var_values[VAR_NB_CHANNELS] = inlink->channels;
+    vol->var_values[VAR_NB_CHANNELS] = inlink->ch_layout.nb_channels;
     vol->var_values[VAR_TB]          = av_q2d(inlink->time_base);
     vol->var_values[VAR_SAMPLE_RATE] = inlink->sample_rate;
 
diff --git a/libavfilter/af_volumedetect.c b/libavfilter/af_volumedetect.c
index 486fccc4e9..ebfad6914f 100644
--- a/libavfilter/af_volumedetect.c
+++ b/libavfilter/af_volumedetect.c
@@ -38,7 +38,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *samples)
     AVFilterContext *ctx = inlink->dst;
     VolDetectContext *vd = ctx->priv;
     int nb_samples  = samples->nb_samples;
-    int nb_channels = samples->channels;
+    int nb_channels = samples->ch_layout.nb_channels;
     int nb_planes   = nb_channels;
     int plane, i;
     int16_t *pcm;
diff --git a/libavfilter/asrc_afirsrc.c b/libavfilter/asrc_afirsrc.c
index 3612610e75..b3651d3862 100644
--- a/libavfilter/asrc_afirsrc.c
+++ b/libavfilter/asrc_afirsrc.c
@@ -109,7 +109,7 @@  static av_cold void uninit(AVFilterContext *ctx)
 static av_cold int query_formats(AVFilterContext *ctx)
 {
     AudioFIRSourceContext *s = ctx->priv;
-    static const int64_t chlayouts[] = { AV_CH_LAYOUT_MONO, -1 };
+    static const AVChannelLayout chlayouts[] = { (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO, { 0 } };
     int sample_rates[] = { s->sample_rate, -1 };
     static const enum AVSampleFormat sample_fmts[] = {
         AV_SAMPLE_FMT_FLT,
diff --git a/libavfilter/asrc_anoisesrc.c b/libavfilter/asrc_anoisesrc.c
index 8c834492fe..8e90a420ea 100644
--- a/libavfilter/asrc_anoisesrc.c
+++ b/libavfilter/asrc_anoisesrc.c
@@ -84,7 +84,7 @@  AVFILTER_DEFINE_CLASS(anoisesrc);
 static av_cold int query_formats(AVFilterContext *ctx)
 {
     ANoiseSrcContext *s = ctx->priv;
-    static const int64_t chlayouts[] = { AV_CH_LAYOUT_MONO, -1 };
+    static const AVChannelLayout chlayouts[] = { (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO, { 0 } };
     int sample_rates[] = { s->sample_rate, -1 };
     static const enum AVSampleFormat sample_fmts[] = {
         AV_SAMPLE_FMT_DBL,
diff --git a/libavfilter/asrc_anullsrc.c b/libavfilter/asrc_anullsrc.c
index 7ee2fa5a5d..17cbc5fb6c 100644
--- a/libavfilter/asrc_anullsrc.c
+++ b/libavfilter/asrc_anullsrc.c
@@ -37,8 +37,7 @@ 
 
 typedef struct ANullContext {
     const AVClass *class;
-    char   *channel_layout_str;
-    uint64_t channel_layout;
+    AVChannelLayout ch_layout;
     char   *sample_rate_str;
     int     sample_rate;
     int64_t duration;
@@ -50,8 +49,8 @@  typedef struct ANullContext {
 #define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
 
 static const AVOption anullsrc_options[]= {
-    { "channel_layout", "set channel_layout", OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, {.str = "stereo"}, 0, 0, FLAGS },
-    { "cl",             "set channel_layout", OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, {.str = "stereo"}, 0, 0, FLAGS },
+    { "channel_layout", "set channel_layout", OFFSET(ch_layout), AV_OPT_TYPE_CHLAYOUT, {.str = "stereo"}, 0, 0, FLAGS },
+    { "cl",             "set channel_layout", OFFSET(ch_layout), AV_OPT_TYPE_CHLAYOUT, {.str = "stereo"}, 0, 0, FLAGS },
     { "sample_rate",    "set sample rate",    OFFSET(sample_rate_str)   , AV_OPT_TYPE_STRING, {.str = "44100"}, 0, 0, FLAGS },
     { "r",              "set sample rate",    OFFSET(sample_rate_str)   , AV_OPT_TYPE_STRING, {.str = "44100"}, 0, 0, FLAGS },
     { "nb_samples",     "set the number of samples per requested frame", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64 = 1024}, 1, UINT16_MAX, FLAGS },
@@ -72,17 +71,13 @@  static av_cold int init(AVFilterContext *ctx)
                                      null->sample_rate_str, ctx)) < 0)
         return ret;
 
-    if ((ret = ff_parse_channel_layout(&null->channel_layout, NULL,
-                                        null->channel_layout_str, ctx)) < 0)
-        return ret;
-
     return 0;
 }
 
 static int query_formats(AVFilterContext *ctx)
 {
     ANullContext *null = ctx->priv;
-    int64_t chlayouts[] = { null->channel_layout, -1 };
+    const AVChannelLayout chlayouts[] = { null->ch_layout, { 0 } };
     int sample_rates[] = { null->sample_rate, -1 };
     int ret;
 
diff --git a/libavfilter/asrc_flite.c b/libavfilter/asrc_flite.c
index 17e7a5b9bc..5fab8086ba 100644
--- a/libavfilter/asrc_flite.c
+++ b/libavfilter/asrc_flite.c
@@ -225,11 +225,13 @@  static int query_formats(AVFilterContext *ctx)
     int ret;
 
     AVFilterChannelLayouts *chlayouts = NULL;
-    int64_t chlayout = av_get_default_channel_layout(flite->wave->num_channels);
     AVFilterFormats *sample_formats = NULL;
     AVFilterFormats *sample_rates = NULL;
+    AVChannelLayout chlayout = { 0 };
 
-    if ((ret = ff_add_channel_layout         (&chlayouts     , chlayout                )) < 0 ||
+    av_channel_layout_default(&chlayout, flite->wave->num_channels);
+
+    if ((ret = ff_add_channel_layout         (&chlayouts     , &chlayout               )) < 0 ||
         (ret = ff_set_common_channel_layouts (ctx            , chlayouts               )) < 0 ||
         (ret = ff_add_format                 (&sample_formats, AV_SAMPLE_FMT_S16       )) < 0 ||
         (ret = ff_set_common_formats         (ctx            , sample_formats          )) < 0 ||
diff --git a/libavfilter/asrc_hilbert.c b/libavfilter/asrc_hilbert.c
index 82996c7362..6469ea2cda 100644
--- a/libavfilter/asrc_hilbert.c
+++ b/libavfilter/asrc_hilbert.c
@@ -77,7 +77,7 @@  static av_cold void uninit(AVFilterContext *ctx)
 static av_cold int query_formats(AVFilterContext *ctx)
 {
     HilbertContext *s = ctx->priv;
-    static const int64_t chlayouts[] = { AV_CH_LAYOUT_MONO, -1 };
+    static const AVChannelLayout chlayouts[] = { (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO, { 0 } };
     int sample_rates[] = { s->sample_rate, -1 };
     static const enum AVSampleFormat sample_fmts[] = {
         AV_SAMPLE_FMT_FLT,
diff --git a/libavfilter/asrc_sinc.c b/libavfilter/asrc_sinc.c
index aaa81291a8..e4ae61c406 100644
--- a/libavfilter/asrc_sinc.c
+++ b/libavfilter/asrc_sinc.c
@@ -76,7 +76,7 @@  static int activate(AVFilterContext *ctx)
 static int query_formats(AVFilterContext *ctx)
 {
     SincContext *s = ctx->priv;
-    static const int64_t chlayouts[] = { AV_CH_LAYOUT_MONO, -1 };
+    static const AVChannelLayout chlayouts[] = { (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO, { 0 } };
     int sample_rates[] = { s->sample_rate, -1 };
     static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLT,
                                                        AV_SAMPLE_FMT_NONE };
diff --git a/libavfilter/asrc_sine.c b/libavfilter/asrc_sine.c
index c8995ae2c9..780070e205 100644
--- a/libavfilter/asrc_sine.c
+++ b/libavfilter/asrc_sine.c
@@ -180,7 +180,7 @@  static av_cold void uninit(AVFilterContext *ctx)
 static av_cold int query_formats(AVFilterContext *ctx)
 {
     SineContext *sine = ctx->priv;
-    static const int64_t chlayouts[] = { AV_CH_LAYOUT_MONO, -1 };
+    static const AVChannelLayout chlayouts[] = { (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO, { 0 } };
     int sample_rates[] = { sine->sample_rate, -1 };
     static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16,
                                                        AV_SAMPLE_FMT_NONE };
diff --git a/libavfilter/audio.c b/libavfilter/audio.c
index cebc9709dd..0567c3c361 100644
--- a/libavfilter/audio.c
+++ b/libavfilter/audio.c
@@ -39,10 +39,14 @@  AVFrame *ff_null_get_audio_buffer(AVFilterLink *link, int nb_samples)
 AVFrame *ff_default_get_audio_buffer(AVFilterLink *link, int nb_samples)
 {
     AVFrame *frame = NULL;
-    int channels = link->channels;
+    int channels = link->ch_layout.nb_channels;
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
     int channel_layout_nb_channels = av_get_channel_layout_nb_channels(link->channel_layout);
 
     av_assert0(channels == channel_layout_nb_channels || !channel_layout_nb_channels);
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
 
     if (!link->frame_pool) {
         link->frame_pool = ff_frame_pool_audio_init(av_buffer_allocz, channels,
@@ -77,7 +81,17 @@  AVFrame *ff_default_get_audio_buffer(AVFilterLink *link, int nb_samples)
         return NULL;
 
     frame->nb_samples = nb_samples;
-    frame->channel_layout = link->channel_layout;
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
+    frame->channel_layout = link->ch_layout.order == AV_CHANNEL_ORDER_NATIVE ?
+                            link->ch_layout.u.mask : 0;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+    if (link->ch_layout.order != AV_CHANNEL_ORDER_UNSPEC &&
+        av_channel_layout_copy(&frame->ch_layout, &link->ch_layout) < 0) {
+        av_frame_free(&frame);
+        return NULL;
+    }
     frame->sample_rate = link->sample_rate;
 
     av_samples_set_silence(frame->extended_data, 0, nb_samples, channels, link->format);
diff --git a/libavfilter/avf_abitscope.c b/libavfilter/avf_abitscope.c
index f74a6eacb0..73a8290c9e 100644
--- a/libavfilter/avf_abitscope.c
+++ b/libavfilter/avf_abitscope.c
@@ -96,7 +96,7 @@  static int config_input(AVFilterLink *inlink)
     char *colors, *saveptr = NULL;
 
     s->nb_samples = FFMAX(1, av_rescale(inlink->sample_rate, s->frame_rate.den, s->frame_rate.num));
-    s->nb_channels = inlink->channels;
+    s->nb_channels = inlink->ch_layout.nb_channels;
     s->depth = inlink->format == AV_SAMPLE_FMT_S16P ? 16 : 32;
 
     s->fg = av_malloc_array(s->nb_channels, 4 * sizeof(*s->fg));
@@ -168,9 +168,9 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
 
     switch (insamples->format) {
     case AV_SAMPLE_FMT_S16P:
-        for (ch = 0; ch < inlink->channels; ch++) {
+        for (ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {
             uint16_t *in = (uint16_t *)insamples->extended_data[ch];
-            int w = outpicref->width / inlink->channels;
+            int w = outpicref->width / inlink->ch_layout.nb_channels;
             int h = outpicref->height / 16;
             uint32_t color = AV_RN32(&s->fg[4 * ch]);
 
@@ -191,9 +191,9 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
         }
         break;
     case AV_SAMPLE_FMT_S32P:
-        for (ch = 0; ch < inlink->channels; ch++) {
+        for (ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {
             uint32_t *in = (uint32_t *)insamples->extended_data[ch];
-            int w = outpicref->width / inlink->channels;
+            int w = outpicref->width / inlink->ch_layout.nb_channels;
             int h = outpicref->height / 32;
             uint32_t color = AV_RN32(&s->fg[4 * ch]);
 
diff --git a/libavfilter/avf_ahistogram.c b/libavfilter/avf_ahistogram.c
index 258b062873..98606b1149 100644
--- a/libavfilter/avf_ahistogram.c
+++ b/libavfilter/avf_ahistogram.c
@@ -121,7 +121,7 @@  static int config_input(AVFilterLink *inlink)
     AudioHistogramContext *s = ctx->priv;
 
     s->nb_samples = FFMAX(1, av_rescale(inlink->sample_rate, s->frame_rate.den, s->frame_rate.num));
-    s->dchannels = s->dmode == SINGLE ? 1 : inlink->channels;
+    s->dchannels = s->dmode == SINGLE ? 1 : inlink->ch_layout.nb_channels;
     s->shistogram = av_calloc(s->w, s->dchannels * sizeof(*s->shistogram));
     if (!s->shistogram)
         return AVERROR(ENOMEM);
@@ -201,7 +201,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 
     switch (s->ascale) {
     case ALINEAR:
-        for (c = 0; c < inlink->channels; c++) {
+        for (c = 0; c < inlink->ch_layout.nb_channels; c++) {
             const float *src = (const float *)in->extended_data[c];
             uint64_t *achistogram = &s->achistogram[(s->dmode == SINGLE ? 0: c) * w];
 
@@ -224,7 +224,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *in)
         }
         break;
     case ALOG:
-        for (c = 0; c < inlink->channels; c++) {
+        for (c = 0; c < inlink->ch_layout.nb_channels; c++) {
             const float *src = (const float *)in->extended_data[c];
             uint64_t *achistogram = &s->achistogram[(s->dmode == SINGLE ? 0: c) * w];
 
diff --git a/libavfilter/avf_aphasemeter.c b/libavfilter/avf_aphasemeter.c
index d9302cf867..eae584d17f 100644
--- a/libavfilter/avf_aphasemeter.c
+++ b/libavfilter/avf_aphasemeter.c
@@ -101,7 +101,7 @@  static int query_formats(AVFilterContext *ctx)
     formats = ff_make_format_list(sample_fmts);
     if ((ret = ff_formats_ref         (formats, &inlink->outcfg.formats        )) < 0 ||
         (ret = ff_formats_ref         (formats, &outlink->incfg.formats        )) < 0 ||
-        (ret = ff_add_channel_layout  (&layout, AV_CH_LAYOUT_STEREO         )) < 0 ||
+        (ret = ff_add_channel_layout  (&layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO )) < 0 ||
         (ret = ff_channel_layouts_ref (layout , &inlink->outcfg.channel_layouts)) < 0 ||
         (ret = ff_channel_layouts_ref (layout , &outlink->incfg.channel_layouts)) < 0)
         return ret;
diff --git a/libavfilter/avf_avectorscope.c b/libavfilter/avf_avectorscope.c
index ba392153f3..c1deaa1ea0 100644
--- a/libavfilter/avf_avectorscope.c
+++ b/libavfilter/avf_avectorscope.c
@@ -207,7 +207,7 @@  static int query_formats(AVFilterContext *ctx)
 
     formats = ff_make_format_list(sample_fmts);
     if ((ret = ff_formats_ref         (formats, &inlink->outcfg.formats        )) < 0 ||
-        (ret = ff_add_channel_layout  (&layout, AV_CH_LAYOUT_STEREO         )) < 0 ||
+        (ret = ff_add_channel_layout  (&layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO)) < 0 ||
         (ret = ff_channel_layouts_ref (layout , &inlink->outcfg.channel_layouts)) < 0)
         return ret;
 
diff --git a/libavfilter/avf_concat.c b/libavfilter/avf_concat.c
index 84c2a52094..c85c17b51f 100644
--- a/libavfilter/avf_concat.c
+++ b/libavfilter/avf_concat.c
@@ -263,7 +263,7 @@  static int send_silence(AVFilterContext *ctx, unsigned in_no, unsigned out_no,
         if (!buf)
             return AVERROR(ENOMEM);
         av_samples_set_silence(buf->extended_data, 0, frame_nb_samples,
-                               outlink->channels, outlink->format);
+                               outlink->ch_layout.nb_channels, outlink->format);
         buf->pts = base_pts + av_rescale_q(sent, rate_tb, outlink->time_base);
         ret = ff_filter_frame(outlink, buf);
         if (ret < 0)
diff --git a/libavfilter/avf_showcqt.c b/libavfilter/avf_showcqt.c
index 6f63574a8f..057a957a2a 100644
--- a/libavfilter/avf_showcqt.c
+++ b/libavfilter/avf_showcqt.c
@@ -1325,7 +1325,8 @@  static int query_formats(AVFilterContext *ctx)
         AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P,
         AV_PIX_FMT_YUV444P, AV_PIX_FMT_RGB24, AV_PIX_FMT_NONE
     };
-    static const int64_t channel_layouts[] = { AV_CH_LAYOUT_STEREO, AV_CH_LAYOUT_STEREO_DOWNMIX, -1 };
+    static const AVChannelLayout channel_layouts[] = { (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO,
+                                                       (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO_DOWNMIX, { 0 } };
     int ret;
 
     /* set input audio formats */
diff --git a/libavfilter/avf_showfreqs.c b/libavfilter/avf_showfreqs.c
index 08dbce53c8..c72a464884 100644
--- a/libavfilter/avf_showfreqs.c
+++ b/libavfilter/avf_showfreqs.c
@@ -177,7 +177,7 @@  static int config_output(AVFilterLink *outlink)
     av_freep(&s->fft_input);
     av_freep(&s->fft_data);
     av_freep(&s->avg_data);
-    s->nb_channels = inlink->channels;
+    s->nb_channels = inlink->ch_layout.nb_channels;
 
     s->fft_input = av_calloc(s->nb_channels, sizeof(*s->fft_input));
     if (!s->fft_input)
@@ -219,7 +219,7 @@  static int config_output(AVFilterLink *outlink)
     outlink->w = s->w;
     outlink->h = s->h;
 
-    s->fifo = av_audio_fifo_alloc(inlink->format, inlink->channels, s->win_size);
+    s->fifo = av_audio_fifo_alloc(inlink->format, inlink->ch_layout.nb_channels, s->win_size);
     if (!s->fifo)
         return AVERROR(ENOMEM);
     return 0;
diff --git a/libavfilter/avf_showspatial.c b/libavfilter/avf_showspatial.c
index 64e5204837..7807628540 100644
--- a/libavfilter/avf_showspatial.c
+++ b/libavfilter/avf_showspatial.c
@@ -94,7 +94,7 @@  static int query_formats(AVFilterContext *ctx)
 
     formats = ff_make_format_list(sample_fmts);
     if ((ret = ff_formats_ref         (formats, &inlink->outcfg.formats        )) < 0 ||
-        (ret = ff_add_channel_layout  (&layout, AV_CH_LAYOUT_STEREO         )) < 0 ||
+        (ret = ff_add_channel_layout  (&layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO)) < 0 ||
         (ret = ff_channel_layouts_ref (layout , &inlink->outcfg.channel_layouts)) < 0)
         return ret;
 
@@ -190,7 +190,7 @@  static int config_output(AVFilterLink *outlink)
     outlink->time_base = av_inv_q(outlink->frame_rate);
 
     av_audio_fifo_free(s->fifo);
-    s->fifo = av_audio_fifo_alloc(inlink->format, inlink->channels, s->win_size);
+    s->fifo = av_audio_fifo_alloc(inlink->format, inlink->ch_layout.nb_channels, s->win_size);
     if (!s->fifo)
         return AVERROR(ENOMEM);
     return 0;
diff --git a/libavfilter/avf_showspectrum.c b/libavfilter/avf_showspectrum.c
index 74d2dd758c..3defc9d05c 100644
--- a/libavfilter/avf_showspectrum.c
+++ b/libavfilter/avf_showspectrum.c
@@ -738,8 +738,7 @@  static int draw_legend(AVFilterContext *ctx, int samples)
     uint8_t *dst;
     char chlayout_str[128];
 
-    av_get_channel_layout_string(chlayout_str, sizeof(chlayout_str), inlink->channels,
-                                 inlink->channel_layout);
+    av_channel_layout_describe(&inlink->ch_layout, chlayout_str, sizeof(chlayout_str));
 
     text = av_asprintf("%d Hz | %s", inlink->sample_rate, chlayout_str);
     if (!text)
@@ -1041,8 +1040,8 @@  static int config_output(AVFilterLink *outlink)
         outlink->h += s->start_y * 2;
     }
 
-    h = (s->mode == COMBINED || s->orientation == HORIZONTAL) ? s->h : s->h / inlink->channels;
-    w = (s->mode == COMBINED || s->orientation == VERTICAL)   ? s->w : s->w / inlink->channels;
+    h = (s->mode == COMBINED || s->orientation == HORIZONTAL) ? s->h : s->h / inlink->ch_layout.nb_channels;
+    w = (s->mode == COMBINED || s->orientation == VERTICAL)   ? s->w : s->w / inlink->ch_layout.nb_channels;
     s->channel_height = h;
     s->channel_width  = w;
 
@@ -1058,14 +1057,14 @@  static int config_output(AVFilterLink *outlink)
     s->buf_size = FFALIGN(s->win_size << (!!s->stop), av_cpu_max_align());
 
     if (!s->fft) {
-        s->fft = av_calloc(inlink->channels, sizeof(*s->fft));
+        s->fft = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->fft));
         if (!s->fft)
             return AVERROR(ENOMEM);
     }
 
     if (s->stop) {
         if (!s->ifft) {
-            s->ifft = av_calloc(inlink->channels, sizeof(*s->ifft));
+            s->ifft = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->ifft));
             if (!s->ifft)
                 return AVERROR(ENOMEM);
         }
@@ -1091,7 +1090,7 @@  static int config_output(AVFilterLink *outlink)
         }
         av_freep(&s->fft_data);
 
-        s->nb_display_channels = inlink->channels;
+        s->nb_display_channels = inlink->ch_layout.nb_channels;
         for (i = 0; i < s->nb_display_channels; i++) {
             float scale;
 
@@ -1240,7 +1239,7 @@  static int config_output(AVFilterLink *outlink)
            s->w, s->h, s->win_size);
 
     av_audio_fifo_free(s->fifo);
-    s->fifo = av_audio_fifo_alloc(inlink->format, inlink->channels, s->win_size);
+    s->fifo = av_audio_fifo_alloc(inlink->format, inlink->ch_layout.nb_channels, s->win_size);
     if (!s->fifo)
         return AVERROR(ENOMEM);
     return 0;
diff --git a/libavfilter/avf_showvolume.c b/libavfilter/avf_showvolume.c
index 401b65ca69..1c072a16a6 100644
--- a/libavfilter/avf_showvolume.c
+++ b/libavfilter/avf_showvolume.c
@@ -166,15 +166,15 @@  static int config_input(AVFilterLink *inlink)
     ShowVolumeContext *s = ctx->priv;
 
     s->nb_samples = FFMAX(1, av_rescale(inlink->sample_rate, s->frame_rate.den, s->frame_rate.num));
-    s->values = av_calloc(inlink->channels * VAR_VARS_NB, sizeof(double));
+    s->values = av_calloc(inlink->ch_layout.nb_channels * VAR_VARS_NB, sizeof(double));
     if (!s->values)
         return AVERROR(ENOMEM);
 
-    s->color_lut = av_calloc(s->w, sizeof(*s->color_lut) * inlink->channels);
+    s->color_lut = av_calloc(s->w, sizeof(*s->color_lut) * inlink->ch_layout.nb_channels);
     if (!s->color_lut)
         return AVERROR(ENOMEM);
 
-    s->max = av_calloc(inlink->channels, sizeof(*s->max));
+    s->max = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->max));
     if (!s->max)
         return AVERROR(ENOMEM);
 
@@ -188,8 +188,8 @@  static int config_input(AVFilterLink *inlink)
 
     if (s->draw_persistent_duration > 0.) {
         s->persistent_max_frames = (int) FFMAX(av_q2d(s->frame_rate) * s->draw_persistent_duration, 1.);
-        s->max_persistent = av_calloc(inlink->channels * s->persistent_max_frames, sizeof(*s->max_persistent));
-        s->nb_frames_max_display = av_calloc(inlink->channels * s->persistent_max_frames, sizeof(*s->nb_frames_max_display));
+        s->max_persistent = av_calloc(inlink->ch_layout.nb_channels * s->persistent_max_frames, sizeof(*s->max_persistent));
+        s->nb_frames_max_display = av_calloc(inlink->ch_layout.nb_channels * s->persistent_max_frames, sizeof(*s->nb_frames_max_display));
     }
     return 0;
 }
@@ -202,16 +202,16 @@  static int config_output(AVFilterLink *outlink)
 
     if (s->orientation) {
         outlink->h = s->w;
-        outlink->w = s->h * inlink->channels + (inlink->channels - 1) * s->b;
+        outlink->w = s->h * inlink->ch_layout.nb_channels + (inlink->ch_layout.nb_channels - 1) * s->b;
     } else {
         outlink->w = s->w;
-        outlink->h = s->h * inlink->channels + (inlink->channels - 1) * s->b;
+        outlink->h = s->h * inlink->ch_layout.nb_channels + (inlink->ch_layout.nb_channels - 1) * s->b;
     }
 
     outlink->sample_aspect_ratio = (AVRational){1,1};
     outlink->frame_rate = s->frame_rate;
 
-    for (ch = 0; ch < inlink->channels; ch++) {
+    for (ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {
         int i;
 
         for (i = 0; i < s->w; i++) {
@@ -322,6 +322,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
     ShowVolumeContext *s = ctx->priv;
     const int step = s->step;
     int c, j, k, max_draw;
+    char channel_name[64];
     AVFrame *out;
 
     if (!s->out || s->out->width  != outlink->w ||
@@ -353,7 +354,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
     }
 
     if (s->orientation) { /* vertical */
-        for (c = 0; c < inlink->channels; c++) {
+        for (c = 0; c < inlink->ch_layout.nb_channels; c++) {
             float *src = (float *)insamples->extended_data[c];
             uint32_t *lut = s->color_lut + s->w * c;
             float max;
@@ -375,8 +376,8 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
             }
 
             if (s->h >= 8 && s->draw_text) {
-                const char *channel_name = av_get_channel_name(av_channel_layout_extract_channel(insamples->channel_layout, c));
-                if (!channel_name)
+                int ret = av_channel_name(channel_name, sizeof(channel_name), av_channel_layout_channel_from_index(&insamples->ch_layout, c));
+                if (ret < 0)
                     continue;
                 drawtext(s->out, c * (s->h + s->b) + (s->h - 10) / 2, outlink->h - 35, channel_name, 1);
             }
@@ -388,7 +389,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
             }
         }
     } else { /* horizontal */
-        for (c = 0; c < inlink->channels; c++) {
+        for (c = 0; c < inlink->ch_layout.nb_channels; c++) {
             float *src = (float *)insamples->extended_data[c];
             uint32_t *lut = s->color_lut + s->w * c;
             float max;
@@ -411,8 +412,8 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
             }
 
             if (s->h >= 8 && s->draw_text) {
-                const char *channel_name = av_get_channel_name(av_channel_layout_extract_channel(insamples->channel_layout, c));
-                if (!channel_name)
+                int ret = av_channel_name(channel_name, sizeof(channel_name), av_channel_layout_channel_from_index(&insamples->ch_layout, c));
+                if (ret < 0)
                     continue;
                 drawtext(s->out, 2, c * (s->h + s->b) + (s->h - 8) / 2, channel_name, 0);
             }
@@ -432,7 +433,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
     av_frame_make_writable(out);
 
     /* draw volume level */
-    for (c = 0; c < inlink->channels && s->h >= 8 && s->draw_volume; c++) {
+    for (c = 0; c < inlink->ch_layout.nb_channels && s->h >= 8 && s->draw_volume; c++) {
         char buf[16];
 
         if (s->orientation) { /* vertical */
diff --git a/libavfilter/avf_showwaves.c b/libavfilter/avf_showwaves.c
index 853f6bbdcb..4aa415b115 100644
--- a/libavfilter/avf_showwaves.c
+++ b/libavfilter/avf_showwaves.c
@@ -415,7 +415,7 @@  static int config_output(AVFilterLink *outlink)
     AVFilterContext *ctx = outlink->src;
     AVFilterLink *inlink = ctx->inputs[0];
     ShowWavesContext *showwaves = ctx->priv;
-    int nb_channels = inlink->channels;
+    int nb_channels = inlink->ch_layout.nb_channels;
     char *colors, *saveptr = NULL;
     uint8_t x;
     int ch;
@@ -551,7 +551,7 @@  inline static int push_frame(AVFilterLink *outlink)
     AVFilterContext *ctx = outlink->src;
     AVFilterLink *inlink = ctx->inputs[0];
     ShowWavesContext *showwaves = outlink->src->priv;
-    int nb_channels = inlink->channels;
+    int nb_channels = inlink->ch_layout.nb_channels;
     int ret, i;
 
     ret = ff_filter_frame(outlink, showwaves->outpicref);
@@ -572,7 +572,7 @@  static int push_single_pic(AVFilterLink *outlink)
     int64_t last_column_samples = column_max_samples + remaining_samples;
     AVFrame *out = showwaves->outpicref;
     struct frame_node *node;
-    const int nb_channels = inlink->channels;
+    const int nb_channels = inlink->ch_layout.nb_channels;
     const int ch_height = showwaves->split_channels ? outlink->h / nb_channels : outlink->h;
     const int linesize = out->linesize[0];
     const int pixstep = showwaves->pixstep;
@@ -661,7 +661,7 @@  static int alloc_out_frame(ShowWavesContext *showwaves, const int16_t *p,
             return AVERROR(ENOMEM);
         out->width  = outlink->w;
         out->height = outlink->h;
-        out->pts = in->pts + av_rescale_q((p - (int16_t *)in->data[0]) / inlink->channels,
+        out->pts = in->pts + av_rescale_q((p - (int16_t *)in->data[0]) / inlink->ch_layout.nb_channels,
                                           av_make_q(1, inlink->sample_rate),
                                           outlink->time_base);
         for (j = 0; j < outlink->h; j++)
@@ -692,7 +692,7 @@  static int showwaves_filter_frame(AVFilterLink *inlink, AVFrame *insamples)
     const int nb_samples = insamples->nb_samples;
     AVFrame *outpicref = showwaves->outpicref;
     int16_t *p = (int16_t *)insamples->data[0];
-    int nb_channels = inlink->channels;
+    int nb_channels = inlink->ch_layout.nb_channels;
     int i, j, ret = 0;
     const int pixstep = showwaves->pixstep;
     const int n = showwaves->n;
@@ -820,7 +820,7 @@  static int showwavespic_config_input(AVFilterLink *inlink)
     ShowWavesContext *showwaves = ctx->priv;
 
     if (showwaves->single_pic) {
-        showwaves->sum = av_calloc(inlink->channels, sizeof(*showwaves->sum));
+        showwaves->sum = av_calloc(inlink->ch_layout.nb_channels, sizeof(*showwaves->sum));
         if (!showwaves->sum)
             return AVERROR(ENOMEM);
     }
diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
index 7362bcdab5..acb2d7db51 100644
--- a/libavfilter/avfilter.c
+++ b/libavfilter/avfilter.c
@@ -204,6 +204,7 @@  void avfilter_link_free(AVFilterLink **link)
 
     ff_framequeue_free(&(*link)->fifo);
     ff_frame_pool_uninit((FFFramePool**)&(*link)->frame_pool);
+    av_channel_layout_uninit(&(*link)->ch_layout);
 
     av_freep(link);
 }
@@ -405,7 +406,7 @@  void ff_tlog_link(void *ctx, AVFilterLink *link, int end)
                 end ? "\n" : "");
     } else {
         char buf[128];
-        av_get_channel_layout_string(buf, sizeof(buf), -1, link->channel_layout);
+        av_channel_layout_describe(&link->ch_layout, buf, sizeof(buf));
 
         ff_tlog(ctx,
                 "link[%p r:%d cl:%s fmt:%s %s->%s]%s",
@@ -1036,11 +1037,21 @@  int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
             av_log(link->dst, AV_LOG_ERROR, "Format change is not supported\n");
             goto error;
         }
-        if (frame->channels != link->channels) {
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
+        if (frame->channels != link->ch_layout.nb_channels) {
             av_log(link->dst, AV_LOG_ERROR, "Channel count change is not supported\n");
             goto error;
         }
-        if (frame->channel_layout != link->channel_layout) {
+        if (frame->channel_layout && frame->channel_layout != link->channel_layout) {
+            av_log(link->dst, AV_LOG_ERROR, "Channel layout change is not supported\n");
+            goto error;
+        }
+FF_ENABLE_DEPRECATION_WARNINGS
+        if (av_channel_layout_check(&frame->ch_layout) && av_channel_layout_compare(&frame->ch_layout, &link->ch_layout)) {
+#else
+        if (av_channel_layout_compare(&frame->ch_layout, &link->ch_layout)) {
+#endif
             av_log(link->dst, AV_LOG_ERROR, "Channel layout change is not supported\n");
             goto error;
         }
@@ -1117,7 +1128,7 @@  static int take_samples(AVFilterLink *link, unsigned min, unsigned max,
     for (i = 0; i < nb_frames; i++) {
         frame = ff_framequeue_take(&link->fifo);
         av_samples_copy(buf->extended_data, frame->extended_data, p, 0,
-                        frame->nb_samples, link->channels, link->format);
+                        frame->nb_samples, link->ch_layout.nb_channels, link->format);
         p += frame->nb_samples;
         av_frame_free(&frame);
     }
@@ -1125,7 +1136,7 @@  static int take_samples(AVFilterLink *link, unsigned min, unsigned max,
         unsigned n = nb_samples - p;
         frame = ff_framequeue_peek(&link->fifo, 0);
         av_samples_copy(buf->extended_data, frame->extended_data, p, 0, n,
-                        link->channels, link->format);
+                        link->ch_layout.nb_channels, link->format);
         ff_framequeue_skip_samples(&link->fifo, n, link->time_base);
     }
 
diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
index b105dc3159..fcde7ab7af 100644
--- a/libavfilter/avfilter.h
+++ b/libavfilter/avfilter.h
@@ -543,7 +543,14 @@  struct AVFilterLink {
     int h;                      ///< agreed upon image height
     AVRational sample_aspect_ratio; ///< agreed upon sample aspect ratio
     /* These parameters apply only to audio */
-    uint64_t channel_layout;    ///< channel layout of current buffer (see libavutil/channel_layout.h)
+#if FF_API_OLD_CHANNEL_LAYOUT
+    /**
+     * channel layout of current buffer (see libavutil/channel_layout.h)
+     * @deprecated use ch_layout
+     */
+    attribute_deprecated
+    uint64_t channel_layout;
+#endif
     int sample_rate;            ///< samples per second
 
     int format;                 ///< agreed upon media format
@@ -557,6 +564,8 @@  struct AVFilterLink {
      */
     AVRational time_base;
 
+    AVChannelLayout ch_layout;  ///< channel layout of current buffer (see libavutil/channel_layout.h)
+
     /*****************************************************************
      * All fields below this line are not part of the public API. They
      * may not be used outside of libavfilter and can be changed and
@@ -632,11 +641,6 @@  struct AVFilterLink {
      */
     int max_samples;
 
-    /**
-     * Number of channels.
-     */
-    int channels;
-
     /**
      * Number of past frames sent through the link.
      */
diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
index b8b432e98b..1d4343d961 100644
--- a/libavfilter/avfiltergraph.c
+++ b/libavfilter/avfiltergraph.c
@@ -639,6 +639,8 @@  static int pick_format(AVFilterLink *link, AVFilterLink *ref)
     link->format = link->incfg.formats->formats[0];
 
     if (link->type == AVMEDIA_TYPE_AUDIO) {
+        int ret;
+
         if (!link->incfg.samplerates->nb_formats) {
             av_log(link->src, AV_LOG_ERROR, "Cannot select sample rate for"
                    " the link between filters %s and %s.\n", link->src->name,
@@ -659,11 +661,15 @@  static int pick_format(AVFilterLink *link, AVFilterLink *ref)
             return AVERROR(EINVAL);
         }
         link->incfg.channel_layouts->nb_channel_layouts = 1;
-        link->channel_layout = link->incfg.channel_layouts->channel_layouts[0];
-        if ((link->channels = FF_LAYOUT2COUNT(link->channel_layout)))
-            link->channel_layout = 0;
-        else
-            link->channels = av_get_channel_layout_nb_channels(link->channel_layout);
+        ret = av_channel_layout_copy(&link->ch_layout, &link->incfg.channel_layouts->channel_layouts[0]);
+        if (ret < 0)
+            return ret;
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
+        link->channel_layout = link->ch_layout.order == AV_CHANNEL_ORDER_NATIVE ?
+                               link->ch_layout.u.mask : 0;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
     }
 
     ff_formats_unref(&link->incfg.formats);
@@ -725,12 +731,12 @@  static int reduce_formats_on_filter(AVFilterContext *filter)
     /* reduce channel layouts */
     for (i = 0; i < filter->nb_inputs; i++) {
         AVFilterLink *inlink = filter->inputs[i];
-        uint64_t fmt;
+        AVChannelLayout fmt = { 0 };
 
         if (!inlink->outcfg.channel_layouts ||
             inlink->outcfg.channel_layouts->nb_channel_layouts != 1)
             continue;
-        fmt = inlink->outcfg.channel_layouts->channel_layouts[0];
+        av_channel_layout_copy(&fmt, &inlink->outcfg.channel_layouts->channel_layouts[0]);
 
         for (j = 0; j < filter->nb_outputs; j++) {
             AVFilterLink *outlink = filter->outputs[j];
@@ -741,23 +747,24 @@  static int reduce_formats_on_filter(AVFilterContext *filter)
                 continue;
 
             if (fmts->all_layouts &&
-                (!FF_LAYOUT2COUNT(fmt) || fmts->all_counts)) {
+                (KNOWN(&fmt) || fmts->all_counts)) {
                 /* Turn the infinite list into a singleton */
                 fmts->all_layouts = fmts->all_counts  = 0;
-                if (ff_add_channel_layout(&outlink->incfg.channel_layouts, fmt) < 0)
+                if (ff_add_channel_layout(&outlink->incfg.channel_layouts, &fmt) < 0)
                     ret = 1;
                 break;
             }
 
             for (k = 0; k < outlink->incfg.channel_layouts->nb_channel_layouts; k++) {
-                if (fmts->channel_layouts[k] == fmt) {
-                    fmts->channel_layouts[0]  = fmt;
+                if (!av_channel_layout_compare(&fmts->channel_layouts[k], &fmt)) {
+                    av_channel_layout_copy(&fmts->channel_layouts[0], &fmt);
                     fmts->nb_channel_layouts = 1;
                     ret = 1;
                     break;
                 }
             }
         }
+        av_channel_layout_uninit(&fmt);
     }
 
     return ret;
@@ -887,26 +894,31 @@  static void swap_channel_layouts_on_filter(AVFilterContext *filter)
             continue;
 
         for (j = 0; j < outlink->incfg.channel_layouts->nb_channel_layouts; j++) {
-            uint64_t  in_chlayout = link->outcfg.channel_layouts->channel_layouts[0];
-            uint64_t out_chlayout = outlink->incfg.channel_layouts->channel_layouts[j];
-            int  in_channels      = av_get_channel_layout_nb_channels(in_chlayout);
-            int out_channels      = av_get_channel_layout_nb_channels(out_chlayout);
-            int count_diff        = out_channels - in_channels;
+            AVChannelLayout in_chlayout = { 0 }, out_chlayout = { 0 };
+            int  in_channels;
+            int out_channels;
+            int count_diff;
             int matched_channels, extra_channels;
             int score = 100000;
 
-            if (FF_LAYOUT2COUNT(in_chlayout) || FF_LAYOUT2COUNT(out_chlayout)) {
+            av_channel_layout_copy(&in_chlayout, &link->outcfg.channel_layouts->channel_layouts[0]);
+            av_channel_layout_copy(&out_chlayout, &outlink->incfg.channel_layouts->channel_layouts[j]);
+            in_channels            = in_chlayout.nb_channels;
+            out_channels           = out_chlayout.nb_channels;
+            count_diff             = out_channels - in_channels;
+            if (!KNOWN(&in_chlayout) || !KNOWN(&out_chlayout)) {
                 /* Compute score in case the input or output layout encodes
                    a channel count; in this case the score is not altered by
                    the computation afterwards, as in_chlayout and
                    out_chlayout have both been set to 0 */
-                if (FF_LAYOUT2COUNT(in_chlayout))
-                    in_channels = FF_LAYOUT2COUNT(in_chlayout);
-                if (FF_LAYOUT2COUNT(out_chlayout))
-                    out_channels = FF_LAYOUT2COUNT(out_chlayout);
+                if (!KNOWN(&in_chlayout))
+                    in_channels = FF_LAYOUT2COUNT(&in_chlayout);
+                if (!KNOWN(&out_chlayout))
+                    out_channels = FF_LAYOUT2COUNT(&out_chlayout);
                 score -= 10000 + FFABS(out_channels - in_channels) +
                          (in_channels > out_channels ? 10000 : 0);
-                in_chlayout = out_chlayout = 0;
+                av_channel_layout_uninit(&in_chlayout);
+                av_channel_layout_uninit(&out_chlayout);
                 /* Let the remaining computation run, even if the score
                    value is not altered */
             }
@@ -915,27 +927,27 @@  static void swap_channel_layouts_on_filter(AVFilterContext *filter)
             for (k = 0; k < FF_ARRAY_ELEMS(ch_subst); k++) {
                 uint64_t cmp0 = ch_subst[k][0];
                 uint64_t cmp1 = ch_subst[k][1];
-                if (( in_chlayout & cmp0) && (!(out_chlayout & cmp0)) &&
-                    (out_chlayout & cmp1) && (!( in_chlayout & cmp1))) {
-                    in_chlayout  &= ~cmp0;
-                    out_chlayout &= ~cmp1;
+                if ( av_channel_layout_subset(& in_chlayout, cmp0) &&
+                    !av_channel_layout_subset(&out_chlayout, cmp0) &&
+                     av_channel_layout_subset(&out_chlayout, cmp1) &&
+                    !av_channel_layout_subset(& in_chlayout, cmp1)) {
+                    av_channel_layout_from_mask(&in_chlayout, av_channel_layout_subset(& in_chlayout, ~cmp0));
+                    av_channel_layout_from_mask(&out_chlayout, av_channel_layout_subset(&out_chlayout, ~cmp1));
                     /* add score for channel match, minus a deduction for
                        having to do the substitution */
-                    score += 10 * av_get_channel_layout_nb_channels(cmp1) - 2;
+                    score += 10 * av_popcount64(cmp1) - 2;
                 }
             }
 
             /* no penalty for LFE channel mismatch */
-            if ( (in_chlayout & AV_CH_LOW_FREQUENCY) &&
-                (out_chlayout & AV_CH_LOW_FREQUENCY))
+            if (av_channel_layout_channel_from_index(&in_chlayout,  AV_CHAN_LOW_FREQUENCY) >= 0 &&
+                av_channel_layout_channel_from_index(&out_chlayout, AV_CHAN_LOW_FREQUENCY) >= 0)
                 score += 10;
-            in_chlayout  &= ~AV_CH_LOW_FREQUENCY;
-            out_chlayout &= ~AV_CH_LOW_FREQUENCY;
+            av_channel_layout_from_mask(&in_chlayout, av_channel_layout_subset(&in_chlayout, ~AV_CH_LOW_FREQUENCY));
+            av_channel_layout_from_mask(&out_chlayout, av_channel_layout_subset(&out_chlayout, ~AV_CH_LOW_FREQUENCY));
 
-            matched_channels = av_get_channel_layout_nb_channels(in_chlayout &
-                                                                 out_chlayout);
-            extra_channels   = av_get_channel_layout_nb_channels(out_chlayout &
-                                                                 (~in_chlayout));
+            matched_channels = av_popcount64(in_chlayout.u.mask & out_chlayout.u.mask);
+            extra_channels   = av_popcount64(out_chlayout.u.mask & (~in_chlayout.u.mask));
             score += 10 * matched_channels - 5 * extra_channels;
 
             if (score > best_score ||
@@ -946,7 +958,7 @@  static void swap_channel_layouts_on_filter(AVFilterContext *filter)
             }
         }
         av_assert0(best_idx >= 0);
-        FFSWAP(uint64_t, outlink->incfg.channel_layouts->channel_layouts[0],
+        FFSWAP(AVChannelLayout, outlink->incfg.channel_layouts->channel_layouts[0],
                outlink->incfg.channel_layouts->channel_layouts[best_idx]);
     }
 
diff --git a/libavfilter/buffersink.c b/libavfilter/buffersink.c
index c0215669e7..c96ac1e626 100644
--- a/libavfilter/buffersink.c
+++ b/libavfilter/buffersink.c
@@ -74,7 +74,7 @@  static void cleanup_redundant_layouts(AVFilterContext *ctx)
         if (buf->channel_counts[i] < 64)
             counts |= (uint64_t)1 << buf->channel_counts[i];
     for (i = lc = 0; i < nb_layouts; i++) {
-        n = av_get_channel_layout_nb_channels(buf->channel_layouts[i]);
+        n = av_popcount64(buf->channel_layouts[i]);
         if (n < 64 && (counts & ((uint64_t)1 << n)))
             av_log(ctx, AV_LOG_WARNING,
                    "Removing channel layout 0x%"PRIx64", redundant with %d channels\n",
@@ -217,12 +217,34 @@  MAKE_AVFILTERLINK_ACCESSOR(int              , w                  )
 MAKE_AVFILTERLINK_ACCESSOR(int              , h                  )
 MAKE_AVFILTERLINK_ACCESSOR(AVRational       , sample_aspect_ratio)
 
-MAKE_AVFILTERLINK_ACCESSOR(int              , channels           )
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
 MAKE_AVFILTERLINK_ACCESSOR(uint64_t         , channel_layout     )
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
 MAKE_AVFILTERLINK_ACCESSOR(int              , sample_rate        )
 
 MAKE_AVFILTERLINK_ACCESSOR(AVBufferRef *    , hw_frames_ctx      )
 
+int av_buffersink_get_channels(const AVFilterContext *ctx)
+{
+    av_assert0(ctx->filter->activate == activate);
+    return ctx->inputs[0]->ch_layout.nb_channels;
+}
+
+int av_buffersink_get_ch_layout(const AVFilterContext *ctx, AVChannelLayout *out)
+{
+    AVChannelLayout ch_layout = { 0 };
+    int ret;
+
+    av_assert0(ctx->filter->activate == activate);
+    ret = av_channel_layout_copy(&ch_layout, &ctx->inputs[0]->ch_layout);
+    if (ret < 0)
+        return ret;
+    *out = ch_layout;
+    return 0;
+}
+
 #define CHECK_LIST_SIZE(field) \
         if (buf->field ## _size % sizeof(*buf->field)) { \
             av_log(ctx, AV_LOG_ERROR, "Invalid size for " #field ": %d, " \
@@ -256,6 +278,7 @@  static int asink_query_formats(AVFilterContext *ctx)
 {
     BufferSinkContext *buf = ctx->priv;
     AVFilterFormats *formats = NULL;
+    AVChannelLayout layout = { 0 };
     AVFilterChannelLayouts *layouts = NULL;
     unsigned i;
     int ret;
@@ -277,11 +300,14 @@  static int asink_query_formats(AVFilterContext *ctx)
         buf->all_channel_counts) {
         cleanup_redundant_layouts(ctx);
         for (i = 0; i < NB_ITEMS(buf->channel_layouts); i++)
-            if ((ret = ff_add_channel_layout(&layouts, buf->channel_layouts[i])) < 0)
+            if ((ret = av_channel_layout_from_mask(&layout, buf->channel_layouts[i])) < 0 ||
+                (ret = ff_add_channel_layout(&layouts, &layout) < 0))
                 return ret;
-        for (i = 0; i < NB_ITEMS(buf->channel_counts); i++)
-            if ((ret = ff_add_channel_layout(&layouts, FF_COUNT2LAYOUT(buf->channel_counts[i]))) < 0)
+        for (i = 0; i < NB_ITEMS(buf->channel_counts); i++) {
+            layout = FF_COUNT2LAYOUT(buf->channel_counts[i]);
+            if ((ret = ff_add_channel_layout(&layouts, &layout)) < 0)
                 return ret;
+        }
         if (buf->all_channel_counts) {
             if (layouts)
                 av_log(ctx, AV_LOG_WARNING,
diff --git a/libavfilter/buffersink.h b/libavfilter/buffersink.h
index 69ed0f29a8..ae90ae87fa 100644
--- a/libavfilter/buffersink.h
+++ b/libavfilter/buffersink.h
@@ -46,7 +46,7 @@ 
  * - av_buffersink_get_h(),
  * - av_buffersink_get_sample_aspect_ratio(),
  * - av_buffersink_get_channels(),
- * - av_buffersink_get_channel_layout(),
+ * - av_buffersink_get_ch_layout(),
  * - av_buffersink_get_sample_rate().
  *
  * The format can be constrained by setting options, using av_opt_set() and
@@ -156,7 +156,12 @@  int              av_buffersink_get_h                   (const AVFilterContext *c
 AVRational       av_buffersink_get_sample_aspect_ratio (const AVFilterContext *ctx);
 
 int              av_buffersink_get_channels            (const AVFilterContext *ctx);
+#if FF_API_OLD_CHANNEL_LAYOUT
+attribute_deprecated
 uint64_t         av_buffersink_get_channel_layout      (const AVFilterContext *ctx);
+#endif
+int              av_buffersink_get_ch_layout           (const AVFilterContext *ctx,
+                                                        AVChannelLayout *ch_layout);
 int              av_buffersink_get_sample_rate         (const AVFilterContext *ctx);
 
 AVBufferRef *    av_buffersink_get_hw_frames_ctx       (const AVFilterContext *ctx);
diff --git a/libavfilter/buffersrc.c b/libavfilter/buffersrc.c
index b0611872f1..a2a08a7d89 100644
--- a/libavfilter/buffersrc.c
+++ b/libavfilter/buffersrc.c
@@ -60,8 +60,8 @@  typedef struct BufferSourceContext {
     int sample_rate;
     enum AVSampleFormat sample_fmt;
     int channels;
-    uint64_t channel_layout;
     char    *channel_layout_str;
+    AVChannelLayout ch_layout;
 
     int eof;
 } BufferSourceContext;
@@ -73,12 +73,12 @@  typedef struct BufferSourceContext {
         av_log(s, AV_LOG_WARNING, "Changing video frame properties on the fly is not supported by all filters.\n");\
     }
 
-#define CHECK_AUDIO_PARAM_CHANGE(s, c, srate, ch_layout, ch_count, format, pts)\
+#define CHECK_AUDIO_PARAM_CHANGE(s, c, srate, layout, format, pts)\
     if (c->sample_fmt != format || c->sample_rate != srate ||\
-        c->channel_layout != ch_layout || c->channels != ch_count) {\
+        av_channel_layout_compare(&c->ch_layout, &layout) || c->channels != layout.nb_channels) {\
         av_log(s, AV_LOG_INFO, "filter context - fmt: %s r: %d layout: %"PRIX64" ch: %d, incoming frame - fmt: %s r: %d layout: %"PRIX64" ch: %d pts_time: %s\n",\
-               av_get_sample_fmt_name(c->sample_fmt), c->sample_rate, c->channel_layout, c->channels,\
-               av_get_sample_fmt_name(format), srate, ch_layout, ch_count, av_ts2timestr(pts, &s->outputs[0]->time_base));\
+               av_get_sample_fmt_name(c->sample_fmt), c->sample_rate, c->ch_layout.order == AV_CHANNEL_ORDER_NATIVE ? c->ch_layout.u.mask : 0, c->channels,\
+               av_get_sample_fmt_name(format), srate, layout.order == AV_CHANNEL_ORDER_NATIVE ? layout.u.mask : 0, layout.nb_channels, av_ts2timestr(pts, &s->outputs[0]->time_base));\
         av_log(s, AV_LOG_ERROR, "Changing audio frame properties on the fly is not supported.\n");\
         return AVERROR(EINVAL);\
     }
@@ -127,8 +127,20 @@  int av_buffersrc_parameters_set(AVFilterContext *ctx, AVBufferSrcParameters *par
         }
         if (param->sample_rate > 0)
             s->sample_rate = param->sample_rate;
-        if (param->channel_layout)
-            s->channel_layout = param->channel_layout;
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
+        // if the old/new fields are set inconsistently, prefer the old ones
+        if (param->channel_layout && (param->ch_layout.order != AV_CHANNEL_ORDER_NATIVE ||
+                                      param->ch_layout.u.mask != param->channel_layout)) {
+            av_channel_layout_from_mask(&s->ch_layout, param->channel_layout);
+FF_ENABLE_DEPRECATION_WARNINGS
+        } else
+#endif
+        if (param->ch_layout.nb_channels) {
+            int ret = av_channel_layout_copy(&s->ch_layout, &param->ch_layout);
+            if (ret < 0)
+                return ret;
+        }
         break;
     default:
         return AVERROR_BUG;
@@ -168,11 +180,15 @@  int attribute_align_arg av_buffersrc_add_frame_flags(AVFilterContext *ctx, AVFra
     AVFrame *copy;
     int refcounted, ret;
 
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
     if (frame && frame->channel_layout &&
         av_get_channel_layout_nb_channels(frame->channel_layout) != frame->channels) {
         av_log(ctx, AV_LOG_ERROR, "Layout indicates a different number of channels than actually present\n");
         return AVERROR(EINVAL);
     }
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
 
     s->nb_failed_requests = 0;
 
@@ -192,10 +208,20 @@  int attribute_align_arg av_buffersrc_add_frame_flags(AVFilterContext *ctx, AVFra
             break;
         case AVMEDIA_TYPE_AUDIO:
             /* For layouts unknown on input but known on link after negotiation. */
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
             if (!frame->channel_layout)
-                frame->channel_layout = s->channel_layout;
-            CHECK_AUDIO_PARAM_CHANGE(ctx, s, frame->sample_rate, frame->channel_layout,
-                                     frame->channels, frame->format, frame->pts);
+                frame->channel_layout = s->ch_layout.order == AV_CHANNEL_ORDER_NATIVE ?
+                                        s->ch_layout.u.mask : 0;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+            if (frame->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC) {
+                ret = av_channel_layout_copy(&frame->ch_layout, &s->ch_layout);
+                if (ret < 0)
+                    return ret;
+            }
+            CHECK_AUDIO_PARAM_CHANGE(ctx, s, frame->sample_rate, frame->ch_layout,
+                                     frame->format, frame->pts);
             break;
         default:
             return AVERROR(EINVAL);
@@ -301,6 +327,7 @@  AVFILTER_DEFINE_CLASS(abuffer);
 static av_cold int init_audio(AVFilterContext *ctx)
 {
     BufferSourceContext *s = ctx->priv;
+    char buf[128];
     int ret = 0;
 
     if (s->sample_fmt == AV_SAMPLE_FMT_NONE) {
@@ -308,24 +335,39 @@  static av_cold int init_audio(AVFilterContext *ctx)
         return AVERROR(EINVAL);
     }
 
-    if (s->channel_layout_str || s->channel_layout) {
+    if (s->channel_layout_str || s->ch_layout.nb_channels) {
         int n;
 
-        if (!s->channel_layout) {
-            s->channel_layout = av_get_channel_layout(s->channel_layout_str);
-            if (!s->channel_layout) {
-                av_log(ctx, AV_LOG_ERROR, "Invalid channel layout %s.\n",
+        if (!s->ch_layout.nb_channels) {
+            ret = av_channel_layout_from_string(&s->ch_layout, s->channel_layout_str);
+            if (ret < 0) {
+#if FF_API_OLD_CHANNEL_LAYOUT
+                uint64_t mask;
+FF_DISABLE_DEPRECATION_WARNINGS
+                mask = av_get_channel_layout(s->channel_layout_str);
+                if (!mask) {
+#endif
+                    av_log(ctx, AV_LOG_ERROR, "Invalid channel layout %s.\n",
+                           s->channel_layout_str);
+                    return AVERROR(EINVAL);
+#if FF_API_OLD_CHANNEL_LAYOUT
+                }
+FF_ENABLE_DEPRECATION_WARNINGS
+                av_log(ctx, AV_LOG_WARNING, "Channel layout '%s' uses a deprecated syntax.\n",
                        s->channel_layout_str);
-                return AVERROR(EINVAL);
+                av_channel_layout_from_mask(&s->ch_layout, mask);
+#endif
             }
         }
-        n = av_get_channel_layout_nb_channels(s->channel_layout);
+
+        n = s->ch_layout.nb_channels;
+        av_channel_layout_describe(&s->ch_layout, buf, sizeof(buf));
         if (s->channels) {
             if (n != s->channels) {
                 av_log(ctx, AV_LOG_ERROR,
                        "Mismatching channel count %d and layout '%s' "
                        "(%d channels)\n",
-                       s->channels, s->channel_layout_str, n);
+                       s->channels, buf, n);
                 return AVERROR(EINVAL);
             }
         }
@@ -334,6 +376,9 @@  static av_cold int init_audio(AVFilterContext *ctx)
         av_log(ctx, AV_LOG_ERROR, "Neither number of channels nor "
                                   "channel layout specified\n");
         return AVERROR(EINVAL);
+    } else {
+        s->ch_layout = FF_COUNT2LAYOUT(s->channels);
+        av_channel_layout_describe(&s->ch_layout, buf, sizeof(buf));
     }
 
     if (!s->time_base.num)
@@ -342,7 +387,7 @@  static av_cold int init_audio(AVFilterContext *ctx)
     av_log(ctx, AV_LOG_VERBOSE,
            "tb:%d/%d samplefmt:%s samplerate:%d chlayout:%s\n",
            s->time_base.num, s->time_base.den, av_get_sample_fmt_name(s->sample_fmt),
-           s->sample_rate, s->channel_layout_str);
+           s->sample_rate, buf);
 
     return ret;
 }
@@ -374,9 +419,7 @@  static int query_formats(AVFilterContext *ctx)
             (ret = ff_set_common_samplerates (ctx         , samplerates   )) < 0)
             return ret;
 
-        if ((ret = ff_add_channel_layout(&channel_layouts,
-                              c->channel_layout ? c->channel_layout :
-                              FF_COUNT2LAYOUT(c->channels))) < 0)
+        if ((ret = ff_add_channel_layout(&channel_layouts, &c->ch_layout)) < 0)
             return ret;
         if ((ret = ff_set_common_channel_layouts(ctx, channel_layouts)) < 0)
             return ret;
@@ -405,8 +448,11 @@  static int config_props(AVFilterLink *link)
         }
         break;
     case AVMEDIA_TYPE_AUDIO:
-        if (!c->channel_layout)
-            c->channel_layout = link->channel_layout;
+        if (!c->ch_layout.nb_channels) {
+            int ret = av_channel_layout_copy(&c->ch_layout, &link->ch_layout);
+            if (ret < 0)
+                return ret;
+        }
         break;
     default:
         return AVERROR(EINVAL);
diff --git a/libavfilter/buffersrc.h b/libavfilter/buffersrc.h
index 08fbd18a47..3b248b37cd 100644
--- a/libavfilter/buffersrc.h
+++ b/libavfilter/buffersrc.h
@@ -110,10 +110,19 @@  typedef struct AVBufferSrcParameters {
      */
     int sample_rate;
 
+#if FF_API_OLD_CHANNEL_LAYOUT
     /**
      * Audio only, the audio channel layout
+     * @deprecated use ch_layout
      */
+    attribute_deprecated
     uint64_t channel_layout;
+#endif
+
+    /**
+     * Audio only, the audio channel layout
+     */
+    AVChannelLayout ch_layout;
 } AVBufferSrcParameters;
 
 /**
diff --git a/libavfilter/f_ebur128.c b/libavfilter/f_ebur128.c
index 88d6a1fe46..2a6edba3d8 100644
--- a/libavfilter/f_ebur128.c
+++ b/libavfilter/f_ebur128.c
@@ -422,7 +422,7 @@  static int config_audio_output(AVFilterLink *outlink)
     int i;
     AVFilterContext *ctx = outlink->src;
     EBUR128Context *ebur128 = ctx->priv;
-    const int nb_channels = av_get_channel_layout_nb_channels(outlink->channel_layout);
+    const int nb_channels = outlink->ch_layout.nb_channels;
 
 #define BACK_MASK (AV_CH_BACK_LEFT    |AV_CH_BACK_CENTER    |AV_CH_BACK_RIGHT| \
                    AV_CH_TOP_BACK_LEFT|AV_CH_TOP_BACK_CENTER|AV_CH_TOP_BACK_RIGHT| \
@@ -439,8 +439,8 @@  static int config_audio_output(AVFilterLink *outlink)
 
     for (i = 0; i < nb_channels; i++) {
         /* channel weighting */
-        const uint64_t chl = av_channel_layout_extract_channel(outlink->channel_layout, i);
-        if (chl & (AV_CH_LOW_FREQUENCY|AV_CH_LOW_FREQUENCY_2)) {
+        const int chl = av_channel_layout_channel_from_index(&outlink->ch_layout, i);
+        if (chl == AV_CHAN_LOW_FREQUENCY || chl == AV_CHAN_LOW_FREQUENCY_2) {
             ebur128->ch_weighting[i] = 0;
         } else if (chl & BACK_MASK) {
             ebur128->ch_weighting[i] = 1.41;
@@ -472,11 +472,11 @@  static int config_audio_output(AVFilterLink *outlink)
             !ebur128->true_peaks_per_frame || !ebur128->swr_ctx)
             return AVERROR(ENOMEM);
 
-        av_opt_set_int(ebur128->swr_ctx, "in_channel_layout",    outlink->channel_layout, 0);
+        av_opt_set_chlayout(ebur128->swr_ctx, "in_ch_layout",   &outlink->ch_layout, 0);
         av_opt_set_int(ebur128->swr_ctx, "in_sample_rate",       outlink->sample_rate, 0);
         av_opt_set_sample_fmt(ebur128->swr_ctx, "in_sample_fmt", outlink->format, 0);
 
-        av_opt_set_int(ebur128->swr_ctx, "out_channel_layout",    outlink->channel_layout, 0);
+        av_opt_set_chlayout(ebur128->swr_ctx, "out_ch_layout",   &outlink->ch_layout, 0);
         av_opt_set_int(ebur128->swr_ctx, "out_sample_rate",       192000, 0);
         av_opt_set_sample_fmt(ebur128->swr_ctx, "out_sample_fmt", outlink->format, 0);
 
diff --git a/libavfilter/f_graphmonitor.c b/libavfilter/f_graphmonitor.c
index 51d0a568e3..f20825a488 100644
--- a/libavfilter/f_graphmonitor.c
+++ b/libavfilter/f_graphmonitor.c
@@ -196,7 +196,7 @@  static void draw_items(AVFilterContext *ctx, AVFrame *out,
         if (l->type == AVMEDIA_TYPE_VIDEO) {
             snprintf(buffer, sizeof(buffer)-1, " | size: %dx%d", l->w, l->h);
         } else if (l->type == AVMEDIA_TYPE_AUDIO) {
-            snprintf(buffer, sizeof(buffer)-1, " | channels: %d", l->channels);
+            snprintf(buffer, sizeof(buffer)-1, " | channels: %d", l->ch_layout.nb_channels);
         }
         drawtext(out, xpos, ypos, buffer, s->white);
         xpos += strlen(buffer) * 8;
diff --git a/libavfilter/f_loop.c b/libavfilter/f_loop.c
index f8ae4a6a3a..c619ba85b3 100644
--- a/libavfilter/f_loop.c
+++ b/libavfilter/f_loop.c
@@ -70,8 +70,8 @@  static int aconfig_input(AVFilterLink *inlink)
     AVFilterContext *ctx = inlink->dst;
     LoopContext *s  = ctx->priv;
 
-    s->fifo = av_audio_fifo_alloc(inlink->format, inlink->channels, 8192);
-    s->left = av_audio_fifo_alloc(inlink->format, inlink->channels, 8192);
+    s->fifo = av_audio_fifo_alloc(inlink->format, inlink->ch_layout.nb_channels, 8192);
+    s->left = av_audio_fifo_alloc(inlink->format, inlink->ch_layout.nb_channels, 8192);
     if (!s->fifo || !s->left)
         return AVERROR(ENOMEM);
 
diff --git a/libavfilter/f_reverse.c b/libavfilter/f_reverse.c
index f7a7e716fa..2776c83b8d 100644
--- a/libavfilter/f_reverse.c
+++ b/libavfilter/f_reverse.c
@@ -148,7 +148,7 @@  const AVFilter ff_vf_reverse = {
 
 static void reverse_samples_planar(AVFrame *out)
 {
-    for (int p = 0; p < out->channels; p++) {
+    for (int p = 0; p < out->ch_layout.nb_channels; p++) {
         switch (out->format) {
         case AV_SAMPLE_FMT_U8P: {
             uint8_t *dst = (uint8_t *)out->extended_data[p];
@@ -192,7 +192,7 @@  static void reverse_samples_planar(AVFrame *out)
 
 static void reverse_samples_packed(AVFrame *out)
 {
-    const int channels = out->channels;
+    const int channels = out->ch_layout.nb_channels;
 
     switch (out->format) {
     case AV_SAMPLE_FMT_U8: {
diff --git a/libavfilter/f_streamselect.c b/libavfilter/f_streamselect.c
index 3708d2b256..1328a842f9 100644
--- a/libavfilter/f_streamselect.c
+++ b/libavfilter/f_streamselect.c
@@ -118,8 +118,12 @@  static int config_output(AVFilterLink *outlink)
         break;
     case AVMEDIA_TYPE_AUDIO:
         outlink->sample_rate    = inlink->sample_rate;
-        outlink->channels       = inlink->channels;
+        outlink->ch_layout.nb_channels       = inlink->ch_layout.nb_channels;
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
         outlink->channel_layout = inlink->channel_layout;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
         break;
     }
 
diff --git a/libavfilter/formats.c b/libavfilter/formats.c
index ba62f73248..5f3e204418 100644
--- a/libavfilter/formats.c
+++ b/libavfilter/formats.c
@@ -28,8 +28,6 @@ 
 #include "internal.h"
 #include "formats.h"
 
-#define KNOWN(l) (!FF_LAYOUT2COUNT(l)) /* for readability */
-
 /**
  * Add all refs from a to ret and destroy a.
  */
@@ -215,7 +213,7 @@  static int merge_channel_layouts(void *va, void *vb)
 {
     AVFilterChannelLayouts *a = va;
     AVFilterChannelLayouts *b = vb;
-    uint64_t *channel_layouts;
+    AVChannelLayout *channel_layouts;
     unsigned a_all = a->all_layouts + a->all_counts;
     unsigned b_all = b->all_layouts + b->all_counts;
     int ret_max, ret_nb = 0, i, j, round;
@@ -233,8 +231,8 @@  static int merge_channel_layouts(void *va, void *vb)
         if (a_all == 1 && !b_all) {
             /* keep only known layouts in b; works also for b_all = 1 */
             for (i = j = 0; i < b->nb_channel_layouts; i++)
-                if (KNOWN(b->channel_layouts[i]))
-                    b->channel_layouts[j++] = b->channel_layouts[i];
+                if (KNOWN(&b->channel_layouts[i]) && i != j++)
+                    av_channel_layout_copy(&b->channel_layouts[j], &b->channel_layouts[i]);
             /* Not optimal: the unknown layouts of b may become known after
                another merge. */
             if (!j)
@@ -246,17 +244,18 @@  static int merge_channel_layouts(void *va, void *vb)
     }
 
     ret_max = a->nb_channel_layouts + b->nb_channel_layouts;
-    if (!(channel_layouts = av_malloc_array(ret_max, sizeof(*channel_layouts))))
+    if (!(channel_layouts = av_mallocz_array(ret_max, sizeof(*channel_layouts))))
         return AVERROR(ENOMEM);
 
     /* a[known] intersect b[known] */
     for (i = 0; i < a->nb_channel_layouts; i++) {
-        if (!KNOWN(a->channel_layouts[i]))
+        if (!KNOWN(&a->channel_layouts[i]))
             continue;
         for (j = 0; j < b->nb_channel_layouts; j++) {
-            if (a->channel_layouts[i] == b->channel_layouts[j]) {
-                channel_layouts[ret_nb++] = a->channel_layouts[i];
-                a->channel_layouts[i] = b->channel_layouts[j] = 0;
+            if (!av_channel_layout_compare(&a->channel_layouts[i], &b->channel_layouts[j])) {
+                av_channel_layout_copy(&channel_layouts[ret_nb++], &a->channel_layouts[i]);
+                av_channel_layout_uninit(&a->channel_layouts[i]);
+                av_channel_layout_uninit(&b->channel_layouts[j]);
                 break;
             }
         }
@@ -265,24 +264,24 @@  static int merge_channel_layouts(void *va, void *vb)
        2nd round: a[generic] intersect b[known] */
     for (round = 0; round < 2; round++) {
         for (i = 0; i < a->nb_channel_layouts; i++) {
-            uint64_t fmt = a->channel_layouts[i], bfmt;
-            if (!fmt || !KNOWN(fmt))
+            AVChannelLayout *fmt = &a->channel_layouts[i], bfmt = { 0 };
+            if (!av_channel_layout_check(fmt) || !KNOWN(fmt))
                 continue;
-            bfmt = FF_COUNT2LAYOUT(av_get_channel_layout_nb_channels(fmt));
+            bfmt = FF_COUNT2LAYOUT(fmt->nb_channels);
             for (j = 0; j < b->nb_channel_layouts; j++)
-                if (b->channel_layouts[j] == bfmt)
-                    channel_layouts[ret_nb++] = a->channel_layouts[i];
+                if (!av_channel_layout_compare(&b->channel_layouts[j], &bfmt))
+                    av_channel_layout_copy(&channel_layouts[ret_nb++], fmt);
         }
         /* 1st round: swap to prepare 2nd round; 2nd round: put it back */
         FFSWAP(AVFilterChannelLayouts *, a, b);
     }
     /* a[generic] intersect b[generic] */
     for (i = 0; i < a->nb_channel_layouts; i++) {
-        if (KNOWN(a->channel_layouts[i]))
+        if (KNOWN(&a->channel_layouts[i]))
             continue;
         for (j = 0; j < b->nb_channel_layouts; j++)
-            if (a->channel_layouts[i] == b->channel_layouts[j])
-                channel_layouts[ret_nb++] = a->channel_layouts[i];
+            if (!av_channel_layout_compare(&a->channel_layouts[i], &b->channel_layouts[j]))
+                av_channel_layout_copy(&channel_layouts[ret_nb++], &a->channel_layouts[i]);
     }
 
     if (!ret_nb) {
@@ -388,15 +387,40 @@  AVFilterFormats *ff_make_format_list(const int *fmts)
     return formats;
 }
 
-AVFilterChannelLayouts *ff_make_format64_list(const int64_t *fmts)
+AVFilterChannelLayouts *ff_make_format64_list(const AVChannelLayout *fmts)
 {
-    MAKE_FORMAT_LIST(AVFilterChannelLayouts,
-                     channel_layouts, nb_channel_layouts);
-    if (count)
-        memcpy(formats->channel_layouts, fmts,
-               sizeof(*formats->channel_layouts) * count);
+    AVFilterChannelLayouts *ch_layouts;
+    int count = 0;
+    if (fmts)
+        for (count = 0; fmts[count].nb_channels; count++)
+            ;
+    ch_layouts = av_mallocz(sizeof(*ch_layouts));
+    if (!ch_layouts)
+        return NULL;
+    ch_layouts->nb_channel_layouts = count;
+    if (count) {
+        ch_layouts->channel_layouts =
+            av_mallocz_array(count, sizeof(*ch_layouts->channel_layouts));
+        if (!ch_layouts->channel_layouts) {
+            av_freep(&ch_layouts);
+            return NULL;
+        }
+        for (int i = 0; i < count; i++) {
+            int ret = av_channel_layout_copy(&ch_layouts->channel_layouts[i], &fmts[i]);
+            if (ret < 0)
+                goto fail;
+        }
+    }
 
-    return formats;
+    return ch_layouts;
+
+fail:
+    for (int i = 0; i < count; i++)
+        av_channel_layout_uninit(&ch_layouts->channel_layouts[i]);
+    av_free(ch_layouts->channel_layouts);
+    av_freep(&ch_layouts);
+
+    return NULL;
 }
 
 #define ADD_FORMAT(f, fmt, unref_fn, type, list, nb)        \
@@ -415,6 +439,11 @@  do {                                                        \
     }                                                       \
                                                             \
     (*f)->list = fmts;                                      \
+    ASSIGN_FMT(f, fmt, list, nb);                           \
+} while (0)
+
+#define ASSIGN_FMT(f, fmt, list, nb)                        \
+do {                                                        \
     (*f)->list[(*f)->nb++] = fmt;                           \
 } while (0)
 
@@ -424,10 +453,21 @@  int ff_add_format(AVFilterFormats **avff, int64_t fmt)
     return 0;
 }
 
-int ff_add_channel_layout(AVFilterChannelLayouts **l, uint64_t channel_layout)
+#undef ASSIGN_FMT
+#define ASSIGN_FMT(f, fmt, list, nb)                              \
+do {                                                              \
+    int ret;                                                      \
+    memset((*f)->list + (*f)->nb, 0, sizeof(*(*f)->list));        \
+    ret = av_channel_layout_copy(&(*f)->list[(*f)->nb], fmt);     \
+    if (ret < 0)                                                  \
+        return ret;                                               \
+    (*f)->nb++;                                                   \
+} while (0)
+
+int ff_add_channel_layout(AVFilterChannelLayouts **l, AVChannelLayout *channel_layout)
 {
     av_assert1(!(*l && (*l)->all_layouts));
-    ADD_FORMAT(l, channel_layout, ff_channel_layouts_unref, uint64_t, channel_layouts, nb_channel_layouts);
+    ADD_FORMAT(l, channel_layout, ff_channel_layouts_unref, AVChannelLayout, channel_layouts, nb_channel_layouts);
     return 0;
 }
 
@@ -583,6 +623,7 @@  do {                                                               \
         --(*ref)->refcount;                                        \
     }                                                              \
     if (!(*ref)->refcount) {                                       \
+        FREE_LIST(ref, list);                                      \
         av_free((*ref)->list);                                     \
         av_free((*ref)->refs);                                     \
         av_free(*ref);                                             \
@@ -590,11 +631,19 @@  do {                                                               \
     *ref = NULL;                                                   \
 } while (0)
 
+#define FREE_LIST(ref, list) do { } while(0)
 void ff_formats_unref(AVFilterFormats **ref)
 {
     FORMATS_UNREF(ref, formats);
 }
 
+#undef FREE_LIST
+#define FREE_LIST(ref, list)                                       \
+    do {                                                           \
+        for (int i = 0; i < (*ref)->nb_channel_layouts; i++)       \
+            av_channel_layout_uninit(&(*ref)->list[i]);            \
+    } while(0)
+
 void ff_channel_layouts_unref(AVFilterChannelLayouts **ref)
 {
     FORMATS_UNREF(ref, channel_layouts);
@@ -664,7 +713,7 @@  int ff_set_common_channel_layouts(AVFilterContext *ctx,
 }
 
 int ff_set_common_channel_layouts_from_list(AVFilterContext *ctx,
-                                            const int64_t *fmts)
+                                            const AVChannelLayout *fmts)
 {
     return ff_set_common_channel_layouts(ctx, ff_make_format64_list(fmts));
 }
@@ -787,23 +836,41 @@  int ff_parse_sample_rate(int *ret, const char *arg, void *log_ctx)
     return 0;
 }
 
-int ff_parse_channel_layout(int64_t *ret, int *nret, const char *arg,
+int ff_parse_channel_layout(AVChannelLayout *ret, int *nret, const char *arg,
                             void *log_ctx)
 {
-    int64_t chlayout;
-    int nb_channels;
-
-    if (av_get_extended_channel_layout(arg, &chlayout, &nb_channels) < 0) {
-        av_log(log_ctx, AV_LOG_ERROR, "Invalid channel layout '%s'\n", arg);
-        return AVERROR(EINVAL);
+    AVChannelLayout chlayout = { 0 };
+    int res;
+
+    res = av_channel_layout_from_string(&chlayout, arg);
+    if (res < 0) {
+#if FF_API_OLD_CHANNEL_LAYOUT
+        int64_t mask;
+        int nb_channels;
+FF_DISABLE_DEPRECATION_WARNINGS
+        if (av_get_extended_channel_layout(arg, &mask, &nb_channels) < 0) {
+#endif
+            av_log(log_ctx, AV_LOG_ERROR, "Invalid channel layout '%s'\n", arg);
+            return AVERROR(EINVAL);
+#if FF_API_OLD_CHANNEL_LAYOUT
+        }
+FF_ENABLE_DEPRECATION_WARNINGS
+        av_log(log_ctx, AV_LOG_WARNING, "Channel layout '%s' uses a deprecated syntax.\n",
+               arg);
+        if (mask)
+            av_channel_layout_from_mask(&chlayout, mask);
+        else
+            chlayout = (AVChannelLayout) { .order = AV_CHANNEL_ORDER_UNSPEC, .nb_channels = nb_channels };
+#endif
     }
-    if (!chlayout && !nret) {
+
+    if (chlayout.order == AV_CHANNEL_ORDER_UNSPEC && !nret) {
         av_log(log_ctx, AV_LOG_ERROR, "Unknown channel layout '%s' is not supported.\n", arg);
         return AVERROR(EINVAL);
     }
     *ret = chlayout;
     if (nret)
-        *nret = nb_channels;
+        *nret = chlayout.nb_channels;
 
     return 0;
 }
@@ -846,11 +913,11 @@  int ff_formats_check_sample_rates(void *log, const AVFilterFormats *fmts)
     return check_list(log, "sample rate", fmts);
 }
 
-static int layouts_compatible(uint64_t a, uint64_t b)
+static int layouts_compatible(const AVChannelLayout *a, const AVChannelLayout *b)
 {
-    return a == b ||
-           (KNOWN(a) && !KNOWN(b) && av_get_channel_layout_nb_channels(a) == FF_LAYOUT2COUNT(b)) ||
-           (KNOWN(b) && !KNOWN(a) && av_get_channel_layout_nb_channels(b) == FF_LAYOUT2COUNT(a));
+    return !av_channel_layout_compare(a, b) ||
+           (KNOWN(a) && !KNOWN(b) && a->nb_channels == b->nb_channels) ||
+           (KNOWN(b) && !KNOWN(a) && b->nb_channels == a->nb_channels);
 }
 
 int ff_formats_check_channel_layouts(void *log, const AVFilterChannelLayouts *fmts)
@@ -869,7 +936,7 @@  int ff_formats_check_channel_layouts(void *log, const AVFilterChannelLayouts *fm
     }
     for (i = 0; i < fmts->nb_channel_layouts; i++) {
         for (j = i + 1; j < fmts->nb_channel_layouts; j++) {
-            if (layouts_compatible(fmts->channel_layouts[i], fmts->channel_layouts[j])) {
+            if (layouts_compatible(&fmts->channel_layouts[i], &fmts->channel_layouts[j])) {
                 av_log(log, AV_LOG_ERROR, "Duplicated or redundant channel layout\n");
                 return AVERROR(EINVAL);
             }
diff --git a/libavfilter/formats.h b/libavfilter/formats.h
index a884d15213..e55180f45c 100644
--- a/libavfilter/formats.h
+++ b/libavfilter/formats.h
@@ -83,7 +83,7 @@  struct AVFilterFormats {
  *   (e.g. AV_CH_LAYOUT_STEREO and FF_COUNT2LAYOUT(2).
  */
 struct AVFilterChannelLayouts {
-    uint64_t *channel_layouts;  ///< list of channel layouts
+    AVChannelLayout *channel_layouts; ///< list of channel layouts
     int    nb_channel_layouts;  ///< number of channel layouts
     char all_layouts;           ///< accept any known channel layout
     char all_counts;            ///< accept any channel layout or count
@@ -99,14 +99,16 @@  struct AVFilterChannelLayouts {
  * The result is only valid inside AVFilterChannelLayouts and immediately
  * related functions.
  */
-#define FF_COUNT2LAYOUT(c) (0x8000000000000000ULL | (c))
+#define FF_COUNT2LAYOUT(c) ((AVChannelLayout) { .order = AV_CHANNEL_ORDER_UNSPEC, .nb_channels = c })
 
 /**
  * Decode a channel count encoded as a channel layout.
  * Return 0 if the channel layout was a real one.
  */
-#define FF_LAYOUT2COUNT(l) (((l) & 0x8000000000000000ULL) ? \
-                           (int)((l) & 0x7FFFFFFF) : 0)
+#define FF_LAYOUT2COUNT(l) (((l)->order == AV_CHANNEL_ORDER_UNSPEC) ? \
+                            (l)->nb_channels : 0)
+
+#define KNOWN(l) (!FF_LAYOUT2COUNT(l)) /* for readability */
 
 /**
  * Construct an empty AVFilterChannelLayouts/AVFilterFormats struct --
@@ -126,7 +128,7 @@  av_warn_unused_result
 AVFilterChannelLayouts *ff_all_channel_counts(void);
 
 av_warn_unused_result
-AVFilterChannelLayouts *ff_make_format64_list(const int64_t *fmts);
+AVFilterChannelLayouts *ff_make_format64_list(const AVChannelLayout *fmts);
 
 /**
  * Helpers for query_formats() which set all free audio links to the same list
@@ -141,7 +143,7 @@  int ff_set_common_channel_layouts(AVFilterContext *ctx,
  */
 av_warn_unused_result
 int ff_set_common_channel_layouts_from_list(AVFilterContext *ctx,
-                                            const int64_t *fmts);
+                                            const AVChannelLayout *fmts);
 /**
  * Equivalent to ff_set_common_channel_layouts(ctx, ff_all_channel_counts())
  */
@@ -178,7 +180,7 @@  av_warn_unused_result
 int ff_set_common_formats_from_list(AVFilterContext *ctx, const int *fmts);
 
 av_warn_unused_result
-int ff_add_channel_layout(AVFilterChannelLayouts **l, uint64_t channel_layout);
+int ff_add_channel_layout(AVFilterChannelLayouts **l, AVChannelLayout *channel_layout);
 
 /**
  * Add *ref as a new reference to f.
diff --git a/libavfilter/framepool.c b/libavfilter/framepool.c
index 7c63807df3..0ef41b9404 100644
--- a/libavfilter/framepool.c
+++ b/libavfilter/framepool.c
@@ -238,7 +238,12 @@  AVFrame *ff_frame_pool_get(FFFramePool *pool)
         break;
     case AVMEDIA_TYPE_AUDIO:
         frame->nb_samples = pool->nb_samples;
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
         frame->channels = pool->channels;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+        frame->ch_layout.nb_channels = pool->channels;
         frame->format = pool->format;
         frame->linesize[0] = pool->linesize[0];
 
diff --git a/libavfilter/framequeue.c b/libavfilter/framequeue.c
index fed1118975..383c195b85 100644
--- a/libavfilter/framequeue.c
+++ b/libavfilter/framequeue.c
@@ -134,10 +134,10 @@  void ff_framequeue_skip_samples(FFFrameQueue *fq, size_t samples, AVRational tim
     b = bucket(fq, 0);
     av_assert1(samples < b->frame->nb_samples);
     planar = av_sample_fmt_is_planar(b->frame->format);
-    planes = planar ? b->frame->channels : 1;
+    planes = planar ? b->frame->ch_layout.nb_channels : 1;
     bytes = samples * av_get_bytes_per_sample(b->frame->format);
     if (!planar)
-        bytes *= b->frame->channels;
+        bytes *= b->frame->ch_layout.nb_channels;
     if (b->frame->pts != AV_NOPTS_VALUE)
         b->frame->pts += av_rescale_q(samples, av_make_q(1, b->frame->sample_rate), time_base);
     b->frame->nb_samples -= samples;
diff --git a/libavfilter/graphdump.c b/libavfilter/graphdump.c
index cf8914b558..80f7bf6c98 100644
--- a/libavfilter/graphdump.c
+++ b/libavfilter/graphdump.c
@@ -30,6 +30,7 @@ 
 static int print_link_prop(AVBPrint *buf, AVFilterLink *link)
 {
     const char *format;
+    char layout[128];
     AVBPrint dummy_buffer;
 
     if (!buf) {
@@ -49,7 +50,8 @@  static int print_link_prop(AVBPrint *buf, AVFilterLink *link)
             format = av_x_if_null(av_get_sample_fmt_name(link->format), "?");
             av_bprintf(buf, "[%dHz %s:",
                        (int)link->sample_rate, format);
-            av_bprint_channel_layout(buf, link->channels, link->channel_layout);
+            av_channel_layout_describe(&link->ch_layout, layout, sizeof(layout));
+            av_bprintf(buf, "%s", layout);
             av_bprint_chars(buf, ']', 1);
             break;
 
diff --git a/libavfilter/internal.h b/libavfilter/internal.h
index 1099b82b4b..3eecaca3fb 100644
--- a/libavfilter/internal.h
+++ b/libavfilter/internal.h
@@ -237,7 +237,7 @@  int ff_parse_sample_rate(int *ret, const char *arg, void *log_ctx);
  * @return >= 0 in case of success, a negative AVERROR code on error
  */
 av_warn_unused_result
-int ff_parse_channel_layout(int64_t *ret, int *nret, const char *arg,
+int ff_parse_channel_layout(AVChannelLayout *ret, int *nret, const char *arg,
                             void *log_ctx);
 
 void ff_update_link_current_pts(AVFilterLink *link, int64_t pts);
diff --git a/libavfilter/src_movie.c b/libavfilter/src_movie.c
index b89a680883..3ebd279df7 100644
--- a/libavfilter/src_movie.c
+++ b/libavfilter/src_movie.c
@@ -189,23 +189,24 @@  static int guess_channel_layout(MovieStream *st, int st_index, void *log_ctx)
 {
     AVCodecParameters *dec_par = st->st->codecpar;
     char buf[256];
-    int64_t chl = av_get_default_channel_layout(dec_par->channels);
+    AVChannelLayout chl = { 0 };
 
-    if (!chl) {
+    av_channel_layout_default(&chl, dec_par->ch_layout.nb_channels);
+
+    if (!KNOWN(&chl)) {
         av_log(log_ctx, AV_LOG_ERROR,
                "Channel layout is not set in stream %d, and could not "
                "be guessed from the number of channels (%d)\n",
-               st_index, dec_par->channels);
+               st_index, dec_par->ch_layout.nb_channels);
         return AVERROR(EINVAL);
     }
 
-    av_get_channel_layout_string(buf, sizeof(buf), dec_par->channels, chl);
+    av_channel_layout_describe(&chl, buf, sizeof(buf));
     av_log(log_ctx, AV_LOG_WARNING,
            "Channel layout is not set in output stream %d, "
            "guessed channel layout is '%s'\n",
            st_index, buf);
-    dec_par->channel_layout = chl;
-    return 0;
+    return av_channel_layout_copy(&dec_par->ch_layout, &chl);
 }
 
 static av_cold int movie_common_init(AVFilterContext *ctx)
@@ -315,7 +316,7 @@  static av_cold int movie_common_init(AVFilterContext *ctx)
         if ((ret = ff_append_outpad_free_name(ctx, &pad)) < 0)
             return ret;
         if ( movie->st[i].st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
-            !movie->st[i].st->codecpar->channel_layout) {
+            !KNOWN(&movie->st[i].st->codecpar->ch_layout)) {
             ret = guess_channel_layout(&movie->st[i], i, ctx);
             if (ret < 0)
                 return ret;
@@ -351,7 +352,7 @@  static int movie_query_formats(AVFilterContext *ctx)
 {
     MovieContext *movie = ctx->priv;
     int list[] = { 0, -1 };
-    int64_t list64[] = { 0, -1 };
+    AVChannelLayout list64[] = { { 0 }, { 0 } };
     int i, ret;
 
     for (i = 0; i < ctx->nb_outputs; i++) {
@@ -372,7 +373,7 @@  static int movie_query_formats(AVFilterContext *ctx)
             list[0] = c->sample_rate;
             if ((ret = ff_formats_ref(ff_make_format_list(list), &outlink->incfg.samplerates)) < 0)
                 return ret;
-            list64[0] = c->channel_layout;
+            list64[0] = c->ch_layout;
             if ((ret = ff_channel_layouts_ref(ff_make_format64_list(list64),
                                    &outlink->incfg.channel_layouts)) < 0)
                 return ret;
diff --git a/libavfilter/tests/filtfmts.c b/libavfilter/tests/filtfmts.c
index d793480344..909c1e8dc9 100644
--- a/libavfilter/tests/filtfmts.c
+++ b/libavfilter/tests/filtfmts.c
@@ -59,8 +59,7 @@  static void print_formats_internal(AVFilterLink **links, const AVFilterPad *pads
 
             for (unsigned j = 0; layouts && j < layouts->nb_channel_layouts; j++) {
                 char buf[256];
-                av_get_channel_layout_string(buf, sizeof(buf), -1,
-                                             layouts->channel_layouts[j]);
+                av_channel_layout_describe(&layouts->channel_layouts[j], buf, sizeof(buf));
                 printf("%s[%u] %s: chlayout:%s\n",
                        inout_string, i, pad_name, buf);
             }
diff --git a/libavfilter/tests/formats.c b/libavfilter/tests/formats.c
index c1e30e73ee..a02f2b49b5 100644
--- a/libavfilter/tests/formats.c
+++ b/libavfilter/tests/formats.c
@@ -129,12 +129,12 @@  int main(void)
     }
 
     for ( i = 0; i<FF_ARRAY_ELEMS(teststrings); i++) {
-        int64_t layout = -1;
+        AVChannelLayout layout = { 0 };
         int count = -1;
         int ret;
         ret = ff_parse_channel_layout(&layout, &count, teststrings[i], NULL);
 
-        printf ("%d = ff_parse_channel_layout(%016"PRIX64", %2d, %s);\n", ret ? -1 : 0, layout, count, teststrings[i]);
+        printf ("%d = ff_parse_channel_layout(%016"PRIX64", %2d, %s);\n", ret ? -1 : 0, layout.order == AV_CHANNEL_ORDER_NATIVE ? layout.u.mask : 0, count, teststrings[i]);
     }
 
     return 0;
diff --git a/libavfilter/trim.c b/libavfilter/trim.c
index e627903c64..59adc54a92 100644
--- a/libavfilter/trim.c
+++ b/libavfilter/trim.c
@@ -309,7 +309,7 @@  static int atrim_filter_frame(AVFilterLink *inlink, AVFrame *frame)
 
         av_frame_copy_props(out, frame);
         av_samples_copy(out->extended_data, frame->extended_data, 0, start_sample,
-                        out->nb_samples, inlink->channels,
+                        out->nb_samples, inlink->ch_layout.nb_channels,
                         frame->format);
         if (out->pts != AV_NOPTS_VALUE)
             out->pts += av_rescale_q(start_sample, (AVRational){ 1, out->sample_rate },
diff --git a/libavfilter/vaf_spectrumsynth.c b/libavfilter/vaf_spectrumsynth.c
index 674e9953b2..e0baf855a8 100644
--- a/libavfilter/vaf_spectrumsynth.c
+++ b/libavfilter/vaf_spectrumsynth.c
@@ -112,7 +112,7 @@  static int query_formats(AVFilterContext *ctx)
 
     formats = ff_make_format_list(sample_fmts);
     if ((ret = ff_formats_ref         (formats, &outlink->incfg.formats        )) < 0 ||
-        (ret = ff_add_channel_layout  (&layout, FF_COUNT2LAYOUT(s->channels))) < 0 ||
+        (ret = ff_add_channel_layout  (&layout, &FF_COUNT2LAYOUT(s->channels))) < 0 ||
         (ret = ff_channel_layouts_ref (layout , &outlink->incfg.channel_layouts)) < 0)
         return ret;
 
diff --git a/tests/ref/fate/filter-formats b/tests/ref/fate/filter-formats
index 17ff5b222f..c179b38ff0 100644
--- a/tests/ref/fate/filter-formats
+++ b/tests/ref/fate/filter-formats
@@ -66,20 +66,20 @@  quad(side)
 7 channels (FL+FR+BC+SL+SR+DL+DR)
 8 channels (FL+FR+LFE+BC+SL+SR+DL+DR)
 8 channels (FL+FR+FC+BC+SL+SR+DL+DR)
--1 = ff_parse_channel_layout(FFFFFFFFFFFFFFFF, -1, blah);
-0 = ff_parse_channel_layout(0000000000000001,  1, 1);
-0 = ff_parse_channel_layout(0000000000000002,  1, 2);
--1 = ff_parse_channel_layout(FFFFFFFFFFFFFFFF, -1, -1);
-0 = ff_parse_channel_layout(000000000000003C,  4, 60);
-0 = ff_parse_channel_layout(0000000000000041,  2, 65);
+-1 = ff_parse_channel_layout(0000000000000000, -1, blah);
+0 = ff_parse_channel_layout(0000000000000000,  1, 1);
+0 = ff_parse_channel_layout(0000000000000000,  2, 2);
+-1 = ff_parse_channel_layout(0000000000000000, -1, -1);
+0 = ff_parse_channel_layout(0000000000000000, 60, 60);
+0 = ff_parse_channel_layout(0000000000000000, 65, 65);
 0 = ff_parse_channel_layout(0000000000000004,  1, 1c);
 0 = ff_parse_channel_layout(0000000000000003,  2, 2c);
--1 = ff_parse_channel_layout(FFFFFFFFFFFFFFFF, -1, -1c);
--1 = ff_parse_channel_layout(FFFFFFFFFFFFFFFF, -1, 60c);
--1 = ff_parse_channel_layout(FFFFFFFFFFFFFFFF, -1, 65c);
+-1 = ff_parse_channel_layout(0000000000000000, -1, -1c);
+0 = ff_parse_channel_layout(0000000000000000, 60, 60c);
+0 = ff_parse_channel_layout(0000000000000000, 65, 65c);
 0 = ff_parse_channel_layout(0000000000000000,  2, 2C);
 0 = ff_parse_channel_layout(0000000000000000, 60, 60C);
--1 = ff_parse_channel_layout(FFFFFFFFFFFFFFFF, -1, 65C);
+0 = ff_parse_channel_layout(0000000000000000, 65, 65C);
 0 = ff_parse_channel_layout(000000000000003F,  6, 5.1);
 0 = ff_parse_channel_layout(0000000000000003,  2, stereo);
 0 = ff_parse_channel_layout(0000000000000001,  1, 1+1+1+1);