diff options
-rw-r--r-- | contrib/ffmpeg/A06-mix-normalization.patch | 39 | ||||
-rw-r--r-- | libhb/audio_resample.c | 21 | ||||
-rw-r--r-- | libhb/audio_resample.h | 4 | ||||
-rw-r--r-- | libhb/common.c | 3 | ||||
-rw-r--r-- | libhb/common.h | 1 | ||||
-rw-r--r-- | libhb/decavcodec.c | 3 | ||||
-rw-r--r-- | libhb/declpcm.c | 3 | ||||
-rw-r--r-- | libhb/encavcodecaudio.c | 2 | ||||
-rw-r--r-- | test/test.c | 48 |
9 files changed, 112 insertions, 12 deletions
diff --git a/contrib/ffmpeg/A06-mix-normalization.patch b/contrib/ffmpeg/A06-mix-normalization.patch new file mode 100644 index 000000000..06fb2754c --- /dev/null +++ b/contrib/ffmpeg/A06-mix-normalization.patch @@ -0,0 +1,39 @@ +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 }, diff --git a/libhb/audio_resample.c b/libhb/audio_resample.c index 3f67da87c..ea09b38a2 100644 --- a/libhb/audio_resample.c +++ b/libhb/audio_resample.c @@ -13,20 +13,23 @@ 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; } @@ -72,6 +75,8 @@ int hb_audio_resample_update(hb_audio_resample_t *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) { diff --git a/libhb/audio_resample.h b/libhb/audio_resample.h index 5982905e6..4b1586e73 100644 --- a/libhb/audio_resample.h +++ b/libhb/audio_resample.h @@ -39,6 +39,7 @@ typedef struct int channels; int linesize; int sample_size; + int normalize_mix_level; uint64_t channel_layout; enum AVSampleFormat sample_fmt; enum AVMatrixEncoding matrix_encoding; @@ -52,7 +53,8 @@ typedef struct */ 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. * diff --git a/libhb/common.c b/libhb/common.c index 13a2e1d95..9ff9f44a3 100644 --- a/libhb/common.c +++ b/libhb/common.c @@ -1637,6 +1637,7 @@ void hb_audio_config_init(hb_audio_config_t * audiocfg) 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; } @@ -1684,6 +1685,7 @@ int hb_audio_add(const hb_job_t * job, const hb_audio_config_t * audiocfg) 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; } @@ -1698,6 +1700,7 @@ int hb_audio_add(const hb_job_t * job, const hb_audio_config_t * audiocfg) 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) { diff --git a/libhb/common.h b/libhb/common.h index 5b2fc08fa..1650f8002 100644 --- a/libhb/common.h +++ b/libhb/common.h @@ -452,6 +452,7 @@ struct hb_audio_config_s 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; diff --git a/libhb/decavcodec.c b/libhb/decavcodec.c index 17f814d61..934f7611e 100644 --- a/libhb/decavcodec.c +++ b/libhb/decavcodec.c @@ -192,7 +192,8 @@ static int decavcodecaInit( hb_work_object_t * w, hb_job_t * job ) 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"); diff --git a/libhb/declpcm.c b/libhb/declpcm.c index e48bf5db7..0d4e449d1 100644 --- a/libhb/declpcm.c +++ b/libhb/declpcm.c @@ -164,7 +164,8 @@ static int declpcmInit( hb_work_object_t * w, hb_job_t * job ) 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"); diff --git a/libhb/encavcodecaudio.c b/libhb/encavcodecaudio.c index 28eb0d9ae..ef5297cca 100644 --- a/libhb/encavcodecaudio.c +++ b/libhb/encavcodecaudio.c @@ -119,7 +119,7 @@ static int encavcodecaInit(hb_work_object_t *w, hb_job_t *job) // 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)) { diff --git a/test/test.c b/test/test.c index 5d61b579c..b59534d44 100644 --- a/test/test.c +++ b/test/test.c @@ -71,6 +71,7 @@ static int allowed_audio_copy = -1; 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; @@ -2096,6 +2097,41 @@ static int HandleEvents( hb_handle_t * h ) } /* 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 ) { @@ -2883,6 +2919,10 @@ static void ShowHelp() " 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++ ) { @@ -3186,6 +3226,7 @@ static int ParseOptions( int argc, char ** argv ) #define X264_PRESET 284 #define X264_TUNE 285 #define H264_LEVEL 286 + #define NORMALIZE_MIX 287 for( ;; ) { @@ -3212,6 +3253,7 @@ static int ParseOptions( int argc, char ** argv ) { "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' }, @@ -3430,6 +3472,12 @@ static int ParseOptions( int argc, char ** argv ) 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; |