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

James Almer jamrial at gmail.com
Thu Jan 13 04:09:07 EET 2022


Signed-off-by: James Almer <jamrial at 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(-)

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);
-- 
2.34.1



More information about the ffmpeg-devel mailing list