tsdemux: Handle rollover in PTS and DTS
authorEdward Hervey <edward.hervey@collabora.co.uk>
Tue, 10 Jan 2012 10:37:13 +0000 (11:37 +0100)
committerEdward Hervey <edward.hervey@collabora.co.uk>
Tue, 10 Jan 2012 10:45:22 +0000 (11:45 +0100)
Also hands back-rollover which can happen with PTS

gst/mpegtsdemux/tsdemux.c

index 118ffb5..58f3a82 100644 (file)
@@ -63,6 +63,7 @@
 #define PCR_SMALL 17775000
 /* maximal PCR time */
 #define PCR_MAX_VALUE (((((guint64)1)<<33) * 300) + 298)
+#define PTS_DTS_MAX_VALUE (((guint64)1) << 33)
 
 /* seek to SEEK_TIMESTAMP_OFFSET before the desired offset and search then
  * either accurately or for the next timestamp
@@ -72,6 +73,8 @@
 GST_DEBUG_CATEGORY_STATIC (ts_demux_debug);
 #define GST_CAT_DEFAULT ts_demux_debug
 
+#define ABSDIFF(a,b) (((a) > (b)) ? ((a) - (b)) : ((b) - (a)))
+
 static GQuark QUARK_TSDEMUX;
 static GQuark QUARK_PID;
 static GQuark QUARK_PCR;
@@ -116,8 +119,15 @@ struct _TSDemuxStream
   GstBufferListIterator *currentit;
   GList *currentlist;
 
-  /* Current PTS for this stream */
+  /* Current PTS/DTS for this stream */
   GstClockTime pts;
+  GstClockTime dts;
+  /* Raw value of current PTS/DTS */
+  guint64 raw_pts;
+  guint64 raw_dts;
+  /* Number of rollover seen for PTS/DTS (default:0) */
+  guint nb_pts_rollover;
+  guint nb_dts_rollover;
 };
 
 #define VIDEO_CAPS \
@@ -1229,7 +1239,13 @@ gst_ts_demux_stream_added (MpegTSBase * base, MpegTSBaseStream * bstream,
     /* Create the pad */
     if (bstream->stream_type != 0xff)
       stream->pad = create_pad_for_stream (base, bstream, program);
+
     stream->pts = GST_CLOCK_TIME_NONE;
+    stream->dts = GST_CLOCK_TIME_NONE;
+    stream->raw_pts = 0;
+    stream->raw_dts = 0;
+    stream->nb_pts_rollover = 0;
+    stream->nb_dts_rollover = 0;
   }
   stream->flow_return = GST_FLOW_OK;
 }
