OSDN Git Service

Leave video tracks on the 90KHz MPEG timebase so we don't end up with constantly...
[handbrake-jp/handbrake-jp-git.git] / libhb / sync.c
index 524ca4d..f7b342b 100644 (file)
@@ -5,10 +5,9 @@
    It may be used under the terms of the GNU General Public License. */
 
 #include "hb.h"
+#include "hbffmpeg.h"
 #include <stdio.h>
-
 #include "samplerate.h"
-#include "libavcodec/avcodec.h"
 
 #ifdef INT64_MIN
 #undef INT64_MIN /* Because it isn't defined correctly in Zeta */
@@ -61,6 +60,7 @@ struct hb_work_private_s
 
     /* Audio */
     hb_sync_audio_t sync_audio[8];
+    int64_t audio_passthru_slip;
 
     /* Statistics */
     uint64_t st_counts[4];
@@ -97,14 +97,26 @@ int syncInit( hb_work_object_t * w, hb_job_t * job )
     pv->pts_offset     = INT64_MIN;
 
     /* Calculate how many video frames we are expecting */
-    duration = 0;
-    for( i = job->chapter_start; i <= job->chapter_end; i++ )
+    if (job->pts_to_stop)
+    {
+        duration = job->pts_to_stop + 90000;
+    }
+    else if( job->frame_to_stop )
     {
-        chapter   = hb_list_item( title->list_chapter, i - 1 );
-        duration += chapter->duration;
+        /* Set the duration to a rough estimate */
+        duration = ( job->frame_to_stop / ( job->vrate / job->vrate_base ) ) * 90000;
     }
-    duration += 90000;
+    else
+    {
+        duration = 0;
+        for( i = job->chapter_start; i <= job->chapter_end; i++ )
+        {
+            chapter   = hb_list_item( title->list_chapter, i - 1 );
+            duration += chapter->duration;
+        }
+        duration += 90000;
         /* 1 second safety so we're sure we won't miss anything */
+    }
     pv->count_frames_max = duration * job->vrate / job->vrate_base / 90000;
 
     hb_log( "sync: expecting %d video frames", pv->count_frames_max );
@@ -188,14 +200,10 @@ int syncWork( hb_work_object_t * w, hb_buffer_t ** unused1,
     if ( pv->busy & 1 )
         SyncVideo( w );
 
-    /* If we ever got a video frame, handle audio now */
-    if( pv->pts_offset != INT64_MIN )
+    for( i = 0; i < hb_list_count( pv->job->title->list_audio ); i++ )
     {
-        for( i = 0; i < hb_list_count( pv->job->title->list_audio ); i++ )
-        {
-            if ( pv->busy & ( 1 << (i + 1) ) )
-                SyncAudio( w, i );
-        }
+        if ( pv->busy & ( 1 << (i + 1) ) )
+            SyncAudio( w, i );
     }
 
     return ( pv->busy? HB_WORK_OK : HB_WORK_DONE );
@@ -235,7 +243,7 @@ static void InitAudio( hb_work_object_t * w, int i )
         c->sample_rate = sync->audio->config.in.samplerate;
         c->channels    = HB_INPUT_CH_LAYOUT_GET_DISCRETE_COUNT( sync->audio->config.in.channel_layout );
 
-        if( avcodec_open( c, codec ) < 0 )
+        if( hb_avcodec_open( c, codec ) < 0 )
         {
             hb_log( "sync: avcodec_open failed" );
             return;
@@ -254,7 +262,7 @@ static void InitAudio( hb_work_object_t * w, int i )
         }
 
         free( zeros );
-        avcodec_close( c );
+        hb_avcodec_close( c );
         av_free( c );
     }
     else
@@ -329,6 +337,10 @@ static void SyncVideo( hb_work_object_t * w )
             }
         }
 
+        if( cur->new_chap ) {
+            hb_log("sync got new chapter %d", cur->new_chap );
+        }
+
         /*
          * since the first frame is always 0 and the upstream reader code
          * is taking care of adjusting for pts discontinuities, we just have
@@ -340,7 +352,8 @@ static void SyncVideo( hb_work_object_t * w )
          * can deal with overlaps of up to a frame time but anything larger
          * we handle by dropping frames here.
          */
