splitmuxsink: Mask async-start/done while switching files.
authorJan Schmidt <jan@centricular.com>
Wed, 17 Jun 2015 23:26:13 +0000 (09:26 +1000)
committerJan Schmidt <jan@centricular.com>
Tue, 23 Jun 2015 02:03:14 +0000 (12:03 +1000)
Sometimes, extra async-start/done from the internal sink
while the element is still starting up can cause splitmuxsink
to stall in PAUSED state when it has been set to PLAYING
by the app. Drop the child's async-start/done messages while
switching, so they don't cause state changes at the
splitmuxsink level.

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

gst/multifile/gstsplitmuxsink.c
gst/multifile/gstsplitmuxsink.h

index 91d7fc4..2c7d15f 100644 (file)
@@ -63,6 +63,9 @@ GST_DEBUG_CATEGORY_STATIC (splitmux_debug);
 #define GST_SPLITMUX_WAIT(s) g_cond_wait (&(s)->data_cond, &(s)->lock)
 #define GST_SPLITMUX_BROADCAST(s) g_cond_broadcast (&(s)->data_cond)
 
+#define GST_SPLITMUX_WAIT_ASYNC_DONE(s) g_cond_wait (&(s)->async_cond, &(s)->lock)
+#define GST_SPLITMUX_BROADCAST_ASYNC_DONE(s) g_cond_broadcast (&(s)->async_cond)
+
 enum
 {
   PROP_0,
@@ -209,6 +212,7 @@ gst_splitmux_sink_init (GstSplitMuxSink * splitmux)
 {
   g_mutex_init (&splitmux->lock);
   g_cond_init (&splitmux->data_cond);
+  g_cond_init (&splitmux->async_cond);
 
   splitmux->mux_overhead = DEFAULT_MUXER_OVERHEAD;
   splitmux->threshold_time = DEFAULT_MAX_SIZE_TIME;
@@ -248,6 +252,7 @@ gst_splitmux_sink_finalize (GObject * object)
 {
   GstSplitMuxSink *splitmux = GST_SPLITMUX_SINK (object);
   g_cond_clear (&splitmux->data_cond);
+  g_cond_clear (&splitmux->async_cond);
   g_mutex_clear (&splitmux->lock);
   if (splitmux->provided_sink)
     gst_object_unref (splitmux->provided_sink);
@@ -667,7 +672,17 @@ restart_context (MqStreamCtx * ctx, GstSplitMuxSink * splitmux)
 static void
 start_next_fragment (GstSplitMuxSink * splitmux)
 {
+  if (splitmux->is_async) {
+    /* Wait for async done on the sink */
+    GST_SPLITMUX_WAIT_ASYNC_DONE (splitmux);
+  }
+
   /* 1 change to new file */
+  splitmux->restarting = TRUE;
+
+  GST_SPLITMUX_UNLOCK (splitmux);
+  GST_STATE_LOCK (splitmux);
+
   gst_element_set_state (splitmux->muxer, GST_STATE_NULL);
   gst_element_set_state (splitmux->active_sink, GST_STATE_NULL);
 
@@ -676,6 +691,12 @@ start_next_fragment (GstSplitMuxSink * splitmux)
   gst_element_sync_state_with_parent (splitmux->active_sink);
   gst_element_sync_state_with_parent (splitmux->muxer);
 
+  GST_STATE_UNLOCK (splitmux);
+  GST_SPLITMUX_LOCK (splitmux);
+
+  splitmux->restarting = FALSE;
+
+  GST_LOG_OBJECT (splitmux, "Restarting contexts to push more data");
   g_list_foreach (splitmux->contexts, (GFunc) restart_context, splitmux);
 
   /* Switch state and go back to processing */
@@ -715,11 +736,26 @@ bus_handler (GstBin * bin, GstMessage * message)
         GST_DEBUG_OBJECT (splitmux, "Caught EOS at end of fragment, dropping");
         splitmux->state = SPLITMUX_STATE_START_NEXT_FRAGMENT;
         GST_SPLITMUX_BROADCAST (splitmux);
-
-        gst_message_unref (message);
-        GST_SPLITMUX_UNLOCK (splitmux);
-        return;
+        goto drop;
+      }
+      GST_SPLITMUX_UNLOCK (splitmux);
+      GST_INFO_OBJECT (splitmux, "Passing EOS message");
+      break;
+    case GST_MESSAGE_ASYNC_START:
+      GST_SPLITMUX_LOCK (splitmux);
+      if (splitmux->restarting)
+        goto drop;
+      splitmux->is_async = TRUE;
+      GST_SPLITMUX_UNLOCK (splitmux);
+      break;
+    case GST_MESSAGE_ASYNC_DONE:
+      GST_SPLITMUX_LOCK (splitmux);
+      if (splitmux->is_async) {
+        GST_SPLITMUX_BROADCAST_ASYNC_DONE (splitmux);
+        splitmux->is_async = FALSE;
       }
+      if (splitmux->restarting)
+        goto drop;
       GST_SPLITMUX_UNLOCK (splitmux);
       break;
     default:
@@ -727,6 +763,11 @@ bus_handler (GstBin * bin, GstMessage * message)
   }
 
   GST_BIN_CLASS (parent_class)->handle_message (bin, message);
+  return;
+
+drop:
+  gst_message_unref (message);
+  GST_SPLITMUX_UNLOCK (splitmux);
 }
 
 /* Called with splitmux lock held */
index a305ed4..a78dbd0 100644 (file)
@@ -88,6 +88,9 @@ struct _GstSplitMuxSink {
 
   GMutex lock;
   GCond data_cond;
+  GCond async_cond;
+  gboolean is_async;
+  gboolean restarting;
 
   SplitMuxState state;
   gdouble mux_overhead;