tsdemux: interpolate gap and fix timestamps depending on upstream segment
authorYouness Alaoui <youness.alaoui@collabora.co.uk>
Tue, 16 Aug 2011 19:54:04 +0000 (19:54 +0000)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Mon, 22 Aug 2011 13:55:47 +0000 (15:55 +0200)
gst/mpegtsdemux/mpegtsbase.c
gst/mpegtsdemux/mpegtsbase.h
gst/mpegtsdemux/tsdemux.c

index c079b11..6ab1184 100644 (file)
@@ -215,6 +215,8 @@ mpegts_base_reset (MpegTSBase * base)
   base->mode = BASE_MODE_STREAMING;
   base->seen_pat = FALSE;
   base->first_pat_offset = -1;
+  base->in_gap = 0;
+  base->first_buf_ts = GST_CLOCK_TIME_NONE;
 
   if (klass->reset)
     klass->reset (base);
@@ -1180,6 +1182,8 @@ mpegts_base_sink_event (GstPad * pad, GstEvent * event)
       gst_segment_set_newsegment_full (&base->segment, update, rate,
           applied_rate, format, start, stop, position);
       gst_event_unref (event);
+      base->in_gap = GST_CLOCK_TIME_NONE;
+      base->first_buf_ts = GST_CLOCK_TIME_NONE;
     }
       break;
     case GST_EVENT_EOS:
@@ -1232,6 +1236,13 @@ mpegts_base_chain (GstPad * pad, GstBuffer * buf)
   base = GST_MPEGTS_BASE (gst_object_get_parent (GST_OBJECT (pad)));
   packetizer = base->packetizer;
 
+  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (base->first_buf_ts)) &&
+      GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
+    base->first_buf_ts = GST_BUFFER_TIMESTAMP (buf);
+    GST_DEBUG_OBJECT (base, "first buffer timestamp %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (base->first_buf_ts));
+  }
+
   mpegts_packetizer_push (base->packetizer, buf);
   while (((pret =
               mpegts_packetizer_next_packet (base->packetizer,
index 369078d..1513898 100644 (file)
@@ -130,6 +130,10 @@ struct _MpegTSBase {
   /* Offset from the origin to the first PAT (pullmode) */
   guint64    first_pat_offset;
 
+  /* interpolation gap between the upstream timestamp and the pts */
+  GstClockTime in_gap;
+  GstClockTime first_buf_ts;
+
   /* Upstream segment */
   GstSegment segment;
 };
index e859ea9..8b685a6 100644 (file)
@@ -1897,6 +1897,7 @@ TSPcrOffset_find_offset (gconstpointer a, gconstpointer b, gpointer user_data)
 static GstFlowReturn
 gst_ts_demux_parse_pes_header (GstTSDemux * demux, TSDemuxStream * stream)
 {
+  MpegTSBase *base = (MpegTSBase *) demux;
   PESHeader header;
   GstFlowReturn res = GST_FLOW_OK;
   gint offset = 0;
@@ -1945,7 +1946,36 @@ gst_ts_demux_parse_pes_header (GstTSDemux * demux, TSDemuxStream * stream)
 #endif
 
     stream->pts = time = MPEGTIME_TO_GSTTIME (header.PTS);
-    GST_BUFFER_TIMESTAMP (stream->pendingbuffers[0]) = time;
+
+    /* safe default if insufficient upstream info */
+    if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (base->in_gap) &&
+            GST_CLOCK_TIME_IS_VALID (base->first_buf_ts) &&
+            base->mode == BASE_MODE_PUSHING &&
+            base->segment.format == GST_FORMAT_TIME)) {
+      /* Find the earliest current PTS we're going to push */
+      GstClockTime firstpts = GST_CLOCK_TIME_NONE;
+      GList *tmp;
+
+      for (tmp = demux->program->stream_list; tmp; tmp = tmp->next) {
+        TSDemuxStream *pstream = (TSDemuxStream *) tmp->data;
+        if (!GST_CLOCK_TIME_IS_VALID (firstpts) || pstream->pts < firstpts)
+          firstpts = pstream->pts;
+      }
+
+      base->in_gap = base->first_buf_ts - firstpts;
+      GST_DEBUG_OBJECT (base, "upstream segment start %" GST_TIME_FORMAT
+          ", first buffer timestamp: %" GST_TIME_FORMAT
+          ", first PTS: %" GST_TIME_FORMAT
+          ", interpolation gap: %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (base->segment.start),
+          GST_TIME_ARGS (base->first_buf_ts), GST_TIME_ARGS (firstpts),
+          GST_TIME_ARGS (base->in_gap));
+    }
+
+    if (!GST_CLOCK_TIME_IS_VALID (base->in_gap))
+      base->in_gap = 0;
+
+    GST_BUFFER_TIMESTAMP (stream->pendingbuffers[0]) = time + base->in_gap;
   }
 
   if (header.DTS != -1)
@@ -2038,9 +2068,7 @@ static void
 calculate_and_push_newsegment (GstTSDemux * demux, TSDemuxStream * stream)
 {
   MpegTSBase *base = (MpegTSBase *) demux;
-  GstClockTime firstpts = GST_CLOCK_TIME_NONE;
   GstEvent *newsegmentevent;
-  GList *tmp;
   gint64 start, stop, position;
 
   GST_DEBUG ("Creating new newsegment");
@@ -2055,13 +2083,6 @@ calculate_and_push_newsegment (GstTSDemux * demux, TSDemuxStream * stream)
    * PTS to that remote clock).
    */
 
-  /* Find the earliest current PTS we're going to push */
-  for (tmp = demux->program->stream_list; tmp; tmp = tmp->next) {
-    TSDemuxStream *pstream = (TSDemuxStream *) tmp->data;
-    if (!GST_CLOCK_TIME_IS_VALID (firstpts) || pstream->pts < firstpts)
-      firstpts = pstream->pts;
-  }
-
   if (base->mode == BASE_MODE_PUSHING) {
     /* FIXME : We're just ignore the upstream format for the time being */
     /* FIXME : We should use base->segment.format and a upstream latency query
@@ -2080,10 +2101,9 @@ calculate_and_push_newsegment (GstTSDemux * demux, TSDemuxStream * stream)
     if (demux->segment.time == 0 && base->segment.format == GST_FORMAT_TIME)
       demux->segment.time = base->segment.time;
 
-    start = firstpts;
-    stop = GST_CLOCK_TIME_NONE;
-    position = demux->segment.time ? firstpts - demux->segment.time : 0;
-    demux->segment.time = start;
+    start = base->segment.start;
+    stop = base->segment.stop;
+    position = base->segment.time;
   } else {
     /* pull mode */
     GST_DEBUG ("pull-based. Segment start:%" GST_TIME_FORMAT " duration:%"