[006/200] lavr: switch to the new channel layout API

Message ID 20170517174712.8625-7-vittorio.giovara@gmail.com
State New
Headers show

Commit Message

Vittorio Giovara May 17, 2017, 5:46 p.m.
From: Anton Khirnov <anton@khirnov.net>

Signed-off-by: Vittorio Giovara <vittorio.giovara@gmail.com>
---
 libavresample/audio_mix.c        | 148 ++++++------
 libavresample/audio_mix_matrix.c | 477 ++++++++++++++++++++++-----------------
 libavresample/avresample.h       |  42 +++-
 libavresample/internal.h         |  10 +-
 libavresample/options.c          |   8 +
 libavresample/tests/avresample.c |  26 +--
 libavresample/utils.c            | 127 +++++++----
 7 files changed, 504 insertions(+), 334 deletions(-)

Comments

Vittorio Giovara May 26, 2017, 3:28 p.m. | #1
On Wed, May 17, 2017 at 1:46 PM, Vittorio Giovara
<vittorio.giovara@gmail.com> wrote:
> From: Anton Khirnov <anton@khirnov.net>
>
> Signed-off-by: Vittorio Giovara <vittorio.giovara@gmail.com>
> ---
>  libavresample/audio_mix.c        | 148 ++++++------
>  libavresample/audio_mix_matrix.c | 477 ++++++++++++++++++++++-----------------
>  libavresample/avresample.h       |  42 +++-
>  libavresample/internal.h         |  10 +-
>  libavresample/options.c          |   8 +
>  libavresample/tests/avresample.c |  26 +--
>  libavresample/utils.c            | 127 +++++++----
>  7 files changed, 504 insertions(+), 334 deletions(-)

ping

Patch

diff --git a/libavresample/audio_mix.c b/libavresample/audio_mix.c
index 89ecc6ba71..36dff2b979 100644
--- a/libavresample/audio_mix.c
+++ b/libavresample/audio_mix.c
@@ -20,6 +20,7 @@ 
 
 #include <stdint.h>
 
+#include "libavutil/channel_layout.h"
 #include "libavutil/common.h"
 #include "libavutil/libm.h"
 #include "libavutil/samplefmt.h"
@@ -34,10 +35,8 @@  struct AudioMix {
     AVAudioResampleContext *avr;
     enum AVSampleFormat fmt;
     enum AVMixCoeffType coeff_type;
-    uint64_t in_layout;
-    uint64_t out_layout;
-    int in_channels;
-    int out_channels;
+    AVChannelLayout in_layout;
+    AVChannelLayout out_layout;
 
     int ptr_align;
     int samples_align;
@@ -331,8 +330,8 @@  static av_cold int mix_function_init(AudioMix *am)
     if (!am->mix) {
         av_log(am->avr, AV_LOG_ERROR, "audio_mix: NO FUNCTION FOUND: [fmt=%s] "
                "[c=%s] [%d to %d]\n", av_get_sample_fmt_name(am->fmt),
-               coeff_type_names[am->coeff_type], am->in_channels,
-               am->out_channels);
+               coeff_type_names[am->coeff_type], am->in_layout.nb_channels,
+               am->out_layout.nb_channels);
         return AVERROR_PATCHWELCOME;
     }
     return 0;
@@ -358,38 +357,42 @@  AudioMix *ff_audio_mix_alloc(AVAudioResampleContext *avr)
 
     am->fmt          = avr->internal_sample_fmt;
     am->coeff_type   = avr->mix_coeff_type;
