Add Dolby/DPLII downmix support to libswresample
authorMichael Niedermayer <michaelni@gmx.at>
Sat, 9 Jun 2012 20:45:49 +0000 (13:45 -0700)
committerMichael Niedermayer <michaelni@gmx.at>
Thu, 6 Sep 2012 22:41:49 +0000 (00:41 +0200)
Based on code by John Stebbins <jstebbins.hb@gmail.com>

Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
libswresample/rematrix.c
libswresample/swresample.c
libswresample/swresample_internal.h

index 7652fd8..8284e5c 100644 (file)
@@ -126,6 +126,7 @@ static int auto_matrix(SwrContext *s)
     int64_t unaccounted= s->in_ch_layout & ~s->out_ch_layout;
     double maxcoef=0;
     char buf[128];
+    const int matrix_encoding = s->matrix_encoding;
 
     memset(s->matrix, 0, sizeof(s->matrix));
     for(i=0; i<64; i++){
@@ -178,8 +179,19 @@ static int auto_matrix(SwrContext *s)
             matrix[ SIDE_LEFT][BACK_CENTER]+= M_SQRT1_2;
             matrix[SIDE_RIGHT][BACK_CENTER]+= M_SQRT1_2;
         }else if(s->out_ch_layout & AV_CH_FRONT_LEFT){
-            matrix[ FRONT_LEFT][BACK_CENTER]+= s->slev*M_SQRT1_2;
-            matrix[FRONT_RIGHT][BACK_CENTER]+= s->slev*M_SQRT1_2;
+            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] -= s->slev * M_SQRT1_2;
+                    matrix[FRONT_RIGHT][BACK_CENTER] += s->slev * M_SQRT1_2;
+                } else {
+                    matrix[FRONT_LEFT ][BACK_CENTER] -= s->slev;
+                    matrix[FRONT_RIGHT][BACK_CENTER] += s->slev;
+                }
+            } else {
+                matrix[ FRONT_LEFT][BACK_CENTER]+= s->slev*M_SQRT1_2;
+                matrix[FRONT_RIGHT][BACK_CENTER]+= s->slev*M_SQRT1_2;
+            }
         }else if(s->out_ch_layout & AV_CH_FRONT_CENTER){
             matrix[ FRONT_CENTER][BACK_CENTER]+= s->slev*M_SQRT1_2;
         }else
