summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorvan <[email protected]>2008-04-13 23:31:37 +0000
committervan <[email protected]>2008-04-13 23:31:37 +0000
commitd3aeb74cdf94f70b643da897dfb666d81a743817 (patch)
tree56f6c5ba9b69726d925e7c13f0e2e0245a134c3f
parent280d49d8ae91af433b4df17b2e42b267dbdbc083 (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.h1
-rw-r--r--libhb/decmpeg2.c23
-rw-r--r--libhb/hb.c6
-rw-r--r--libhb/reader.c3
-rw-r--r--libhb/sync.c83
-rw-r--r--libhb/work.c12
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