OSDN Git Service

LinGui: Changes required by latest x264
[handbrake-jp/handbrake-jp-git.git] / libhb / reader.c
index 8e9da7f..c93c2a0 100644 (file)
@@ -8,8 +8,8 @@
 
 typedef struct
 {
-    int64_t last;   // last timestamp seen on this stream
     double average; // average time between packets
+    int64_t last;   // last timestamp seen on this stream
     int id;         // stream id
 } stream_timing_t;
 
@@ -83,10 +83,23 @@ static void push_buf( const hb_reader_t *r, hb_fifo_t *fifo, hb_buffer_t *buf )
 // seemlessly join packets on either side of the discontinuity. This join
 // requires that we know the timestamp of the previous packet and the
 // average inter-packet time (since we position the new packet at the end
-// of the previous packet). The next three routines keep track of this
+// of the previous packet). The next four routines keep track of this
 // per-stream timing.
 
-// find the per-stream timing state associated with 'buf'
+// find the per-stream timing state for 'buf'
+
+static stream_timing_t *find_st( hb_reader_t *r, const hb_buffer_t *buf )
+{
+    stream_timing_t *st = r->stream_timing;
+    for ( ; st->id != -1; ++st )
+    {
+        if ( st->id == buf->id )
+            return st;
+    }
+    return NULL;
+}
+
+// find or create the per-stream timing state for 'buf'
 
 static stream_timing_t *id_to_st( hb_reader_t *r, const hb_buffer_t *buf )
 {
@@ -125,7 +138,7 @@ static void update_ipt( hb_reader_t *r, const hb_buffer_t *buf )
 {
     stream_timing_t *st = id_to_st( r, buf );
     double dt = buf->renderOffset - st->last;
-    st->average += ( dt - st->average ) * (1./16.);
+    st->average += ( dt - st->average ) * (1./32.);
     st->last = buf->renderOffset;
 }
 
@@ -133,11 +146,12 @@ static void update_ipt( hb_reader_t *r, const hb_buffer_t *buf )
 // such that 'buf' will follow the previous packet of this stream separated
 // by the average packet time of the stream.
 
-static void new_scr_offset( hb_reader_t *r, const hb_buffer_t *buf )
+static void new_scr_offset( hb_reader_t *r, hb_buffer_t *buf )
 {
     stream_timing_t *st = id_to_st( r, buf );
-    int64_t nxt = st->last + st->average - r->scr_offset;
+    int64_t nxt = st->last + st->average;
     r->scr_offset = buf->renderOffset - nxt;
+    buf->renderOffset = nxt;
     r->scr_changes = r->demux.scr_changes;
     st->last = buf->renderOffset;
 }
@@ -195,6 +209,7 @@ static void ReaderFunc( void * _r )
 
     list  = hb_list_init();
     hb_buffer_t *ps = hb_buffer_init( HB_DVD_READ_BUFFER_SIZE );
+    r->demux.flaky_clock = r->title->flaky_clock;
 
     while( !*r->die && !r->job->done )
     {
@@ -273,11 +288,10 @@ static void ReaderFunc( void * _r )
                 if ( buf->id == r->title->video_id && buf->start != -1 &&
                      buf->renderOffset != -1 )
                 {
+                    // force a new scr offset computation
+                    r->scr_changes = r->demux.scr_changes - 1;
                     r->saw_video = 1;
-                    r->scr_changes = r->demux.scr_changes;
-                    new_scr_offset( r, buf );
-                    hb_log( "reader: first SCR %lld scr_offset %lld",
-                            r->demux.last_scr, r->scr_offset );
+                    hb_log( "reader: first SCR %lld", r->demux.last_scr );
                 }
                 else
                 {
@@ -291,7 +305,10 @@ static void ReaderFunc( void * _r )
                     if ( r->scr_changes == r->demux.scr_changes )
                     {
                         // This packet is referenced to the same SCR as the last.
-                        // Update the average inter-packet time for this stream.
+                        // 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
@@ -300,10 +317,38 @@ static void ReaderFunc( void * _r )
                         // change. Compute a new scr offset that would make this
                         // packet follow the last of this stream with the correct
                         // average spacing.
-                        new_scr_offset( r, buf );
+                        stream_timing_t *st = find_st( r, buf );
+
+                        if ( st )
+                        {
+                            // if this isn't the video stream or we don't
+                            // have audio yet then generate a new scr
+                            if ( st != r->stream_timing ||
+                                 r->stream_timing[1].id == -1 )
+                            {
+                                new_scr_offset( r, buf );
+                            }
+                            else
+                            {
+                                // defer the scr change until we get some
+                                // audio since audio has a timestamp per
+                                // frame but video doesn't. Clear the timestamps
+                                // so the decoder will regenerate them from
+                                // the frame durations.
+                                buf->start = -1;
+                                buf->renderOffset = -1;
+                            }
+                        }
+                        else
+                        {
+                            // we got a new scr at the same time as the first
+                            // packet of a stream we've never seen before. We
+                            // have no idea what the timing should be so toss
+                            // this buffer & wait for a stream we've already seen.
+                            hb_buffer_close( &buf );
+                            continue;
+                        }
                     }
-                    // adjust timestamps to remove System Clock Reference offsets.
-                    buf->renderOffset -= r->scr_offset;
                 }
                 if ( buf->start != -1 )
                     buf->start -= r->scr_offset;
@@ -357,6 +402,10 @@ static void ReaderFunc( void * _r )
     }
 
     hb_log( "reader: done. %d scr changes", r->demux.scr_changes );
+    if ( r->demux.dts_drops )
+    {
+        hb_log( "reader: %d drops because DTS out of range", r->demux.dts_drops );
+    }
 
     free( r );
     _r = NULL;