diff options
author | van <[email protected]> | 2008-04-13 23:31:37 +0000 |
---|---|---|
committer | van <[email protected]> | 2008-04-13 23:31:37 +0000 |
commit | d3aeb74cdf94f70b643da897dfb666d81a743817 (patch) | |
tree | 56f6c5ba9b69726d925e7c13f0e2e0245a134c3f | |
parent | 280d49d8ae91af433b4df17b2e42b267dbdbc083 (diff) |
Fixes for different number of frames between pass 1 & 2, missing frames at end, and an deadlock with pcm audio.
- since the SCR clock recovery is done in reader.c we can't currently skip audio frames during pass 1 or we miss clock changes signaled by those frames & end up dropping more video frames in pass 1 than pass 2.
- since many modules buffer frames we can't tell if we're done just by looking for empty fifos. Send an empty buffer to mark end-of-stream all the way along the processing pipeline & use it to flush internally buffered data.
- in a processing pipeline you're done when the end of the pipe says your done. add a thread status variable so we can tell when individual threads are finished then make do_job wait until the encoder thread is done so that we're sure all the frames have been processed and sent to the muxer.
- since the muxer alternates between reading video & audio packets we have to have enough buffer in the audio pipeline to handle a video-frame's worth of audio packets (33ms). Since pcm packets are <1ms we need >60 slots in the audio fifos or we'll deadlock.
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@1412 b64f7644-9d1e-0410-96f1-a4d463321fa5
-rw-r--r-- | libhb/common.h | 1 | ||||
-rw-r--r-- | libhb/decmpeg2.c | 23 | ||||
-rw-r--r-- | libhb/hb.c | 6 | ||||
-rw-r--r-- | libhb/reader.c | 3 | ||||
-rw-r--r-- | libhb/sync.c | 83 | ||||
-rw-r--r-- | libhb/work.c | 12 |
6 files changed, 55 insertions, 73 deletions
diff --git a/libhb/common.h b/libhb/common.h index 1eef164e6..ae02fecda 100644 --- a/libhb/common.h +++ b/libhb/common.h @@ -523,6 +523,7 @@ struct hb_work_object_s hb_thread_t * thread; volatile int * done; + int status; hb_work_object_t * next; int thread_sleep_interval; diff --git a/libhb/decmpeg2.c b/libhb/decmpeg2.c index 76bece134..03f6656b6 100644 --- a/libhb/decmpeg2.c +++ b/libhb/decmpeg2.c @@ -77,14 +77,17 @@ int hb_libmpeg2_decode( hb_libmpeg2_t * m, hb_buffer_t * buf_es, hb_buffer_t * buf; uint8_t * data; - /* Feed libmpeg2 */ - if( buf_es->start > -1 ) + if ( buf_es->size ) { - mpeg2_tag_picture( m->libmpeg2, buf_es->start >> 32, - buf_es->start & 0xFFFFFFFF ); + /* Feed libmpeg2 */ + if( buf_es->start > -1 ) + { + mpeg2_tag_picture( m->libmpeg2, buf_es->start >> 32, + buf_es->start & 0xFFFFFFFF ); + } + mpeg2_buffer( m->libmpeg2, buf_es->data, + buf_es->data + buf_es->size ); } - mpeg2_buffer( m->libmpeg2, buf_es->data, - buf_es->data + buf_es->size ); for( ;; ) { @@ -397,6 +400,13 @@ int decmpeg2Work( hb_work_object_t * w, hb_buffer_t ** buf_in, hb_libmpeg2_decode( pv->libmpeg2, *buf_in, pv->list ); + /* if we got an empty buffer signaling end-of-stream send it downstream */ + if ( (*buf_in)->size == 0 ) + { + hb_list_add( pv->list, *buf_in ); + *buf_in = NULL; + } + *buf_out = NULL; while( ( buf = hb_list_item( pv->list, 0 ) ) ) { @@ -424,6 +434,7 @@ int decmpeg2Work( hb_work_object_t * w, hb_buffer_t ** buf_in, void decmpeg2Close( hb_work_object_t * w ) { hb_work_private_t * pv = w->private_data; + hb_log( "mpeg2 done: %d frames", pv->libmpeg2->nframes ); hb_list_close( &pv->list ); hb_libmpeg2_close( &pv->libmpeg2 ); free( pv ); diff --git a/libhb/hb.c b/libhb/hb.c index 5f176f1ae..a6fc87fca 100644 --- a/libhb/hb.c +++ b/libhb/hb.c @@ -857,7 +857,11 @@ void hb_add( hb_handle_t * h, hb_job_t * job ) title_copy->list_audio = hb_list_init(); /* Do nothing about audio during first pass */ - if( job->pass == 0 || job->pass == 2 ) + // XXX for right now we need to see the audio in libhb/reader.c to track + // clock changes otherwise we'll discard more video frames in pass 1 than + // pass 2 & screw up the encoding. Once the clock tracking is moved from + // reader to the mpeg demuxer this code can be restored. + //if( job->pass == 0 || job->pass == 2 ) { for( i = 0; i < hb_list_count(job->list_audio); i++ ) { diff --git a/libhb/reader.c b/libhb/reader.c index 823dfbe84..a57c79641 100644 --- a/libhb/reader.c +++ b/libhb/reader.c @@ -269,6 +269,9 @@ static void ReaderFunc( void * _r ) } } + /* send an empty buffer upstream to signal we're done */ + hb_fifo_push( r->job->fifo_mpeg2, hb_buffer_init(0) ); + hb_list_empty( &list ); hb_buffer_close( &r->ps ); if (r->dvd) diff --git a/libhb/sync.c b/libhb/sync.c index d943e62a3..61e23ff00 100644 --- a/libhb/sync.c +++ b/libhb/sync.c @@ -26,7 +26,6 @@ typedef struct int64_t start_silence; /* if we're inserting silence, the time we started */ int64_t first_drop; /* PTS of first 'went backwards' frame dropped */ int drop_count; /* count of 'time went backwards' drops */ - int inserting_silence; /* Raw */ SRC_STATE * state; @@ -284,22 +283,6 @@ static int SyncVideo( hb_work_object_t * w ) return HB_WORK_DONE; } - if( hb_thread_has_exited( job->reader ) && - !hb_fifo_size( job->fifo_mpeg2 ) && - !hb_fifo_size( job->fifo_raw ) ) - { - pv->done = 1; - - hb_buffer_t * buf_tmp; - - // Drop an empty buffer into our output to ensure that things - // get flushed all the way out. - buf_tmp = hb_buffer_init(0); // Empty end buffer - hb_fifo_push( job->fifo_sync, buf_tmp ); - - return HB_WORK_DONE; - } - if( !pv->cur && !( pv->cur = hb_fifo_get( job->fifo_raw ) ) ) { /* We haven't even got a frame yet */ @@ -316,6 +299,15 @@ static int SyncVideo( hb_work_object_t * w ) { hb_buffer_t * buf_tmp; + if( next->size == 0 ) + { + // we got the empty buffer that signals end-of-stream + // note that we're done but continue to the end of this + // loop so that the final frame gets processed. + pv->done = 1; + next->start = pv->next_pts + 90*30; + } + if( pv->pts_offset == INT64_MIN ) { /* This is our first frame */ @@ -627,16 +619,18 @@ static int SyncVideo( hb_work_object_t * w ) { hb_log( "sync: got too many frames (%d), exiting early", pv->count_frames ); pv->done = 1; + } - // Drop an empty buffer into our output to ensure that things - // get flushed all the way out. - buf_tmp = hb_buffer_init(0); // Empty end buffer - hb_fifo_push( job->fifo_sync, buf_tmp ); + if ( pv->done ) + { + hb_buffer_close( &pv->cur ); - break; + // Drop an empty buffer into our output to ensure that things + // get flushed all the way out. + hb_fifo_push( job->fifo_sync, hb_buffer_init( 0 ) ); + return HB_WORK_DONE; } } - return HB_WORK_OK; } @@ -701,16 +695,6 @@ static void OutputAudioFrame( hb_job_t *job, hb_audio_t *audio, hb_buffer_t *buf buf->start = start; buf->stop = start + duration; sync->next_start = start + duration; - while( hb_fifo_is_full( fifo ) ) - { - hb_snooze( 50 ); - if ( job->done && hb_fifo_is_full( fifo ) ) - { - /* don't block here if the job's finished */ - hb_buffer_close( &buf ); - return; - } - } hb_fifo_push( fifo, buf ); } @@ -764,41 +748,18 @@ static void SyncAudio( hb_work_object_t * w, int i ) sync->first_drop = 0; sync->drop_count = 0; } - - if ( sync->inserting_silence && (int64_t)(buf->start - sync->next_pts) > 0 ) - { - /* - * if we're within one frame time of the amount of silence - * we need, insert just what we need otherwise insert a frame time. - */ - int64_t framedur = buf->stop - buf->start; - if ( buf->start - sync->next_pts <= framedur ) - { - InsertSilence( w, i, buf->start - sync->next_pts ); - sync->inserting_silence = 0; - } - else - { - InsertSilence( w, i, framedur ); - } - continue; - } if ( buf->start - sync->next_pts >= (90 * 70) ) { /* * there's a gap of at least 70ms between the last * frame we processed & the next. Fill it with silence. */ - if ( ! sync->inserting_silence ) - { - hb_log( "sync: adding %d ms of silence to audio %d" - " start %lld, next %lld", - (int)((buf->start - sync->next_pts) / 90), - i, buf->start, sync->next_pts ); - sync->inserting_silence = 1; - } + hb_log( "sync: adding %d ms of silence to audio %d" + " start %lld, next %lld", + (int)((buf->start - sync->next_pts) / 90), + i, buf->start, sync->next_pts ); InsertSilence( w, i, buf->start - sync->next_pts ); - continue; + return; } /* diff --git a/libhb/work.c b/libhb/work.c index a3507027e..d2290ebf0 100644 --- a/libhb/work.c +++ b/libhb/work.c @@ -103,6 +103,7 @@ static void do_job( hb_job_t * job, int cpu_count ) /* FIXME: This feels really hackish, anything better? */ hb_work_object_t * audio_w = NULL; hb_work_object_t * sub_w = NULL; + hb_work_object_t * encoder_w = NULL; hb_audio_t * audio; hb_subtitle_t * subtitle; @@ -274,6 +275,8 @@ static void do_job( hb_job_t * job, int cpu_count ) w->config = &job->config; hb_list_add( job->list_work, w ); + /* remember the encoder so we can wait for it to finish */ + encoder_w = w; if( job->select_subtitle && !job->indepth_scan ) { @@ -504,9 +507,9 @@ static void do_job( hb_job_t * job, int cpu_count ) audio->priv.config.vorbis.language = audio->config.lang.simple; /* set up the audio work structures */ - audio->priv.fifo_in = hb_fifo_init( 2048 ); + audio->priv.fifo_in = hb_fifo_init( 256 ); audio->priv.fifo_raw = hb_fifo_init( FIFO_CPU_MULT * cpu_count ); - audio->priv.fifo_sync = hb_fifo_init( FIFO_CPU_MULT * cpu_count ); + audio->priv.fifo_sync = hb_fifo_init( 256 ); audio->priv.fifo_out = hb_fifo_init( FIFO_CPU_MULT * cpu_count ); @@ -618,8 +621,7 @@ static void do_job( hb_job_t * job, int cpu_count ) done = 1; } if( done && - !hb_fifo_size( job->fifo_sync ) && - !hb_fifo_size( job->fifo_render ) && + encoder_w->status == HB_WORK_DONE && !hb_fifo_size( job->fifo_mpeg4 ) ) { break; @@ -831,7 +833,7 @@ static void work_loop( void * _w ) } // w->thread_sleep_interval = MAX(1, (w->thread_sleep_interval - 1)); - w->work( w, &buf_in, &buf_out ); + w->status = w->work( w, &buf_in, &buf_out ); // Propagate any chapter breaks for the worker if and only if the // output frame has the same time stamp as the input frame (any |