OSDN Git Service

WinGui:
[handbrake-jp/handbrake-jp-git.git] / libhb / reader.c
index 346cafd..6e7f0e6 100644 (file)
@@ -31,6 +31,9 @@ typedef struct
     uint8_t        st_slots;        // size (in slots) of stream_timing array
     uint8_t        saw_video;       // != 0 if we've seen video
     uint8_t        saw_audio;       // != 0 if we've seen audio
+
+    int            start_found;     // found pts_to_start point
+    uint64_t       st_first;
 } hb_reader_t;
 
 /***********************************************************************
@@ -38,6 +41,7 @@ typedef struct
  **********************************************************************/
 static void        ReaderFunc( void * );
 static hb_fifo_t ** GetFifoForId( hb_job_t * job, int id );
+static void UpdateState( hb_reader_t  * r, int64_t start);
 
 /***********************************************************************
  * hb_reader_init
@@ -63,13 +67,23 @@ hb_thread_t * hb_reader_init( hb_job_t * job )
     r->stream_timing[0].last = -r->stream_timing[0].average;
     r->stream_timing[1].id = -1;
 
+    if ( !job->pts_to_start )
+        r->start_found = 1;
+
     return hb_thread_init( "reader", ReaderFunc, r,
                            HB_NORMAL_PRIORITY );
 }
 
 static void push_buf( const hb_reader_t *r, hb_fifo_t *fifo, hb_buffer_t *buf )
 {
-    hb_fifo_push_wait( fifo, buf );
+    while ( !*r->die && !r->job->done )
+    {
+        if ( hb_fifo_full_wait( fifo ) )
+        {
+            hb_fifo_push( fifo, buf );
+            break;
+        }
+    }
 }
 
 static int is_audio( hb_reader_t *r, int id )
@@ -202,6 +216,7 @@ static void ReaderFunc( void * _r )
         return;
     }
 
+    hb_buffer_t *ps = hb_buffer_init( HB_DVD_READ_BUFFER_SIZE );
     if (r->dvd)
     {
         /*
@@ -226,6 +241,7 @@ static void ReaderFunc( void * _r )
         if( !hb_dvd_start( r->dvd, r->title, start ) )
         {
             hb_dvd_close( &r->dvd );
+            hb_buffer_close( &ps );
             return;
         }
         if (r->job->angle)
@@ -248,6 +264,28 @@ static void ReaderFunc( void * _r )
                         ( r->job->seek_points ? ( r->job->seek_points + 1.0 ) : 11.0 ) );
 
     } 
+    else if ( r->stream && r->job->pts_to_start )
+    {
+        int64_t pts_to_start = r->job->pts_to_start;
+        
+        // Find out what the first timestamp of the stream is
+        // and then seek to the appropriate offset from it
+        if ( hb_stream_read( r->stream, ps ) )
+        {
+            if ( ps->start > 0 )
+                pts_to_start += ps->start;
+        }
+        
+        if ( hb_stream_seek_ts( r->stream, pts_to_start ) >= 0 )
+        {
+            // Seek takes us to the nearest I-frame before the timestamp
+            // that we want.  So we will retrieve the start time of the
+            // first packet we get, subtract that from pts_to_start, and
+            // inspect the reset of the frames in sync.
+            r->start_found = 2;
+            r->job->pts_to_start = pts_to_start;
+        }
+    } 
     else if( r->stream )
     {
         /*
@@ -271,7 +309,6 @@ static void ReaderFunc( void * _r )
     }
 
     list  = hb_list_init();
-    hb_buffer_t *ps = hb_buffer_init( HB_DVD_READ_BUFFER_SIZE );
 
     while( !*r->die && !r->job->done )
     {
@@ -305,6 +342,17 @@ static void ReaderFunc( void * _r )
           {
             break;
           }
+          if ( r->start_found == 2 )
+          {
+            // We will inspect the timestamps of each frame in sync
+            // to skip from this seek point to the timestamp we
+            // want to start at.
+            if ( ps->start > 0 && ps->start < r->job->pts_to_start )
+                r->job->pts_to_start -= ps->start;
+            else if ( ps->start >= r->job->pts_to_start )
+                r->job->pts_to_start = 0;
+            r->start_found = 1;
+          }
         }
 
         if( r->job->indepth_scan )
@@ -336,7 +384,7 @@ static void ReaderFunc( void * _r )
             hb_list_rem( list, buf );
             fifos = GetFifoForId( r->job, buf->id );
 
-            if ( fifos && ! r->saw_video )
+            if ( fifos && ! r->saw_video && !r->job->indepth_scan )
             {
                 // The first data packet with a PTS from an audio or video stream
                 // that we're decoding defines 'time zero'. Discard packets until
@@ -362,16 +410,7 @@ static void ReaderFunc( void * _r )
             {
                 if ( buf->renderOffset != -1 )
                 {
-                    if ( r->scr_changes == r->demux.scr_changes )
-                    {
-                        // This packet is referenced to the same SCR as the last.
-                        // Adjust timestamp to remove the System Clock Reference
-                        // offset then update the average inter-packet time
-                        // for this stream.
-                        buf->renderOffset -= r->scr_offset;
-                        update_ipt( r, buf );
-                    }
-                    else
+                    if ( r->scr_changes != r->demux.scr_changes )
                     {
                         // This is the first audio or video packet after an SCR
                         // change. Compute a new scr offset that would make this
@@ -425,15 +464,48 @@ static void ReaderFunc( void * _r )
                 }
                 if ( buf->start != -1 )
                 {
+                    int64_t start = buf->start - r->scr_offset;
+                    if ( !r->start_found )
+                        UpdateState( r, start );
+
+                    if ( !r->start_found &&
+                        r->job->pts_to_start && 
+                        buf->renderOffset != -1 &&
+                        start >= r->job->pts_to_start )
+                    {
+                        // pts_to_start point found
+                        // force a new scr offset computation
+                        stream_timing_t *st = find_st( r, buf );
+                        if ( st && 
+                            (st->is_audio ||
+                            ( st == r->stream_timing && !r->saw_audio ) ) )
+                        {
+                            // Re-zero our timestamps
+                            st->last = -st->average;
+                            new_scr_offset( r, buf );
+                            r->start_found = 1;
+                            r->job->pts_to_start = 0;
+                        }
+                    }
                     buf->start -= r->scr_offset;
-                    if ( r->job->pts_to_stop && buf->start > r->job->pts_to_stop )
+                }
+                if ( buf->renderOffset != -1 )
+                {
+                    if ( r->scr_changes == r->demux.scr_changes )
                     {
-                        // we're doing a subset of the input and we've hit the
-                        // stopping point.
-                        hb_buffer_close( &buf );
-                        goto done;
+                        // This packet is referenced to the same SCR as the last.
+                        // Adjust timestamp to remove the System Clock Reference
+                        // offset then update the average inter-packet time
+                        // for this stream.
+                        buf->renderOffset -= r->scr_offset;
+                        update_ipt( r, buf );
                     }
                 }
+                if ( !r->start_found )
+                {
+                    hb_buffer_close( &buf );
+                    continue;
+                }
 
                 buf->sequence = r->sequence++;
                 /* if there are mutiple output fifos, send a copy of the
@@ -456,7 +528,6 @@ static void ReaderFunc( void * _r )
         }
     }
 
-  done:
     // send empty buffers downstream to video & audio decoders to signal we're done.
     if( !*r->die && !r->job->done )
     {
@@ -504,6 +575,46 @@ static void ReaderFunc( void * _r )
     _r = NULL;
 }
 
+static void UpdateState( hb_reader_t  * r, int64_t start)
+{
+    hb_state_t state;
+    uint64_t now;
+    double avg;
+
+    now = hb_get_date();
+    if( !r->st_first )
+    {
+        r->st_first = now;
+    }
+
+#define p state.param.working
+    state.state = HB_STATE_SEARCHING;
+    p.progress  = (float) start / (float) r->job->pts_to_start;
+    if( p.progress > 1.0 )
+    {
+        p.progress = 1.0;
+    }
+    if (now > r->st_first)
+    {
+        int eta;
+
+        avg = 1000.0 * (double)start / (now - r->st_first);
+        eta = ( r->job->pts_to_start - start ) / avg;
+        p.hours   = eta / 3600;
+        p.minutes = ( eta % 3600 ) / 60;
+        p.seconds = eta % 60;
+    }
+    else
+    {
+        p.rate_avg = 0.0;
+        p.hours    = -1;
+        p.minutes  = -1;
+        p.seconds  = -1;
+    }
+#undef p
+
+    hb_set_state( r->job->h, &state );
+}
 /***********************************************************************
  * GetFifoForId
  ***********************************************************************