media: start media pipeline in context
authorWim Taymans <wim.taymans@collabora.co.uk>
Tue, 9 Jul 2013 18:44:51 +0000 (20:44 +0200)
committerWim Taymans <wim.taymans@collabora.co.uk>
Tue, 9 Jul 2013 18:44:51 +0000 (20:44 +0200)
Start the media pipeline in the provided context (or our default one
when NULL). This makes sure that we run the bus thread in this context and that
all media threads are children of this context.

gst/rtsp-server/rtsp-media.c

index 777a27f..c9e83f3 100644 (file)
@@ -1556,6 +1556,85 @@ struct _DynPaySignalHandlers
   gulong no_more_pads_handler;
 };
 
+static gboolean
+start_prepare (GstRTSPMedia * media)
+{
+  GstRTSPMediaPrivate *priv = media->priv;
+  GstStateChangeReturn ret;
+  guint i;
+  GList *walk;
+
+  /* link streams we already have, other streams might appear when we have
+   * dynamic elements */
+  for (i = 0; i < priv->streams->len; i++) {
+    GstRTSPStream *stream;
+
+    stream = g_ptr_array_index (priv->streams, i);
+
+    gst_rtsp_stream_join_bin (stream, GST_BIN (priv->pipeline),
+        priv->rtpbin, GST_STATE_NULL);
+  }
+
+  for (walk = priv->dynamic; walk; walk = g_list_next (walk)) {
+    GstElement *elem = walk->data;
+    DynPaySignalHandlers *handlers = g_slice_new (DynPaySignalHandlers);
+
+    GST_INFO ("adding callbacks for dynamic element %p", elem);
+
+    handlers->pad_added_handler = g_signal_connect (elem, "pad-added",
+        (GCallback) pad_added_cb, media);
+    handlers->pad_removed_handler = g_signal_connect (elem, "pad-removed",
+        (GCallback) pad_removed_cb, media);
+    handlers->no_more_pads_handler = g_signal_connect (elem, "no-more-pads",
+        (GCallback) no_more_pads_cb, media);
+
+    g_object_set_data (G_OBJECT (elem), "gst-rtsp-dynpay-handlers", handlers);
+
+    /* we add a fakesink here in order to make the state change async. We remove
+     * the fakesink again in the no-more-pads callback. */
+    priv->fakesink = gst_element_factory_make ("fakesink", "fakesink");
+    gst_bin_add (GST_BIN (priv->pipeline), priv->fakesink);
+  }
+
+  GST_INFO ("setting pipeline to PAUSED for media %p", media);
+  /* first go to PAUSED */
+  ret = gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
+  priv->target_state = GST_STATE_PAUSED;
+
+  switch (ret) {
+    case GST_STATE_CHANGE_SUCCESS:
+      GST_INFO ("SUCCESS state change for media %p", media);
+      priv->seekable = TRUE;
+      break;
+    case GST_STATE_CHANGE_ASYNC:
+      GST_INFO ("ASYNC state change for media %p", media);
+      priv->seekable = TRUE;
+      break;
+    case GST_STATE_CHANGE_NO_PREROLL:
+      /* we need to go to PLAYING */
+      GST_INFO ("NO_PREROLL state change: live media %p", media);
+      /* FIXME we disable seeking for live streams for now. We should perform a
+       * seeking query in preroll instead */
+      priv->seekable = FALSE;
+      priv->is_live = TRUE;
+      ret = gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
+      if (ret == GST_STATE_CHANGE_FAILURE)
+        goto state_failed;
+      break;
+    case GST_STATE_CHANGE_FAILURE:
+      goto state_failed;
+  }
+
+  return FALSE;
+
+state_failed:
+  {
+    GST_WARNING ("failed to preroll pipeline");
+    gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_ERROR);
+    return FALSE;
+  }
+}
+
 /**
  * gst_rtsp_media_prepare:
  * @media: a #GstRTSPMedia
@@ -1574,12 +1653,10 @@ gboolean
 gst_rtsp_media_prepare (GstRTSPMedia * media, GMainContext * context)
 {
   GstRTSPMediaPrivate *priv;
-  GstStateChangeReturn ret;
   GstRTSPMediaStatus status;
-  guint i;
   GstRTSPMediaClass *klass;
   GstBus *bus;
-  GList *walk;
+  GSource *source;
 
   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
 
@@ -1613,6 +1690,11 @@ gst_rtsp_media_prepare (GstRTSPMedia * media, GMainContext * context)
   /* we're preparing now */
   priv->status = GST_RTSP_MEDIA_STATUS_PREPARING;
 
