summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libhb/common.c1
-rw-r--r--libhb/common.h1
-rw-r--r--libhb/sync.c116
-rw-r--r--libhb/work.c4
-rw-r--r--test/test.c41
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;