oggdemux: Better handling of sparse streams by sending segment updates
authorTim-Philipp Müller <tim.muller@collabora.co.uk>
Thu, 10 Sep 2009 08:00:16 +0000 (10:00 +0200)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Thu, 10 Sep 2009 08:16:56 +0000 (10:16 +0200)
Fixes bug #397419.

ext/ogg/gstoggdemux.c
ext/ogg/gstoggdemux.h

index 0f30778..5c7cd0a 100644 (file)
@@ -127,6 +127,7 @@ static GstClockTime gst_annodex_granule_to_time (gint64 granulepos,
 
 static GstFlowReturn gst_ogg_demux_combine_flows (GstOggDemux * ogg,
     GstOggPad * pad, GstFlowReturn ret);
+static void gst_ogg_demux_sync_streams (GstOggDemux * ogg);
 
 G_DEFINE_TYPE (GstOggPad, gst_ogg_pad, GST_TYPE_PAD);
 
@@ -161,6 +162,8 @@ gst_ogg_pad_init (GstOggPad * pad)
   pad->start_time = GST_CLOCK_TIME_NONE;
   pad->first_time = GST_CLOCK_TIME_NONE;
 
+  pad->last_stop = GST_CLOCK_TIME_NONE;
+
   pad->have_type = FALSE;
   pad->continued = NULL;
   pad->headers = NULL;
@@ -415,6 +418,7 @@ gst_ogg_pad_reset (GstOggPad * pad)
   pad->continued = NULL;
 
   pad->last_ret = GST_FLOW_OK;
+  pad->last_stop = GST_CLOCK_TIME_NONE;
 }
 
 /* the filter function for selecting the elements we can use in
@@ -874,6 +878,8 @@ gst_ogg_demux_chain_peer (GstOggPad * pad, ogg_packet * packet)
     pad->discont = FALSE;
   }
 
+  pad->last_stop = ogg->segment.last_stop;
+
   ret = gst_pad_push (GST_PAD_CAST (pad), buf);
 
   /* combine flows */
@@ -1812,6 +1818,10 @@ gst_ogg_demux_activate_chain (GstOggDemux * ogg, GstOggChain * chain,
       pad->discont = TRUE;
       pad->last_ret = GST_FLOW_OK;
 
+      pad->is_sparse =
+          gst_structure_has_name (gst_caps_get_structure (GST_PAD_CAPS (pad),
+              0), "application/x-ogm-text");
+
       /* activate first */
       gst_pad_set_active (GST_PAD_CAST (pad), TRUE);
 
@@ -2918,7 +2928,7 @@ static GstFlowReturn
 gst_ogg_demux_chain (GstPad * pad, GstBuffer * buffer)
 {
   GstOggDemux *ogg;
-  gint ret;
+  gint ret = 0;
   GstFlowReturn result = GST_FLOW_OK;
 
   ogg = GST_OGG_DEMUX (GST_OBJECT_PARENT (pad));
@@ -2940,6 +2950,9 @@ gst_ogg_demux_chain (GstPad * pad, GstBuffer * buffer)
       result = gst_ogg_demux_handle_page (ogg, &page);
     }
   }
+  if (ret == 0 || result == GST_FLOW_OK) {
+    gst_ogg_demux_sync_streams (ogg);
+  }
   return result;
 }
 
@@ -3090,6 +3103,41 @@ done:
   return ret;
 }
 
+static void
+gst_ogg_demux_sync_streams (GstOggDemux * ogg)
+{
+  GstClockTime cur;
+  GstOggChain *chain;
+  guint i;
+
+  chain = ogg->current_chain;
+  cur = ogg->segment.last_stop;
+  if (chain == NULL || cur == -1)
+    return;
+
+  for (i = 0; i < chain->streams->len; i++) {
+    GstOggPad *stream = g_array_index (chain->streams, GstOggPad *, i);
+
+    /* Theoretically, we should be doing this for all streams, but we're only
+     * doing it for known-to-be-sparse streams at the moment in order not to
+     * break things for wrongly-muxed streams (like we used to produce once) */
+    if (stream->is_sparse && stream->last_stop != GST_CLOCK_TIME_NONE) {
+
+      /* Does this stream lag? Random threshold of 2 seconds */
+      if (GST_CLOCK_DIFF (stream->last_stop, cur) > (2 * GST_SECOND)) {
+        GST_DEBUG_OBJECT (stream, "synchronizing stream with others by "
+            "advancing time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
+            GST_TIME_ARGS (stream->last_stop), GST_TIME_ARGS (cur));
+        stream->last_stop = cur;
+        /* advance stream time (FIXME: is this right, esp. time_pos?) */
+        gst_pad_push_event (GST_PAD_CAST (stream),
+            gst_event_new_new_segment (TRUE, ogg->segment.rate,
+                GST_FORMAT_TIME, stream->last_stop, -1, stream->last_stop));
+      }
+    }
+  }
+}
+
 /* random access code
  *
  * - first find all the chains and streams by scanning the file.
@@ -3140,6 +3188,7 @@ gst_ogg_demux_loop (GstOggPad * pad)
   if (ret != GST_FLOW_OK)
     goto pause;
 
+  gst_ogg_demux_sync_streams (ogg);
   return;
 
   /* ERRORS */
index 46f5460..6cc7fb9 100644 (file)
@@ -112,6 +112,10 @@ struct _GstOggPad
   gint64 first_granule;         /* the granulepos of first page == first sample in next page */
   GstClockTime first_time;      /* the timestamp of the second page or granuletime of first page */
 
+  gboolean     is_sparse;       /* TRUE if this is a subtitle pad or some other sparse stream */
+  GstClockTime last_stop;       /* last_stop when last push occured; used to detect when we
+                                 * need to send a newsegment update event for sparse streams */
+
   ogg_stream_state stream;
   GList *continued;