asfdemux: Fix prerolling files with "empty" streams
authorEdward Hervey <edward@centricular.com>
Mon, 13 Nov 2017 10:13:30 +0000 (11:13 +0100)
committerEdward Hervey <bilboed@bilboed.com>
Mon, 13 Nov 2017 10:13:30 +0000 (11:13 +0100)
This is a regression that was introduced by
commit 1803b3c18530cb0100d140c2b8e49a8dfe41f941
"    asfdemux: Add support for dvr-ms"

The problem is that some files/streams might contain stream definition
but there is no actual packets for those streams.

This was used to "define" streams with different bitrates for example.

The first_ts calculation resulted in never ever finding a valid first_ts
since some streams were empty, and therefore never "activating" itself.

Instead of that we first check if we are prerolled. And if we are we
unconditionally get the "first_ts"

The preroll check has been adapted to check whether streams of
each defined type (i.e. audio/video/sub) has been prerolled. This solves
the problem of having different streams of a particular type where only
one stream actually has data.

gst/asfdemux/gstasfdemux.c

index a12bc8a..520df67 100644 (file)
@@ -1304,6 +1304,7 @@ all_streams_prerolled (GstASFDemux * demux)
 {
   GstClockTime preroll_time;
   guint i, num_no_data = 0;
+  AsfStreamType prerolled_types = 0, all_types = 0;
 
   /* Allow at least 500ms of preroll_time  */
   preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
@@ -1317,12 +1318,17 @@ all_streams_prerolled (GstASFDemux * demux)
     gint last_idx;
 
     stream = &demux->stream[i];
+
+    all_types |= stream->type;
+
     if (G_UNLIKELY (stream->payloads->len == 0)) {
       ++num_no_data;
       GST_LOG_OBJECT (stream->pad, "no data queued");
       continue;
     }
 
+    prerolled_types |= stream->type;
+
     /* find last payload with timestamp */
     for (last_idx = stream->payloads->len - 1;
         last_idx >= 0 && (last_payload == NULL
@@ -1340,6 +1346,13 @@ all_streams_prerolled (GstASFDemux * demux)
     }
   }
 
+  GST_LOG_OBJECT (demux, "all_types:%d prerolled_types:%d",
+      all_types, prerolled_types);
+
+  /* If streams of each present type have prerolled, we are good to go */
+  if (all_types != 0 && prerolled_types == all_types)
+    return TRUE;
+
   if (G_UNLIKELY (num_no_data > 0))
     return FALSE;
 
@@ -1403,7 +1416,7 @@ gst_asf_demux_check_segment_ts (GstASFDemux * demux, GstClockTime payload_ts)
 }
 
 static gboolean
-gst_asf_demux_check_first_ts (GstASFDemux * demux, gboolean force)
+gst_asf_demux_get_first_ts (GstASFDemux * demux)
 {
   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
     GstClockTime first_ts = GST_CLOCK_TIME_NONE;
@@ -1438,22 +1451,20 @@ gst_asf_demux_check_first_ts (GstASFDemux * demux, gboolean force)
          from it. I havent found a better way to distinguish between these two, except to set an arbitrary boundary
          and disregard the first 0 timestamp if the second timestamp is bigger than the boundary) */
 
-      if (stream_min_ts == 0 && stream_min_ts2 == GST_CLOCK_TIME_NONE && !force)        /* still waiting for the second timestamp */
-        return FALSE;
+      GST_DEBUG_OBJECT (demux,
+          "stream #%u stream_min_ts %" GST_TIME_FORMAT " stream_min_ts2 %"
+          GST_TIME_FORMAT, stream->id, GST_TIME_ARGS (stream_min_ts),
+          GST_TIME_ARGS (stream_min_ts2));
 
       if (stream_min_ts == 0 && stream_min_ts2 > GST_SECOND)    /* first timestamp is 0 and second is significantly larger, disregard the 0 */
         stream_min_ts = stream_min_ts2;
 
-      /* if we don't have timestamp for this stream, wait for more data */
-      if (!GST_CLOCK_TIME_IS_VALID (stream_min_ts) && !force)
-        return FALSE;
-
       if (GST_CLOCK_TIME_IS_VALID (stream_min_ts) &&
           (!GST_CLOCK_TIME_IS_VALID (first_ts) || first_ts > stream_min_ts))
         first_ts = stream_min_ts;
     }
 
-    if (!GST_CLOCK_TIME_IS_VALID (first_ts))    /* can happen with force = TRUE */
+    if (!GST_CLOCK_TIME_IS_VALID (first_ts))    /* can happen */
       first_ts = 0;
 
     demux->first_ts = first_ts;
@@ -1547,14 +1558,14 @@ gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
   if (demux->activated_streams)
     return TRUE;
 
-  if (G_UNLIKELY (!gst_asf_demux_check_first_ts (demux, force)))
-    return FALSE;
-
   if (!all_streams_prerolled (demux) && !force) {
     GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
     return FALSE;
   }
 
+  if (G_UNLIKELY (!gst_asf_demux_get_first_ts (demux)))
+    return FALSE;
+
   for (i = 0; i < demux->num_streams; ++i) {
     AsfStream *stream = &demux->stream[i];