diff --git a/libavcodec/opus.c b/libavcodec/opus.c
index df8ba93fa9..c18ff47f71 100644
--- a/libavcodec/opus.c
+++ b/libavcodec/opus.c
@@ -296,14 +296,15 @@ av_cold int ff_opus_parse_extradata(AVCodecContext *avctx,
     static const uint8_t default_channel_map[2] = { 0, 1 };
 
     int (*channel_reorder)(int, int) = channel_reorder_unknown;
+    int channels = avctx->ch_layout.nb_channels;
 
     const uint8_t *extradata, *channel_map;
     int extradata_size;
-    int version, channels, map_type, streams, stereo_streams, i, j;
-    uint64_t layout;
+    int version, map_type, streams, stereo_streams, i, j, ret;
+    AVChannelLayout layout = { 0 };
 
     if (!avctx->extradata) {
-        if (avctx->channels > 2) {
+        if (channels > 2) {
             av_log(avctx, AV_LOG_ERROR,
                    "Multichannel configuration without extradata.\n");
             return AVERROR(EINVAL);
@@ -331,7 +332,7 @@ av_cold int ff_opus_parse_extradata(AVCodecContext *avctx,
     if (avctx->internal)
         avctx->internal->skip_samples = avctx->delay;
 
-    channels = avctx->extradata ? extradata[9] : (avctx->channels == 1) ? 1 : 2;
+    channels = avctx->extradata ? extradata[9] : (channels == 1) ? 1 : 2;
     if (!channels) {
         av_log(avctx, AV_LOG_ERROR, "Zero channel count specified in the extradata\n");
         return AVERROR_INVALIDDATA;
@@ -346,9 +347,11 @@ av_cold int ff_opus_parse_extradata(AVCodecContext *avctx,
         if (channels > 2) {
             av_log(avctx, AV_LOG_ERROR,
                    "Channel mapping 0 is only specified for up to 2 channels\n");
-            return AVERROR_INVALIDDATA;
+            ret = AVERROR_INVALIDDATA;
+            goto fail;
         }
-        layout         = (channels == 1) ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO;
+        layout         = (channels == 1) ? (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO :
+                                           (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO;
         streams        = 1;
         stereo_streams = channels - 1;
         channel_map    = default_channel_map;
@@ -356,7 +359,8 @@ av_cold int ff_opus_parse_extradata(AVCodecContext *avctx,
         if (extradata_size < 21 + channels) {
             av_log(avctx, AV_LOG_ERROR, "Invalid extradata size: %d\n",
                    extradata_size);
-            return AVERROR_INVALIDDATA;
+            ret = AVERROR_INVALIDDATA;
+            goto fail;
         }
 
         streams        = extradata[19];
@@ -365,16 +369,18 @@ av_cold int ff_opus_parse_extradata(AVCodecContext *avctx,
             streams + stereo_streams > 255) {
             av_log(avctx, AV_LOG_ERROR,
                    "Invalid stream/stereo stream count: %d/%d\n", streams, stereo_streams);
-            return AVERROR_INVALIDDATA;
+            ret = AVERROR_INVALIDDATA;
+            goto fail;
         }
 
         if (map_type == 1) {
             if (channels > 8) {
                 av_log(avctx, AV_LOG_ERROR,
                        "Channel mapping 1 is only specified for up to 8 channels\n");
-                return AVERROR_INVALIDDATA;
+                ret = AVERROR_INVALIDDATA;
+                goto fail;
             }
-            layout = ff_vorbis_channel_layouts[channels - 1];
+            av_channel_layout_copy(&layout, &ff_vorbis_ch_layouts[channels - 1]);
             channel_reorder = channel_reorder_vorbis;
         } else if (map_type == 2) {
             int ambisonic_order = ff_sqrt(channels) - 1;
@@ -384,15 +390,20 @@ av_cold int ff_opus_parse_extradata(AVCodecContext *avctx,
                        "Channel mapping 2 is only specified for channel counts"
                        " which can be written as (n + 1)^2 or (n + 1)^2 + 2"
                        " for nonnegative integer n\n");
-                return AVERROR_INVALIDDATA;
+                ret = AVERROR_INVALIDDATA;
+                goto fail;
             }
             if (channels > 227) {
                 av_log(avctx, AV_LOG_ERROR, "Too many channels\n");
-                return AVERROR_INVALIDDATA;
+                ret = AVERROR_INVALIDDATA;
+                goto fail;
             }
-            layout = 0;
-        } else
-            layout = 0;
+            layout.order       = AV_CHANNEL_ORDER_UNSPEC;
+            layout.nb_channels = channels;
+        } else {
+            layout.order       = AV_CHANNEL_ORDER_UNSPEC;
+            layout.nb_channels = channels;
+        }
 
         channel_map = extradata + 21;
     } else {
@@ -401,8 +412,10 @@ av_cold int ff_opus_parse_extradata(AVCodecContext *avctx,
     }
 
     s->channel_maps = av_calloc(channels, sizeof(*s->channel_maps));
-    if (!s->channel_maps)
-        return AVERROR(ENOMEM);
+    if (!s->channel_maps) {
+        ret = AVERROR(ENOMEM);
+        goto fail;
+    }
 
     for (i = 0; i < channels; i++) {
         ChannelMap *map = &s->channel_maps[i];
@@ -415,7 +428,8 @@ av_cold int ff_opus_parse_extradata(AVCodecContext *avctx,
             av_log(avctx, AV_LOG_ERROR,
                    "Invalid channel map for output channel %d: %d\n", i, idx);
             av_freep(&s->channel_maps);
-            return AVERROR_INVALIDDATA;
+            ret = AVERROR_INVALIDDATA;
+            goto fail;
         }
 
         /* check that we did not see this index yet */
@@ -436,12 +450,15 @@ av_cold int ff_opus_parse_extradata(AVCodecContext *avctx,
         }
     }
 
-    avctx->channels       = channels;
-    avctx->channel_layout = layout;
+    av_channel_layout_uninit(&avctx->ch_layout);
+    avctx->ch_layout = layout;
     s->nb_streams         = streams;
     s->nb_stereo_streams  = stereo_streams;
 
     return 0;
+fail:
+    av_channel_layout_uninit(&layout);
+    return ret;
 }
 
 void ff_celt_quant_bands(CeltFrame *f, OpusRangeCoder *rc)
diff --git a/libavcodec/opusdec.c b/libavcodec/opusdec.c
index b063e0efeb..2133a4c63b 100644
--- a/libavcodec/opusdec.c
+++ b/libavcodec/opusdec.c
@@ -458,7 +458,7 @@ static int opus_decode_packet(AVCodecContext *avctx, void *data,
         return ret;
     frame->nb_samples = 0;
 
-    for (i = 0; i < avctx->channels; i++) {
+    for (i = 0; i < avctx->ch_layout.nb_channels; i++) {
         ChannelMap *map = &c->channel_maps[i];
         if (!map->copy)
             c->streams[map->stream_idx].out[map->channel_idx] = (float*)frame->extended_data[i];
@@ -541,7 +541,7 @@ static int opus_decode_packet(AVCodecContext *avctx, void *data,
         }
     }
 
-    for (i = 0; i < avctx->channels; i++) {
+    for (i = 0; i < avctx->ch_layout.nb_channels; i++) {
         ChannelMap *map = &c->channel_maps[i];
 
         /* handle copied channels */
diff --git a/libavcodec/opusenc.c b/libavcodec/opusenc.c
index b7f4760a25..a36f59bf23 100644
--- a/libavcodec/opusenc.c
+++ b/libavcodec/opusenc.c
@@ -66,7 +66,7 @@ static void opus_write_extradata(AVCodecContext *avctx)
 
     bytestream_put_buffer(&bs, "OpusHead", 8);
     bytestream_put_byte  (&bs, 0x1);
-    bytestream_put_byte  (&bs, avctx->channels);
+    bytestream_put_byte  (&bs, avctx->ch_layout.nb_channels);
     bytestream_put_le16  (&bs, avctx->initial_padding);
     bytestream_put_le32  (&bs, avctx->sample_rate);
     bytestream_put_le16  (&bs, 0x0);
@@ -518,11 +518,16 @@ static void opus_packet_assembler(OpusEncContext *s, AVPacket *avpkt)
 static AVFrame *spawn_empty_frame(OpusEncContext *s)
 {
     AVFrame *f = av_frame_alloc();
+    int ret;
     if (!f)
         return NULL;
     f->format         = s->avctx->sample_fmt;
     f->nb_samples     = s->avctx->frame_size;
-    f->channel_layout = s->avctx->channel_layout;
+    ret = av_channel_layout_copy(&f->ch_layout, &s->avctx->ch_layout);
+    if (ret < 0) {
+        av_frame_free(&f);
+        return NULL;
+    }
     if (av_frame_get_buffer(f, 4)) {
         av_frame_free(&f);
         return NULL;
@@ -626,7 +631,7 @@ static av_cold int opus_encode_init(AVCodecContext *avctx)
     OpusEncContext *s = avctx->priv_data;
 
     s->avctx = avctx;
-    s->channels = avctx->channels;
+    s->channels = avctx->ch_layout.nb_channels;
 
     /* Opus allows us to change the framesize on each packet (and each packet may
      * have multiple frames in it) but we can't change the codec's frame size on
@@ -734,8 +739,12 @@ const AVCodec ff_opus_encoder = {
     .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP,
     .capabilities   = AV_CODEC_CAP_EXPERIMENTAL | AV_CODEC_CAP_SMALL_LAST_FRAME | AV_CODEC_CAP_DELAY,
     .supported_samplerates = (const int []){ 48000, 0 },
+#if FF_API_OLD_CHANNEL_LAYOUT
     .channel_layouts = (const uint64_t []){ AV_CH_LAYOUT_MONO,
                                             AV_CH_LAYOUT_STEREO, 0 },
+#endif
+    .ch_layouts      = (const AVChannelLayout []){ AV_CHANNEL_LAYOUT_MONO,
+                                                   AV_CHANNEL_LAYOUT_STEREO, { 0 } },
     .sample_fmts    = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP,
                                                      AV_SAMPLE_FMT_NONE },
 };
diff --git a/libavcodec/opusenc_psy.c b/libavcodec/opusenc_psy.c
index 5a50db942f..1c8f69269c 100644
--- a/libavcodec/opusenc_psy.c
+++ b/libavcodec/opusenc_psy.c
@@ -83,7 +83,7 @@ static void step_collect_psy_metrics(OpusPsyContext *s, int index)
 
     st->index = index;
 
-    for (ch = 0; ch < s->avctx->channels; ch++) {
+    for (ch = 0; ch < s->avctx->ch_layout.nb_channels; ch++) {
         const int lap_size = (1 << s->bsize_analysis);
         for (i = 1; i <= FFMIN(lap_size, index); i++) {
             const int offset = i*120;
@@ -105,7 +105,7 @@ static void step_collect_psy_metrics(OpusPsyContext *s, int index)
             st->bands[ch][i] = &st->coeffs[ch][ff_celt_freq_bands[i] << s->bsize_analysis];
     }
 
-    for (ch = 0; ch < s->avctx->channels; ch++) {
+    for (ch = 0; ch < s->avctx->ch_layout.nb_channels; ch++) {
         for (i = 0; i < CELT_MAX_BANDS; i++) {
             float avg_c_s, energy = 0.0f, dist_dev = 0.0f;
             const int range = ff_celt_freq_range[i] << s->bsize_analysis;
@@ -128,7 +128,7 @@ static void step_collect_psy_metrics(OpusPsyContext *s, int index)
 
     st->silence = !silence;
 
-    if (s->avctx->channels > 1) {
+    if (s->avctx->ch_layout.nb_channels > 1) {
         for (i = 0; i < CELT_MAX_BANDS; i++) {
             float incompat = 0.0f;
             const float *coeffs1 = st->bands[0][i];
@@ -140,7 +140,7 @@ static void step_collect_psy_metrics(OpusPsyContext *s, int index)
         }
     }
 
-    for (ch = 0; ch < s->avctx->channels; ch++) {
+    for (ch = 0; ch < s->avctx->ch_layout.nb_channels; ch++) {
         for (i = 0; i < CELT_MAX_BANDS; i++) {
             OpusBandExcitation *ex = &s->ex[ch][i];
             float bp_e = bessel_filter(&s->bfilter_lo[ch][i], st->energy[ch][i]);
@@ -259,7 +259,7 @@ void ff_opus_psy_celt_frame_init(OpusPsyContext *s, CeltFrame *f, int index)
 
     f->start_band = (s->p.mode == OPUS_MODE_HYBRID) ? 17 : 0;
     f->end_band   = ff_celt_band_end[s->p.bandwidth];
-    f->channels   = s->avctx->channels;
+    f->channels   = s->avctx->ch_layout.nb_channels;
     f->size       = s->p.framesize;
 
     for (i = 0; i < (1 << f->size); i++)
@@ -327,7 +327,7 @@ static void celt_gauge_psy_weight(OpusPsyContext *s, OpusPsyStep **start,
         float tonal_contrib = 0.0f;
         for (f = 0; f < (1 << s->p.framesize); f++) {
             weight = start[f]->stereo[i];
-            for (ch = 0; ch < s->avctx->channels; ch++) {
+            for (ch = 0; ch < s->avctx->ch_layout.nb_channels; ch++) {
                 weight += start[f]->change_amp[ch][i] + start[f]->tone[ch][i] + start[f]->energy[ch][i];
                 tonal_contrib += start[f]->tone[ch][i];
             }
@@ -384,7 +384,7 @@ static void celt_search_for_dual_stereo(OpusPsyContext *s, CeltFrame *f)
     float td1, td2;
     f->dual_stereo = 0;
 
-    if (s->avctx->channels < 2)
+    if (s->avctx->ch_layout.nb_channels < 2)
         return;
 
     bands_dist(s, f, &td1);
@@ -402,7 +402,7 @@ static void celt_search_for_intensity(OpusPsyContext *s, CeltFrame *f)
     /* TODO: fix, make some heuristic up here using the lambda value */
     float end_band = 0;
 
-    if (s->avctx->channels < 2)
+    if (s->avctx->ch_layout.nb_channels < 2)
         return;
 
     for (i = f->end_band; i >= end_band; i--) {
@@ -436,7 +436,7 @@ static int celt_search_for_tf(OpusPsyContext *s, OpusPsyStep **start, CeltFrame
             float iscore0 = 0.0f;
             float iscore1 = 0.0f;
             for (j = 0; j < (1 << f->size); j++) {
-                for (k = 0; k < s->avctx->channels; k++) {
+                for (k = 0; k < s->avctx->ch_layout.nb_channels; k++) {
                     iscore0 += start[j]->tone[k][i]*start[j]->change_amp[k][i]/mag[0];
                     iscore1 += start[j]->tone[k][i]*start[j]->change_amp[k][i]/mag[1];
                 }
@@ -540,7 +540,7 @@ av_cold int ff_opus_psy_init(OpusPsyContext *s, AVCodecContext *avctx,
         goto fail;
     }
 
-    for (ch = 0; ch < s->avctx->channels; ch++) {
+    for (ch = 0; ch < s->avctx->ch_layout.nb_channels; ch++) {
         for (i = 0; i < CELT_MAX_BANDS; i++) {
             bessel_init(&s->bfilter_hi[ch][i], 1.0f, 19.0f, 100.0f, 1);
             bessel_init(&s->bfilter_lo[ch][i], 1.0f, 20.0f, 100.0f, 0);
