OSDN Git Service

import 0.9.4
[handbrake-jp/handbrake-jp.git] / libhb / demuxmpeg.c
index b92a8de..afeda30 100644 (file)
@@ -6,6 +6,44 @@
 
 #include "hb.h"
 
+static inline void check_mpeg_scr( hb_psdemux_t *state, int64_t scr, int tol )
+{
+    /*
+     * This section of code implements the timing model of
+     * the "Standard Target Decoder" (STD) of the MPEG2 standard
+     * (specified in ISO 13818-1 sections 2.4.2, 2.5.2 & Annex D).
+     * The STD removes and corrects for clock discontinuities so
+     * that the time stamps on the video, audio & other media
+     * streams can be used for cross-media synchronization. To do
+     * this the STD has its own timestamp value, the System Clock
+     * Reference or SCR, in the PACK header. Clock discontinuities
+     * are detected using the SCR & and the adjustment needed
+     * to correct post-discontinuity timestamps to be contiguous
+     * with pre-discontinuity timestamps is computed from pre- and
+     * post-discontinuity values of the SCR. Then this adjustment
+     * is applied to every media timestamp (PTS).
+     *
+     * ISO 13818-1 says there must be an SCR at least every 700ms
+     * (100ms for Transport Streams) so if the difference between
+     * this SCR & the previous is >700ms it's a discontinuity.
+     * If the difference is negative it's non-physical (time doesn't
+     * go backward) and must also be a discontinuity. When we find a
+     * discontinuity we adjust the scr_offset so that the SCR of the
+     * new packet lines up with that of the previous packet.
+     */
+
+    // we declare a discontinuity if there's a gap of more than
+    // 'tol'ms between the last scr & this or if this scr goes back
+    // by more than half a frame time.
+    int64_t scr_delta = scr - state->last_scr;
+    if ( scr_delta > 90*tol || scr_delta < -90*10 )
+    {
+        ++state->scr_changes;
+        state->last_pts = -1;
+    }
+    state->last_scr = scr;
+}
+
 /* Basic MPEG demuxer */
 
 int hb_demux_ps( hb_buffer_t * buf_ps, hb_list_t * list_es, hb_psdemux_t* state )
