diff options
author | jstebbins <[email protected]> | 2011-08-01 18:06:22 +0000 |
---|---|---|
committer | jstebbins <[email protected]> | 2011-08-01 18:06:22 +0000 |
commit | 76d480815a9c6773e0fa5bcffaded04646279b8a (patch) | |
tree | 01fb72f321632a8bfb928bb3cfc40448f371eb0c /libhb/sync.c | |
parent | 7a083edaa1a8d331ca8eb2878f051a4fc1966d43 (diff) |
add more audio passthru options
adds aac and mp3 passthru for mp4 and mkv containers
adds dts and dtshd for mp4 container (mkv already had it)
Note: The only player known (to me) to support dts(hd) in mp4 is ff/avplay
In LinGui there is a new option to limit which passthru codecs
will be used by the "Auto Passthru" audio codec options. The CLI
already has this ability with "--audio_copy-mask" which is use
in conjunction with the "copy" audio codec option.
Also corrects some A/V sync issues when video frames are dropped due to
a gap detected in the audio.
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@4149 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'libhb/sync.c')
-rw-r--r-- | libhb/sync.c | 174 |
1 files changed, 108 insertions, 66 deletions
diff --git a/libhb/sync.c b/libhb/sync.c index b754a54cc..b1ec99619 100644 --- a/libhb/sync.c +++ b/libhb/sync.c @@ -14,8 +14,6 @@ #endif #define INT64_MIN (-9223372036854775807LL-1) -#define AC3_SAMPLES_PER_FRAME 1536 - typedef struct { hb_lock_t * mutex; @@ -44,9 +42,10 @@ typedef struct SRC_STATE * state; SRC_DATA data; - /* AC-3 */ - int ac3_size; - uint8_t * ac3_buf; + int silence_size; + uint8_t * silence_buf; + + int drop_video_to_sync; double gain_factor; } hb_sync_audio_t; @@ -261,7 +260,7 @@ int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in, hb_subtitle_t * subtitle; hb_sync_video_t * sync = &pv->type.video; int i; - int64_t start, next_start; + int64_t next_start; *buf_out = NULL; next = *buf_in; @@ -456,16 +455,12 @@ int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in, return HB_WORK_DONE; } - hb_lock( pv->common->mutex ); - start = cur->start - pv->common->video_pts_slip; - hb_unlock( pv->common->mutex ); - /* Check for end of point-to-point pts encoding */ if( job->pts_to_stop && sync->next_start >= job->pts_to_stop ) { // Drop an empty buffer into our output to ensure that things // get flushed all the way out. - hb_log( "sync: reached pts %"PRId64", exiting early", start ); + hb_log( "sync: reached pts %"PRId64", exiting early", cur->start ); hb_buffer_close( &sync->cur ); hb_buffer_close( &next ); *buf_out = hb_buffer_init( 0 ); @@ -487,7 +482,7 @@ int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in, if( sync->first_frame ) { /* This is our first frame */ - if ( start > 0 ) + if ( cur->start > 0 ) { /* * The first pts from a dvd should always be zero but @@ -497,8 +492,8 @@ int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in, * as if it started at zero so that our audio timing will * be in sync. */ - hb_log( "sync: first pts is %"PRId64, start ); - start = 0; + hb_log( "sync: first pts is %"PRId64, cur->start ); + cur->start = 0; } sync->first_frame = 0; } @@ -514,7 +509,7 @@ int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in, * can deal with overlaps of up to a frame time but anything larger * we handle by dropping frames here. */ - if ( next_start - start <= 0 ) + if ( next_start - cur->start <= 0 ) { if ( sync->first_drop == 0 ) { @@ -533,8 +528,8 @@ int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in, { hb_log( "sync: video time didn't advance - dropped %d frames " "(delta %d ms, current %"PRId64", next %"PRId64", dur %d)", - sync->drop_count, (int)( start - sync->first_drop ) / 90, - start, next_start, (int)( next_start - start ) ); + sync->drop_count, (int)( cur->start - sync->first_drop ) / 90, + cur->start, next_start, (int)( next_start - cur->start ) ); sync->first_drop = 0; sync->drop_count = 0; } @@ -766,14 +761,16 @@ int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in, * explicit stop time from the start time of the next frame. */ *buf_out = cur; + int64_t duration = next_start - cur->start; sync->cur = cur = next; cur->sub = NULL; - int64_t duration = next_start - start; + cur->start -= pv->common->video_pts_slip; + cur->stop -= pv->common->video_pts_slip; sync->pts_skip = 0; if ( duration <= 0 ) { hb_log( "sync: invalid video duration %"PRId64", start %"PRId64", next %"PRId64"", - duration, start, next_start ); + duration, cur->start, next_start ); } (*buf_out)->start = sync->next_start; @@ -837,11 +834,11 @@ void syncAudioClose( hb_work_object_t * w ) hb_work_private_t * pv = w->private_data; hb_sync_audio_t * sync = &pv->type.audio; - if( w->audio->config.out.codec == HB_ACODEC_AC3_PASS ) + if( sync->silence_buf ) { - free( sync->ac3_buf ); + free( sync->silence_buf ); } - else + if ( sync->state ) { src_delete( sync->state ); } @@ -985,29 +982,26 @@ static int syncAudioWork( hb_work_object_t * w, hb_buffer_t ** buf_in, return HB_WORK_DONE; } - if ( start - sync->next_start < 0 ) + // audio time went backwards. + // If our output clock is more than a half frame ahead of the + // input clock drop this frame to move closer to sync. + // Otherwise drop frames until the input clock matches the output clock. + if ( sync->next_start - start > 90*15 ) { - // audio time went backwards. - // If our output clock is more than a half frame ahead of the - // input clock drop this frame to move closer to sync. - // Otherwise drop frames until the input clock matches the output clock. - if ( sync->first_drop || sync->next_start - start > 90*15 ) + // Discard data that's in the past. + if ( sync->first_drop == 0 ) { - // Discard data that's in the past. - if ( sync->first_drop == 0 ) - { - sync->first_drop = sync->next_start; - } - ++sync->drop_count; - hb_buffer_close( &buf ); - return HB_WORK_OK; + sync->first_drop = start; } + ++sync->drop_count; + hb_buffer_close( &buf ); + return HB_WORK_OK; } if ( sync->first_drop ) { // we were dropping old data but input buf time is now current hb_log( "sync: audio 0x%x time went backwards %d ms, dropped %d frames " - "(next %"PRId64", current %"PRId64")", w->audio->id, + "(start %"PRId64", next %"PRId64")", w->audio->id, (int)( sync->next_start - sync->first_drop ) / 90, sync->drop_count, sync->first_drop, (int64_t)sync->next_start ); sync->first_drop = 0; @@ -1033,8 +1027,7 @@ static int syncAudioWork( hb_work_object_t * w, hb_buffer_t ** buf_in, * Or in the case of DCA, skip some frames from the * other streams. */ - if( w->audio->config.out.codec == HB_ACODEC_DCA_PASS || - w->audio->config.out.codec == HB_ACODEC_DCA_HD_PASS ) + if ( sync->drop_video_to_sync ) { hb_log( "sync: audio gap %d ms. Skipping frames. Audio 0x%x" " start %"PRId64", next %"PRId64, @@ -1103,21 +1096,41 @@ static void InitAudio( hb_job_t * job, hb_sync_common_t * common, int i ) w->fifo_out = w->audio->priv.fifo_sync; } - if( w->audio->config.out.codec == HB_ACODEC_AC3_PASS ) + if( w->audio->config.out.codec == HB_ACODEC_AC3_PASS || + w->audio->config.out.codec == HB_ACODEC_AAC_PASS ) { - /* Have a silent AC-3 frame ready in case we have to fill a + /* Have a silent AC-3/AAC frame ready in case we have to fill a gap */ AVCodec * codec; AVCodecContext * c; short * zeros; - codec = avcodec_find_encoder( CODEC_ID_AC3 ); + switch ( w->audio->config.out.codec ) + { + case HB_ACODEC_AC3_PASS: + { + codec = avcodec_find_encoder( CODEC_ID_AC3 ); + } break; + case HB_ACODEC_AAC_PASS: + { + codec = avcodec_find_encoder( CODEC_ID_AAC ); + } break; + case HB_ACODEC_MP3_PASS: + { + codec = avcodec_find_encoder( CODEC_ID_MP3 ); + } break; + default: + { + // Never gets here + } break; + } + c = avcodec_alloc_context3( codec ); c->bit_rate = w->audio->config.in.bitrate; c->sample_rate = w->audio->config.in.samplerate; c->channels = HB_INPUT_CH_LAYOUT_GET_DISCRETE_COUNT( w->audio->config.in.channel_layout ); - c->sample_fmt = AV_SAMPLE_FMT_FLT; + hb_ff_set_sample_fmt( c, codec ); switch( w->audio->config.in.channel_layout & HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK ) { @@ -1167,14 +1180,26 @@ static void InitAudio( hb_job_t * job, hb_sync_common_t * common, int i ) return; } - zeros = calloc( AC3_SAMPLES_PER_FRAME * - sizeof( float ) * c->channels, 1 ); - sync->ac3_size = w->audio->config.in.bitrate * AC3_SAMPLES_PER_FRAME / - w->audio->config.in.samplerate / 8; - sync->ac3_buf = malloc( sync->ac3_size ); + int input_size = c->frame_size * av_get_bytes_per_sample( c->sample_fmt ) * c->channels; + zeros = calloc( 1, input_size ); + // Allocate enough space for the encoded silence + // The output should be < the input + sync->silence_buf = malloc( input_size ); + + // There is some delay in getting output from some audio encoders. + // So encode a few packets till we get output. + int ii; + for ( ii = 0; ii < 10; ii++ ) + { + sync->silence_size = avcodec_encode_audio( c, sync->silence_buf, + input_size, zeros ); - if( avcodec_encode_audio( c, sync->ac3_buf, sync->ac3_size, - zeros ) != sync->ac3_size ) + if (sync->silence_size) + { + break; + } + } + if (!sync->silence_size) { hb_log( "sync: avcodec_encode_audio failed" ); } @@ -1185,12 +1210,19 @@ static void InitAudio( hb_job_t * job, hb_sync_common_t * common, int i ) } else { - /* Initialize libsamplerate */ - int error; - sync->state = src_new( SRC_SINC_MEDIUM_QUALITY, - HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT( - w->audio->config.out.mixdown), &error ); - sync->data.end_of_input = 0; + if( w->audio->config.out.codec & HB_ACODEC_PASS_FLAG ) + { + sync->drop_video_to_sync = 1; + } + else + { + /* Not passthru, Initialize libsamplerate */ + int error; + sync->state = src_new( SRC_SINC_MEDIUM_QUALITY, + HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT( + w->audio->config.out.mixdown), &error ); + sync->data.end_of_input = 0; + } } sync->gain_factor = pow(LVL_PLUS1DB, w->audio->config.out.gain); @@ -1293,29 +1325,39 @@ static void InsertSilence( hb_work_object_t * w, int64_t duration ) hb_sync_audio_t *sync = &pv->type.audio; hb_buffer_t *buf; hb_fifo_t *fifo; + int frame_dur, frame_count; // to keep pass-thru and regular audio in sync we generate silence in - // AC3 frame-sized units. If the silence duration isn't an integer multiple - // of the AC3 frame duration we will truncate or round up depending on + // frame-sized units. If the silence duration isn't an integer multiple + // of the frame duration we will truncate or round up depending on // which minimizes the timing error. - const int frame_dur = ( 90000 * AC3_SAMPLES_PER_FRAME ) / - w->audio->config.in.samplerate; - int frame_count = ( duration + (frame_dur >> 1) ) / frame_dur; + if( w->audio->config.out.codec & HB_ACODEC_PASS_FLAG ) + { + frame_dur = ( 90000 * w->audio->config.in.samples_per_frame ) / + w->audio->config.in.samplerate; + } + else + { + frame_dur = ( 90000 * w->audio->config.out.samples_per_frame ) / + w->audio->config.in.samplerate; + } + frame_count = ( duration + (frame_dur >> 1) ) / frame_dur; while ( --frame_count >= 0 ) { - if( w->audio->config.out.codec == HB_ACODEC_AC3_PASS ) + if( w->audio->config.out.codec & HB_ACODEC_PASS_FLAG ) { - buf = hb_buffer_init( sync->ac3_size ); + buf = hb_buffer_init( sync->silence_size ); buf->start = sync->next_start; buf->stop = buf->start + frame_dur; - memcpy( buf->data, sync->ac3_buf, buf->size ); + memcpy( buf->data, sync->silence_buf, buf->size ); fifo = w->audio->priv.fifo_out; } else { - buf = hb_buffer_init( AC3_SAMPLES_PER_FRAME * sizeof( float ) * - HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT( + buf = hb_buffer_init( w->audio->config.out.samples_per_frame * + sizeof( float ) * + HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT( w->audio->config.out.mixdown) ); buf->start = sync->next_start; buf->stop = buf->start + frame_dur; |