@@ -1865,9 +1881,33 @@ gst_ts_demux_record_pts (GstTSDemux * demux, TSDemuxStream * stream,
 {
   MpegTSBaseStream *bs = (MpegTSBaseStream *) stream;
 
-  GST_LOG ("pid 0x%04x pts:%" GST_TIME_FORMAT " at offset %"
-      G_GUINT64_FORMAT, bs->pid,
-      GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (pts)), offset);
+  GST_LOG ("pid 0x%04x pts:%" G_GUINT64_FORMAT " at offset %"
+      G_GUINT64_FORMAT, bs->pid, pts, offset);
+
+  if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (stream->pts) &&
+          ABSDIFF (stream->raw_pts, pts) > 900000)) {
+    /* Detect rollover if diff > 10s */
+    GST_LOG ("Detected rollover (previous:%" G_GUINT64_FORMAT " new:%"
+        G_GUINT64_FORMAT ")", stream->raw_pts, pts);
+    if (pts < stream->raw_pts) {
+      /* Forward rollover */
+      GST_LOG ("Forward rollover, incrementing nb_pts_rollover");
+      stream->nb_pts_rollover++;
+    } else {
+      /* Reverse rollover */
+      GST_LOG ("Reverse rollover, decrementing nb_pts_rollover");
+      stream->nb_pts_rollover--;
+    }
+  }
+
+  /* Compute PTS in GstClockTime */
+  stream->raw_pts = pts;
+  stream->pts =
+      MPEGTIME_TO_GSTTIME (pts + stream->nb_pts_rollover * PTS_DTS_MAX_VALUE);
+
+  GST_LOG ("pid 0x%04x Stored PTS %" G_GUINT64_FORMAT " (%" GST_TIME_FORMAT ")",
+      bs->pid, stream->raw_pts, GST_TIME_ARGS (stream->pts));
+
 
   if (G_UNLIKELY (demux->emit_statistics)) {
     GstStructure *st;
@@ -1887,9 +1927,32 @@ gst_ts_demux_record_dts (GstTSDemux * demux, TSDemuxStream * stream,
 {
   MpegTSBaseStream *bs = (MpegTSBaseStream *) stream;
 
-  GST_LOG ("pid 0x%04x dts:%" GST_TIME_FORMAT " at offset %"
-      G_GUINT64_FORMAT, bs->pid,
-      GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (dts)), offset);
+  GST_LOG ("pid 0x%04x dts:%" G_GUINT64_FORMAT " at offset %"
+      G_GUINT64_FORMAT, bs->pid, dts, offset);
+
+  if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (stream->dts) &&
+          ABSDIFF (stream->raw_dts, dts) > 900000)) {
+    /* Detect rollover if diff > 10s */
+    GST_LOG ("Detected rollover (previous:%" G_GUINT64_FORMAT " new:%"
+        G_GUINT64_FORMAT ")", stream->raw_dts, dts);
+    if (dts < stream->raw_dts) {
+      /* Forward rollover */
+      GST_LOG ("Forward rollover, incrementing nb_dts_rollover");
+      stream->nb_dts_rollover++;
+    } else {
+      /* Reverse rollover */
+      GST_LOG ("Reverse rollover, decrementing nb_dts_rollover");
+      stream->nb_dts_rollover--;
+    }
+  }
+
+  /* Compute DTS in GstClockTime */
+  stream->raw_dts = dts;
+  stream->dts =
+      MPEGTIME_TO_GSTTIME (dts + stream->nb_dts_rollover * PTS_DTS_MAX_VALUE);
+
+  GST_LOG ("pid 0x%04x Stored DTS %" G_GUINT64_FORMAT " (%" GST_TIME_FORMAT ")",
+      bs->pid, stream->raw_dts, GST_TIME_ARGS (stream->dts));
 
   if (G_UNLIKELY (demux->emit_statistics)) {
     GstStructure *st;
@@ -1939,7 +2002,6 @@ gst_ts_demux_parse_pes_header (GstTSDemux * demux, TSDemuxStream * stream)
   guint8 *data;
   guint32 length;
   guint64 bufferoffset;
-  GstClockTime time;
   PESParsingResult parseres;
 
   data = GST_BUFFER_DATA (stream->pendingbuffers[0]);
@@ -1957,6 +2019,9 @@ gst_ts_demux_parse_pes_header (GstTSDemux * demux, TSDemuxStream * stream)
     goto discont;
   }
 
+  if (header.DTS != -1)
+    gst_ts_demux_record_dts (demux, stream, header.DTS, bufferoffset);
+
   if (header.PTS != -1) {
     gst_ts_demux_record_pts (demux, stream, header.PTS, bufferoffset);
 
@@ -1980,7 +2045,6 @@ gst_ts_demux_parse_pes_header (GstTSDemux * demux, TSDemuxStream * stream)
     time = calc_gsttime_from_pts (&demux->index_pcr, pts);
 #endif
 
-    stream->pts = time = MPEGTIME_TO_GSTTIME (header.PTS);
     GST_DEBUG_OBJECT (base, "stream PTS %" GST_TIME_FORMAT,
         GST_TIME_ARGS (stream->pts));
 
@@ -2012,12 +2076,10 @@ gst_ts_demux_parse_pes_header (GstTSDemux * demux, TSDemuxStream * stream)
     if (!GST_CLOCK_TIME_IS_VALID (base->in_gap))
       base->in_gap = 0;
 
-    GST_BUFFER_TIMESTAMP (stream->pendingbuffers[0]) = time + base->in_gap;
+    GST_BUFFER_TIMESTAMP (stream->pendingbuffers[0]) =
+        stream->pts + base->in_gap;
   }
 
-  if (header.DTS != -1)
-    gst_ts_demux_record_dts (demux, stream, header.DTS, bufferoffset);
-
   /* Remove PES headers */
   GST_DEBUG ("Moving data forward  by %d bytes", header.header_size);
   GST_BUFFER_DATA (stream->pendingbuffers[0]) += header.header_size;