diff mbox series

[FFmpeg-devel,273/279] swresample: convert to new channel layout API

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

Commit Message

James Almer Dec. 8, 2021, 1:06 a.m. UTC
Signed-off-by: James Almer <jamrial@gmail.com>
---
 libswresample/options.c             |  33 +++-
 libswresample/rematrix.c            | 227 ++++++++++++++++++----------
 libswresample/rematrix_template.c   |   7 +-
 libswresample/swresample.c          | 158 ++++++++++++++++---
 libswresample/swresample.h          |  63 ++++++++
 libswresample/swresample_frame.c    |  65 +++++++-
 libswresample/swresample_internal.h |  10 +-
 7 files changed, 443 insertions(+), 120 deletions(-)
diff mbox series

Patch

diff --git a/libswresample/options.c b/libswresample/options.c
index 6911709157..ffa27c590d 100644
--- a/libswresample/options.c
+++ b/libswresample/options.c
@@ -34,12 +34,19 @@ 
 
 #define OFFSET(x) offsetof(SwrContext,x)
 #define PARAM AV_OPT_FLAG_AUDIO_PARAM
+#define DEPREC AV_OPT_FLAG_DEPRECATED
 
 static const AVOption options[]={
-{"ich"                  , "set input channel count"     , OFFSET(user_in_ch_count  ), AV_OPT_TYPE_INT, {.i64=0                    }, 0      , SWR_CH_MAX, PARAM},
-{"in_channel_count"     , "set input channel count"     , OFFSET(user_in_ch_count  ), AV_OPT_TYPE_INT, {.i64=0                    }, 0      , SWR_CH_MAX, PARAM},
-{"och"                  , "set output channel count"    , OFFSET(user_out_ch_count ), AV_OPT_TYPE_INT, {.i64=0                    }, 0      , SWR_CH_MAX, PARAM},
-{"out_channel_count"    , "set output channel count"    , OFFSET(user_out_ch_count ), AV_OPT_TYPE_INT, {.i64=0                    }, 0      , SWR_CH_MAX, PARAM},
+#if FF_API_OLD_CHANNEL_LAYOUT
+{"ich"                  , "set input channel count (Deprecated, use ichl)",
+                                                          OFFSET(user_in_ch_count  ), AV_OPT_TYPE_INT, {.i64=0                    }, 0      , SWR_CH_MAX, PARAM|DEPREC},
+{"in_channel_count"     , "set input channel count (Deprecated, use in_chlayout)",
+                                                          OFFSET(user_in_ch_count  ), AV_OPT_TYPE_INT, {.i64=0                    }, 0      , SWR_CH_MAX, PARAM|DEPREC},
+{"och"                  , "set output channel count (Deprecated, use ochl)",
+                                                          OFFSET(user_out_ch_count ), AV_OPT_TYPE_INT, {.i64=0                    }, 0      , SWR_CH_MAX, PARAM|DEPREC},
+{"out_channel_count"    , "set output channel count (Deprecated, use out_chlayout)",
+                                                          OFFSET(user_out_ch_count ), AV_OPT_TYPE_INT, {.i64=0                    }, 0      , SWR_CH_MAX, PARAM|DEPREC},
+#endif
 {"uch"                  , "set used channel count"      , OFFSET(user_used_ch_count), AV_OPT_TYPE_INT, {.i64=0                    }, 0      , SWR_CH_MAX, PARAM},
 {"used_channel_count"   , "set used channel count"      , OFFSET(user_used_ch_count), AV_OPT_TYPE_INT, {.i64=0                    }, 0      , SWR_CH_MAX, PARAM},
 {"isr"                  , "set input sample rate"       , OFFSET( in_sample_rate), AV_OPT_TYPE_INT  , {.i64=0                     }, 0      , INT_MAX   , PARAM},
@@ -52,10 +59,20 @@  static const AVOption options[]={
 {"out_sample_fmt"       , "set output sample format"    , OFFSET(out_sample_fmt ), AV_OPT_TYPE_SAMPLE_FMT , {.i64=AV_SAMPLE_FMT_NONE}, -1   , INT_MAX, PARAM},
 {"tsf"                  , "set internal sample format"  , OFFSET(user_int_sample_fmt), AV_OPT_TYPE_SAMPLE_FMT , {.i64=AV_SAMPLE_FMT_NONE}, -1   , INT_MAX, PARAM},
 {"internal_sample_fmt"  , "set internal sample format"  , OFFSET(user_int_sample_fmt), AV_OPT_TYPE_SAMPLE_FMT , {.i64=AV_SAMPLE_FMT_NONE}, -1   , INT_MAX, PARAM},
-{"icl"                  , "set input channel layout"    , OFFSET(user_in_ch_layout ), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=0           }, INT64_MIN, INT64_MAX , PARAM, "channel_layout"},
-{"in_channel_layout"    , "set input channel layout"    , OFFSET(user_in_ch_layout ), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=0           }, INT64_MIN, INT64_MAX , PARAM, "channel_layout"},
-{"ocl"                  , "set output channel layout"   , OFFSET(user_out_ch_layout), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=0           }, INT64_MIN, INT64_MAX , PARAM, "channel_layout"},
-{"out_channel_layout"   , "set output channel layout"   , OFFSET(user_out_ch_layout), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=0           }, INT64_MIN, INT64_MAX , PARAM, "channel_layout"},
+#if FF_API_OLD_CHANNEL_LAYOUT
+{"icl"                  , "set input channel layout (Deprecated, use ichl)",
+                                                          OFFSET(user_in_ch_layout), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=0          }, INT64_MIN, INT64_MAX, PARAM|DEPREC, "channel_layout"},
+{"in_channel_layout"    , "set input channel layout (Deprecated, use in_chlayout)",
+                                                          OFFSET(user_in_ch_layout), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=0          }, INT64_MIN, INT64_MAX, PARAM|DEPREC, "channel_layout"},
+{"ocl"                  , "set output channel layout (Deprecated, use ochl)",
+                                                          OFFSET(user_out_ch_layout), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=0         }, INT64_MIN, INT64_MAX, PARAM|DEPREC, "channel_layout"},
+{"out_channel_layout"   , "set output channel layout (Deprecated, use out_chlayout)",
+                                                          OFFSET(user_out_ch_layout), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=0         }, INT64_MIN, INT64_MAX, PARAM|DEPREC, "channel_layout"},
+#endif
+{"ichl"                 , "set input channel layout"    , OFFSET(user_in_chlayout ), AV_OPT_TYPE_CHLAYOUT, {.str=NULL             }, 0, 0 , PARAM, "chlayout"},
+{"in_chlayout"          , "set input channel layout"    , OFFSET(user_in_chlayout ), AV_OPT_TYPE_CHLAYOUT, {.str=NULL             }, 0, 0 , PARAM, "chlayout"},
+{"ochl"                 , "set output channel layout"   , OFFSET(user_out_chlayout), AV_OPT_TYPE_CHLAYOUT, {.str=NULL             }, 0, 0 , PARAM, "chlayout"},
+{"out_chlayout"         , "set output channel layout"   , OFFSET(user_out_chlayout), AV_OPT_TYPE_CHLAYOUT, {.str=NULL             }, 0, 0 , PARAM, "chlayout"},
 {"clev"                 , "set center mix level"        , OFFSET(clev           ), AV_OPT_TYPE_FLOAT, {.dbl=C_30DB                }, -32    , 32        , PARAM},
 {"center_mix_level"     , "set center mix level"        , OFFSET(clev           ), AV_OPT_TYPE_FLOAT, {.dbl=C_30DB                }, -32    , 32        , PARAM},
 {"slev"                 , "set surround mix level"      , OFFSET(slev           ), AV_OPT_TYPE_FLOAT, {.dbl=C_30DB                }, -32    , 32        , PARAM},