@@ -198,8 +210,20 @@ static int auto_matrix(SwrContext *s)
             matrix[SIDE_RIGHT][BACK_RIGHT]+= 1.0;
             }
         }else if(s->out_ch_layout & AV_CH_FRONT_LEFT){
-            matrix[ FRONT_LEFT][ BACK_LEFT]+= s->slev;
-            matrix[FRONT_RIGHT][BACK_RIGHT]+= s->slev;
+            if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY) {
+                matrix[FRONT_LEFT ][BACK_LEFT ] -= s->slev * M_SQRT1_2;
+                matrix[FRONT_LEFT ][BACK_RIGHT] -= s->slev * M_SQRT1_2;
+                matrix[FRONT_RIGHT][BACK_LEFT ] += s->slev * M_SQRT1_2;
+                matrix[FRONT_RIGHT][BACK_RIGHT] += s->slev * M_SQRT1_2;
+            } else if (matrix_encoding == AV_MATRIX_ENCODING_DPLII) {
+                matrix[FRONT_LEFT ][BACK_LEFT ] -= s->slev * SQRT3_2;
+                matrix[FRONT_LEFT ][BACK_RIGHT] -= s->slev * M_SQRT1_2;
+                matrix[FRONT_RIGHT][BACK_LEFT ] += s->slev * M_SQRT1_2;
+                matrix[FRONT_RIGHT][BACK_RIGHT] += s->slev * SQRT3_2;
+            } else {
+                matrix[ FRONT_LEFT][ BACK_LEFT] += s->slev;
+                matrix[FRONT_RIGHT][BACK_RIGHT] += s->slev;
+            }
         }else if(s->out_ch_layout & AV_CH_FRONT_CENTER){
             matrix[ FRONT_CENTER][BACK_LEFT ]+= s->slev*M_SQRT1_2;
             matrix[ FRONT_CENTER][BACK_RIGHT]+= s->slev*M_SQRT1_2;
@@ -222,8 +246,20 @@ static int auto_matrix(SwrContext *s)
             matrix[BACK_CENTER][ SIDE_LEFT]+= M_SQRT1_2;
             matrix[BACK_CENTER][SIDE_RIGHT]+= M_SQRT1_2;
         }else if(s->out_ch_layout & AV_CH_FRONT_LEFT){
-            matrix[ FRONT_LEFT][ SIDE_LEFT]+= s->slev;
-            matrix[FRONT_RIGHT][SIDE_RIGHT]+= s->slev;
+            if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY) {
+                matrix[FRONT_LEFT ][SIDE_LEFT ] -= s->slev * M_SQRT1_2;
+                matrix[FRONT_LEFT ][SIDE_RIGHT] -= s->slev * M_SQRT1_2;
+                matrix[FRONT_RIGHT][SIDE_LEFT ] += s->slev * M_SQRT1_2;
+                matrix[FRONT_RIGHT][SIDE_RIGHT] += s->slev * M_SQRT1_2;
+            } else if (matrix_encoding == AV_MATRIX_ENCODING_DPLII) {
+                matrix[FRONT_LEFT ][SIDE_LEFT ] -= s->slev * SQRT3_2;
+                matrix[FRONT_LEFT ][SIDE_RIGHT] -= s->slev * M_SQRT1_2;
+                matrix[FRONT_RIGHT][SIDE_LEFT ] += s->slev * M_SQRT1_2;
+                matrix[FRONT_RIGHT][SIDE_RIGHT] += s->slev * SQRT3_2;
+            } else {
+                matrix[ FRONT_LEFT][ SIDE_LEFT] += s->slev;
+                matrix[FRONT_RIGHT][SIDE_RIGHT] += s->slev;
+            }
         }else if(s->out_ch_layout & AV_CH_FRONT_CENTER){
             matrix[ FRONT_CENTER][SIDE_LEFT ]+= s->slev*M_SQRT1_2;
             matrix[ FRONT_CENTER][SIDE_RIGHT]+= s->slev*M_SQRT1_2;
index 2d70eac..e5ca54f 100644 (file)
@@ -88,6 +88,10 @@ static const AVOption options[]={
                                               , OFFSET(soft_compensation_duration),AV_OPT_TYPE_FLOAT ,{.dbl=1                     }, 0      , INT_MAX   , PARAM },
 {"max_soft_comp"        , "Maximum factor by which data is stretched/squeezed to make it match the timestamps."
                                                    , OFFSET(max_soft_compensation),AV_OPT_TYPE_FLOAT ,{.dbl=0                     }, INT_MIN, INT_MAX   , PARAM },
+{ "matrix_encoding"     , "Matrixed Stereo Encoding"    , OFFSET(matrix_encoding), AV_OPT_TYPE_INT   ,{.i64 = AV_MATRIX_ENCODING_NONE}, AV_MATRIX_ENCODING_NONE,     AV_MATRIX_ENCODING_NB-1, PARAM, "matrix_encoding" },
+    { "none",  "None",               0, AV_OPT_TYPE_CONST, { .i64 = AV_MATRIX_ENCODING_NONE  }, INT_MIN, INT_MAX, PARAM, "matrix_encoding" },
+    { "dolby", "Dolby",              0, AV_OPT_TYPE_CONST, { .i64 = AV_MATRIX_ENCODING_DOLBY }, INT_MIN, INT_MAX, PARAM, "matrix_encoding" },
+    { "dplii", "Dolby Pro Logic II", 0, AV_OPT_TYPE_CONST, { .i64 = AV_MATRIX_ENCODING_DPLII }, INT_MIN, INT_MAX, PARAM, "matrix_encoding" },
 { "filter_type"         , "Filter Type"                 , OFFSET(filter_type)    , AV_OPT_TYPE_INT  , { .i64 = SWR_FILTER_TYPE_KAISER }, SWR_FILTER_TYPE_CUBIC, SWR_FILTER_TYPE_KAISER, PARAM, "filter_type" },
     { "cubic"           , "Cubic"                       , 0                      , AV_OPT_TYPE_CONST, { .i64 = SWR_FILTER_TYPE_CUBIC            }, INT_MIN, INT_MAX, PARAM, "filter_type" },
     { "blackman_nuttall", "Blackman Nuttall Windowed Sinc", 0                    , AV_OPT_TYPE_CONST, { .i64 = SWR_FILTER_TYPE_BLACKMAN_NUTTALL }, INT_MIN, INT_MAX, PARAM, "filter_type" },
index 0ef5f96..a32cf76 100644 (file)
@@ -22,6 +22,9 @@
 #define SWR_INTERNAL_H
 
 #include "swresample.h"
+#include "libavutil/audioconvert.h"
+
+#define SQRT3_2      1.22474487139158904909  /* sqrt(3/2) */
 
 typedef void (mix_1_1_func_type)(void *out, const void *in, void *coeffp, int index, int len);
 typedef void (mix_2_1_func_type)(void *out, const void *in1, const void *in2, void *coeffp, int index1, int index2, int len);
@@ -54,6 +57,7 @@ struct SwrContext {
     float clev;                                     ///< center mixing level
     float lfe_mix_level;                            ///< LFE mixing level
     float rematrix_volume;                          ///< rematrixing volume coefficient
+    enum AVMatrixEncoding matrix_encoding;          /**< matrixed stereo encoding */
     const int *channel_map;                         ///< channel index (or -1 if muted channel) map
     int used_ch_count;                              ///< number of used input channels (mapped channel count if channel_map, otherwise in.ch_count)
     enum SwrDitherType dither_method;