--- /dev/null
+diff --git a/libavresample/audio_mix.c b/libavresample/audio_mix.c
+index 2c2a356..25f9f98 100644
+--- a/libavresample/audio_mix.c
++++ b/libavresample/audio_mix.c
+@@ -327,7 +327,9 @@ int ff_audio_mix_init(AVAudioResampleContext *avr)
+ avr->out_channel_layout,
+ avr->center_mix_level,
+ avr->surround_mix_level,
+- avr->lfe_mix_level, 1, matrix_dbl,
++ avr->lfe_mix_level,
++ avr->normalize_mix_level,
++ matrix_dbl,
+ avr->in_channels,
+ avr->matrix_encoding);
+ if (ret < 0) {
+diff --git a/libavresample/internal.h b/libavresample/internal.h
+index 7b7648f..006b6fd 100644
+--- a/libavresample/internal.h
++++ b/libavresample/internal.h
+@@ -45,6 +45,7 @@ struct AVAudioResampleContext {
+ double center_mix_level; /**< center mix level */
+ double surround_mix_level; /**< surround mix level */
+ double lfe_mix_level; /**< lfe mix level */
++ int normalize_mix_level; /**< enable mix level normalization */
+ int force_resampling; /**< force resampling */
+ int filter_size; /**< length of each FIR filter in the resampling filterbank relative to the cutoff frequency */
+ int phase_shift; /**< log2 of the number of entries in the resampling polyphase filterbank */
+diff --git a/libavresample/options.c b/libavresample/options.c
+index 02e1f86..e7e0c27 100644
+--- a/libavresample/options.c
++++ b/libavresample/options.c
+@@ -47,6 +47,7 @@ static const AVOption options[] = {
+ { "center_mix_level", "Center Mix Level", OFFSET(center_mix_level), AV_OPT_TYPE_DOUBLE, { M_SQRT1_2 }, -32.0, 32.0, PARAM },
+ { "surround_mix_level", "Surround Mix Level", OFFSET(surround_mix_level), AV_OPT_TYPE_DOUBLE, { M_SQRT1_2 }, -32.0, 32.0, PARAM },
+ { "lfe_mix_level", "LFE Mix Level", OFFSET(lfe_mix_level), AV_OPT_TYPE_DOUBLE, { 0.0 }, -32.0, 32.0, PARAM },
++ { "normalize_mix_level", "Normalize Mix Level", OFFSET(normalize_mix_level), AV_OPT_TYPE_INT, { 1 }, 0, 1, PARAM },
+ { "force_resampling", "Force Resampling", OFFSET(force_resampling), AV_OPT_TYPE_INT, { 0 }, 0, 1, PARAM },
+ { "filter_size", "Resampling Filter Size", OFFSET(filter_size), AV_OPT_TYPE_INT, { 16 }, 0, 32, /* ??? */ PARAM },
+ { "phase_shift", "Resampling Phase Shift", OFFSET(phase_shift), AV_OPT_TYPE_INT, { 10 }, 0, 30, /* ??? */ PARAM },
hb_audio_resample_t* hb_audio_resample_init(enum AVSampleFormat output_sample_fmt,
uint64_t output_channel_layout,
- enum AVMatrixEncoding matrix_encoding)
+ enum AVMatrixEncoding matrix_encoding,
+ int normalize_mix_level)
{
hb_audio_resample_t *resample = malloc(sizeof(hb_audio_resample_t));
if (resample == NULL)
return NULL;
- resample->out.sample_fmt = output_sample_fmt;
- resample->out.sample_size = av_get_bytes_per_sample(output_sample_fmt);
- resample->out.channel_layout = output_channel_layout;
- resample->out.channels =
+ resample->out.sample_fmt = output_sample_fmt;
+ resample->out.sample_size =
+ av_get_bytes_per_sample(output_sample_fmt);
+ resample->out.channel_layout = output_channel_layout;
+ resample->out.channels =
av_get_channel_layout_nb_channels(output_channel_layout);
- resample->out.matrix_encoding = matrix_encoding;
- resample->resample_needed = 0;
- resample->avresample = NULL;
+ resample->out.matrix_encoding = matrix_encoding;
+ resample->out.normalize_mix_level = normalize_mix_level;
+ resample->resample_needed = 0;
+ resample->avresample = NULL;
return resample;
}
resample->out.channel_layout, 0);
av_opt_set_int(resample->avresample, "matrix_encoding",
resample->out.matrix_encoding, 0);
+ av_opt_set_int(resample->avresample, "normalize_mix_level",
+ resample->out.normalize_mix_level, 0);
}
else if (resample_changed)
{
int channels;
int linesize;
int sample_size;
+ int normalize_mix_level;
uint64_t channel_layout;
enum AVSampleFormat sample_fmt;
enum AVMatrixEncoding matrix_encoding;
*/
hb_audio_resample_t* hb_audio_resample_init(enum AVSampleFormat output_sample_fmt,
uint64_t output_channel_layout,
- enum AVMatrixEncoding matrix_encoding);
+ enum AVMatrixEncoding matrix_encoding,
+ int normalize_mix_level);
/* Update an hb_audio_resample_t, setting the input sample characteristics.
*
audiocfg->out.mixdown = HB_INVALID_AMIXDOWN;
audiocfg->out.dynamic_range_compression = 0;
audiocfg->out.gain = 0;
+ audiocfg->out.normalize_mix_level = 0;
audiocfg->out.name = NULL;
}
audio->config.out.mixdown = HB_AMIXDOWN_NONE;
audio->config.out.dynamic_range_compression = 0;
audio->config.out.gain = 0;
+ audio->config.out.normalize_mix_level = 0;
audio->config.out.compression_level = -1;
audio->config.out.quality = HB_INVALID_AUDIO_QUALITY;
}
audio->config.out.dynamic_range_compression = audiocfg->out.dynamic_range_compression;
audio->config.out.mixdown = audiocfg->out.mixdown;
audio->config.out.gain = audiocfg->out.gain;
+ audio->config.out.normalize_mix_level = audiocfg->out.normalize_mix_level;
}
if (audiocfg->out.name && *audiocfg->out.name)
{
float compression_level; /* Output compression level (encoder-specific) */
double dynamic_range_compression; /* Amount of DRC applied to this track */
double gain; /* Gain (in dB), negative is quieter */
+ int normalize_mix_level; /* mix level normalization (boolean) */
char * name; /* Output track name */
} out;
int mode;
uint64_t layout = hb_ff_mixdown_xlat(w->audio->config.out.mixdown,
&mode);
- pv->resample = hb_audio_resample_init(AV_SAMPLE_FMT_FLT, layout, mode);
+ pv->resample = hb_audio_resample_init(AV_SAMPLE_FMT_FLT, layout, mode,
+ w->audio->config.out.normalize_mix_level);
if (pv->resample == NULL)
{
hb_error("decavcodecaInit: hb_audio_resample_init() failed");
int mode;
uint64_t layout = hb_ff_mixdown_xlat(w->audio->config.out.mixdown, &mode);
- pv->resample = hb_audio_resample_init(AV_SAMPLE_FMT_FLT, layout, mode);
+ pv->resample = hb_audio_resample_init(AV_SAMPLE_FMT_FLT, layout, mode,
+ w->audio->config.out.normalize_mix_level);
if (pv->resample == NULL)
{
hb_error("declpcmInit: hb_audio_resample_init() failed");
// sample_fmt conversion
pv->resample = hb_audio_resample_init(context->sample_fmt,
context->channel_layout,
- AV_MATRIX_ENCODING_NONE);
+ AV_MATRIX_ENCODING_NONE, 0);
if (hb_audio_resample_update(pv->resample, AV_SAMPLE_FMT_FLT,
context->channel_layout, context->channels))
{
static char * mixdowns = NULL;
static char * dynamic_range_compression = NULL;
static char * audio_gain = NULL;
+static char ** normalize_mix_level = NULL;
static char * atracks = NULL;
static char * arates = NULL;
static char ** abitrates = NULL;
}
/* Audio Gain */
+ /* Audio Mix Normalization */
+ i = 0;
+ int norm = 0;
+ if( normalize_mix_level )
+ {
+ for ( i = 0; normalize_mix_level[i] != NULL && i < num_audio_tracks; i++ )
+ {
+ char * token = normalize_mix_level[i];
+ norm = atoi(token);
+ audio = hb_list_audio_config_item(job->list_audio, i);
+
+ if( audio != NULL )
+ {
+ audio->out.normalize_mix_level = norm;
+ }
+ else
+ {
+ fprintf(stderr, "Ignoring normalization %d, no audio tracks\n", norm);
+ }
+ }
+ }
+ if (i < num_audio_tracks && i == 1)
+ {
+ /* We have fewer inputs than audio tracks,
+ * and we only have one input, use
+ * that for all tracks.
+ */
+ for (; i < num_audio_tracks; i++)
+ {
+ audio = hb_list_audio_config_item(job->list_audio, i);
+ audio->out.normalize_mix_level = norm;
+ }
+ }
+ /* Audio Mix Normalization */
+
/* Audio Track Names */
if ( anames )
{
" Separated by commas for more than one audio track.\n"
" (mono/stereo/dpl1/dpl2/6ch, default: up to 6ch for ac3,\n"
" up to dpl2 for other encoders)\n"
+ " --normalize-mix Normalize audio mix levels to prevent clipping.\n"
+ " <string> Separated by commas for more than one audio track.\n"
+ " 0 = Disable Normalization (default)\n"
+ " 1 = Enable Normalization\n"
" -R, --arate Set audio samplerate(s) (" );
for( i = 0; i < hb_audio_rates_count; i++ )
{
#define X264_PRESET 284
#define X264_TUNE 285
#define H264_LEVEL 286
+ #define NORMALIZE_MIX 287
for( ;; )
{
{ "markers", optional_argument, NULL, 'm' },
{ "audio", required_argument, NULL, 'a' },
{ "mixdown", required_argument, NULL, '6' },
+ { "normalize-mix", required_argument, NULL, NORMALIZE_MIX },
{ "drc", required_argument, NULL, 'D' },
{ "gain", required_argument, NULL, AUDIO_GAIN },
{ "subtitle", required_argument, NULL, 's' },
audio_gain = strdup( optarg );
}
break;
+ case NORMALIZE_MIX:
+ if( optarg != NULL )
+ {
+ normalize_mix_level = str_split( optarg, ',' );
+ }
+ break;
case 's':
subtracks = str_split( optarg, ',' );
break;