diff options
-rw-r--r-- | libhb/common.c | 1 | ||||
-rw-r--r-- | libhb/common.h | 1 | ||||
-rw-r--r-- | libhb/sync.c | 116 | ||||
-rw-r--r-- | libhb/work.c | 4 | ||||
-rw-r--r-- | test/test.c | 41 |
5 files changed, 122 insertions, 41 deletions
diff --git a/libhb/common.c b/libhb/common.c index 2387aa4ef..4c382e57c 100644 --- a/libhb/common.c +++ b/libhb/common.c @@ -1222,6 +1222,7 @@ int hb_audio_add(const hb_job_t * job, const hb_audio_config_t * audiocfg) audio->config.out.bitrate = audiocfg->out.bitrate; 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; } hb_list_add(job->list_audio, audio); diff --git a/libhb/common.h b/libhb/common.h index a3461e864..bb0c219cb 100644 --- a/libhb/common.h +++ b/libhb/common.h @@ -399,6 +399,7 @@ struct hb_audio_config_s int bitrate; /* Output bitrate (kbps) */ int mixdown; /* The mixdown format to be used for this audio track (see HB_AMIXDOWN_*) */ double dynamic_range_compression; /* Amount of DRC that gets applied to this track */ + double gain; /* Gain in dB. negative is quieter */ char * name; /* Output track name */ } out; diff --git a/libhb/sync.c b/libhb/sync.c index 7061aa1da..19ee605f0 100644 --- a/libhb/sync.c +++ b/libhb/sync.c @@ -47,6 +47,8 @@ typedef struct /* AC-3 */ int ac3_size; uint8_t * ac3_buf; + + double gain_factor; } hb_sync_audio_t; typedef struct @@ -1024,6 +1026,8 @@ hb_work_object_t hb_sync_audio = syncAudioClose }; +#define LVL_PLUS1DB 1.122462048 + static void InitAudio( hb_job_t * job, hb_sync_common_t * common, int i ) { hb_work_object_t * w; @@ -1101,6 +1105,9 @@ static void InitAudio( hb_job_t * job, hb_sync_common_t * common, int i ) w->audio->config.out.mixdown), &error ); sync->data.end_of_input = 0; } + + sync->gain_factor = pow(LVL_PLUS1DB, w->audio->config.out.gain); + hb_list_add( job->list_work, w ); } @@ -1110,54 +1117,81 @@ static hb_buffer_t * OutputAudioFrame( hb_audio_t *audio, hb_buffer_t *buf, int64_t start = (int64_t)sync->next_start; double duration = buf->stop - buf->start; - if( audio->config.in.samplerate == audio->config.out.samplerate || - audio->config.out.codec == HB_ACODEC_AC3_PASS || - audio->config.out.codec == HB_ACODEC_DCA_PASS ) - { - /* - * If we don't have to do sample rate conversion or this audio is - * pass-thru just send the input buffer downstream after adjusting - * its timestamps to make the output stream continuous. - */ - } - else + if ( !( audio->config.out.codec & HB_ACODEC_PASS_FLAG ) ) { - /* Not pass-thru - do sample rate conversion */ - int count_in, count_out; - hb_buffer_t * buf_raw = buf; - int channel_count = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown) * - sizeof( float ); + // Audio is not passthru. Check if we need to modify the audio + // in any way. + if( audio->config.in.samplerate != audio->config.out.samplerate ) + { + /* do sample rate conversion */ + int count_in, count_out; + hb_buffer_t * buf_raw = buf; + int channel_count = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown) * + sizeof( float ); - count_in = buf_raw->size / channel_count; - /* - * When using stupid rates like 44.1 there will always be some - * truncation error. E.g., a 1536 sample AC3 frame will turn into a - * 1536*44.1/48.0 = 1411.2 sample frame. If we just truncate the .2 - * the error will build up over time and eventually the audio will - * substantially lag the video. libsamplerate will keep track of the - * fractional sample & give it to us when appropriate if we give it - * an extra sample of space in the output buffer. - */ - count_out = ( duration * audio->config.out.samplerate ) / 90000 + 1; + count_in = buf_raw->size / channel_count; + /* + * When using stupid rates like 44.1 there will always be some + * truncation error. E.g., a 1536 sample AC3 frame will turn into a + * 1536*44.1/48.0 = 1411.2 sample frame. If we just truncate the .2 + * the error will build up over time and eventually the audio will + * substantially lag the video. libsamplerate will keep track of the + * fractional sample & give it to us when appropriate if we give it + * an extra sample of space in the output buffer. + */ + count_out = ( duration * audio->config.out.samplerate ) / 90000 + 1; - sync->data.input_frames = count_in; - sync->data.output_frames = count_out; - sync->data.src_ratio = (double)audio->config.out.samplerate / - (double)audio->config.in.samplerate; + sync->data.input_frames = count_in; + sync->data.output_frames = count_out; + sync->data.src_ratio = (double)audio->config.out.samplerate / + (double)audio->config.in.samplerate; - buf = hb_buffer_init( count_out * channel_count ); - sync->data.data_in = (float *) buf_raw->data; - sync->data.data_out = (float *) buf->data; - if( src_process( sync->state, &sync->data ) ) + buf = hb_buffer_init( count_out * channel_count ); + sync->data.data_in = (float *) buf_raw->data; + sync->data.data_out = (float *) buf->data; + if( src_process( sync->state, &sync->data ) ) + { + /* XXX If this happens, we're screwed */ + hb_log( "sync: audio 0x%x src_process failed", audio->id ); + } + hb_buffer_close( &buf_raw ); + + buf->size = sync->data.output_frames_gen * channel_count; + duration = (double)( sync->data.output_frames_gen * 90000 ) / + audio->config.out.samplerate; + } + if( audio->config.out.gain > 0.0 ) { - /* XXX If this happens, we're screwed */ - hb_log( "sync: audio 0x%x src_process failed", audio->id ); + int count, ii; + + count = buf->size / sizeof(float); + for ( ii = 0; ii < count; ii++ ) + { + double sample; + + sample = (double)*(((float*)buf->data)+ii); + sample *= sync->gain_factor; + if (sample > 0) + sample = MIN(sample, 32767.0); + else + sample = MAX(sample, -32768.0); + *(((float*)buf->data)+ii) = sample; + } } - hb_buffer_close( &buf_raw ); + else if( audio->config.out.gain < 0.0 ) + { + int count, ii; - buf->size = sync->data.output_frames_gen * channel_count; - duration = (double)( sync->data.output_frames_gen * 90000 ) / - audio->config.out.samplerate; + count = buf->size / sizeof(float); + for ( ii = 0; ii < count; ii++ ) + { + double sample; + + sample = (double)*(((float*)buf->data)+ii); + sample *= sync->gain_factor; + *(((float*)buf->data)+ii) = sample; + } + } } buf->frametype = HB_FRAME_AUDIO; buf->start = start; diff --git a/libhb/work.c b/libhb/work.c index 11b8d27c4..8c182fa66 100644 --- a/libhb/work.c +++ b/libhb/work.c @@ -347,6 +347,10 @@ void hb_display_job_info( hb_job_t * job ) break; } } + if ( audio->config.out.gain != 0.0 ) + { + hb_log( " + gain: %.fdB", audio->config.out.gain ); + } } if ( audio->config.out.dynamic_range_compression && (audio->config.out.codec != HB_ACODEC_AC3_PASS) && (audio->config.out.codec != HB_ACODEC_DCA_PASS)) diff --git a/test/test.c b/test/test.c index 97ecfd3e9..33cc9e7e8 100644 --- a/test/test.c +++ b/test/test.c @@ -67,6 +67,7 @@ static hb_audio_config_t * audio = NULL; static int num_audio_tracks = 0; static char * mixdowns = NULL; static char * dynamic_range_compression = NULL; +static char * audio_gain = NULL; static char * atracks = NULL; static char * arates = NULL; static char * abitrates = NULL; @@ -346,6 +347,7 @@ int main( int argc, char ** argv ) } if( mixdowns ) free( mixdowns ); if( dynamic_range_compression ) free( dynamic_range_compression ); + if( audio_gain ) free( audio_gain ); if( atracks ) free( atracks ); if( arates ) free( arates ); if( abitrates ) free( abitrates ); @@ -1864,6 +1866,33 @@ static int HandleEvents( hb_handle_t * h ) } /* Audio DRC */ + /* Audio Gain */ + i = 0; + if ( audio_gain ) + { + double gain; + char * token = strtok(audio_gain, ","); + if (token == NULL) + token = audio_gain; + while ( token != NULL ) + { + gain = atof(token); + audio = hb_list_audio_config_item(job->list_audio, i); + if( audio != NULL ) + { + audio->out.gain = gain; + if( (++i) >= num_audio_tracks ) + break; /* We have more inputs than audio tracks, oops */ + } + else + { + fprintf(stderr, "Ignoring gain, no audio tracks\n"); + } + token = strtok(NULL, ","); + } + } + /* Audio Gain */ + /* Audio Track Names */ i = 0; if ( anames ) @@ -2543,6 +2572,10 @@ static void ShowHelp() " making soft sounds louder. Range is 1.0 to 4.0\n" " (too loud), with 1.5 - 2.5 being a useful range.\n" " Separated by commas for more than one audio track.\n" + " --gain <float> Amplify or attenuate audio before encoding. Does\n" + " NOT work with audio passthru (copy). Values are in\n" + " dB. Negative values attenuate, positive values\n" + " amplify. A 1 dB difference is barely audible.\n" " -A, --aname <string> Audio track name(s),\n" " Separated by commas for more than one audio track.\n" "\n" @@ -2787,6 +2820,7 @@ static int ParseOptions( int argc, char ** argv ) #define SCAN_ONLY 276 #define MAIN_FEATURE 277 #define MIN_DURATION 278 + #define AUDIO_GAIN 279 for( ;; ) { @@ -2814,6 +2848,7 @@ static int ParseOptions( int argc, char ** argv ) { "audio", required_argument, NULL, 'a' }, { "mixdown", required_argument, NULL, '6' }, { "drc", required_argument, NULL, 'D' }, + { "gain", required_argument, NULL, AUDIO_GAIN }, { "subtitle", required_argument, NULL, 's' }, { "subtitle-forced", optional_argument, NULL, 'F' }, { "subtitle-burned", optional_argument, NULL, SUB_BURNED }, @@ -3016,6 +3051,12 @@ static int ParseOptions( int argc, char ** argv ) dynamic_range_compression = strdup( optarg ); } break; + case AUDIO_GAIN: + if( optarg != NULL ) + { + audio_gain = strdup( optarg ); + } + break; case 's': subtracks = str_split( optarg, ',' ); break; |