splitmux: Handle a hang draining out at EOS
authorJan Schmidt <jan@centricular.com>
Wed, 30 Mar 2016 15:15:04 +0000 (02:15 +1100)
committerJan Schmidt <jan@centricular.com>
Thu, 31 Mar 2016 13:48:05 +0000 (00:48 +1100)
Make sure that all data is drained out when the reference pad
goes EOS. Fixes a problem where data that arrives on other
pads after the reference pad finishes can stall forever and
never pass EOS.

https://bugzilla.gnome.org/show_bug.cgi?id=763711

gst/multifile/gstsplitmuxsink.c

index 10096be7f1ac17181663f8535e8db45c243f93eb..5d4a6b31f3ce7b726e3ecb38f635c2725e03f65d 100644 (file)
@@ -718,8 +718,8 @@ restart_context (MqStreamCtx * ctx, GstSplitMuxSink * splitmux)
   gst_pad_sticky_events_foreach (ctx->srcpad,
       (GstPadStickyEventsForeachFunction) (resend_sticky), peer);
 
-  /* Clear EOS flag */
-  ctx->out_eos = FALSE;
+  /* Clear EOS flag if not actually EOS */
+  ctx->out_eos = GST_PAD_IS_EOS (ctx->srcpad);
 
   gst_object_unref (peer);
 }
@@ -743,11 +743,11 @@ start_next_fragment (GstSplitMuxSink * splitmux)
   g_list_foreach (splitmux->contexts, (GFunc) restart_context, splitmux);
 
   /* Switch state and go back to processing */
-  splitmux->state = SPLITMUX_STATE_COLLECTING_GOP_START;
-
   if (!splitmux->reference_ctx->in_eos) {
+    splitmux->state = SPLITMUX_STATE_COLLECTING_GOP_START;
     splitmux->max_out_running_time = splitmux->reference_ctx->in_running_time;
   } else {
+    splitmux->state = SPLITMUX_STATE_WAITING_GOP_COMPLETE;
     splitmux->max_out_running_time = GST_CLOCK_TIME_NONE;
     splitmux->have_muxed_something = FALSE;
   }
@@ -811,6 +811,7 @@ handle_gathered_gop (GstSplitMuxSink * splitmux)
   GList *cur;
   gsize queued_bytes = 0;
   GstClockTime queued_time = 0;
+  gboolean at_eos = TRUE;
 
   /* Assess if the multiqueue contents overflowed the current file */
   for (cur = g_list_first (splitmux->contexts);
@@ -819,6 +820,7 @@ handle_gathered_gop (GstSplitMuxSink * splitmux)
     if (tmpctx->in_running_time > queued_time)
       queued_time = tmpctx->in_running_time;
     queued_bytes += tmpctx->in_bytes;
+    at_eos &= tmpctx->in_eos;
   }
 
   g_assert (queued_bytes >= splitmux->mux_start_bytes);
@@ -835,11 +837,11 @@ handle_gathered_gop (GstSplitMuxSink * splitmux)
 
   /* Check for overrun - have we output at least one byte and overrun
    * either threshold? */
-  if (splitmux->have_muxed_something &&
-      ((splitmux->threshold_bytes > 0 &&
-              queued_bytes >= splitmux->threshold_bytes) ||
-          (splitmux->threshold_time > 0 &&
-              queued_time >= splitmux->threshold_time))) {
+  if ((splitmux->have_muxed_something &&
+          ((splitmux->threshold_bytes > 0 &&
+                  queued_bytes >= splitmux->threshold_bytes) ||
+              (splitmux->threshold_time > 0 &&
+                  queued_time >= splitmux->threshold_time))) || at_eos) {
 
     splitmux->state = SPLITMUX_STATE_ENDING_FILE;
 
@@ -857,13 +859,15 @@ handle_gathered_gop (GstSplitMuxSink * splitmux)
         queued_bytes, GST_TIME_ARGS (queued_time));
 
     /* Wake everyone up to push this one GOP, then sleep */
-    splitmux->state = SPLITMUX_STATE_COLLECTING_GOP_START;
     splitmux->have_muxed_something = TRUE;
 
-    if (!splitmux->reference_ctx->in_eos)
+    if (!splitmux->reference_ctx->in_eos) {
+      splitmux->state = SPLITMUX_STATE_COLLECTING_GOP_START;
       splitmux->max_out_running_time = splitmux->reference_ctx->in_running_time;
-    else
+    } else {
+      splitmux->state = SPLITMUX_STATE_WAITING_GOP_COMPLETE;
       splitmux->max_out_running_time = GST_CLOCK_TIME_NONE;
+    }
 
     GST_LOG_OBJECT (splitmux, "Waking output for complete GOP, TS %"
         GST_TIME_FORMAT, GST_TIME_ARGS (splitmux->max_out_running_time));
@@ -887,9 +891,11 @@ check_completed_gop (GstSplitMuxSink * splitmux, MqStreamCtx * ctx)
   if (splitmux->state == SPLITMUX_STATE_WAITING_GOP_COMPLETE) {
     /* Iterate each pad, and check that the input running time is at least
      * up to the reference running time, and if so handle the collected GOP */
-    GST_LOG_OBJECT (splitmux, "Checking GOP collected, ctx %p", ctx);
-    for (cur = g_list_first (splitmux->contexts);
-        cur != NULL; cur = g_list_next (cur)) {
+    GST_LOG_OBJECT (splitmux, "Checking GOP collected, Max in running time %"
+        GST_TIME_FORMAT " ctx %p",
+        GST_TIME_ARGS (splitmux->max_in_running_time), ctx);
+    for (cur = g_list_first (splitmux->contexts); cur != NULL;
+        cur = g_list_next (cur)) {
       MqStreamCtx *tmpctx = (MqStreamCtx *) (cur->data);
 
       GST_LOG_OBJECT (splitmux,
@@ -897,7 +903,8 @@ check_completed_gop (GstSplitMuxSink * splitmux, MqStreamCtx * ctx)
           " EOS %d", tmpctx, tmpctx->srcpad,
           GST_TIME_ARGS (tmpctx->in_running_time), tmpctx->in_eos);
 
-      if (tmpctx->in_running_time < splitmux->max_in_running_time &&
+      if (splitmux->max_in_running_time != GST_CLOCK_TIME_NONE &&
+          tmpctx->in_running_time < splitmux->max_in_running_time &&
           !tmpctx->in_eos) {
         GST_LOG_OBJECT (splitmux,
             "Context %p (src pad %" GST_PTR_FORMAT ") not ready. We'll sleep",