-        if ( (int64_t)( next->start - cur->start ) <= 0 )
+        if ( (int64_t)( next->start - cur->start ) <= 0 ||
+             (int64_t)( (cur->start - pv->audio_passthru_slip ) - pv->next_pts ) < 0 )
         {
             if ( pv->first_drop == 0 )
             {
@@ -615,6 +628,17 @@ static void SyncVideo( hb_work_object_t * w )
 
         /* Update UI */
         UpdateState( w );
+        
+        if( job->frame_to_stop && pv->count_frames > job->frame_to_stop )
+        {
+            // 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 ) );
+            pv->busy &=~ 1;
+            hb_log( "sync: reached %d frames, exiting early (%i busy)",
+                    pv->count_frames, pv->busy );
+            return;
+        }
 
         /* Make sure we won't get more frames then expected */
         if( pv->count_frames >= pv->count_frames_max * 2)
@@ -708,8 +732,10 @@ static void SyncAudio( hb_work_object_t * w, int i )
     hb_audio_t      * audio = sync->audio;
     hb_buffer_t     * buf;
     hb_fifo_t       * fifo;
+    int64_t start;
 
-    if( audio->config.out.codec == HB_ACODEC_AC3 )
+    if( audio->config.out.codec == HB_ACODEC_AC3 ||
+        audio->config.out.codec == HB_ACODEC_DCA )
     {
         fifo = audio->priv.fifo_out;
     }
@@ -720,6 +746,7 @@ static void SyncAudio( hb_work_object_t * w, int i )
 
     while( !hb_fifo_is_full( fifo ) && ( buf = hb_fifo_see( audio->priv.fifo_raw ) ) )
     {
+        start = buf->start - pv->audio_passthru_slip;
         /* if the next buffer is an eof send it downstream */
         if ( buf->size <= 0 )
         {
@@ -728,13 +755,19 @@ static void SyncAudio( hb_work_object_t * w, int i )
             pv->busy &=~ (1 << (i + 1) );
             return;
         }
-        if ( (int64_t)( buf->start - sync->next_pts ) < 0 )
+        if( job->frame_to_stop && pv->count_frames >= job->frame_to_stop )
+        {
+            hb_fifo_push( fifo, hb_buffer_init(0) );
+            pv->busy &=~ (1 << (i + 1) );
+            return;
+        }
+        if ( (int64_t)( start - sync->next_pts ) < 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->first_drop || sync->next_start - buf->start > 90*15 )
+            if ( sync->first_drop || sync->next_start - start > 90*15 )
             {
                 // Discard data that's in the past.
                 if ( sync->first_drop == 0 )
@@ -746,7 +779,7 @@ static void SyncAudio( hb_work_object_t * w, int i )
                 hb_buffer_close( &buf );
                 continue;
             }
-            sync->next_pts = buf->start;
+            sync->next_pts = start;
         }
         if ( sync->first_drop )
         {
@@ -757,19 +790,43 @@ static void SyncAudio( hb_work_object_t * w, int i )
                     sync->drop_count, sync->first_drop, sync->next_pts );
             sync->first_drop = 0;
             sync->drop_count = 0;
-            sync->next_pts = buf->start;
+            sync->next_pts = start;
         }
-        if ( buf->start - sync->next_pts >= (90 * 70) )
+        if ( start - sync->next_pts >= (90 * 70) )
         {
+            if ( start - sync->next_pts > (90000LL * 60) )
+            {
+                // there's a gap of more than a minute between the last
+                // frame and this. assume we got a corrupted timestamp
+                // and just drop the next buf.
+                hb_log( "sync: %d minute time gap in audio %d - dropping buf"
+                        "  start %lld, next %lld",
+                        (int)((start - sync->next_pts) / (90000*60)),
+                        i, start, sync->next_pts );
+                buf = hb_fifo_get( audio->priv.fifo_raw );
+                hb_buffer_close( &buf );
+                continue;
+            }
             /*
              * there's a gap of at least 70ms between the last
              * frame we processed & the next. Fill it with silence.
+             * Or in the case of DCA, skip some frames from the
+             * other streams.
              */
+            if( sync->audio->config.out.codec == HB_ACODEC_DCA )
+            {
+                hb_log( "sync: audio gap %d ms. Skipping frames. Audio %d"
+                        "  start %lld, next %lld",
+                        (int)((start - sync->next_pts) / 90),
+                        i, start, sync->next_pts );
+                pv->audio_passthru_slip += (start - sync->next_pts);
+                return;
+            }
             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 );
+                    (int)((start - sync->next_pts) / 90),
+                    i, start, sync->next_pts );
+            InsertSilence( w, i, start - sync->next_pts );
             return;
         }