]> granicus.if.org Git - handbrake/commitdiff
Fixes for different number of frames between pass 1 & 2, missing frames at end, and...
authorvan <vanj.hb@gmail.com>
Sun, 13 Apr 2008 23:31:37 +0000 (23:31 +0000)
committervan <vanj.hb@gmail.com>
Sun, 13 Apr 2008 23:31:37 +0000 (23:31 +0000)
 - 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

libhb/common.h
libhb/decmpeg2.c
libhb/hb.c
libhb/reader.c
libhb/sync.c
libhb/work.c

index 1eef164e6fac4f902ba89677982244dd3ff7d336..ae02fecda608e8985aa80eb6c82c55188d53d1de 100644 (file)
@@ -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;
index 76bece1347b3f3b0e5163aa31b0c97c9d3a15d33..03f6656b6a138239dfdbf3f2676beb99f39ac7f0 100644 (file)
@@ -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 );
index 5f176f1ae373b6e5cb2e4c68413f1be33c5d9edb..a6fc87fcaf8229fa7fdeaa85a74078156d21c544 100644 (file)
@@ -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++ )
         {
index 823dfbe84f9aedbdccb76f2455c27eb400898307..a57c79641348a0385db43c02fec3b7b4ea5114d5 100644 (file)
@@ -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)
index d943e62a33eb0b77db30cfb98260837f2a5bd6a3..61e23ff005ea51cd85722ae71cf41442b9d43811 100644 (file)
@@ -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;
         }
 
         /*
index a3507027e806bae9604a96c4b68ad4aa66f7a843..d2290ebf0cf36012946d96ab0285d898e414f736 100644 (file)
@@ -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