diff --git a/libswresample/rematrix.c b/libswresample/rematrix.c
index 94b3de88f6..106ab88454 100644
--- a/libswresample/rematrix.c
+++ b/libswresample/rematrix.c
@@ -64,15 +64,31 @@ 
 int swr_set_matrix(struct SwrContext *s, const double *matrix, int stride)
 {
     int nb_in, nb_out, in, out;
+    int user_in_chlayout_nb_channels, user_out_chlayout_nb_channels;
 
     if (!s || s->in_convert) // s needs to be allocated but not initialized
         return AVERROR(EINVAL);
     memset(s->matrix, 0, sizeof(s->matrix));
     memset(s->matrix_flt, 0, sizeof(s->matrix_flt));
+
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
+    user_in_chlayout_nb_channels = av_get_channel_layout_nb_channels(s->user_in_ch_layout);
+FF_ENABLE_DEPRECATION_WARNINGS
+    if (!user_in_chlayout_nb_channels)
+#endif
+    user_in_chlayout_nb_channels = s->user_in_chlayout.nb_channels;
     nb_in = (s->user_in_ch_count > 0) ? s->user_in_ch_count :
-        av_get_channel_layout_nb_channels(s->user_in_ch_layout);
+        user_in_chlayout_nb_channels;
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
+    user_out_chlayout_nb_channels = av_get_channel_layout_nb_channels(s->user_out_ch_layout);
+FF_ENABLE_DEPRECATION_WARNINGS
+    if (!user_out_chlayout_nb_channels)
+#endif
+    user_out_chlayout_nb_channels = s->user_out_chlayout.nb_channels;
     nb_out = (s->user_out_ch_count > 0) ? s->user_out_ch_count :
-        av_get_channel_layout_nb_channels(s->user_out_ch_layout);
+        user_out_chlayout_nb_channels;
     for (out = 0; out < nb_out; out++) {
         for (in = 0; in < nb_in; in++)
             s->matrix_flt[out][in] = s->matrix[out][in] = matrix[in];
@@ -88,95 +104,141 @@  static int even(int64_t layout){
     return 0;
 }
 
-static int64_t clean_layout(void *s, int64_t layout){
-    if(layout && layout != AV_CH_FRONT_CENTER && !(layout&(layout-1))) {
+static int clean_layout(AVChannelLayout *out, const AVChannelLayout *in, void *s)
+{
+    int ret = 0;
+
+    if(av_channel_layout_index_from_channel(in, AV_CH_FRONT_CENTER) < 0 && in->nb_channels == 1) {
         char buf[128];
-        av_get_channel_layout_string(buf, sizeof(buf), -1, layout);
+        av_channel_layout_describe(in, buf, sizeof(buf));
         av_log(s, AV_LOG_VERBOSE, "Treating %s as mono\n", buf);
-        return AV_CH_FRONT_CENTER;
-    }
+        *out = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO;
+    } else
+        ret = av_channel_layout_copy(out, in);
 
-    return layout;
+    return ret;
 }
 
-static int sane_layout(int64_t layout){
-    if(!(layout & AV_CH_LAYOUT_SURROUND)) // at least 1 front speaker
+static int sane_layout(AVChannelLayout *ch_layout) {
+    if (ch_layout->order != AV_CHANNEL_ORDER_NATIVE)
+        return 0;
+    if(!av_channel_layout_subset(ch_layout, AV_CH_LAYOUT_SURROUND)) // at least 1 front speaker
         return 0;
-    if(!even(layout & (AV_CH_FRONT_LEFT | AV_CH_FRONT_RIGHT))) // no asymetric front
+    if(!even(av_channel_layout_subset(ch_layout, (AV_CH_FRONT_LEFT | AV_CH_FRONT_RIGHT)))) // no asymetric front
         return 0;
-    if(!even(layout & (AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT)))   // no asymetric side
+    if(!even(av_channel_layout_subset(ch_layout, (AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT))))   // no asymetric side
         return 0;
-    if(!even(layout & (AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT)))
+    if(!even(av_channel_layout_subset(ch_layout, (AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT))))
         return 0;
-    if(!even(layout & (AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER)))
+    if(!even(av_channel_layout_subset(ch_layout, (AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER))))
         return 0;
-    if(av_get_channel_layout_nb_channels(layout) >= SWR_CH_MAX)
+    if(ch_layout->nb_channels >= SWR_CH_MAX)
         return 0;
 
     return 1;
 }
 
+#if FF_API_OLD_CHANNEL_LAYOUT
 av_cold int swr_build_matrix(uint64_t in_ch_layout_param, uint64_t out_ch_layout_param,
                              double center_mix_level, double surround_mix_level,
                              double lfe_mix_level, double maxval,
                              double rematrix_volume, double *matrix_param,
                              int stride, enum AVMatrixEncoding matrix_encoding, void *log_context)
 {
-    int i, j, out_i;
+    AVChannelLayout in_ch_layout = { 0 }, out_ch_layout = { 0 };
+    int ret;
+
+    ret  = av_channel_layout_from_mask(&in_ch_layout, in_ch_layout_param);
+    ret |= av_channel_layout_from_mask(&out_ch_layout, out_ch_layout_param);
+    if (ret < 0)
+        return ret;
+
+    return swr_build_matrix2(&in_ch_layout, &out_ch_layout, center_mix_level, surround_mix_level,
+                             lfe_mix_level, maxval, rematrix_volume, matrix_param,
+                             stride, matrix_encoding, log_context);
+}
+#endif
+
+av_cold int swr_build_matrix2(const AVChannelLayout *in_layout, const AVChannelLayout *out_layout,
+                              double center_mix_level, double surround_mix_level,
+                              double lfe_mix_level, double maxval,
+                              double rematrix_volume, double *matrix_param,
+                              ptrdiff_t stride, enum AVMatrixEncoding matrix_encoding, void *log_context)
+{
+    int i, j, out_i, ret;
+    AVChannelLayout in_ch_layout = { 0 }, out_ch_layout = { 0 };
     double matrix[NUM_NAMED_CHANNELS][NUM_NAMED_CHANNELS]={{0}};
-    int64_t unaccounted, in_ch_layout, out_ch_layout;
+    int64_t unaccounted;
     double maxcoef=0;
     char buf[128];
 
-     in_ch_layout = clean_layout(log_context,  in_ch_layout_param);
-    out_ch_layout = clean_layout(log_context, out_ch_layout_param);
-
-    if(   out_ch_layout == AV_CH_LAYOUT_STEREO_DOWNMIX
-       && (in_ch_layout & AV_CH_LAYOUT_STEREO_DOWNMIX) == 0
-    )
-        out_ch_layout = AV_CH_LAYOUT_STEREO;
+    ret  = clean_layout(&in_ch_layout, in_layout, log_context);
+    ret |= clean_layout(&out_ch_layout, out_layout, log_context);
+    if (ret < 0)
+        goto fail;
 
-    if(    in_ch_layout == AV_CH_LAYOUT_STEREO_DOWNMIX
-       && (out_ch_layout & AV_CH_LAYOUT_STEREO_DOWNMIX) == 0
-    )
-        in_ch_layout = AV_CH_LAYOUT_STEREO;
-
-    if (in_ch_layout == AV_CH_LAYOUT_22POINT2 &&
-        out_ch_layout != AV_CH_LAYOUT_22POINT2) {
-        in_ch_layout = (AV_CH_LAYOUT_7POINT1_WIDE_BACK|AV_CH_BACK_CENTER);
-        av_get_channel_layout_string(buf, sizeof(buf), -1, in_ch_layout);
+    if(   !av_channel_layout_compare(&out_ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO_DOWNMIX)
+       && !av_channel_layout_subset(&in_ch_layout, AV_CH_LAYOUT_STEREO_DOWNMIX)
+    ) {
+        av_channel_layout_uninit(&out_ch_layout);
+        out_ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO;
+    }
+    if(   !av_channel_layout_compare(&in_ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO_DOWNMIX)
+       && !av_channel_layout_subset(&out_ch_layout, AV_CH_LAYOUT_STEREO_DOWNMIX)
+    ) {
+        av_channel_layout_uninit(&in_ch_layout);
+        in_ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO;
+    }
+    if (!av_channel_layout_compare(&in_ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_22POINT2) &&
+        av_channel_layout_compare(&out_ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_22POINT2)) {
+        av_channel_layout_from_mask(&in_ch_layout, (AV_CH_LAYOUT_7POINT1_WIDE_BACK|AV_CH_BACK_CENTER));
+        av_channel_layout_describe(&in_ch_layout, buf, sizeof(buf));
         av_log(log_context, AV_LOG_WARNING,
                "Full-on remixing from 22.2 has not yet been implemented! "
                "Processing the input as '%s'\n",
                buf);
     }
 
-    if(!sane_layout(in_ch_layout)){
-        av_get_channel_layout_string(buf, sizeof(buf), -1, in_ch_layout_param);
+    if(!av_channel_layout_check(&in_ch_layout)) {
+        av_log(log_context, AV_LOG_ERROR, "Input channel layout is invalid\n");
+        ret = AVERROR(EINVAL);
+        goto fail;
+    }
+    if(!sane_layout(&in_ch_layout)) {
+        av_channel_layout_describe(&in_ch_layout, buf, sizeof(buf));
         av_log(log_context, AV_LOG_ERROR, "Input channel layout '%s' is not supported\n", buf);
-        return AVERROR(EINVAL);
+        ret = AVERROR(EINVAL);
+        goto fail;
     }
 
-    if(!sane_layout(out_ch_layout)){
-        av_get_channel_layout_string(buf, sizeof(buf), -1, out_ch_layout_param);
+    if(!av_channel_layout_check(&out_ch_layout)) {
+        av_log(log_context, AV_LOG_ERROR, "Output channel layout is invalid\n");
+        ret = AVERROR(EINVAL);
+        goto fail;
+    }
+    if(!sane_layout(&out_ch_layout)) {
+        av_channel_layout_describe(&out_ch_layout, buf, sizeof(buf));
         av_log(log_context, AV_LOG_ERROR, "Output channel layout '%s' is not supported\n", buf);
-        return AVERROR(EINVAL);
+        ret = AVERROR(EINVAL);
+        goto fail;
     }
 
     for(i=0; i<FF_ARRAY_ELEMS(matrix); i++){
-        if(in_ch_layout & out_ch_layout & (1ULL<<i))
+        int idx;
+        if(   (idx = av_channel_layout_index_from_channel(&in_ch_layout, i)) >= 0
+           && av_channel_layout_index_from_channel(&out_ch_layout, i) == idx)
             matrix[i][i]= 1.0;
     }
 
-    unaccounted= in_ch_layout & ~out_ch_layout;
+    unaccounted =  in_ch_layout.u.mask & ~out_ch_layout.u.mask;
 
 //FIXME implement dolby surround
 //FIXME implement full ac3
 
 
     if(unaccounted & AV_CH_FRONT_CENTER){
-        if((out_ch_layout & AV_CH_LAYOUT_STEREO) == AV_CH_LAYOUT_STEREO){
-            if(in_ch_layout & AV_CH_LAYOUT_STEREO) {
+        if(av_channel_layout_subset(&out_ch_layout, AV_CH_LAYOUT_STEREO) == AV_CH_LAYOUT_STEREO){
+            if(av_channel_layout_subset(&in_ch_layout, AV_CH_LAYOUT_STEREO)) {
                 matrix[ FRONT_LEFT][FRONT_CENTER]+= center_mix_level;
                 matrix[FRONT_RIGHT][FRONT_CENTER]+= center_mix_level;
             } else {
@@ -187,23 +249,23 @@  av_cold int swr_build_matrix(uint64_t in_ch_layout_param, uint64_t out_ch_layout
             av_assert0(0);
     }
     if(unaccounted & AV_CH_LAYOUT_STEREO){
-        if(out_ch_layout & AV_CH_FRONT_CENTER){
+        if(av_channel_layout_index_from_channel(&out_ch_layout, AV_CHAN_FRONT_CENTER) >= 0){
             matrix[FRONT_CENTER][ FRONT_LEFT]+= M_SQRT1_2;
             matrix[FRONT_CENTER][FRONT_RIGHT]+= M_SQRT1_2;
-            if(in_ch_layout & AV_CH_FRONT_CENTER)
+            if(av_channel_layout_index_from_channel(&in_ch_layout, AV_CHAN_FRONT_CENTER) >= 0)
                 matrix[FRONT_CENTER][ FRONT_CENTER] = center_mix_level*sqrt(2);
         }else
             av_assert0(0);
     }
 
     if(unaccounted & AV_CH_BACK_CENTER){
-        if(out_ch_layout & AV_CH_BACK_LEFT){
+        if(av_channel_layout_index_from_channel(&out_ch_layout, AV_CHAN_BACK_LEFT) >= 0){
             matrix[ BACK_LEFT][BACK_CENTER]+= M_SQRT1_2;
             matrix[BACK_RIGHT][BACK_CENTER]+= M_SQRT1_2;
-        }else if(out_ch_layout & AV_CH_SIDE_LEFT){
+        }else if(av_channel_layout_index_from_channel(&out_ch_layout, AV_CHAN_SIDE_LEFT) >= 0){
             matrix[ SIDE_LEFT][BACK_CENTER]+= M_SQRT1_2;
             matrix[SIDE_RIGHT][BACK_CENTER]+= M_SQRT1_2;
-        }else if(out_ch_layout & AV_CH_FRONT_LEFT){
+        }else if(av_channel_layout_index_from_channel(&out_ch_layout, AV_CHAN_FRONT_LEFT) >= 0){
             if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY ||
                 matrix_encoding == AV_MATRIX_ENCODING_DPLII) {
                 if (unaccounted & (AV_CH_BACK_LEFT | AV_CH_SIDE_LEFT)) {
@@ -217,24 +279,24 @@  av_cold int swr_build_matrix(uint64_t in_ch_layout_param, uint64_t out_ch_layout
                 matrix[ FRONT_LEFT][BACK_CENTER]+= surround_mix_level * M_SQRT1_2;
                 matrix[FRONT_RIGHT][BACK_CENTER]+= surround_mix_level * M_SQRT1_2;
             }
-        }else if(out_ch_layout & AV_CH_FRONT_CENTER){
+        }else if(av_channel_layout_index_from_channel(&out_ch_layout, AV_CHAN_FRONT_CENTER) >= 0){
             matrix[ FRONT_CENTER][BACK_CENTER]+= surround_mix_level * M_SQRT1_2;
         }else
             av_assert0(0);
     }
     if(unaccounted & AV_CH_BACK_LEFT){
-        if(out_ch_layout & AV_CH_BACK_CENTER){
+        if(av_channel_layout_index_from_channel(&out_ch_layout, AV_CHAN_BACK_CENTER) >= 0){
             matrix[BACK_CENTER][ BACK_LEFT]+= M_SQRT1_2;
             matrix[BACK_CENTER][BACK_RIGHT]+= M_SQRT1_2;
-        }else if(out_ch_layout & AV_CH_SIDE_LEFT){
-            if(in_ch_layout & AV_CH_SIDE_LEFT){
+        }else if(av_channel_layout_index_from_channel(&out_ch_layout, AV_CHAN_SIDE_LEFT) >= 0){
+            if(av_channel_layout_index_from_channel(&in_ch_layout, AV_CHAN_SIDE_LEFT) >= 0){
                 matrix[ SIDE_LEFT][ BACK_LEFT]+= M_SQRT1_2;
                 matrix[SIDE_RIGHT][BACK_RIGHT]+= M_SQRT1_2;
             }else{
             matrix[ SIDE_LEFT][ BACK_LEFT]+= 1.0;
             matrix[SIDE_RIGHT][BACK_RIGHT]+= 1.0;
             }
-        }else if(out_ch_layout & AV_CH_FRONT_LEFT){
+        }else if(av_channel_layout_index_from_channel(&out_ch_layout, AV_CHAN_FRONT_LEFT) >= 0){
             if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY) {
                 matrix[FRONT_LEFT ][BACK_LEFT ] -= surround_mix_level * M_SQRT1_2;
                 matrix[FRONT_LEFT ][BACK_RIGHT] -= surround_mix_level * M_SQRT1_2;
@@ -249,7 +311,7 @@  av_cold int swr_build_matrix(uint64_t in_ch_layout_param, uint64_t out_ch_layout
                 matrix[ FRONT_LEFT][ BACK_LEFT] += surround_mix_level;
                 matrix[FRONT_RIGHT][BACK_RIGHT] += surround_mix_level;
             }
-        }else if(out_ch_layout & AV_CH_FRONT_CENTER){
+        }else if(av_channel_layout_index_from_channel(&out_ch_layout, AV_CHAN_FRONT_CENTER) >= 0){
             matrix[ FRONT_CENTER][BACK_LEFT ]+= surround_mix_level*M_SQRT1_2;
             matrix[ FRONT_CENTER][BACK_RIGHT]+= surround_mix_level*M_SQRT1_2;
         }else
@@ -257,20 +319,20 @@  av_cold int swr_build_matrix(uint64_t in_ch_layout_param, uint64_t out_ch_layout
     }
 
     if(unaccounted & AV_CH_SIDE_LEFT){
-        if(out_ch_layout & AV_CH_BACK_LEFT){
+        if(av_channel_layout_index_from_channel(&out_ch_layout, AV_CHAN_BACK_LEFT) >= 0){
             /* if back channels do not exist in the input, just copy side
                channels to back channels, otherwise mix side into back */
-            if (in_ch_layout & AV_CH_BACK_LEFT) {
+            if (av_channel_layout_index_from_channel(&in_ch_layout, AV_CHAN_BACK_LEFT) >= 0) {
                 matrix[BACK_LEFT ][SIDE_LEFT ] += M_SQRT1_2;
                 matrix[BACK_RIGHT][SIDE_RIGHT] += M_SQRT1_2;
             } else {
                 matrix[BACK_LEFT ][SIDE_LEFT ] += 1.0;
                 matrix[BACK_RIGHT][SIDE_RIGHT] += 1.0;
             }
-        }else if(out_ch_layout & AV_CH_BACK_CENTER){
+        }else if(av_channel_layout_index_from_channel(&out_ch_layout, AV_CHAN_BACK_CENTER) >= 0){
             matrix[BACK_CENTER][ SIDE_LEFT]+= M_SQRT1_2;
             matrix[BACK_CENTER][SIDE_RIGHT]+= M_SQRT1_2;
-        }else if(out_ch_layout & AV_CH_FRONT_LEFT){
+        }else if(av_channel_layout_index_from_channel(&out_ch_layout, AV_CHAN_FRONT_LEFT) >= 0){
             if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY) {
                 matrix[FRONT_LEFT ][SIDE_LEFT ] -= surround_mix_level * M_SQRT1_2;
                 matrix[FRONT_LEFT ][SIDE_RIGHT] -= surround_mix_level * M_SQRT1_2;
@@ -285,7 +347,7 @@  av_cold int swr_build_matrix(uint64_t in_ch_layout_param, uint64_t out_ch_layout
                 matrix[ FRONT_LEFT][ SIDE_LEFT] += surround_mix_level;
                 matrix[FRONT_RIGHT][SIDE_RIGHT] += surround_mix_level;
             }
-        }else if(out_ch_layout & AV_CH_FRONT_CENTER){
+        }else if(av_channel_layout_index_from_channel(&out_ch_layout, AV_CHAN_FRONT_CENTER) >= 0){
             matrix[ FRONT_CENTER][SIDE_LEFT ]+= surround_mix_level * M_SQRT1_2;
             matrix[ FRONT_CENTER][SIDE_RIGHT]+= surround_mix_level * M_SQRT1_2;
         }else
@@ -293,10 +355,10 @@  av_cold int swr_build_matrix(uint64_t in_ch_layout_param, uint64_t out_ch_layout
     }
 
     if(unaccounted & AV_CH_FRONT_LEFT_OF_CENTER){
-        if(out_ch_layout & AV_CH_FRONT_LEFT){
+        if(av_channel_layout_index_from_channel(&out_ch_layout, AV_CHAN_FRONT_LEFT) >= 0){
             matrix[ FRONT_LEFT][ FRONT_LEFT_OF_CENTER]+= 1.0;
             matrix[FRONT_RIGHT][FRONT_RIGHT_OF_CENTER]+= 1.0;
-        }else if(out_ch_layout & AV_CH_FRONT_CENTER){
+        }else if(av_channel_layout_index_from_channel(&out_ch_layout, AV_CHAN_FRONT_CENTER) >= 0){
             matrix[ FRONT_CENTER][ FRONT_LEFT_OF_CENTER]+= M_SQRT1_2;
             matrix[ FRONT_CENTER][FRONT_RIGHT_OF_CENTER]+= M_SQRT1_2;
         }else
@@ -304,9 +366,9 @@  av_cold int swr_build_matrix(uint64_t in_ch_layout_param, uint64_t out_ch_layout
     }
     /* mix LFE into front left/right or center */
     if (unaccounted & AV_CH_LOW_FREQUENCY) {
-        if (out_ch_layout & AV_CH_FRONT_CENTER) {
+        if (av_channel_layout_index_from_channel(&out_ch_layout, AV_CHAN_FRONT_CENTER) >= 0) {
             matrix[FRONT_CENTER][LOW_FREQUENCY] += lfe_mix_level;
-        } else if (out_ch_layout & AV_CH_FRONT_LEFT) {
+        } else if (av_channel_layout_index_from_channel(&out_ch_layout, AV_CHAN_FRONT_LEFT) >= 0) {
             matrix[FRONT_LEFT ][LOW_FREQUENCY] += lfe_mix_level * M_SQRT1_2;
             matrix[FRONT_RIGHT][LOW_FREQUENCY] += lfe_mix_level * M_SQRT1_2;
         } else
@@ -316,15 +378,19 @@  av_cold int swr_build_matrix(uint64_t in_ch_layout_param, uint64_t out_ch_layout
     for(out_i=i=0; i<64; i++){
         double sum=0;
         int in_i=0;
-        if((out_ch_layout & (1ULL<<i)) == 0)
+        if(av_channel_layout_index_from_channel(&out_ch_layout, i) < 0)
             continue;
         for(j=0; j<64; j++){
-            if((in_ch_layout & (1ULL<<j)) == 0)
+            if(av_channel_layout_index_from_channel(&in_ch_layout, j) < 0)
                continue;
             if (i < FF_ARRAY_ELEMS(matrix) && j < FF_ARRAY_ELEMS(matrix[0]))
                 matrix_param[stride*out_i + in_i] = matrix[i][j];
-            else
-                matrix_param[stride*out_i + in_i] = i == j && (in_ch_layout & out_ch_layout & (1ULL<<i));
+            else {
+                int idx;
+                matrix_param[stride*out_i + in_i] = i == j &&
+                (   (idx = av_channel_layout_index_from_channel(&in_ch_layout, i)) >= 0
+                 && av_channel_layout_index_from_channel(&out_ch_layout, i) == idx);
+            }
             sum += fabs(matrix_param[stride*out_i + in_i]);
             in_i++;
         }
@@ -350,17 +416,22 @@  av_cold int swr_build_matrix(uint64_t in_ch_layout_param, uint64_t out_ch_layout
     }
 
     av_log(log_context, AV_LOG_DEBUG, "Matrix coefficients:\n");
-    for(i=0; i<av_get_channel_layout_nb_channels(out_ch_layout); i++){
-        const char *c =
-            av_get_channel_name(av_channel_layout_extract_channel(out_ch_layout, i));
-        av_log(log_context, AV_LOG_DEBUG, "%s: ", c ? c : "?");
-        for(j=0; j<av_get_channel_layout_nb_channels(in_ch_layout); j++){
-            c = av_get_channel_name(av_channel_layout_extract_channel(in_ch_layout, j));
-            av_log(log_context, AV_LOG_DEBUG, "%s:%f ", c ? c : "?", matrix_param[stride*i + j]);
+    for(i = 0; i < out_ch_layout.nb_channels; i++){
+        av_channel_name(buf, sizeof(buf), av_channel_layout_channel_from_index(&out_ch_layout, i));
+        av_log(log_context, AV_LOG_DEBUG, "%s: ", buf);
+        for(j = 0; j < in_ch_layout.nb_channels; j++){
+            av_channel_name(buf, sizeof(buf), av_channel_layout_channel_from_index(&in_ch_layout, j));
+            av_log(log_context, AV_LOG_DEBUG, "%s:%f ", buf, matrix_param[stride*i + j]);
         }
         av_log(log_context, AV_LOG_DEBUG, "\n");
     }
-    return 0;
+
+    ret = 0;
+fail:
+    av_channel_layout_uninit(&in_ch_layout);
+    av_channel_layout_uninit(&out_ch_layout);
+
+    return ret;
 }
 
 av_cold static int auto_matrix(SwrContext *s)
@@ -377,7 +448,7 @@  av_cold static int auto_matrix(SwrContext *s)
         maxval = INT_MAX;
 
     memset(s->matrix, 0, sizeof(s->matrix));
-    ret = swr_build_matrix(s->in_ch_layout, s->out_ch_layout,
+    ret = swr_build_matrix2(&s->in_ch_layout, &s->out_ch_layout,
                            s->clev, s->slev, s->lfe_mix_level,
                            maxval, s->rematrix_volume, (double*)s->matrix,
                            s->matrix[1] - s->matrix[0], s->matrix_encoding, s);
@@ -519,8 +590,8 @@  int swri_rematrix(SwrContext *s, AudioData *out, AudioData *in, int len, int mus
         off = len1 * out->bps;
     }
 
-    av_assert0(!s->out_ch_layout || out->ch_count == av_get_channel_layout_nb_channels(s->out_ch_layout));
-    av_assert0(!s-> in_ch_layout || in ->ch_count == av_get_channel_layout_nb_channels(s-> in_ch_layout));
+    av_assert0(s->out_ch_layout.order == AV_CHANNEL_ORDER_UNSPEC || out->ch_count == s->out_ch_layout.nb_channels);
+    av_assert0(s-> in_ch_layout.order == AV_CHANNEL_ORDER_UNSPEC || in ->ch_count == s->in_ch_layout.nb_channels);
 
     for(out_i=0; out_i<out->ch_count; out_i++){
         switch(s->matrix_ch[out_i][0]){
diff --git a/libswresample/rematrix_template.c b/libswresample/rematrix_template.c
index add65e3155..f5a508361c 100644
--- a/libswresample/rematrix_template.c
+++ b/libswresample/rematrix_template.c
@@ -88,13 +88,16 @@  static void RENAME(mix8to2)(SAMPLE **out, const SAMPLE **in, COEFF *coeffp, inte
 }
 
 static RENAME(mix_any_func_type) *RENAME(get_mix_any_func)(SwrContext *s){
-    if(   s->out_ch_layout == AV_CH_LAYOUT_STEREO && (s->in_ch_layout == AV_CH_LAYOUT_5POINT1 || s->in_ch_layout == AV_CH_LAYOUT_5POINT1_BACK)
+    if(   !av_channel_layout_compare(&s->out_ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO)
+       && (   !av_channel_layout_compare(&s->in_ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_5POINT1)
+           || !av_channel_layout_compare(&s->in_ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_5POINT1_BACK))
        && s->matrix[0][2] == s->matrix[1][2] && s->matrix[0][3] == s->matrix[1][3]
        && !s->matrix[0][1] && !s->matrix[0][5] && !s->matrix[1][0] && !s->matrix[1][4]
     )
         return RENAME(mix6to2);
 
-    if(   s->out_ch_layout == AV_CH_LAYOUT_STEREO && s->in_ch_layout == AV_CH_LAYOUT_7POINT1
+    if(   !av_channel_layout_compare(&s->out_ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO)
+       && !av_channel_layout_compare(&s->in_ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_7POINT1)
        && s->matrix[0][2] == s->matrix[1][2] && s->matrix[0][3] == s->matrix[1][3]
        && !s->matrix[0][1] && !s->matrix[0][5] && !s->matrix[1][0] && !s->matrix[1][4]
        && !s->matrix[0][7] && !s->matrix[1][6]
diff --git a/libswresample/swresample.c b/libswresample/swresample.c
index c03fe5528f..fe75e847af 100644
--- a/libswresample/swresample.c
+++ b/libswresample/swresample.c
@@ -56,6 +56,8 @@  int swr_set_channel_mapping(struct SwrContext *s, const int *channel_map){
     return 0;
 }
 
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
 struct SwrContext *swr_alloc_set_opts(struct SwrContext *s,
                                       int64_t out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate,
                                       int64_t  in_ch_layout, enum AVSampleFormat  in_sample_fmt, int  in_sample_rate,
@@ -97,6 +99,58 @@  fail:
     swr_free(&s);
     return NULL;
 }
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+
+int swr_alloc_set_opts2(struct SwrContext **ps,
+                        AVChannelLayout *out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate,
+                        AVChannelLayout *in_ch_layout, enum AVSampleFormat  in_sample_fmt, int  in_sample_rate,
+                        int log_offset, void *log_ctx) {
+    struct SwrContext *s = *ps;
+    int ret;
+
+    if (!s) s = swr_alloc();
+    if (!s) return AVERROR(ENOMEM);
+
+    s->log_level_offset= log_offset;
+    s->log_ctx= log_ctx;
+
+    if ((ret = av_opt_set_chlayout(s, "ochl", out_ch_layout, 0)) < 0)
+        goto fail;
+
+    if ((ret = av_opt_set_int(s, "osf", out_sample_fmt, 0)) < 0)
+        goto fail;
+
+    if ((ret = av_opt_set_int(s, "osr", out_sample_rate, 0)) < 0)
+        goto fail;
+
+    if ((ret = av_opt_set_chlayout(s, "ichl", in_ch_layout, 0)) < 0)
+        goto fail;
+
+    if ((ret = av_opt_set_int(s, "isf", in_sample_fmt, 0)) < 0)
+        goto fail;
+
+    if ((ret = av_opt_set_int(s, "isr", in_sample_rate, 0)) < 0)
+        goto fail;
+
+    av_opt_set_int(s, "uch", 0, 0);
+
+#if FF_API_OLD_CHANNEL_LAYOUT
+    // Clear old API values so they don't take precedence in swr_init()
+    av_opt_set_int(s, "icl", 0, 0);
+    av_opt_set_int(s, "ocl", 0, 0);
+    av_opt_set_int(s, "ich", 0, 0);
+    av_opt_set_int(s, "och", 0, 0);
+#endif
+
+    *ps = s;
+
+    return 0;
+fail:
+    av_log(s, AV_LOG_ERROR, "Failed to set option\n");
+    swr_free(ps);
+    return ret;
+}
 
 static void set_audiodata_fmt(AudioData *a, enum AVSampleFormat fmt){
     a->fmt   = fmt;
@@ -125,6 +179,8 @@  static void clear_context(SwrContext *s){
     free_temp(&s->drop_temp);
     free_temp(&s->dither.noise);
     free_temp(&s->dither.temp);
+    av_channel_layout_uninit(&s->in_ch_layout);
+    av_channel_layout_uninit(&s->out_ch_layout);
     swri_audio_convert_free(&s-> in_convert);
     swri_audio_convert_free(&s->out_convert);
     swri_audio_convert_free(&s->full_convert);
@@ -138,6 +194,9 @@  av_cold void swr_free(SwrContext **ss){
     SwrContext *s= *ss;
     if(s){
         clear_context(s);
+        av_channel_layout_uninit(&s->user_in_chlayout);
+        av_channel_layout_uninit(&s->user_out_chlayout);
+
         if (s->resampler)
             s->resampler->free(&s->resample);
     }
@@ -172,25 +231,72 @@  av_cold int swr_init(struct SwrContext *s){
         av_log(s, AV_LOG_ERROR, "Requested output sample rate %d is invalid\n", s->out_sample_rate);
         return AVERROR(EINVAL);
     }
+    s->used_ch_count = s->user_used_ch_count;
+#if FF_API_OLD_CHANNEL_LAYOUT
     s->out.ch_count  = s-> user_out_ch_count;
     s-> in.ch_count  = s->  user_in_ch_count;
-    s->used_ch_count = s->user_used_ch_count;
 
-    s-> in_ch_layout = s-> user_in_ch_layout;
-    s->out_ch_layout = s->user_out_ch_layout;
+    // if the old/new fields are set inconsistently, prefer the old ones
+    if ((s->user_in_ch_count && s->user_in_ch_count != s->user_in_chlayout.nb_channels) ||
+        (s->user_in_ch_layout && (s->user_in_chlayout.order != AV_CHANNEL_ORDER_NATIVE ||
+                                  s->user_in_chlayout.u.mask != s->user_in_ch_layout))) {
+        av_channel_layout_uninit(&s->in_ch_layout);
+        if (s->user_in_ch_layout)
+            av_channel_layout_from_mask(&s->in_ch_layout, s->user_in_ch_layout);
+        else {
+            s->in_ch_layout.order       = AV_CHANNEL_ORDER_UNSPEC;
+            s->in_ch_layout.nb_channels = s->user_in_ch_count;
+        }
+    } else
+        av_channel_layout_copy(&s->in_ch_layout, &s->user_in_chlayout);
+
+    if ((s->user_out_ch_count && s->user_out_ch_count != s->user_out_chlayout.nb_channels) ||
+        (s->user_out_ch_layout && (s->user_out_chlayout.order != AV_CHANNEL_ORDER_NATIVE ||
+                                   s->user_out_chlayout.u.mask != s->user_out_ch_layout))) {
+        av_channel_layout_uninit(&s->out_ch_layout);
+        if (s->user_out_ch_layout)
+            av_channel_layout_from_mask(&s->out_ch_layout, s->user_out_ch_layout);
+        else {
+            s->out_ch_layout.order       = AV_CHANNEL_ORDER_UNSPEC;
+            s->out_ch_layout.nb_channels = s->user_out_ch_count;
+        }
+    } else
+        av_channel_layout_copy(&s->out_ch_layout, &s->user_out_chlayout);
+
+    if (!s->out.ch_count && !s->user_out_ch_layout)
+        s->out.ch_count  = s->out_ch_layout.nb_channels;
+    if (!s-> in.ch_count && !s-> user_in_ch_layout)
+        s-> in.ch_count  = s->in_ch_layout.nb_channels;
+#else
+    s->out.ch_count  = s-> user_out_chlayout.nb_channels;
+    s-> in.ch_count  = s->  user_in_chlayout.nb_channels;
+
+    ret  = av_channel_layout_copy(&s->in_ch_layout, &s->user_in_chlayout);
+    ret |= av_channel_layout_copy(&s->out_ch_layout, &s->user_out_chlayout);
+    if (ret < 0)
+        return ret;
+#endif
 
     s->int_sample_fmt= s->user_int_sample_fmt;
 
     s->dither.method = s->user_dither_method;
 
-    if(av_get_channel_layout_nb_channels(s-> in_ch_layout) > SWR_CH_MAX) {
-        av_log(s, AV_LOG_WARNING, "Input channel layout 0x%"PRIx64" is invalid or unsupported.\n", s-> in_ch_layout);
-        s->in_ch_layout = 0;
+    if(!av_channel_layout_check(&s->in_ch_layout) ||
+       s->in_ch_layout.nb_channels > SWR_CH_MAX ||
+       (   s->in_ch_layout.order != AV_CHANNEL_ORDER_NATIVE
+        && s->in_ch_layout.order != AV_CHANNEL_ORDER_UNSPEC)) {
+        av_channel_layout_describe(&s->in_ch_layout, l1, sizeof(l1));
+        av_log(s, AV_LOG_WARNING, "Input channel layout \"%s\" is invalid or unsupported.\n", l1);
+        av_channel_layout_uninit(&s->in_ch_layout);
     }
 
-    if(av_get_channel_layout_nb_channels(s->out_ch_layout) > SWR_CH_MAX) {
-        av_log(s, AV_LOG_WARNING, "Output channel layout 0x%"PRIx64" is invalid or unsupported.\n", s->out_ch_layout);
-        s->out_ch_layout = 0;
+    if(!av_channel_layout_check(&s->out_ch_layout) ||
+       s->out_ch_layout.nb_channels > SWR_CH_MAX ||
+       (   s->out_ch_layout.order != AV_CHANNEL_ORDER_NATIVE
+        && s->out_ch_layout.order != AV_CHANNEL_ORDER_UNSPEC)) {
+        av_channel_layout_describe(&s->out_ch_layout, l2, sizeof(l2));
+        av_log(s, AV_LOG_WARNING, "Output channel layout \"%s\" is invalid or unsupported.\n", l2);
+        av_channel_layout_uninit(&s->out_ch_layout);
     }
 
     switch(s->engine){
@@ -206,17 +312,18 @@  av_cold int swr_init(struct SwrContext *s){
     if(!s->used_ch_count)
         s->used_ch_count= s->in.ch_count;
 
-    if(s->used_ch_count && s-> in_ch_layout && s->used_ch_count != av_get_channel_layout_nb_channels(s-> in_ch_layout)){
+    if(s->used_ch_count && s->in_ch_layout.order != AV_CHANNEL_ORDER_UNSPEC && s->used_ch_count != s->in_ch_layout.nb_channels){
         av_log(s, AV_LOG_WARNING, "Input channel layout has a different number of channels than the number of used channels, ignoring layout\n");
-        s-> in_ch_layout= 0;
+        av_channel_layout_uninit(&s->in_ch_layout);
     }
 
-    if(!s-> in_ch_layout)
-        s-> in_ch_layout= av_get_default_channel_layout(s->used_ch_count);
-    if(!s->out_ch_layout)
-        s->out_ch_layout= av_get_default_channel_layout(s->out.ch_count);
+    if(!s->in_ch_layout.nb_channels || s->in_ch_layout.order == AV_CHANNEL_ORDER_UNSPEC)
+        av_channel_layout_default(&s->in_ch_layout, s->used_ch_count);
+    if(!s->out_ch_layout.nb_channels || s->out_ch_layout.order == AV_CHANNEL_ORDER_UNSPEC)
+        av_channel_layout_default(&s->out_ch_layout, s->out.ch_count);
 
-    s->rematrix= s->out_ch_layout  !=s->in_ch_layout || s->rematrix_volume!=1.0 ||
+    s->rematrix= av_channel_layout_compare(&s->out_ch_layout, &s->in_ch_layout) ||
+                 s->rematrix_volume!=1.0 ||
                  s->rematrix_custom;
 
     if(s->int_sample_fmt == AV_SAMPLE_FMT_NONE){
@@ -291,33 +398,36 @@  av_cold int swr_init(struct SwrContext *s){
 
 #define RSC 1 //FIXME finetune
     if(!s-> in.ch_count)
-        s-> in.ch_count= av_get_channel_layout_nb_channels(s-> in_ch_layout);
+        s-> in.ch_count = s->in_ch_layout.nb_channels;
     if(!s->used_ch_count)
         s->used_ch_count= s->in.ch_count;
     if(!s->out.ch_count)
-        s->out.ch_count= av_get_channel_layout_nb_channels(s->out_ch_layout);
+        s->out.ch_count = s->out_ch_layout.nb_channels;
 
     if(!s-> in.ch_count){
-        av_assert0(!s->in_ch_layout);
+        av_assert0(s->in_ch_layout.order == AV_CHANNEL_ORDER_UNSPEC);
         av_log(s, AV_LOG_ERROR, "Input channel count and layout are unset\n");
         ret = AVERROR(EINVAL);
         goto fail;
     }
 
-    av_get_channel_layout_string(l1, sizeof(l1), s-> in.ch_count, s-> in_ch_layout);
-    av_get_channel_layout_string(l2, sizeof(l2), s->out.ch_count, s->out_ch_layout);
-    if (s->out_ch_layout && s->out.ch_count != av_get_channel_layout_nb_channels(s->out_ch_layout)) {
+#if FF_API_OLD_CHANNEL_LAYOUT
+    av_channel_layout_describe(&s->out_ch_layout, l1, sizeof(l1));
+    if (s->out_ch_layout.order != AV_CHANNEL_ORDER_UNSPEC && s->out.ch_count != s->out_ch_layout.nb_channels) {
         av_log(s, AV_LOG_ERROR, "Output channel layout %s mismatches specified channel count %d\n", l2, s->out.ch_count);
         ret = AVERROR(EINVAL);
         goto fail;
     }
-    if (s->in_ch_layout && s->used_ch_count != av_get_channel_layout_nb_channels(s->in_ch_layout)) {
+#endif
+    av_channel_layout_describe(&s->in_ch_layout, l1, sizeof(l1));
+    if (s->in_ch_layout.order != AV_CHANNEL_ORDER_UNSPEC && s->used_ch_count != s->in_ch_layout.nb_channels) {
         av_log(s, AV_LOG_ERROR, "Input channel layout %s mismatches specified channel count %d\n", l1, s->used_ch_count);
         ret = AVERROR(EINVAL);
         goto fail;
     }
 
-    if ((!s->out_ch_layout || !s->in_ch_layout) && s->used_ch_count != s->out.ch_count && !s->rematrix_custom) {
+    if ((   s->out_ch_layout.order == AV_CHANNEL_ORDER_UNSPEC
+         || s-> in_ch_layout.order == AV_CHANNEL_ORDER_UNSPEC) && s->used_ch_count != s->out.ch_count && !s->rematrix_custom) {
         av_log(s, AV_LOG_ERROR, "Rematrix is needed between %s and %s "
                "but there is not enough information to do it\n", l1, l2);
         ret = AVERROR(EINVAL);
diff --git a/libswresample/swresample.h b/libswresample/swresample.h
index c7b84fbcac..c6ff2345e9 100644
--- a/libswresample/swresample.h
+++ b/libswresample/swresample.h
@@ -227,6 +227,7 @@  int swr_init(struct SwrContext *s);
  */
 int swr_is_initialized(struct SwrContext *s);
 
+#if FF_API_OLD_CHANNEL_LAYOUT
 /**
  * Allocate SwrContext if needed and set/reset common parameters.
  *
@@ -246,12 +247,40 @@  int swr_is_initialized(struct SwrContext *s);
  *
  * @see swr_init(), swr_free()
  * @return NULL on error, allocated context otherwise
+ * @deprecated use @ref swr_alloc_set_opts2()
  */
+attribute_deprecated
 struct SwrContext *swr_alloc_set_opts(struct SwrContext *s,
                                       int64_t out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate,
                                       int64_t  in_ch_layout, enum AVSampleFormat  in_sample_fmt, int  in_sample_rate,
                                       int log_offset, void *log_ctx);
+#endif
 
+/**
+ * Allocate SwrContext if needed and set/reset common parameters.
+ *
+ * This function does not require s to be allocated with swr_alloc(). On the
+ * other hand, swr_alloc() can use swr_alloc_set_opts() to set the parameters
+ * on the allocated context.
+ *
+ * @param ps              Pointer to an existing Swr context if available, or to NULL if not.
+ *                        On success, *ps will be set the allocated context.
+ * @param out_ch_layout   output channel layout (AV_CH_LAYOUT_*)
+ * @param out_sample_fmt  output sample format (AV_SAMPLE_FMT_*).
+ * @param out_sample_rate output sample rate (frequency in Hz)
+ * @param in_ch_layout    input channel layout (AV_CH_LAYOUT_*)
+ * @param in_sample_fmt   input sample format (AV_SAMPLE_FMT_*).
+ * @param in_sample_rate  input sample rate (frequency in Hz)
+ * @param log_offset      logging level offset
+ * @param log_ctx         parent logging context, can be NULL
+ *
+ * @see swr_init(), swr_free()
+ * @return 0 on success, a negative AVERROR code on error.
+ */
+int swr_alloc_set_opts2(struct SwrContext **ps,
+                        AVChannelLayout *out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate,
+                        AVChannelLayout *in_ch_layout, enum AVSampleFormat  in_sample_fmt, int  in_sample_rate,
+                        int log_offset, void *log_ctx);
 /**
  * @}
  *
@@ -362,6 +391,7 @@  int swr_set_compensation(struct SwrContext *s, int sample_delta, int compensatio
  */
 int swr_set_channel_mapping(struct SwrContext *s, const int *channel_map);
 
+#if FF_API_OLD_CHANNEL_LAYOUT
 /**
  * Generate a channel mixing matrix.
  *
@@ -384,13 +414,46 @@  int swr_set_channel_mapping(struct SwrContext *s, const int *channel_map);
  * @param matrix_encoding     matrixed stereo downmix mode (e.g. dplii)
  * @param log_ctx             parent logging context, can be NULL
  * @return                    0 on success, negative AVERROR code on failure
+ * @deprecated                use @ref swr_build_matrix2()
  */
+attribute_deprecated
 int swr_build_matrix(uint64_t in_layout, uint64_t out_layout,
                      double center_mix_level, double surround_mix_level,
                      double lfe_mix_level, double rematrix_maxval,
                      double rematrix_volume, double *matrix,
                      int stride, enum AVMatrixEncoding matrix_encoding,
                      void *log_ctx);
+#endif
+
+/**
+ * Generate a channel mixing matrix.
+ *
+ * This function is the one used internally by libswresample for building the
+ * default mixing matrix. It is made public just as a utility function for
+ * building custom matrices.
+ *
+ * @param in_layout           input channel layout
+ * @param out_layout          output channel layout
+ * @param center_mix_level    mix level for the center channel
+ * @param surround_mix_level  mix level for the surround channel(s)
+ * @param lfe_mix_level       mix level for the low-frequency effects channel
+ * @param rematrix_maxval     if 1.0, coefficients will be normalized to prevent
+ *                            overflow. if INT_MAX, coefficients will not be
+ *                            normalized.
+ * @param[out] matrix         mixing coefficients; matrix[i + stride * o] is
+ *                            the weight of input channel i in output channel o.
+ * @param stride              distance between adjacent input channels in the
+ *                            matrix array
+ * @param matrix_encoding     matrixed stereo downmix mode (e.g. dplii)
+ * @param log_ctx             parent logging context, can be NULL
+ * @return                    0 on success, negative AVERROR code on failure
+ */
+int swr_build_matrix2(const AVChannelLayout *in_layout, const AVChannelLayout *out_layout,
+                      double center_mix_level, double surround_mix_level,
+                      double lfe_mix_level, double maxval,
+                      double rematrix_volume, double *matrix_param,
+                      ptrdiff_t stride, enum AVMatrixEncoding matrix_encoding,
+                      void *log_context);
 
 /**
  * Set a customized remix matrix.
diff --git a/libswresample/swresample_frame.c b/libswresample/swresample_frame.c
index d95c1cc537..747cf119a9 100644
--- a/libswresample/swresample_frame.c
+++ b/libswresample/swresample_frame.c
@@ -29,7 +29,19 @@  int swr_config_frame(SwrContext *s, const AVFrame *out, const AVFrame *in)
     swr_close(s);
 
     if (in) {
-        if (av_opt_set_int(s, "icl", in->channel_layout, 0) < 0)
+        AVChannelLayout in_ch_layout = { 0 };
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
+        // if the old/new fields are set inconsistently, prefer the old ones
+        if ((in->channel_layout && (in->ch_layout.order != AV_CHANNEL_ORDER_NATIVE ||
+                                    in->ch_layout.u.mask != in->channel_layout))) {
+            av_channel_layout_from_mask(&in_ch_layout, in->channel_layout);
+FF_ENABLE_DEPRECATION_WARNINGS
+        } else
+#endif
+        if (av_channel_layout_copy(&in_ch_layout, &in->ch_layout) < 0)
+            goto fail;
+        if (av_opt_set_chlayout(s, "ichl", &in_ch_layout, 0) < 0)
             goto fail;
         if (av_opt_set_int(s, "isf", in->format, 0) < 0)
             goto fail;
@@ -38,7 +50,19 @@  int swr_config_frame(SwrContext *s, const AVFrame *out, const AVFrame *in)
     }
 
     if (out) {
-        if (av_opt_set_int(s, "ocl", out->channel_layout, 0) < 0)
+        AVChannelLayout out_ch_layout = { 0 };
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
+        // if the old/new fields are set inconsistently, prefer the old ones
+        if ((out->channel_layout && (out->ch_layout.order != AV_CHANNEL_ORDER_NATIVE ||
+                                     out->ch_layout.u.mask != out->channel_layout))) {
+            av_channel_layout_from_mask(&out_ch_layout, out->channel_layout);
+FF_ENABLE_DEPRECATION_WARNINGS
+        } else
+#endif
+        if (av_channel_layout_copy(&out_ch_layout, &out->ch_layout) < 0)
+            goto fail;
+        if (av_opt_set_chlayout(s, "ochl", &out_ch_layout, 0) < 0)
             goto fail;
         if (av_opt_set_int(s, "osf", out->format,  0) < 0)
             goto fail;
@@ -58,7 +82,19 @@  static int config_changed(SwrContext *s,
     int ret = 0;
 
     if (in) {
-        if (s->in_ch_layout   != in->channel_layout ||
+        AVChannelLayout in_ch_layout = { 0 };
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
+        // if the old/new fields are set inconsistently, prefer the old ones
+        if ((in->channel_layout && (in->ch_layout.order != AV_CHANNEL_ORDER_NATIVE ||
+                                    in->ch_layout.u.mask != in->channel_layout))) {
+            av_channel_layout_from_mask(&in_ch_layout, in->channel_layout);
+FF_ENABLE_DEPRECATION_WARNINGS
+        } else
+#endif
+        if ((ret = av_channel_layout_copy(&in_ch_layout, &in->ch_layout)) < 0)
+            return ret;
+        if (av_channel_layout_compare(&s->in_ch_layout, &in_ch_layout) ||
             s->in_sample_rate != in->sample_rate ||
             s->in_sample_fmt  != in->format) {
             ret |= AVERROR_INPUT_CHANGED;
@@ -66,7 +102,19 @@  static int config_changed(SwrContext *s,
     }
 
     if (out) {
-        if (s->out_ch_layout   != out->channel_layout ||
+        AVChannelLayout out_ch_layout = { 0 };
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
+        // if the old/new fields are set inconsistently, prefer the old ones
+        if ((out->channel_layout && (out->ch_layout.order != AV_CHANNEL_ORDER_NATIVE ||
+                                     out->ch_layout.u.mask != out->channel_layout))) {
+            av_channel_layout_from_mask(&out_ch_layout, out->channel_layout);
+FF_ENABLE_DEPRECATION_WARNINGS
+        } else
+#endif
+        if ((ret = av_channel_layout_copy(&out_ch_layout, &out->ch_layout)) < 0)
+            return ret;
+        if (av_channel_layout_compare(&s->out_ch_layout, &out_ch_layout) ||
             s->out_sample_rate != out->sample_rate ||
             s->out_sample_fmt  != out->format) {
             ret |= AVERROR_OUTPUT_CHANGED;
@@ -116,7 +164,14 @@  static inline int available_samples(AVFrame *out)
     if (av_sample_fmt_is_planar(out->format)) {
         return samples;
     } else {
-        int channels = av_get_channel_layout_nb_channels(out->channel_layout);
+        int channels;
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
+        channels = av_get_channel_layout_nb_channels(out->channel_layout);
+FF_ENABLE_DEPRECATION_WARNINGS
+        if (!channels)
+#endif
+        channels = out->ch_layout.nb_channels;
         return samples / channels;
     }
 }
diff --git a/libswresample/swresample_internal.h b/libswresample/swresample_internal.h
index f2ea5a226d..262a0e2b8c 100644
--- a/libswresample/swresample_internal.h
+++ b/libswresample/swresample_internal.h
@@ -99,8 +99,8 @@  struct SwrContext {
     enum AVSampleFormat  in_sample_fmt;             ///< input sample format
     enum AVSampleFormat int_sample_fmt;             ///< internal sample format (AV_SAMPLE_FMT_FLTP or AV_SAMPLE_FMT_S16P)
     enum AVSampleFormat out_sample_fmt;             ///< output sample format
-    int64_t  in_ch_layout;                          ///< input channel layout
-    int64_t out_ch_layout;                          ///< output channel layout
+    AVChannelLayout  in_ch_layout;                  ///< input channel layout
+    AVChannelLayout out_ch_layout;                  ///< output channel layout
     int      in_sample_rate;                        ///< input sample rate
     int     out_sample_rate;                        ///< output sample rate
     int flags;                                      ///< miscellaneous flags such as SWR_FLAG_RESAMPLE
@@ -114,11 +114,15 @@  struct SwrContext {
     int used_ch_count;                              ///< number of used input channels (mapped channel count if channel_map, otherwise in.ch_count)
     int engine;
 
+    int user_used_ch_count;                         ///< User set used channel count
+#if FF_API_OLD_CHANNEL_LAYOUT
     int user_in_ch_count;                           ///< User set input channel count
     int user_out_ch_count;                          ///< User set output channel count
-    int user_used_ch_count;                         ///< User set used channel count
     int64_t user_in_ch_layout;                      ///< User set input channel layout
     int64_t user_out_ch_layout;                     ///< User set output channel layout
+#endif
+    AVChannelLayout user_in_chlayout;               ///< User set input channel layout
+    AVChannelLayout user_out_chlayout;              ///< User set output channel layout
     enum AVSampleFormat user_int_sample_fmt;        ///< User set internal sample format
     int user_dither_method;                         ///< User set dither method