@@ -27,29 +65,6 @@ int hb_demux_ps( hb_buffer_t * buf_ps, hb_list_t * list_es, hb_psdemux_t* state
 
     if ( state )
     {
-        /*
-         * This section of code implements the timing model of
-         * the "Standard Target Decoder" (STD) of the MPEG2 standard
-         * (specified in ISO 13818-1 sections 2.4.2, 2.5.2 & Annex D).
-         * The STD removes and corrects for clock discontinuities so
-         * that the time stamps on the video, audio & other media
-         * streams can be used for cross-media synchronization. To do
-         * this the STD has its own timestamp value, the System Clock
-         * Reference or SCR, in the PACK header. Clock discontinuities
-         * are detected using the SCR & and the adjustment needed
-         * to correct post-discontinuity timestamps to be contiguous
-         * with pre-discontinuity timestamps is computed from pre- and
-         * post-discontinuity values of the SCR. Then this adjustment
-         * is applied to every media timestamp (PTS).
-         *
-         * ISO 13818-1 says there must be an SCR at least every 700ms
-         * (100ms for Transport Streams) so if the difference between
-         * this SCR & the previous is >700ms it's a discontinuity.
-         * If the difference is negative it's non-physical (time doesn't
-         * go backward) and must also be a discontinuity. When we find a
-         * discontinuity we adjust the scr_offset so that the SCR of the
-         * new packet lines up with that of the previous packet.
-         */
         /* extract the system clock reference (scr) */
         int64_t scr = ((uint64_t)(d[pos] & 0x38) << 27) |
                       ((uint64_t)(d[pos] & 0x03) << 28) |
@@ -58,15 +73,7 @@ int hb_demux_ps( hb_buffer_t * buf_ps, hb_list_t * list_es, hb_psdemux_t* state
                       ((uint64_t)(d[pos+2] & 3) << 13) |
                       ((uint64_t)(d[pos+3]) << 5) |
                       (d[pos+4] >> 3);
-        // we declare a discontinuity if there's a gap of more than
-        // 100ms between the last scr & this or if this scr goes back
-        // by more than half a frame time.
-        int64_t scr_delta = scr - state->last_scr;
-        if ( scr_delta > 90*100 || scr_delta < -90*10 )
-        {
-            ++state->scr_changes;
-        }
-        state->last_scr = scr;
+        check_mpeg_scr( state, scr, 300 );
     }
 
     pos += 9;                    /* pack_header */
@@ -137,26 +144,6 @@ int hb_demux_ps( hb_buffer_t * buf_ps, hb_list_t * list_es, hb_psdemux_t* state
             {
                 dts = pts;
             }
-            if ( state && state->flaky_clock )
-            {
-                // Program streams have an SCR in every PACK header so they
-                // can't lose their clock reference. But the PCR in Transport
-                // streams is typically on <.1% of the packets. If a PCR
-                // packet gets lost and it marks a clock discontinuity then
-                // the data following it will be referenced to the wrong
-                // clock & introduce huge gaps or throw our A/V sync off.
-                // We try to protect against that here by sanity checking
-                // timestamps against the current reference clock and discarding
-                // packets where the DTS is "too far" from its clock.
-                int64_t fdelta = dts - state->last_scr;
-                if ( fdelta < -300 * 90000LL || fdelta > 300 * 90000LL )
-                {
-                    // packet too far behind or ahead of its clock reference
-                    ++state->dts_drops;
-                    pos = pes_packet_end;
-                    continue;
-                }
-            }
         }
 
         pos = pes_header_end;
@@ -206,6 +193,64 @@ int hb_demux_ps( hb_buffer_t * buf_ps, hb_list_t * list_es, hb_psdemux_t* state
     return 1;
 }
 
+// mpeg transport stream demuxer. the elementary stream headers have been
+// stripped off and buf_ps has all the info gleaned from them: id is set,
+// start contains the pts (if any), renderOffset contains the dts (if any)
+// and stop contains the pcr (if it changed).
+int hb_demux_ts( hb_buffer_t *buf_ps, hb_list_t *list_es, hb_psdemux_t *state )
+{
+    if ( state )
+    {
+        // we're keeping track of timing (i.e., not in scan)
+        // check if there's a new pcr in this packet
+        if ( buf_ps->stop >= 0 )
+        {
+            // we have a new pcr
+            check_mpeg_scr( state, buf_ps->stop, 300 );
+            buf_ps->stop = -1;
+        }
+        if ( buf_ps->start >= 0 )
+        {
+            // Program streams have an SCR in every PACK header so they
+            // can't lose their clock reference. But the PCR in Transport
+            // streams is typically on <.1% of the packets. If a PCR
+            // packet gets lost and it marks a clock discontinuity then
+            // the data following it will be referenced to the wrong
+            // clock & introduce huge gaps or throw our A/V sync off.
+            // We try to protect against that here by sanity checking
+            // timestamps against the current reference clock and discarding
+            // packets where the DTS is "too far" from its clock.
+            int64_t fdelta = buf_ps->start - state->last_scr;
+            if ( fdelta < -300 * 90000LL || fdelta > 300 * 90000LL )
+            {
+                // packet too far behind or ahead of its clock reference
+                ++state->dts_drops;
+                return 1;
+            }
+            if ( state->last_pts >= 0 )
+            {
+                fdelta = buf_ps->start - state->last_pts;
+                if ( fdelta < -5 * 90000LL || fdelta > 5 * 90000LL )
+                {
+                    // Packet too far from last. This may be a NZ TV broadcast
+                    // as they like to change the PCR without sending a PCR
+                    // update. Since it may be a while until they actually tell
+                    // us the new PCR use the PTS as the PCR.
+                    ++state->scr_changes;
+                    state->last_scr = buf_ps->start;
+                }
+            }
+            state->last_pts = buf_ps->start;
+        }
+    }
+
+    hb_buffer_t *buf = hb_buffer_init( buf_ps->alloc );
+    hb_buffer_swap_copy( buf_ps, buf );
+    hb_list_add( list_es, buf );
+
+    return 1;
+}
+
 // "null" demuxer (makes a copy of input buf & returns it in list)
 // used when the reader for some format includes its own demuxer.
 // for example, ffmpeg.
@@ -219,17 +264,11 @@ int hb_demux_null( hb_buffer_t * buf_ps, hb_list_t * list_es, hb_psdemux_t* stat
         state->last_scr = buf_ps->start >= 0 ? buf_ps->start : buf_ps->renderOffset;
     }
 
-    hb_buffer_t *buf = hb_buffer_init( buf_ps->size );
-
-    // copy everything from the old to the new except the data ptr & alloc
-    uint8_t *data = buf->data;
-    int alloc = buf->alloc;
-    *buf = *buf_ps;
-    buf->data = data;
-    buf->alloc = alloc;
-
-    // now copy the data
-    memcpy( buf->data, buf_ps->data, buf_ps->size );
+    hb_buffer_t *buf = hb_buffer_init( buf_ps->alloc );
+    hb_buffer_swap_copy( buf_ps, buf );
     hb_list_add( list_es, buf );
+
     return 1;
 }
+
+const hb_muxer_t hb_demux[] = { hb_demux_ps, hb_demux_ts, hb_demux_null };