+  klass = GST_RTSP_MEDIA_GET_CLASS (media);
+
+  if (context == NULL)
+    context = klass->context;
+
   bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (priv->pipeline));
 
   /* add the pipeline bus to our custom mainloop */
@@ -1622,72 +1704,17 @@ gst_rtsp_media_prepare (GstRTSPMedia * media, GMainContext * context)
   g_source_set_callback (priv->source, (GSourceFunc) bus_message,
       g_object_ref (media), (GDestroyNotify) watch_destroyed);
 
-  klass = GST_RTSP_MEDIA_GET_CLASS (media);
-  priv->id = g_source_attach (priv->source, context ? context : klass->context);
+  priv->id = g_source_attach (priv->source, context);
 
   /* add stuff to the bin */
   gst_bin_add (GST_BIN (priv->pipeline), priv->rtpbin);
 
-  /* link streams we already have, other streams might appear when we have
-   * dynamic elements */
-  for (i = 0; i < priv->streams->len; i++) {
-    GstRTSPStream *stream;
-
-    stream = g_ptr_array_index (priv->streams, i);
-
-    gst_rtsp_stream_join_bin (stream, GST_BIN (priv->pipeline),
-        priv->rtpbin, GST_STATE_NULL);
-  }
-
-  for (walk = priv->dynamic; walk; walk = g_list_next (walk)) {
-    GstElement *elem = walk->data;
-    DynPaySignalHandlers *handlers = g_slice_new (DynPaySignalHandlers);
-
-    GST_INFO ("adding callbacks for dynamic element %p", elem);
-
-    handlers->pad_added_handler = g_signal_connect (elem, "pad-added",
-        (GCallback) pad_added_cb, media);
-    handlers->pad_removed_handler = g_signal_connect (elem, "pad-removed",
-        (GCallback) pad_removed_cb, media);
-    handlers->no_more_pads_handler = g_signal_connect (elem, "no-more-pads",
-        (GCallback) no_more_pads_cb, media);
-
-    g_object_set_data (G_OBJECT (elem), "gst-rtsp-dynpay-handlers", handlers);
-
-    /* we add a fakesink here in order to make the state change async. We remove
-     * the fakesink again in the no-more-pads callback. */
-    priv->fakesink = gst_element_factory_make ("fakesink", "fakesink");
-    gst_bin_add (GST_BIN (priv->pipeline), priv->fakesink);
-  }
-
-  GST_INFO ("setting pipeline to PAUSED for media %p", media);
-  /* first go to PAUSED */
-  ret = gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
-  priv->target_state = GST_STATE_PAUSED;
+  /* do remainder in context */
+  source = g_idle_source_new ();
+  g_source_set_callback (source, (GSourceFunc) start_prepare, media, NULL);
+  g_source_attach (source, context);
+  g_source_unref (source);
 
-  switch (ret) {
-    case GST_STATE_CHANGE_SUCCESS:
-      GST_INFO ("SUCCESS state change for media %p", media);
-      priv->seekable = TRUE;
-      break;
-    case GST_STATE_CHANGE_ASYNC:
-      GST_INFO ("ASYNC state change for media %p", media);
-      priv->seekable = TRUE;
-      break;
-    case GST_STATE_CHANGE_NO_PREROLL:
-      /* we need to go to PLAYING */
-      GST_INFO ("NO_PREROLL state change: live media %p", media);
-      /* FIXME we disable seeking for live streams for now. We should perform a
-       * seeking query in preroll instead */
-      priv->seekable = FALSE;
-      priv->is_live = TRUE;
-      ret = gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
-      if (ret == GST_STATE_CHANGE_FAILURE)
-        goto state_failed;
-      break;
-    case GST_STATE_CHANGE_FAILURE:
-      goto state_failed;
-  }
 wait_status:
   g_rec_mutex_unlock (&priv->state_lock);
 
@@ -1737,7 +1764,6 @@ state_failed:
   {
     GST_WARNING ("failed to preroll pipeline");
     gst_rtsp_media_unprepare (media);
-    g_rec_mutex_unlock (&priv->state_lock);
     return FALSE;
   }
 }