Howdy, I expect this will get some red ink on it. But here's a patch that adds dolby and dolby pro logic ii downmix support to libavresample. I am in the process of updating the version of libav that is used by HandBrake and this is the only missing feature of libavresample that prevents us from dropping our internal downmix code and switching to libavresample.
I've tested it on a dplii capable receiver and I get the expected results.
John
---
libavresample/audio_mix.c | 5 +--
libavresample/audio_mix_matrix.c | 72 +++++++++++++++++++++++++++++++++-----
libavresample/avresample.h | 5 +++
libavresample/internal.h | 1 +
libavresample/options.c | 1 +
libavutil/audioconvert.h | 7 ++++
6 files changed, 80 insertions(+), 11 deletions(-)
diff --git a/libavresample/audio_mix.c b/libavresample/audio_mix.c
index 7ab11b0..f974153 100644
--- a/libavresample/audio_mix.c
+++ b/libavresample/audio_mix.c
@@ -315,12 +315,13 @@ int ff_audio_mix_init(AVAudioResampleContext *avr)
if (!matrix_dbl)
return AVERROR(ENOMEM);
- ret = avresample_build_matrix(avr->in_channel_layout,
+ ret = avresample_build_matrix2(avr->in_channel_layout,
avr->out_channel_layout,
avr->center_mix_level,
avr->surround_mix_level,
avr->lfe_mix_level, 1, matrix_dbl,
- avr->in_channels);
+ avr->in_channels,
+ avr->stereo_downmix_mode);
if (ret < 0) {
av_free(matrix_dbl);
return ret;
diff --git a/libavresample/audio_mix_matrix.c b/libavresample/audio_mix_matrix.c
index 6135b02..221eb85 100644
--- a/libavresample/audio_mix_matrix.c
+++ b/libavresample/audio_mix_matrix.c
@@ -54,6 +54,8 @@
#define SURROUND_DIRECT_LEFT 33
#define SURROUND_DIRECT_RIGHT 34
+#define SQRT3_2 1.22474487139158904909 /* sqrt(3/2) */
+
static av_always_inline int even(uint64_t layout)
{
return (!layout || (layout & (layout - 1)));
@@ -80,17 +82,24 @@ static int sane_layout(uint64_t layout)
return 1;
}
-int avresample_build_matrix(uint64_t in_layout, uint64_t out_layout,
+int avresample_build_matrix2(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)
+ double *matrix_out, int stride,
+ int stereo_downmix_mode)
{
int i, j, out_i, out_j;
double matrix[64][64] = {{0}};
- int64_t unaccounted = in_layout & ~out_layout;
+ int64_t unaccounted;
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);
@@ -140,8 +149,19 @@ int avresample_build_matrix(uint64_t in_layout, uint64_t
out_layout,
matrix[SIDE_LEFT ][BACK_CENTER] += M_SQRT1_2;
matrix[SIDE_RIGHT][BACK_CENTER] += M_SQRT1_2;
} else if (out_layout & AV_CH_FRONT_LEFT) {
- matrix[FRONT_LEFT ][BACK_CENTER] += surround_mix_level * M_SQRT1_2;
- matrix[FRONT_RIGHT][BACK_CENTER] += surround_mix_level * M_SQRT1_2;
+ if (stereo_downmix_mode == AV_STEREO_DOWNMIX_DOLBY ||
+ stereo_downmix_mode == AV_STEREO_DOWNMIX_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;
+ } else {
+ matrix[FRONT_LEFT ][BACK_CENTER] -= surround_mix_level;
+ matrix[FRONT_RIGHT][BACK_CENTER] += surround_mix_level;
+ }
+ } else {
+ 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_layout & AV_CH_FRONT_CENTER) {
matrix[FRONT_CENTER][BACK_CENTER] += surround_mix_level *
M_SQRT1_2;
} else
@@ -163,8 +183,20 @@ int avresample_build_matrix(uint64_t in_layout, uint64_t
out_layout,
matrix[SIDE_RIGHT][BACK_RIGHT] += 1.0;
}
} else if (out_layout & AV_CH_FRONT_LEFT) {
- matrix[FRONT_LEFT ][BACK_LEFT ] += surround_mix_level;
- matrix[FRONT_RIGHT][BACK_RIGHT] += surround_mix_level;
+ if (stereo_downmix_mode == AV_STEREO_DOWNMIX_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 (stereo_downmix_mode == AV_STEREO_DOWNMIX_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;
+ }
} 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;
@@ -187,8 +219,20 @@ int avresample_build_matrix(uint64_t in_layout, uint64_t
out_layout,
matrix[BACK_CENTER][SIDE_LEFT ] += M_SQRT1_2;
matrix[BACK_CENTER][SIDE_RIGHT] += M_SQRT1_2;
} else if (out_layout & AV_CH_FRONT_LEFT) {
- matrix[FRONT_LEFT ][SIDE_LEFT ] += surround_mix_level;
- matrix[FRONT_RIGHT][SIDE_RIGHT] += surround_mix_level;
+ if (stereo_downmix_mode == AV_STEREO_DOWNMIX_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 (stereo_downmix_mode == AV_STEREO_DOWNMIX_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;
+ }
} 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;
@@ -242,6 +286,16 @@ int avresample_build_matrix(uint64_t in_layout, uint64_t
out_layout,
return 0;
}
+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)
+{
+ return avresample_build_matrix2(in_layout, out_layout, center_mix_level,
+ surround_mix_level, lfe_mix_level, normalize, matrix_out, stride,
+ AV_STEREO_DOWNMIX_NONE);
+}
+
int avresample_get_matrix(AVAudioResampleContext *avr, double *matrix,
int stride)
{
diff --git a/libavresample/avresample.h b/libavresample/avresample.h
index 65d4d2d..d0a8467 100644
--- a/libavresample/avresample.h
+++ b/libavresample/avresample.h
@@ -138,6 +138,11 @@ int avresample_build_matrix(uint64_t in_layout, uint64_t
out_layout,
double lfe_mix_level, int normalize, double
*matrix,
int stride);
+int avresample_build_matrix2(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, int stereo_downmix_mode);
+
/**
* Get the current channel mixing matrix.
*
diff --git a/libavresample/internal.h b/libavresample/internal.h
index 49ea6a6..401ef97 100644
--- a/libavresample/internal.h
+++ b/libavresample/internal.h
@@ -70,6 +70,7 @@ struct AVAudioResampleContext {
AudioConvert *ac_out; /**< output sample format conversion context */
ResampleContext *resample; /**< resampling context */
AudioMix *am; /**< channel mixing context */
+ int stereo_downmix_mode;
};
#endif /* AVRESAMPLE_INTERNAL_H */
diff --git a/libavresample/options.c b/libavresample/options.c
index 5430c4d..65295dd 100644
--- a/libavresample/options.c
+++ b/libavresample/options.c
@@ -52,6 +52,7 @@ static const AVOption options[] = {
{ "phase_shift", "Resampling Phase Shift",
OFFSET(phase_shift), AV_OPT_TYPE_INT, { 10 },
0, 30, /* ??? */ PARAM },
{ "linear_interp", "Use Linear Interpolation",
OFFSET(linear_interp), AV_OPT_TYPE_INT, { 0 },
0, 1, PARAM },
{ "cutoff", "Cutoff Frequency Ratio", OFFSET(cutoff),
AV_OPT_TYPE_DOUBLE, { 0.8 }, 0.0,
1.0, PARAM },
+ { "stereo_downmix_mode", "Stereo Downmix Mode",
OFFSET(stereo_downmix_mode), AV_OPT_TYPE_INT, { AV_STEREO_DOWNMIX_NONE},
AV_STEREO_DOWNMIX_NONE, AV_STEREO_DOWNMIX_NB-1, PARAM },
{ NULL },
};
diff --git a/libavutil/audioconvert.h b/libavutil/audioconvert.h
index 35a1a08..48da68e 100644
--- a/libavutil/audioconvert.h
+++ b/libavutil/audioconvert.h
@@ -101,6 +101,13 @@
#define AV_CH_LAYOUT_OCTAGONAL
(AV_CH_LAYOUT_5POINT0|AV_CH_BACK_LEFT|AV_CH_BACK_CENTER|AV_CH_BACK_RIGHT)
#define AV_CH_LAYOUT_STEREO_DOWNMIX (AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT)
+enum AVStereoMixdown {
+ AV_STEREO_DOWNMIX_NONE,
+ AV_STEREO_DOWNMIX_DOLBY,
+ AV_STEREO_DOWNMIX_DPLII,
+ AV_STEREO_DOWNMIX_NB
+};
+
/**
* @}
*/
--
1.7.9.5
signature.asc
Description: OpenPGP digital signature
_______________________________________________ libav-devel mailing list [email protected] https://lists.libav.org/mailman/listinfo/libav-devel