-    am->in_layout    = avr->in_channel_layout;
-    am->out_layout   = avr->out_channel_layout;
-    am->in_channels  = avr->in_channels;
-    am->out_channels = avr->out_channels;
+
+    ret = av_channel_layout_copy(&am->in_layout, &avr->in_ch_layout);
+    if (ret < 0)
+        goto error;
+    ret = av_channel_layout_copy(&am->out_layout, &avr->out_ch_layout);
+    if (ret < 0)
+        goto error;
 
     /* build matrix if the user did not already set one */
     if (avr->mix_matrix) {
-        ret = ff_audio_mix_set_matrix(am, avr->mix_matrix, avr->in_channels);
+        ret = ff_audio_mix_set_matrix(am, avr->mix_matrix, avr->in_ch_layout.nb_channels);
         if (ret < 0)
             goto error;
         av_freep(&avr->mix_matrix);
     } else {
-        double *matrix_dbl = av_mallocz(avr->out_channels * avr->in_channels *
+        double *matrix_dbl = av_mallocz(avr->out_ch_layout.nb_channels *
+                                        avr->in_ch_layout.nb_channels *
                                         sizeof(*matrix_dbl));
         if (!matrix_dbl)
             goto error;
 
-        ret = avresample_build_matrix(avr->in_channel_layout,
-                                      avr->out_channel_layout,
-                                      avr->center_mix_level,
-                                      avr->surround_mix_level,
-                                      avr->lfe_mix_level,
-                                      avr->normalize_mix_level,
-                                      matrix_dbl,
-                                      avr->in_channels,
-                                      avr->matrix_encoding);
+        ret = avresample_build_matrix2(&avr->in_ch_layout,
+                                       &avr->out_ch_layout,
+                                       avr->center_mix_level,
+                                       avr->surround_mix_level,
+                                       avr->lfe_mix_level,
+                                       avr->normalize_mix_level,
+                                       matrix_dbl,
+                                       avr->in_ch_layout.nb_channels,
+                                       avr->matrix_encoding);
         if (ret < 0) {
             av_free(matrix_dbl);
             goto error;
         }
 
-        ret = ff_audio_mix_set_matrix(am, matrix_dbl, avr->in_channels);
+        ret = ff_audio_mix_set_matrix(am, matrix_dbl, avr->in_ch_layout.nb_channels);
         if (ret < 0) {
             av_log(avr, AV_LOG_ERROR, "error setting mix matrix\n");
             av_free(matrix_dbl);
@@ -402,7 +405,7 @@  AudioMix *ff_audio_mix_alloc(AVAudioResampleContext *avr)
     return am;
 
 error:
-    av_free(am);
+    ff_audio_mix_free(&am);
     return NULL;
 }
 
@@ -422,11 +425,16 @@  void ff_audio_mix_free(AudioMix **am_p)
     memset(am->matrix_q15, 0, sizeof(am->matrix_q15));
     memset(am->matrix_flt, 0, sizeof(am->matrix_flt));
 
+    av_channel_layout_uninit(&am->in_layout);
+    av_channel_layout_uninit(&am->out_layout);
+
     av_freep(am_p);
 }
 
 int ff_audio_mix(AudioMix *am, AudioData *src)
 {
+    int in_channels  = am->in_layout.nb_channels;
+    int out_channels = am->out_layout.nb_channels;
     int use_generic = 1;
     int len = src->nb_samples;
     int i, j;
@@ -442,16 +450,16 @@  int ff_audio_mix(AudioMix *am, AudioData *src)
         }
     }
     av_log(am->avr, AV_LOG_TRACE, "audio_mix: %d samples - %d to %d channels (%s)\n",
-            src->nb_samples, am->in_channels, am->out_channels,
+            src->nb_samples, in_channels, out_channels,
             use_generic ? am->func_descr_generic : am->func_descr);
 
     if (am->in_matrix_channels && am->out_matrix_channels) {
         uint8_t **data;
         uint8_t *data0[AVRESAMPLE_MAX_CHANNELS] = { NULL };
 
-        if (am->out_matrix_channels < am->out_channels ||
-             am->in_matrix_channels <  am->in_channels) {
-            for (i = 0, j = 0; i < FFMAX(am->in_channels, am->out_channels); i++) {
+        if (am->out_matrix_channels < out_channels ||
+             am->in_matrix_channels <  in_channels) {
+            for (i = 0, j = 0; i < FFMAX(in_channels, out_channels); i++) {
                 if (am->input_skip[i] || am->output_skip[i] || am->output_zero[i])
                     continue;
                 data0[j++] = src->data[i];
@@ -469,23 +477,25 @@  int ff_audio_mix(AudioMix *am, AudioData *src)
                     am->in_matrix_channels);
     }
 
-    if (am->out_matrix_channels < am->out_channels) {
-        for (i = 0; i < am->out_channels; i++)
+    if (am->out_matrix_channels < out_channels) {
+        for (i = 0; i < out_channels; i++)
             if (am->output_zero[i])
                 av_samples_set_silence(&src->data[i], 0, len, 1, am->fmt);
     }
 
-    ff_audio_data_set_channels(src, am->out_channels);
+    ff_audio_data_set_channels(src, out_channels);
 
     return 0;
 }
 
 int ff_audio_mix_get_matrix(AudioMix *am, double *matrix, int stride)
 {
+    int in_channels  = am->in_layout.nb_channels;
+    int out_channels = am->out_layout.nb_channels;
     int i, o, i0, o0;
 
-    if ( am->in_channels <= 0 ||  am->in_channels > AVRESAMPLE_MAX_CHANNELS ||
-        am->out_channels <= 0 || am->out_channels > AVRESAMPLE_MAX_CHANNELS) {
+    if (in_channels  <= 0 || in_channels > AVRESAMPLE_MAX_CHANNELS ||
+        out_channels <= 0 || out_channels > AVRESAMPLE_MAX_CHANNELS) {
         av_log(am->avr, AV_LOG_ERROR, "Invalid channel counts\n");
         return AVERROR(EINVAL);
     }
@@ -495,8 +505,8 @@  int ff_audio_mix_get_matrix(AudioMix *am, double *matrix, int stride)
         av_log(am->avr, AV_LOG_ERROR, "matrix is not set\n");               \
         return AVERROR(EINVAL);                                             \
     }                                                                       \
-    for (o = 0, o0 = 0; o < am->out_channels; o++) {                        \
-        for (i = 0, i0 = 0; i < am->in_channels; i++) {                     \
+    for (o = 0, o0 = 0; o < out_channels; o++) {                            \
+        for (i = 0, i0 = 0; i < in_channels; i++) {                         \
             if (am->input_skip[i] || am->output_zero[o])                    \
                 matrix[o * stride + i] = 0.0;                               \
             else                                                            \
@@ -529,6 +539,8 @@  int ff_audio_mix_get_matrix(AudioMix *am, double *matrix, int stride)
 
 static void reduce_matrix(AudioMix *am, const double *matrix, int stride)
 {
+    int in_channels  = am->in_layout.nb_channels;
+    int out_channels = am->out_layout.nb_channels;
     int i, o;
 
     memset(am->output_zero, 0, sizeof(am->output_zero));
@@ -536,11 +548,11 @@  static void reduce_matrix(AudioMix *am, const double *matrix, int stride)
     memset(am->output_skip, 0, sizeof(am->output_skip));
 
     /* exclude output channels if they can be zeroed instead of mixed */
-    for (o = 0; o < am->out_channels; o++) {
+    for (o = 0; o < out_channels; o++) {
         int zero = 1;
 
         /* check if the output is always silent */
-        for (i = 0; i < am->in_channels; i++) {
+        for (i = 0; i < in_channels; i++) {
             if (matrix[o * stride + i] != 0.0) {
                 zero = 0;
                 break;
@@ -548,8 +560,8 @@  static void reduce_matrix(AudioMix *am, const double *matrix, int stride)
         }
         /* check if the corresponding input channel makes a contribution to
            any output channel */
-        if (o < am->in_channels) {
-            for (i = 0; i < am->out_channels; i++) {
+        if (o < in_channels) {
+            for (i = 0; i < out_channels; i++) {
                 if (matrix[i * stride + o] != 0.0) {
                     zero = 0;
                     break;
@@ -559,7 +571,7 @@  static void reduce_matrix(AudioMix *am, const double *matrix, int stride)
         if (zero) {
             am->output_zero[o] = 1;
             am->out_matrix_channels--;
-            if (o < am->in_channels)
+            if (o < in_channels)
                 am->in_matrix_channels--;
         }
     }
@@ -571,10 +583,10 @@  static void reduce_matrix(AudioMix *am, const double *matrix, int stride)
 
     /* skip input channels that contribute fully only to the corresponding
        output channel */
-    for (i = 0; i < FFMIN(am->in_channels, am->out_channels); i++) {
+    for (i = 0; i < FFMIN(in_channels, out_channels); i++) {
         int skip = 1;
 
-        for (o = 0; o < am->out_channels; o++) {
+        for (o = 0; o < out_channels; o++) {
             int i0;
             if ((o != i && matrix[o * stride + i] != 0.0) ||
                 (o == i && matrix[o * stride + i] != 1.0)) {
@@ -584,7 +596,7 @@  static void reduce_matrix(AudioMix *am, const double *matrix, int stride)
             /* if the input contributes fully to the output, also check that no
                other inputs contribute to this output */
             if (o == i) {
-                for (i0 = 0; i0 < am->in_channels; i0++) {
+                for (i0 = 0; i0 < in_channels; i0++) {
                     if (i0 != i && matrix[o * stride + i0] != 0.0) {
                         skip = 0;
                         break;
@@ -598,10 +610,10 @@  static void reduce_matrix(AudioMix *am, const double *matrix, int stride)
         }
     }
     /* skip input channels that do not contribute to any output channel */
-    for (; i < am->in_channels; i++) {
+    for (; i < in_channels; i++) {
         int contrib = 0;
 
-        for (o = 0; o < am->out_channels; o++) {
+        for (o = 0; o < out_channels; o++) {
             if (matrix[o * stride + i] != 0.0) {
                 contrib = 1;
                 break;
@@ -619,11 +631,11 @@  static void reduce_matrix(AudioMix *am, const double *matrix, int stride)
 
     /* skip output channels that only get full contribution from the
        corresponding input channel */
-    for (o = 0; o < FFMIN(am->in_channels, am->out_channels); o++) {
+    for (o = 0; o < FFMIN(in_channels, out_channels); o++) {
         int skip = 1;
         int o0;
 
-        for (i = 0; i < am->in_channels; i++) {
+        for (i = 0; i < in_channels; i++) {
             if ((o != i && matrix[o * stride + i] != 0.0) ||
                 (o == i && matrix[o * stride + i] != 1.0)) {
                 skip = 0;
@@ -633,7 +645,7 @@  static void reduce_matrix(AudioMix *am, const double *matrix, int stride)
         /* check if the corresponding input channel makes a contribution to
            any other output channel */
         i = o;
-        for (o0 = 0; o0 < am->out_channels; o0++) {
+        for (o0 = 0; o0 < out_channels; o0++) {
             if (o0 != i && matrix[o0 * stride + i] != 0.0) {
                 skip = 0;
                 break;
@@ -653,11 +665,15 @@  static void reduce_matrix(AudioMix *am, const double *matrix, int stride)
 int ff_audio_mix_set_matrix(AudioMix *am, const double *matrix, int stride)
 {
     int i, o, i0, o0, ret;
-    char in_layout_name[128];
-    char out_layout_name[128];
-
-    if ( am->in_channels <= 0 ||  am->in_channels > AVRESAMPLE_MAX_CHANNELS ||
-        am->out_channels <= 0 || am->out_channels > AVRESAMPLE_MAX_CHANNELS) {
+    int in_channels  = am->in_layout.nb_channels;
+    int out_channels = am->out_layout.nb_channels;
+    char *in_layout_name;
+    char *out_layout_name;
+
+    if (!av_channel_layout_check(&am->in_layout) ||
+        !av_channel_layout_check(&am->out_layout) ||
+        am->in_layout.nb_channels > AVRESAMPLE_MAX_CHANNELS ||
+        am->out_layout.nb_channels > AVRESAMPLE_MAX_CHANNELS) {
         av_log(am->avr, AV_LOG_ERROR, "Invalid channel counts\n");
         return AVERROR(EINVAL);
     }
@@ -667,8 +683,8 @@  int ff_audio_mix_set_matrix(AudioMix *am, const double *matrix, int stride)
         am->matrix = NULL;
     }
 
-    am->in_matrix_channels  = am->in_channels;
-    am->out_matrix_channels = am->out_channels;
+    am->in_matrix_channels  = am->in_layout.nb_channels;
+    am->out_matrix_channels = am->out_layout.nb_channels;
 
     reduce_matrix(am, matrix, stride);
 
@@ -678,13 +694,13 @@  int ff_audio_mix_set_matrix(AudioMix *am, const double *matrix, int stride)
                                        sizeof(*am->matrix_## type[0]));     \
     if (!am->matrix_## type[0])                                             \
         return AVERROR(ENOMEM);                                             \
-    for (o = 0, o0 = 0; o < am->out_channels; o++) {                        \
+    for (o = 0, o0 = 0; o < out_channels; o++) {                            \
         if (am->output_zero[o] || am->output_skip[o])                       \
             continue;                                                       \
         if (o0 > 0)                                                         \
             am->matrix_## type[o0] = am->matrix_## type[o0 - 1] +           \
                                      am->in_matrix_channels;                \
-        for (i = 0, i0 = 0; i < am->in_channels; i++) {                     \
+        for (i = 0, i0 = 0; i < in_channels; i++) {                         \
             double v;                                                       \
             if (am->input_skip[i] || am->output_zero[i])                    \
                 continue;                                                   \
@@ -717,26 +733,28 @@  int ff_audio_mix_set_matrix(AudioMix *am, const double *matrix, int stride)
     if (ret < 0)
         return ret;
 
-    av_get_channel_layout_string(in_layout_name, sizeof(in_layout_name),
-                                 am->in_channels, am->in_layout);
-    av_get_channel_layout_string(out_layout_name, sizeof(out_layout_name),
-                                 am->out_channels, am->out_layout);
-    av_log(am->avr, AV_LOG_DEBUG, "audio_mix: %s to %s\n",
-           in_layout_name, out_layout_name);
+    in_layout_name  = av_channel_layout_describe(&am->in_layout);
+    out_layout_name = av_channel_layout_describe(&am->out_layout);
+    if (in_layout_name && out_layout_name)
+        av_log(am->avr, AV_LOG_DEBUG, "audio_mix: %s to %s\n",
+               in_layout_name, out_layout_name);
     av_log(am->avr, AV_LOG_DEBUG, "matrix size: %d x %d\n",
            am->in_matrix_channels, am->out_matrix_channels);
-    for (o = 0; o < am->out_channels; o++) {
-        for (i = 0; i < am->in_channels; i++) {
+    for (o = 0; o < out_channels; o++) {
+        for (i = 0; i < in_channels; i++) {
             if (am->output_zero[o])
                 av_log(am->avr, AV_LOG_DEBUG, "  (ZERO)");
             else if (am->input_skip[i] || am->output_zero[i] || am->output_skip[o])
                 av_log(am->avr, AV_LOG_DEBUG, "  (SKIP)");
             else
                 av_log(am->avr, AV_LOG_DEBUG, "  %0.3f ",
-                       matrix[o * am->in_channels + i]);
+                       matrix[o * in_channels + i]);
         }
         av_log(am->avr, AV_LOG_DEBUG, "\n");
     }
 
+    av_freep(&in_layout_name);
+    av_freep(&out_layout_name);
+
     return 0;
 }
diff --git a/libavresample/audio_mix_matrix.c b/libavresample/audio_mix_matrix.c
index 5182ae1bf9..a5a16edca1 100644
--- a/libavresample/audio_mix_matrix.c
+++ b/libavresample/audio_mix_matrix.c
@@ -21,6 +21,7 @@ 
 
 #include <stdint.h>
 
+#include "libavutil/channel_layout.h"
 #include "libavutil/common.h"
 #include "libavutil/libm.h"
 #include "libavutil/samplefmt.h"
@@ -29,33 +30,6 @@ 
 #include "audio_data.h"
 #include "audio_mix.h"
 
-/* channel positions */
-#define FRONT_LEFT              0
-#define FRONT_RIGHT             1
-#define FRONT_CENTER            2
-#define LOW_FREQUENCY           3
-#define BACK_LEFT               4
-#define BACK_RIGHT              5
-#define FRONT_LEFT_OF_CENTER    6
-#define FRONT_RIGHT_OF_CENTER   7
-#define BACK_CENTER             8
-#define SIDE_LEFT               9
-#define SIDE_RIGHT             10
-#define TOP_CENTER             11
-#define TOP_FRONT_LEFT         12
-#define TOP_FRONT_CENTER       13
-#define TOP_FRONT_RIGHT        14
-#define TOP_BACK_LEFT          15
-#define TOP_BACK_CENTER        16
-#define TOP_BACK_RIGHT         17
-#define STEREO_LEFT            29
-#define STEREO_RIGHT           30
-#define WIDE_LEFT              31
-#define WIDE_RIGHT             32
-#define SURROUND_DIRECT_LEFT   33
-#define SURROUND_DIRECT_RIGHT  34
-#define LOW_FREQUENCY_2        35
-
 #define SQRT3_2      1.22474487139158904909  /* sqrt(3/2) */
 
 static av_always_inline int even(uint64_t layout)
@@ -63,232 +37,313 @@  static av_always_inline int even(uint64_t layout)
     return (!layout || !!(layout & (layout - 1)));
 }
 
-static int sane_layout(uint64_t layout)
+static int sane_layout(const AVChannelLayout *layout)
 {
     /* check that there is at least 1 front speaker */
-    if (!(layout & AV_CH_LAYOUT_SURROUND))
+    if (!av_channel_layout_subset(layout, AV_CH_LAYOUT_SURROUND))
         return 0;
 
     /* check for left/right symmetry */
-    if (!even(layout & (AV_CH_FRONT_LEFT           | AV_CH_FRONT_RIGHT))           ||
-        !even(layout & (AV_CH_SIDE_LEFT            | AV_CH_SIDE_RIGHT))            ||
-        !even(layout & (AV_CH_BACK_LEFT            | AV_CH_BACK_RIGHT))            ||
-        !even(layout & (AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER)) ||
-        !even(layout & (AV_CH_TOP_FRONT_LEFT       | AV_CH_TOP_FRONT_RIGHT))       ||
-        !even(layout & (AV_CH_TOP_BACK_LEFT        | AV_CH_TOP_BACK_RIGHT))        ||
-        !even(layout & (AV_CH_STEREO_LEFT          | AV_CH_STEREO_RIGHT))          ||
-        !even(layout & (AV_CH_WIDE_LEFT            | AV_CH_WIDE_RIGHT))            ||
-        !even(layout & (AV_CH_SURROUND_DIRECT_LEFT | AV_CH_SURROUND_DIRECT_RIGHT)))
+    if (!even(av_channel_layout_subset(layout, (AV_CH_FRONT_LEFT           | AV_CH_FRONT_RIGHT)))           ||
+        !even(av_channel_layout_subset(layout, (AV_CH_SIDE_LEFT            | AV_CH_SIDE_RIGHT)))            ||
+        !even(av_channel_layout_subset(layout, (AV_CH_BACK_LEFT            | AV_CH_BACK_RIGHT)))            ||
+        !even(av_channel_layout_subset(layout, (AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER))) ||
+        !even(av_channel_layout_subset(layout, (AV_CH_TOP_FRONT_LEFT       | AV_CH_TOP_FRONT_RIGHT)))       ||
+        !even(av_channel_layout_subset(layout, (AV_CH_TOP_BACK_LEFT        | AV_CH_TOP_BACK_RIGHT)))        ||
+        !even(av_channel_layout_subset(layout, (AV_CH_STEREO_LEFT          | AV_CH_STEREO_RIGHT)))          ||
+        !even(av_channel_layout_subset(layout, (AV_CH_WIDE_LEFT            | AV_CH_WIDE_RIGHT)))            ||
+        !even(av_channel_layout_subset(layout, (AV_CH_SURROUND_DIRECT_LEFT | AV_CH_SURROUND_DIRECT_RIGHT))))
         return 0;
 
     return 1;
 }
 
-int avresample_build_matrix(uint64_t in_layout, uint64_t out_layout,
-                            double center_mix_level, double surround_mix_level,
-                            double lfe_mix_level, int normalize,
-                            double *matrix_out, int stride,
-                            enum AVMatrixEncoding matrix_encoding)
+#define IDX_OUT(ch) (av_channel_layout_channel_index(out_layout, ch))
+
+int avresample_build_matrix2(const AVChannelLayout *in_layout,
+                             const AVChannelLayout *out_layout,
+                             double center_mix_level, double surround_mix_level,
+                             double lfe_mix_level, int normalize,
+                             double *matrix, int stride,
+                             enum AVMatrixEncoding matrix_encoding)
 {
-    int i, j, out_i, out_j;
-    double matrix[64][64] = {{0}};
-    int64_t unaccounted;
+    static const AVChannelLayout stereo = AV_CHANNEL_LAYOUT_STEREO;
+    int i, j;
     double maxcoef = 0;
-    int in_channels, out_channels;
-
-    if ((out_layout & AV_CH_LAYOUT_STEREO_DOWNMIX) == AV_CH_LAYOUT_STEREO_DOWNMIX) {
-        out_layout = AV_CH_LAYOUT_STEREO;
-    }
-
-    unaccounted = in_layout & ~out_layout;
-
-    in_channels  = av_get_channel_layout_nb_channels( in_layout);
-    out_channels = av_get_channel_layout_nb_channels(out_layout);
-
-    memset(matrix_out, 0, out_channels * stride * sizeof(*matrix_out));
+    int idx_in, idx_out, idx_r, idx_l;
+    int in_channels  = in_layout->nb_channels;
+    int out_channels = out_layout->nb_channels;;
 
     /* check if layouts are supported */
-    if (!in_layout || in_channels > AVRESAMPLE_MAX_CHANNELS)
+    if (!av_channel_layout_check(in_layout) ||
+        in_channels > AVRESAMPLE_MAX_CHANNELS)
         return AVERROR(EINVAL);
-    if (!out_layout || out_channels > AVRESAMPLE_MAX_CHANNELS)
+    if (!av_channel_layout_check(out_layout) ||
+        out_channels > AVRESAMPLE_MAX_CHANNELS)
         return AVERROR(EINVAL);
 
     /* check if layouts are unbalanced or abnormal */
     if (!sane_layout(in_layout) || !sane_layout(out_layout))
         return AVERROR_PATCHWELCOME;
 
-    /* route matching input/output channels */
-    for (i = 0; i < 64; i++) {
-        if (in_layout & out_layout & (1ULL << i))
-            matrix[i][i] = 1.0;
-    }
+    if (out_channels == 2                  &&
+        IDX_OUT(AV_CHAN_STEREO_LEFT)  >= 0 &&
+        IDX_OUT(AV_CHAN_STEREO_RIGHT) >= 0)
+        out_layout = &stereo;
+
+    memset(matrix, 0, out_channels * stride * sizeof(*matrix));
 
-    /* mix front center to front left/right */
-    if (unaccounted & AV_CH_FRONT_CENTER) {
-        if ((out_layout & AV_CH_LAYOUT_STEREO) == AV_CH_LAYOUT_STEREO) {
-            if ((in_layout & AV_CH_LAYOUT_STEREO) == AV_CH_LAYOUT_STEREO) {
-                matrix[FRONT_LEFT ][FRONT_CENTER] += center_mix_level;
-                matrix[FRONT_RIGHT][FRONT_CENTER] += center_mix_level;
+    for (idx_in = 0; idx_in < in_channels; idx_in++) {
+        enum AVChannel in_ch = av_channel_layout_get_channel(in_layout, idx_in);
+
+        idx_out = IDX_OUT(in_ch);
+
+        /* check if the input channel is also present in output */
+        if (idx_out >= 0) {
+            if (in_ch == AV_CHAN_FRONT_CENTER &&
+                av_channel_layout_subset(in_layout,   AV_CH_LAYOUT_STEREO) == AV_CH_LAYOUT_STEREO &&
+                !av_channel_layout_subset(out_layout, AV_CH_LAYOUT_STEREO)) {
+                /* mix left/right/center to center */
+                matrix[idx_out * stride + idx_in] = center_mix_level * M_SQRT2;
             } else {
-                matrix[FRONT_LEFT ][FRONT_CENTER] += M_SQRT1_2;
-                matrix[FRONT_RIGHT][FRONT_CENTER] += M_SQRT1_2;
+                /* just copy it */
+                matrix[idx_out * stride + idx_in] = 1.0;
             }
-        } else
-            return AVERROR_PATCHWELCOME;
-    }
-    /* mix front left/right to center */
-    if (unaccounted & AV_CH_LAYOUT_STEREO) {
-        if (out_layout & AV_CH_FRONT_CENTER) {
-            matrix[FRONT_CENTER][FRONT_LEFT ] += M_SQRT1_2;
-            matrix[FRONT_CENTER][FRONT_RIGHT] += M_SQRT1_2;
-            /* mix left/right/center to center */
-            if (in_layout & AV_CH_FRONT_CENTER)
-                matrix[FRONT_CENTER][FRONT_CENTER] = center_mix_level * M_SQRT2;
-        } else
-            return AVERROR_PATCHWELCOME;
-    }
-    /* mix back center to back, side, or front */
-    if (unaccounted & AV_CH_BACK_CENTER) {
-        if (out_layout & AV_CH_BACK_LEFT) {
-            matrix[BACK_LEFT ][BACK_CENTER] += M_SQRT1_2;
-            matrix[BACK_RIGHT][BACK_CENTER] += M_SQRT1_2;
-        } else if (out_layout & AV_CH_SIDE_LEFT) {
-            matrix[SIDE_LEFT ][BACK_CENTER] += M_SQRT1_2;
-            matrix[SIDE_RIGHT][BACK_CENTER] += M_SQRT1_2;
-        } else if (out_layout & AV_CH_FRONT_LEFT) {
-            if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY ||
-                matrix_encoding == AV_MATRIX_ENCODING_DPLII) {
-                if (unaccounted & (AV_CH_BACK_LEFT | AV_CH_SIDE_LEFT)) {
-                    matrix[FRONT_LEFT ][BACK_CENTER] -= surround_mix_level * M_SQRT1_2;
-                    matrix[FRONT_RIGHT][BACK_CENTER] += surround_mix_level * M_SQRT1_2;
+
+            continue;
+        }
+
+        /* the input channel is not present in the output layout */
+
+        /* mix front center to front left/right */
+        if (in_ch == AV_CHAN_FRONT_CENTER) {
+            int idx_l = IDX_OUT(AV_CHAN_FRONT_LEFT);
+            int idx_r = IDX_OUT(AV_CHAN_FRONT_RIGHT);
+            if (idx_l >= 0 && idx_r >= 0) {
+                matrix[idx_l * stride + idx_in] += M_SQRT1_2;
+                matrix[idx_r * stride + idx_in] += M_SQRT1_2;
+            }
+        }
+
+        /* mix front left/right to center */
+        if (in_ch == AV_CHAN_FRONT_LEFT || in_ch == AV_CHAN_FRONT_RIGHT) {
+            idx_out = IDX_OUT(AV_CHAN_FRONT_CENTER);
+            if (idx_out >= 0)
+                matrix[idx_out * stride + idx_in] += M_SQRT1_2;
+        }
+
+        /* mix back center to back, side, or front */
+        if (in_ch == AV_CHAN_BACK_CENTER) {
+            int idx_l = IDX_OUT(AV_CHAN_BACK_LEFT);
+            int idx_r = IDX_OUT(AV_CHAN_BACK_RIGHT);
+            if (idx_l >= 0 && idx_r >= 0) {
+                matrix[idx_l * stride + idx_in] += M_SQRT1_2;
+                matrix[idx_r * stride + idx_in] += M_SQRT1_2;
+                continue;
+            }
+
+            idx_l = IDX_OUT(AV_CHAN_SIDE_LEFT);
+            idx_r = IDX_OUT(AV_CHAN_SIDE_RIGHT);
+            if (idx_l >= 0 && idx_r >= 0) {
+                matrix[idx_l * stride + idx_in] += M_SQRT1_2;
+                matrix[idx_r * stride + idx_in] += M_SQRT1_2;
+                continue;
+            }
+
+            idx_l = IDX_OUT(AV_CHAN_FRONT_LEFT);
+            idx_r = IDX_OUT(AV_CHAN_FRONT_RIGHT);
+            if (idx_l >= 0 && idx_r >= 0) {
+                if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY ||
+                    matrix_encoding == AV_MATRIX_ENCODING_DPLII) {
+                    if (!av_channel_layout_subset(out_layout, AV_CH_BACK_LEFT | AV_CH_SIDE_LEFT) &&
+                         av_channel_layout_subset(in_layout,  AV_CH_BACK_LEFT | AV_CH_SIDE_LEFT)) {
+                        matrix[idx_l * stride + idx_in] -= surround_mix_level * M_SQRT1_2;
+                        matrix[idx_r * stride + idx_in] += surround_mix_level * M_SQRT1_2;
+                    } else {
+                        matrix[idx_l * stride + idx_in] -= surround_mix_level;
+                        matrix[idx_r * stride + idx_in] += surround_mix_level;
+                    }
                 } else {
-                    matrix[FRONT_LEFT ][BACK_CENTER] -= surround_mix_level;
-                    matrix[FRONT_RIGHT][BACK_CENTER] += surround_mix_level;
+                    matrix[idx_l * stride + idx_in] += surround_mix_level * M_SQRT1_2;
+                    matrix[idx_r * stride + idx_in] += surround_mix_level * M_SQRT1_2;
                 }
-            } else {
-                matrix[FRONT_LEFT ][BACK_CENTER] += surround_mix_level * M_SQRT1_2;
-                matrix[FRONT_RIGHT][BACK_CENTER] += surround_mix_level * M_SQRT1_2;
+                continue;
             }
-        } else if (out_layout & AV_CH_FRONT_CENTER) {
-            matrix[FRONT_CENTER][BACK_CENTER] += surround_mix_level * M_SQRT1_2;
-        } else
-            return AVERROR_PATCHWELCOME;
-    }
-    /* mix back left/right to back center, side, or front */
-    if (unaccounted & AV_CH_BACK_LEFT) {
-        if (out_layout & AV_CH_BACK_CENTER) {
-            matrix[BACK_CENTER][BACK_LEFT ] += M_SQRT1_2;
-            matrix[BACK_CENTER][BACK_RIGHT] += M_SQRT1_2;
-        } else if (out_layout & AV_CH_SIDE_LEFT) {
-            /* if side channels do not exist in the input, just copy back
-               channels to side channels, otherwise mix back into side */
-            if (in_layout & AV_CH_SIDE_LEFT) {
-                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;
+
+            idx_out = IDX_OUT(AV_CHAN_FRONT_CENTER);
+            if (idx_out >= 0) {
+                matrix[idx_out * stride + idx_in] += surround_mix_level * M_SQRT1_2;
+                continue;
             }
-        } else if (out_layout & AV_CH_FRONT_LEFT) {
-            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;
-                matrix[FRONT_RIGHT][BACK_LEFT ] += surround_mix_level * M_SQRT1_2;
-                matrix[FRONT_RIGHT][BACK_RIGHT] += surround_mix_level * M_SQRT1_2;
-            } else if (matrix_encoding == AV_MATRIX_ENCODING_DPLII) {
-                matrix[FRONT_LEFT ][BACK_LEFT ] -= surround_mix_level * SQRT3_2;
-                matrix[FRONT_LEFT ][BACK_RIGHT] -= surround_mix_level * M_SQRT1_2;
-                matrix[FRONT_RIGHT][BACK_LEFT ] += surround_mix_level * M_SQRT1_2;
-                matrix[FRONT_RIGHT][BACK_RIGHT] += surround_mix_level * SQRT3_2;
-            } else {
-                matrix[FRONT_LEFT ][BACK_LEFT ] += surround_mix_level;
-                matrix[FRONT_RIGHT][BACK_RIGHT] += surround_mix_level;
+        }
+
+        /* mix back left/right to back center, side, or front */
+        if (in_ch == AV_CHAN_BACK_LEFT || in_ch == AV_CHAN_BACK_RIGHT) {
+            idx_out = IDX_OUT(AV_CHAN_BACK_CENTER);
+            if (idx_out >= 0) {
+                matrix[idx_out * stride + idx_in] += M_SQRT1_2;
+                continue;
             }
-        } else if (out_layout & AV_CH_FRONT_CENTER) {
-            matrix[FRONT_CENTER][BACK_LEFT ] += surround_mix_level * M_SQRT1_2;
-            matrix[FRONT_CENTER][BACK_RIGHT] += surround_mix_level * M_SQRT1_2;
-        } else
-            return AVERROR_PATCHWELCOME;
-    }
-    /* mix side left/right into back or front */
-    if (unaccounted & AV_CH_SIDE_LEFT) {
-        if (out_layout & AV_CH_BACK_LEFT) {
-            /* if back channels do not exist in the input, just copy side
-               channels to back channels, otherwise mix side into back */
-            if (in_layout & AV_CH_BACK_LEFT) {
-                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;
+
+            idx_out = IDX_OUT(in_ch == AV_CHAN_BACK_LEFT ? AV_CHAN_SIDE_LEFT :
+                                                           AV_CHAN_SIDE_RIGHT);
+            if (idx_out >= 0) {
+                /* if side channels do not exist in the input, just copy back
+                   channels to side channels, otherwise mix back into side */
+                if (av_channel_layout_subset(in_layout, AV_CH_SIDE_LEFT))
+                    matrix[idx_out * stride + idx_in] += M_SQRT1_2;
+                else
+                    matrix[idx_out * stride + idx_in] += 1.0;
+
+                continue;
             }
-        } else if (out_layout & AV_CH_BACK_CENTER) {
-            matrix[BACK_CENTER][SIDE_LEFT ] += M_SQRT1_2;
-            matrix[BACK_CENTER][SIDE_RIGHT] += M_SQRT1_2;
-        } else if (out_layout & AV_CH_FRONT_LEFT) {
-            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;
-                matrix[FRONT_RIGHT][SIDE_LEFT ] += surround_mix_level * M_SQRT1_2;
-                matrix[FRONT_RIGHT][SIDE_RIGHT] += surround_mix_level * M_SQRT1_2;
-            } else if (matrix_encoding == AV_MATRIX_ENCODING_DPLII) {
-                matrix[FRONT_LEFT ][SIDE_LEFT ] -= surround_mix_level * SQRT3_2;
-                matrix[FRONT_LEFT ][SIDE_RIGHT] -= surround_mix_level * M_SQRT1_2;
-                matrix[FRONT_RIGHT][SIDE_LEFT ] += surround_mix_level * M_SQRT1_2;
-                matrix[FRONT_RIGHT][SIDE_RIGHT] += surround_mix_level * SQRT3_2;
-            } else {
-                matrix[FRONT_LEFT ][SIDE_LEFT ] += surround_mix_level;
-                matrix[FRONT_RIGHT][SIDE_RIGHT] += surround_mix_level;
+
+            idx_l = IDX_OUT(AV_CHAN_FRONT_LEFT);
+            idx_r = IDX_OUT(AV_CHAN_FRONT_RIGHT);
+            if (idx_l >= 0 && idx_r >= 0) {
+                if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY) {
+                    matrix[idx_l * stride + idx_in] -= surround_mix_level * M_SQRT1_2;
+                    matrix[idx_r * stride + idx_in] += surround_mix_level * M_SQRT1_2;
+                } else if (matrix_encoding == AV_MATRIX_ENCODING_DPLII) {
+                    if (in_ch == AV_CHAN_BACK_LEFT) {
+                        matrix[idx_l * stride + idx_in] -= surround_mix_level * SQRT3_2;
+                        matrix[idx_r * stride + idx_in] += surround_mix_level * M_SQRT1_2;
+                    } else {
+                        matrix[idx_l * stride + idx_in] -= surround_mix_level * M_SQRT1_2;
+                        matrix[idx_r * stride + idx_in] += surround_mix_level * SQRT3_2;
+                    }
+                } else {
+                    idx_out = (in_ch == AV_CHAN_BACK_LEFT) ? idx_l : idx_r;
+                    matrix[idx_out * stride + idx_in] += surround_mix_level;
+                }
+
+                continue;
             }
-        } else if (out_layout & AV_CH_FRONT_CENTER) {
-            matrix[FRONT_CENTER][SIDE_LEFT ] += surround_mix_level * M_SQRT1_2;
-            matrix[FRONT_CENTER][SIDE_RIGHT] += surround_mix_level * M_SQRT1_2;
-        } else
-            return AVERROR_PATCHWELCOME;
-    }
-    /* mix left-of-center/right-of-center into front left/right or center */
-    if (unaccounted & AV_CH_FRONT_LEFT_OF_CENTER) {
-        if (out_layout & AV_CH_FRONT_LEFT) {
-            matrix[FRONT_LEFT ][FRONT_LEFT_OF_CENTER ] += 1.0;
-            matrix[FRONT_RIGHT][FRONT_RIGHT_OF_CENTER] += 1.0;
-        } else if (out_layout & AV_CH_FRONT_CENTER) {
-            matrix[FRONT_CENTER][FRONT_LEFT_OF_CENTER ] += M_SQRT1_2;
-            matrix[FRONT_CENTER][FRONT_RIGHT_OF_CENTER] += M_SQRT1_2;
-        } else
-            return AVERROR_PATCHWELCOME;
-    }
-    /* mix LFE into front left/right or center */
-    if (unaccounted & AV_CH_LOW_FREQUENCY) {
-        if (out_layout & AV_CH_FRONT_CENTER) {
-            matrix[FRONT_CENTER][LOW_FREQUENCY] += lfe_mix_level;
-        } else if (out_layout & AV_CH_FRONT_LEFT) {
-            matrix[FRONT_LEFT ][LOW_FREQUENCY] += lfe_mix_level * M_SQRT1_2;
-            matrix[FRONT_RIGHT][LOW_FREQUENCY] += lfe_mix_level * M_SQRT1_2;
-        } else
-            return AVERROR_PATCHWELCOME;
+
+            idx_out = IDX_OUT(AV_CHAN_FRONT_CENTER);
+            if (idx_out >= 0) {
+                matrix[idx_out * stride + idx_in] += surround_mix_level * M_SQRT1_2;
+                continue;
+            }
+        }
+
+        /* mix side left/right into back or front */
+        if (in_ch == AV_CHAN_SIDE_LEFT || in_ch == AV_CHAN_SIDE_RIGHT) {
+            idx_out = IDX_OUT(in_ch == AV_CHAN_SIDE_LEFT ? AV_CHAN_BACK_LEFT :
+                                                           AV_CHAN_BACK_RIGHT);
+            if (idx_out >= 0) {
+                /* if back channels do not exist in the input, just copy side
+                   channels to back channels, otherwise mix side into back */
+                if (av_channel_layout_subset(in_layout, AV_CH_BACK_LEFT))
+                    matrix[idx_out * stride + idx_in] += M_SQRT1_2;
+                else
+                    matrix[idx_out * stride + idx_in] += 1.0;
+
+                continue;
+            }
+
+            idx_out = IDX_OUT(AV_CHAN_BACK_CENTER);
+            if (idx_out >= 0) {
+                matrix[idx_out * stride + idx_in] += M_SQRT1_2;
+                continue;
+            }
+
+
+            idx_l = IDX_OUT(AV_CHAN_FRONT_LEFT);
+            idx_r = IDX_OUT(AV_CHAN_FRONT_RIGHT);
+            if (idx_l >= 0 && idx_r >= 0) {
+                if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY) {
+                    matrix[idx_l * stride + idx_in] -= surround_mix_level * M_SQRT1_2;
+                    matrix[idx_r * stride + idx_in] += surround_mix_level * M_SQRT1_2;
+                } else if (matrix_encoding == AV_MATRIX_ENCODING_DPLII) {
+                    if (in_ch == AV_CHAN_SIDE_LEFT) {
+                        matrix[idx_l * stride + idx_in] -= surround_mix_level * SQRT3_2;
+                        matrix[idx_r * stride + idx_in] += surround_mix_level * M_SQRT1_2;
+                    } else {
+                        matrix[idx_l * stride + idx_in] -= surround_mix_level * M_SQRT1_2;
+                        matrix[idx_r * stride + idx_in] += surround_mix_level * SQRT3_2;
+                    }
+                } else {
+                    idx_out = (in_ch == AV_CHAN_SIDE_LEFT) ? idx_l : idx_r;
+                    matrix[idx_out * stride + idx_in] += surround_mix_level;
+                }
+
+                continue;
+            }
+
+            idx_out = IDX_OUT(AV_CHAN_FRONT_CENTER);
+            if (idx_out >= 0) {
+                matrix[idx_out * stride + idx_in] += surround_mix_level * M_SQRT1_2;
+                continue;
+            }
+        }
+
+        /* mix left-of-center/right-of-center into front left/right or center */
+        if (in_ch == AV_CHAN_FRONT_LEFT_OF_CENTER ||
+            in_ch == AV_CHAN_FRONT_RIGHT_OF_CENTER) {
+            idx_out = IDX_OUT(in_ch == AV_CHAN_FRONT_LEFT_OF_CENTER ?
+                              AV_CHAN_FRONT_LEFT : AV_CHAN_FRONT_RIGHT);
+            if (idx_out >= 0) {
+                matrix[idx_out * stride + idx_in] += 1.0;
+                continue;
+            }
+
+            idx_out = IDX_OUT(AV_CHAN_FRONT_CENTER);
+            if (idx_out >= 0) {
+                matrix[idx_out * stride + idx_in] += M_SQRT1_2;
+                continue;
+            }
+        }
+
+        /* mix LFE into front left/right or center */
+        if (in_ch == AV_CHAN_LOW_FREQUENCY) {
+            idx_out = IDX_OUT(AV_CHAN_FRONT_CENTER);
+            if (idx_out >= 0) {
+                matrix[idx_out * stride + idx_in] += lfe_mix_level;
+                continue;
+            }
+
+            idx_l = IDX_OUT(AV_CHAN_FRONT_LEFT);
+            idx_r = IDX_OUT(AV_CHAN_FRONT_RIGHT);
+            if (idx_l >= 0 && idx_r >= 0) {
+                matrix[idx_l * stride + idx_in] += lfe_mix_level * M_SQRT1_2;
+                matrix[idx_r * stride + idx_in] += lfe_mix_level * M_SQRT1_2;
+                continue;
+            }
+        }
     }
 
-    /* transfer internal matrix to output matrix and calculate maximum
-       per-channel coefficient sum */
-    for (out_i = i = 0; out_i < out_channels && i < 64; i++) {
+    /* calculate maximum per-channel coefficient sum */
+    for (idx_out = 0; idx_out < out_channels; idx_out++) {
         double sum = 0;
-        for (out_j = j = 0; out_j < in_channels && j < 64; j++) {
-            matrix_out[out_i * stride + out_j] = matrix[i][j];
-            sum += fabs(matrix[i][j]);
-            if (in_layout & (1ULL << j))
-                out_j++;
-        }
+        for (idx_in = 0; idx_in < in_channels; idx_in++)
+            sum += fabs(matrix[idx_out * stride + idx_in]);
         maxcoef = FFMAX(maxcoef, sum);
-        if (out_layout & (1ULL << i))
-            out_i++;
     }
 
     /* normalize */
     if (normalize && maxcoef > 1.0) {
         for (i = 0; i < out_channels; i++)
             for (j = 0; j < in_channels; j++)
-                matrix_out[i * stride + j] /= maxcoef;
+                matrix[i * stride + j] /= maxcoef;
     }
 
     return 0;
 }
+
+#if FF_API_OLD_CHANNEL_LAYOUT
+int avresample_build_matrix(uint64_t in_layout, uint64_t out_layout,
+                            double center_mix_level, double surround_mix_level,
+                            double lfe_mix_level, int normalize,
+                            double *matrix_out, int stride,
+                            enum AVMatrixEncoding matrix_encoding)
+{
+    AVChannelLayout in_chl, out_chl;
+
+    av_channel_layout_from_mask(&in_chl,  in_layout);
+    av_channel_layout_from_mask(&out_chl, out_layout);
+    return avresample_build_matrix2(&in_chl, &out_chl, center_mix_level,
+                                    surround_mix_level, lfe_mix_level, normalize,
+                                    matrix_out, stride, matrix_encoding);
+}
+#endif
diff --git a/libavresample/avresample.h b/libavresample/avresample.h
index 3f9b9433c1..5a60423470 100644
--- a/libavresample/avresample.h
+++ b/libavresample/avresample.h
@@ -44,8 +44,10 @@ 
  * matrix):
  * @code
  * AVAudioResampleContext *avr = avresample_alloc_context();
- * av_opt_set_int(avr, "in_channel_layout",  AV_CH_LAYOUT_5POINT1, 0);
- * av_opt_set_int(avr, "out_channel_layout", AV_CH_LAYOUT_STEREO,  0);
+ * AVChannelLayout in_ch_layout  = (AVChannelLayout)AV_CHANNEL_LAYOUT_5POINT1;
+ * AVChannelLayout out_ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO;
+ * av_opt_set_channel_layout(avr, "in_ch_layout",  &in_ch_layout,  0);
+ * av_opt_set_channel_layout(avr, "out_ch_layout", &out_ch_layout, 0);
  * av_opt_set_int(avr, "in_sample_rate",     48000,                0);
  * av_opt_set_int(avr, "out_sample_rate",    44100,                0);
  * av_opt_set_int(avr, "in_sample_fmt",      AV_SAMPLE_FMT_FLTP,   0);
@@ -92,6 +94,7 @@ 
  *  avresample_free().
  */
 
+#include "libavutil/attributes.h"
 #include "libavutil/avutil.h"
 #include "libavutil/channel_layout.h"
 #include "libavutil/dict.h"
@@ -167,7 +170,7 @@  AVAudioResampleContext *avresample_alloc_context(void);
 /**
  * Initialize AVAudioResampleContext.
  * @note The context must be configured using the AVOption API.
- * @note The fields "in_channel_layout", "out_channel_layout",
+ * @note The fields "in_ch_layout", "out_ch_layout",
  *       "in_sample_rate", "out_sample_rate", "in_sample_fmt",
  *       "out_sample_fmt" must be set.
  *
@@ -212,6 +215,7 @@  void avresample_close(AVAudioResampleContext *avr);
  */
 void avresample_free(AVAudioResampleContext **avr);
 
+#if FF_API_OLD_CHANNEL_LAYOUT
 /**
  * Generate a channel mixing matrix.
  *
@@ -233,11 +237,43 @@  void avresample_free(AVAudioResampleContext **avr);
  *                            matrix array
  * @param matrix_encoding     matrixed stereo downmix mode (e.g. dplii)
  * @return                    0 on success, negative AVERROR code on failure
+ *
+ * @deprecated use avresample_build_matrix2()
  */
+attribute_deprecated
 int avresample_build_matrix(uint64_t in_layout, uint64_t out_layout,
                             double center_mix_level, double surround_mix_level,
                             double lfe_mix_level, int normalize, double *matrix,
                             int stride, enum AVMatrixEncoding matrix_encoding);
+#endif
+
+/**
+ * Generate a channel mixing matrix.
+ *
+ * This function is the one used internally by libavresample 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 normalize           if 1, coefficients will be normalized to prevent
+ *                            overflow. if 0, 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)
+ * @return                    0 on success, negative AVERROR code on failure
+ */
+int avresample_build_matrix2(const AVChannelLayout *in_layout,
+                             const AVChannelLayout *out_layout,
+                             double center_mix_level, double surround_mix_level,
+                             double lfe_mix_level, int normalize, double *matrix,
+                             int stride, enum AVMatrixEncoding matrix_encoding);
 
 /**
  * Get the current channel mixing matrix.
diff --git a/libavresample/internal.h b/libavresample/internal.h
index b88b7587aa..a6bf2d400e 100644
--- a/libavresample/internal.h
+++ b/libavresample/internal.h
@@ -22,6 +22,7 @@ 
 #define AVRESAMPLE_INTERNAL_H
 
 #include "libavutil/audio_fifo.h"
+#include "libavutil/channel_layout.h"
 #include "libavutil/log.h"
 #include "libavutil/opt.h"
 #include "libavutil/samplefmt.h"
@@ -53,10 +54,17 @@  typedef struct ChannelMapInfo {
 struct AVAudioResampleContext {
     const AVClass *av_class;        /**< AVClass for logging and AVOptions  */
 
+#if FF_API_OLD_CHANNEL_LAYOUT
     uint64_t in_channel_layout;                 /**< input channel layout   */
+#endif
+    AVChannelLayout in_ch_layout;               /**< input channel layout   */
+
     enum AVSampleFormat in_sample_fmt;          /**< input sample format    */
     int in_sample_rate;                         /**< input sample rate      */
+#if FF_API_OLD_CHANNEL_LAYOUT
     uint64_t out_channel_layout;                /**< output channel layout  */
+#endif
+    AVChannelLayout out_ch_layout;              /**< output channel layout  */
     enum AVSampleFormat out_sample_fmt;         /**< output sample format   */
     int out_sample_rate;                        /**< output sample rate     */
     enum AVSampleFormat internal_sample_fmt;    /**< internal sample format */
@@ -74,8 +82,6 @@  struct AVAudioResampleContext {
     int kaiser_beta;                            /**< beta value for Kaiser window (only applicable if filter_type == AV_FILTER_TYPE_KAISER) */
     enum AVResampleDitherMethod dither_method;  /**< dither method          */
 
-    int in_channels;        /**< number of input channels                   */
-    int out_channels;       /**< number of output channels                  */
     int resample_channels;  /**< number of channels used for resampling     */
     int downmix_needed;     /**< downmixing is needed                       */
     int upmix_needed;       /**< upmixing is needed                         */
diff --git a/libavresample/options.c b/libavresample/options.c
index 6249f90115..78af61a6e1 100644
--- a/libavresample/options.c
+++ b/libavresample/options.c
@@ -36,10 +36,18 @@ 
 #define PARAM AV_OPT_FLAG_AUDIO_PARAM
 
 static const AVOption avresample_options[] = {
+#if FF_API_OLD_CHANNEL_LAYOUT
     { "in_channel_layout",      "Input Channel Layout",     OFFSET(in_channel_layout),      AV_OPT_TYPE_INT64,  { .i64 = 0              }, INT64_MIN,            INT64_MAX,              PARAM },
+#endif
+    { "in_ch_layout",           "Input Channel Layout",     OFFSET(in_ch_layout),           AV_OPT_TYPE_CHANNEL_LAYOUT,
+                                                                                                                { .str = NULL           },                                      .flags = PARAM },
     { "in_sample_fmt",          "Input Sample Format",      OFFSET(in_sample_fmt),          AV_OPT_TYPE_INT,    { .i64 = AV_SAMPLE_FMT_S16 }, AV_SAMPLE_FMT_U8,     AV_SAMPLE_FMT_NB-1,     PARAM },
     { "in_sample_rate",         "Input Sample Rate",        OFFSET(in_sample_rate),         AV_OPT_TYPE_INT,    { .i64 = 48000          }, 1,                    INT_MAX,                PARAM },
+#if FF_API_OLD_CHANNEL_LAYOUT
     { "out_channel_layout",     "Output Channel Layout",    OFFSET(out_channel_layout),     AV_OPT_TYPE_INT64,  { .i64 = 0              }, INT64_MIN,            INT64_MAX,              PARAM },
+#endif
+    { "out_ch_layout",          "Output Channel Layout",    OFFSET(out_ch_layout),          AV_OPT_TYPE_CHANNEL_LAYOUT,
+                                                                                                                { .str = NULL           },                                      .flags = PARAM },
     { "out_sample_fmt",         "Output Sample Format",     OFFSET(out_sample_fmt),         AV_OPT_TYPE_INT,    { .i64 = AV_SAMPLE_FMT_S16 }, AV_SAMPLE_FMT_U8,     AV_SAMPLE_FMT_NB-1,     PARAM },
     { "out_sample_rate",        "Output Sample Rate",       OFFSET(out_sample_rate),        AV_OPT_TYPE_INT,    { .i64 = 48000          }, 1,                    INT_MAX,                PARAM },
     { "internal_sample_fmt",    "Internal Sample Format",   OFFSET(internal_sample_fmt),    AV_OPT_TYPE_INT,    { .i64 = AV_SAMPLE_FMT_NONE }, AV_SAMPLE_FMT_NONE,   AV_SAMPLE_FMT_NB-1,     PARAM, "internal_sample_fmt" },
diff --git a/libavresample/tests/avresample.c b/libavresample/tests/avresample.c
index 77599960f8..19027b2df1 100644
--- a/libavresample/tests/avresample.c
+++ b/libavresample/tests/avresample.c
@@ -179,11 +179,11 @@  static const int rates[] = {
     16000
 };
 
-static const uint64_t layouts[] = {
-    AV_CH_LAYOUT_STEREO,
-    AV_CH_LAYOUT_MONO,
-    AV_CH_LAYOUT_5POINT1,
-    AV_CH_LAYOUT_7POINT1,
+static const AVChannelLayout layouts[] = {
+    AV_CHANNEL_LAYOUT_STEREO,
+    AV_CHANNEL_LAYOUT_MONO,
+    AV_CHANNEL_LAYOUT_5POINT1,
+    AV_CHANNEL_LAYOUT_7POINT1,
 };
 
 int main(int argc, char **argv)
@@ -199,12 +199,8 @@  int main(int argc, char **argv)
     uint8_t *out_data[AVRESAMPLE_MAX_CHANNELS] = { 0 };
     int in_linesize;
     int out_linesize;
-    uint64_t in_ch_layout;
-    int in_channels;
     enum AVSampleFormat in_fmt;
     int in_rate;
-    uint64_t out_ch_layout;
-    int out_channels;
     enum AVSampleFormat out_fmt;
     int out_rate;
     int num_formats, num_rates, num_layouts;
@@ -257,8 +253,8 @@  int main(int argc, char **argv)
     for (i = 0; i < num_formats; i++) {
         in_fmt = formats[i];
         for (k = 0; k < num_layouts; k++) {
-            in_ch_layout = layouts[k];
-            in_channels  = av_get_channel_layout_nb_channels(in_ch_layout);
+            AVChannelLayout in_ch_layout = layouts[k];
+            int in_channels = in_ch_layout.nb_channels;
             for (m = 0; m < num_rates; m++) {
                 in_rate = rates[m];
 
@@ -274,8 +270,8 @@  int main(int argc, char **argv)
                 for (j = 0; j < num_formats; j++) {
                     out_fmt = formats[j];
                     for (l = 0; l < num_layouts; l++) {
-                        out_ch_layout = layouts[l];
-                        out_channels  = av_get_channel_layout_nb_channels(out_ch_layout);
+                        AVChannelLayout out_ch_layout = layouts[l];
+                        int out_channels = out_ch_layout.nb_channels;
                         for (n = 0; n < num_rates; n++) {
                             out_rate = rates[n];
 
@@ -291,10 +287,10 @@  int main(int argc, char **argv)
                                 goto end;
                             }
 
-                            av_opt_set_int(s, "in_channel_layout",  in_ch_layout,  0);
+                            av_opt_set_channel_layout(s, "in_ch_layout",  &in_ch_layout,  0);
+                            av_opt_set_channel_layout(s, "out_ch_layout", &out_ch_layout, 0);
                             av_opt_set_int(s, "in_sample_fmt",      in_fmt,        0);
                             av_opt_set_int(s, "in_sample_rate",     in_rate,       0);
-                            av_opt_set_int(s, "out_channel_layout", out_ch_layout, 0);
                             av_opt_set_int(s, "out_sample_fmt",     out_fmt,       0);
                             av_opt_set_int(s, "out_sample_rate",    out_rate,      0);
 
diff --git a/libavresample/utils.c b/libavresample/utils.c
index bab2153b4b..15c827efbe 100644
--- a/libavresample/utils.c
+++ b/libavresample/utils.c
@@ -18,6 +18,7 @@ 
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include "libavutil/channel_layout.h"
 #include "libavutil/common.h"
 #include "libavutil/dict.h"
 #include "libavutil/error.h"
@@ -35,6 +36,7 @@ 
 
 int avresample_open(AVAudioResampleContext *avr)
 {
+    int in_ch, out_ch;
     int ret;
 
     if (avresample_is_open(avr)) {
@@ -42,24 +44,67 @@  int avresample_open(AVAudioResampleContext *avr)
         return AVERROR(EINVAL);
     }
 
+    if ( avr->in_ch_layout.order == AV_CHANNEL_ORDER_CUSTOM ||
+        avr->out_ch_layout.order == AV_CHANNEL_ORDER_CUSTOM) {
+        av_log(avr, AV_LOG_ERROR,
+              "Resampling a custom channel layout order is not supported.\n");
+       return AVERROR(ENOSYS);
+    }
+
+    if (avr->in_ch_layout.order == AV_CHANNEL_ORDER_UNSPEC) {
+        if (avr->in_ch_layout.nb_channels > 63) {
+           av_log(avr, AV_LOG_ERROR,
+                  "Unspecified channel layout order is supported only for up "
+                  "to 63 channels (got %d).\n", avr->in_ch_layout.nb_channels);
+           return AVERROR(ENOSYS);
+        }
+        av_channel_layout_default(&avr->in_ch_layout, avr->in_ch_layout.nb_channels);
+    }
+    if (avr->out_ch_layout.order == AV_CHANNEL_ORDER_UNSPEC) {
+        if (avr->out_ch_layout.nb_channels > 63) {
+           av_log(avr, AV_LOG_ERROR,
+                  "Unspecified channel layout order is supported only for up "
+                  "to 63 channels (got %d).\n", avr->out_ch_layout.nb_channels);
+           return AVERROR(ENOSYS);
+        }
+        av_channel_layout_default(&avr->out_ch_layout, avr->out_ch_layout.nb_channels);
+    }
+
     /* set channel mixing parameters */
-    avr->in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout);
-    if (avr->in_channels <= 0 || avr->in_channels > AVRESAMPLE_MAX_CHANNELS) {
-        av_log(avr, AV_LOG_ERROR, "Invalid input channel layout: %"PRIu64"\n",
-               avr->in_channel_layout);
+#if FF_API_OLD_CHANNEL_LAYOUT
+    if (avr->in_channel_layout) {
+        av_log(avr, AV_LOG_WARNING, "Setting the input channel layout with the "
+               "'in_channel_layout' option is deprecated, use the "
+               "'in_ch_layout' option instead].\n");
+        av_channel_layout_uninit(&avr->in_ch_layout);
+        av_channel_layout_from_mask(&avr->in_ch_layout, avr->in_channel_layout);
+    }
+    if (avr->out_channel_layout) {
+        av_log(avr, AV_LOG_WARNING, "Setting the output channel layout with the "
+               "'out_channel_layout' option is deprecated, use the "
+               "'out_ch_layout' option instead].\n");
+        av_channel_layout_uninit(&avr->out_ch_layout);
+        av_channel_layout_from_mask(&avr->out_ch_layout, avr->out_channel_layout);
+    }
+#endif
+    in_ch  = avr->in_ch_layout.nb_channels;
+    out_ch = avr->out_ch_layout.nb_channels;
+    if (!av_channel_layout_check(&avr->in_ch_layout) ||
+        in_ch > AVRESAMPLE_MAX_CHANNELS) {
+        av_log(avr, AV_LOG_ERROR, "Invalid input channel layout.\n");
         return AVERROR(EINVAL);
     }
-    avr->out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout);
-    if (avr->out_channels <= 0 || avr->out_channels > AVRESAMPLE_MAX_CHANNELS) {
-        av_log(avr, AV_LOG_ERROR, "Invalid output channel layout: %"PRIu64"\n",
-               avr->out_channel_layout);
+    if (!av_channel_layout_check(&avr->out_ch_layout) ||
+        out_ch > AVRESAMPLE_MAX_CHANNELS) {
+        av_log(avr, AV_LOG_ERROR, "Invalid output channel layout.\n");
         return AVERROR(EINVAL);
     }
-    avr->resample_channels = FFMIN(avr->in_channels, avr->out_channels);
-    avr->downmix_needed    = avr->in_channels  > avr->out_channels;
-    avr->upmix_needed      = avr->out_channels > avr->in_channels ||
+    avr->resample_channels = FFMIN(in_ch, out_ch);
+    avr->downmix_needed    = in_ch > out_ch;
+    avr->upmix_needed      = out_ch > in_ch ||
                              (!avr->downmix_needed && (avr->mix_matrix ||
-                              avr->in_channel_layout != avr->out_channel_layout));
+                              av_channel_layout_compare(&avr->in_ch_layout,
+                                                        &avr->out_ch_layout)));
     avr->mixing_needed     = avr->downmix_needed || avr->upmix_needed;
 
     /* set resampling parameters */
@@ -105,7 +150,7 @@  int avresample_open(AVAudioResampleContext *avr)
     /* we may need to add an extra conversion in order to remap channels if
        the output format is not planar */
     if (avr->use_channel_map && !avr->mixing_needed && !avr->resample_needed &&
-        !ff_sample_fmt_is_planar(avr->out_sample_fmt, avr->out_channels)) {
+        !ff_sample_fmt_is_planar(avr->out_sample_fmt, avr->out_ch_layout.nb_channels)) {
         avr->internal_sample_fmt = av_get_planar_sample_fmt(avr->out_sample_fmt);
     }
 
@@ -114,7 +159,8 @@  int avresample_open(AVAudioResampleContext *avr)
         avr->in_convert_needed = avr->in_sample_fmt != avr->internal_sample_fmt;
     else
         avr->in_convert_needed = avr->use_channel_map &&
-                                 !ff_sample_fmt_is_planar(avr->out_sample_fmt, avr->out_channels);
+                                 !ff_sample_fmt_is_planar(avr->out_sample_fmt,
+                                                          avr->out_ch_layout.nb_channels);
 
     if (avr->resample_needed || avr->mixing_needed || avr->in_convert_needed)
         avr->out_convert_needed = avr->internal_sample_fmt != avr->out_sample_fmt;
@@ -144,27 +190,27 @@  int avresample_open(AVAudioResampleContext *avr)
             int ch;
             av_log(avr, AV_LOG_TRACE, "output map: ");
             if (avr->ch_map_info.do_remap)
-                for (ch = 0; ch < avr->in_channels; ch++)
+                for (ch = 0; ch < in_ch; ch++)
                     av_log(avr, AV_LOG_TRACE, " % 2d", avr->ch_map_info.channel_map[ch]);
             else
                 av_log(avr, AV_LOG_TRACE, "n/a");
             av_log(avr, AV_LOG_TRACE, "\n");
             av_log(avr, AV_LOG_TRACE, "copy map:   ");
             if (avr->ch_map_info.do_copy)
-                for (ch = 0; ch < avr->in_channels; ch++)
+                for (ch = 0; ch < in_ch; ch++)
                     av_log(avr, AV_LOG_TRACE, " % 2d", avr->ch_map_info.channel_copy[ch]);
             else
                 av_log(avr, AV_LOG_TRACE, "n/a");
             av_log(avr, AV_LOG_TRACE, "\n");
             av_log(avr, AV_LOG_TRACE, "zero map:   ");
             if (avr->ch_map_info.do_zero)
-                for (ch = 0; ch < avr->in_channels; ch++)
+                for (ch = 0; ch < in_ch; ch++)
                     av_log(avr, AV_LOG_TRACE, " % 2d", avr->ch_map_info.channel_zero[ch]);
             else
                 av_log(avr, AV_LOG_TRACE, "n/a");
             av_log(avr, AV_LOG_TRACE, "\n");
             av_log(avr, AV_LOG_TRACE, "input map:  ");
-            for (ch = 0; ch < avr->in_channels; ch++)
+            for (ch = 0; ch < in_ch; ch++)
                 av_log(avr, AV_LOG_TRACE, " % 2d", avr->ch_map_info.input_map[ch]);
             av_log(avr, AV_LOG_TRACE, "\n");
         }
@@ -174,7 +220,7 @@  int avresample_open(AVAudioResampleContext *avr)
 
     /* allocate buffers */
     if (avr->in_copy_needed || avr->in_convert_needed) {
-        avr->in_buffer = ff_audio_data_alloc(FFMAX(avr->in_channels, avr->out_channels),
+        avr->in_buffer = ff_audio_data_alloc(FFMAX(in_ch, out_ch),
                                              0, avr->internal_sample_fmt,
                                              "in_buffer");
         if (!avr->in_buffer) {
@@ -183,7 +229,7 @@  int avresample_open(AVAudioResampleContext *avr)
         }
     }
     if (avr->resample_needed) {
-        avr->resample_out_buffer = ff_audio_data_alloc(avr->out_channels,
+        avr->resample_out_buffer = ff_audio_data_alloc(out_ch,
                                                        1024, avr->internal_sample_fmt,
                                                        "resample_out_buffer");
         if (!avr->resample_out_buffer) {
@@ -192,15 +238,14 @@  int avresample_open(AVAudioResampleContext *avr)
         }
     }
     if (avr->out_convert_needed) {
-        avr->out_buffer = ff_audio_data_alloc(avr->out_channels, 0,
+        avr->out_buffer = ff_audio_data_alloc(out_ch, 0,
                                               avr->out_sample_fmt, "out_buffer");
         if (!avr->out_buffer) {
             ret = AVERROR(EINVAL);
             goto error;
         }
     }
-    avr->out_fifo = av_audio_fifo_alloc(avr->out_sample_fmt, avr->out_channels,
-                                        1024);
+    avr->out_fifo = av_audio_fifo_alloc(avr->out_sample_fmt, out_ch, 1024);
     if (!avr->out_fifo) {
         ret = AVERROR(ENOMEM);
         goto error;
@@ -209,7 +254,7 @@  int avresample_open(AVAudioResampleContext *avr)
     /* setup contexts */
     if (avr->in_convert_needed) {
         avr->ac_in = ff_audio_convert_alloc(avr, avr->internal_sample_fmt,
-                                            avr->in_sample_fmt, avr->in_channels,
+                                            avr->in_sample_fmt, in_ch,
                                             avr->in_sample_rate,
                                             avr->remap_point == REMAP_IN_CONVERT);
         if (!avr->ac_in) {
@@ -224,7 +269,7 @@  int avresample_open(AVAudioResampleContext *avr)
         else
             src_fmt = avr->in_sample_fmt;
         avr->ac_out = ff_audio_convert_alloc(avr, avr->out_sample_fmt, src_fmt,
-                                             avr->out_channels,
+                                             out_ch,
                                              avr->out_sample_rate,
                                              avr->remap_point == REMAP_OUT_CONVERT);
         if (!avr->ac_out) {
@@ -361,7 +406,7 @@  int attribute_align_arg avresample_convert(AVAudioResampleContext *avr,
     direct_output = output && av_audio_fifo_size(avr->out_fifo) == 0;
     if (output) {
         ret = ff_audio_data_init(&output_buffer, output, out_plane_size,
-                                 avr->out_channels, out_samples,
+                                 avr->out_ch_layout.nb_channels, out_samples,
                                  avr->out_sample_fmt, 0, "output");
         if (ret < 0)
             return ret;
@@ -371,7 +416,7 @@  int attribute_align_arg avresample_convert(AVAudioResampleContext *avr,
     if (input) {
         /* initialize input_buffer with input data */
         ret = ff_audio_data_init(&input_buffer, input, in_plane_size,
-                                 avr->in_channels, in_samples,
+                                 avr->in_ch_layout.nb_channels, in_samples,
                                  avr->in_sample_fmt, 1, "input");
         if (ret < 0)
             return ret;
@@ -420,7 +465,7 @@  int attribute_align_arg avresample_convert(AVAudioResampleContext *avr,
                 if (ret < 0)
                     return ret;
             }
-            ff_audio_data_set_channels(avr->in_buffer, avr->in_channels);
+            ff_audio_data_set_channels(avr->in_buffer, avr->in_ch_layout.nb_channels);
             if (avr->downmix_needed) {
                 av_log(avr, AV_LOG_TRACE, "[downmix] in_buffer\n");
                 ret = ff_audio_mix(avr->am, avr->in_buffer);
@@ -504,18 +549,24 @@  int attribute_align_arg avresample_convert(AVAudioResampleContext *avr,
 
 int avresample_config(AVAudioResampleContext *avr, AVFrame *out, AVFrame *in)
 {
+    int ret;
+
     if (avresample_is_open(avr)) {
         avresample_close(avr);
     }
 
     if (in) {
-        avr->in_channel_layout  = in->channel_layout;
+        ret = av_channel_layout_copy(&avr->in_ch_layout, &in->ch_layout);
+        if (ret < 0)
+            return ret;
         avr->in_sample_rate     = in->sample_rate;
         avr->in_sample_fmt      = in->format;
     }
 
     if (out) {
-        avr->out_channel_layout = out->channel_layout;
+        ret = av_channel_layout_copy(&avr->out_ch_layout, &out->ch_layout);
+        if (ret < 0)
+            return ret;
         avr->out_sample_rate    = out->sample_rate;
         avr->out_sample_fmt     = out->format;
     }
@@ -529,7 +580,7 @@  static int config_changed(AVAudioResampleContext *avr,
     int ret = 0;
 
     if (in) {
-        if (avr->in_channel_layout != in->channel_layout ||
+        if (av_channel_layout_compare(&avr->in_ch_layout, &in->ch_layout) ||
             avr->in_sample_rate    != in->sample_rate ||
             avr->in_sample_fmt     != in->format) {
             ret |= AVERROR_INPUT_CHANGED;
@@ -537,7 +588,7 @@  static int config_changed(AVAudioResampleContext *avr,
     }
 
     if (out) {
-        if (avr->out_channel_layout != out->channel_layout ||
+        if (av_channel_layout_compare(&avr->out_ch_layout, &out->ch_layout) ||
             avr->out_sample_rate    != out->sample_rate ||
             avr->out_sample_fmt     != out->format) {
             ret |= AVERROR_OUTPUT_CHANGED;
@@ -595,7 +646,7 @@  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 = out->ch_layout.nb_channels;
         return samples / channels;
     }
 }
@@ -642,8 +693,8 @@  int avresample_get_matrix(AVAudioResampleContext *avr, double *matrix,
     if (avr->am)
         return ff_audio_mix_get_matrix(avr->am, matrix, stride);
 
-    in_channels  = av_get_channel_layout_nb_channels(avr->in_channel_layout);
-    out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout);
+    in_channels  = avr->in_ch_layout.nb_channels;
+    out_channels = avr->out_ch_layout.nb_channels;
 
     if ( in_channels <= 0 ||  in_channels > AVRESAMPLE_MAX_CHANNELS ||
         out_channels <= 0 || out_channels > AVRESAMPLE_MAX_CHANNELS) {
@@ -671,8 +722,8 @@  int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix,
     if (avr->am)
         return ff_audio_mix_set_matrix(avr->am, matrix, stride);
 
-    in_channels  = av_get_channel_layout_nb_channels(avr->in_channel_layout);
-    out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout);
+    in_channels  = avr->in_ch_layout.nb_channels;
+    out_channels = avr->out_ch_layout.nb_channels;
 
     if ( in_channels <= 0 ||  in_channels > AVRESAMPLE_MAX_CHANNELS ||
         out_channels <= 0 || out_channels > AVRESAMPLE_MAX_CHANNELS) {
@@ -700,7 +751,7 @@  int avresample_set_channel_mapping(AVAudioResampleContext *avr,
     ChannelMapInfo *info = &avr->ch_map_info;
     int in_channels, ch, i;
 
-    in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout);
+    in_channels = avr->in_ch_layout.nb_channels;
     if (in_channels <= 0 ||  in_channels > AVRESAMPLE_MAX_CHANNELS) {
         av_log(avr, AV_LOG_ERROR, "Invalid input channel layout\n");
         return AVERROR(EINVAL);