demux: Create timeline from the streaming thread
authorThibault Saunier <tsaunier@igalia.com>
Sat, 15 Jun 2019 03:48:20 +0000 (23:48 -0400)
committerThibault Saunier <tsaunier@igalia.com>
Fri, 5 Jul 2019 21:57:04 +0000 (17:57 -0400)
First marshilling it to the main thread is dangerous as it is a blocking
operation and it should never happen there.

The asset cache is MT safe now so it is possible to load the timeline
from that thread directly

plugins/ges/gesdemux.c

index 4985378..6e191ce 100644 (file)
@@ -135,25 +135,19 @@ ges_demux_class_init (GESDemuxClass * self_class)
 typedef struct
 {
   GESTimeline *timeline;
-  gchar *uri;
   GMainLoop *ml;
   GError *error;
-  GMutex lock;
-  GCond cond;
   gulong loaded_sigid;
   gulong error_sigid;
-  GESDemux *self;
 } TimelineConstructionData;
 
 static void
 project_loaded_cb (GESProject * project, GESTimeline * timeline,
     TimelineConstructionData * data)
 {
-  g_mutex_lock (&data->lock);
   data->timeline = timeline;
   g_signal_handler_disconnect (project, data->loaded_sigid);
   data->loaded_sigid = 0;
-  g_mutex_unlock (&data->lock);
 
   g_main_loop_quit (data->ml);
 }
@@ -162,69 +156,55 @@ static void
 error_loading_asset_cb (GESProject * project, GError * error, gchar * id,
     GType extractable_type, TimelineConstructionData * data)
 {
-  g_mutex_lock (&data->lock);
   data->error = g_error_copy (error);
   g_signal_handler_disconnect (project, data->error_sigid);
   data->error_sigid = 0;
-  g_mutex_unlock (&data->lock);
 
   g_main_loop_quit (data->ml);
 }
 
 static gboolean
-ges_timeline_new_from_uri_from_main_thread (TimelineConstructionData * data)
+ges_demux_create_timeline (GESDemux * self, gchar * uri, GError ** error)
 {
-  GESProject *project = ges_project_new (data->uri);
+  GESProject *project = ges_project_new (uri);
   G_GNUC_UNUSED void *unused;
+  TimelineConstructionData data = { 0, };
+  GMainContext *ctx = g_main_context_new ();
 
-  g_mutex_lock (&data->lock);
-  klass->discoverer = gst_discoverer_new (timeout, &data->error);
-  g_object_set (klass->discoverer, "use-cache", TRUE, NULL);
-  if (data->error) {
-    g_mutex_unlock (&data->lock);
+  g_main_context_push_thread_default (ctx);
+  data.ml = g_main_loop_new (ctx, TRUE);
 
-    goto done;
-  }
-  g_signal_connect (klass->discoverer, "discovered",
-      G_CALLBACK (klass->discovered), NULL);
-  gst_discoverer_start (klass->discoverer);
-
-  data->ml = g_main_loop_new (NULL, TRUE);
-  data->loaded_sigid =
+  data.loaded_sigid =
       g_signal_connect (project, "loaded", G_CALLBACK (project_loaded_cb),
-      data);
-  data->error_sigid =
-      g_signal_connect (project, "error-loading-asset",
-      G_CALLBACK (error_loading_asset_cb), data);
+      &data);
+  data.error_sigid =
+      g_signal_connect_after (project, "error-loading-asset",
+      G_CALLBACK (error_loading_asset_cb), &data);
 
-  unused = GES_TIMELINE (ges_asset_extract (GES_ASSET (project), &data->error));
-  if (data->error) {
-    g_mutex_unlock (&data->lock);
+  unused = GES_TIMELINE (ges_asset_extract (GES_ASSET (project), &data.error));
+  if (data.error) {
+    *error = data.error;
 
     goto done;
   }
-  g_mutex_unlock (&data->lock);
 
-  g_main_loop_run (data->ml);
-  g_main_loop_unref (data->ml);
+  g_main_loop_run (data.ml);
+  g_main_loop_unref (data.ml);
 
 done:
+  if (data.loaded_sigid)
+    g_signal_handler_disconnect (project, data.loaded_sigid);
 
-  g_mutex_lock (&data->lock);
-
-  if (data->loaded_sigid)
-    g_signal_handler_disconnect (project, data->loaded_sigid);
+  if (data.error_sigid)
+    g_signal_handler_disconnect (project, data.error_sigid);
 
-  if (data->error_sigid)
-    g_signal_handler_disconnect (project, data->error_sigid);
+  g_clear_object (&project);
 
-  gst_clear_object (&project);
+  GST_INFO_OBJECT (self, "Timeline properly loaded: %" GST_PTR_FORMAT,
+      data.timeline);
+  ges_base_bin_set_timeline (GES_BASE_BIN (self), data.timeline);
 
-  GST_INFO_OBJECT (data->self, "Timeline properly loaded: %" GST_PTR_FORMAT,
-      data->timeline);
-  ges_base_bin_set_timeline (GES_BASE_BIN (data->self), data->timeline);
-  g_cond_broadcast (&data->cond);
-  g_mutex_unlock (&data->lock);
+  g_main_context_pop_thread_default (ctx);
 
   return G_SOURCE_REMOVE;
 }
@@ -253,9 +233,8 @@ ges_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
       if (gst_buffer_map (xges_buffer, &map, GST_MAP_READ)) {
         GError *err = NULL;
         gchar *filename = NULL, *uri = NULL;
-        TimelineConstructionData data = { 0, };
+        GError *error = NULL;
         gint f = g_file_open_tmp (NULL, &filename, &err);
-        GMainContext *main_context = g_main_context_default ();
 
         if (err) {
           GST_ELEMENT_ERROR (self, RESOURCE, OPEN_WRITE,
@@ -275,34 +254,25 @@ ges_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
         }
 
         uri = gst_filename_to_uri (filename, NULL);
-        data.uri = uri;
-        data.self = self;
-
-        g_main_context_invoke (main_context,
-            (GSourceFunc) ges_timeline_new_from_uri_from_main_thread, &data);
-        g_mutex_lock (&data.lock);
-        while (!data.error && !data.timeline)
-          g_cond_wait (&data.cond, &data.lock);
-        data.loaded_sigid = 0;
-        data.error_sigid = 0;
-        g_mutex_unlock (&data.lock);
-
-        if (data.error) {
-          GST_ELEMENT_ERROR (self, STREAM, DEMUX,
-              ("Could not create timeline from description"),
-              ("%s", data.error->message));
-          g_clear_error (&data.error);
+        GST_INFO_OBJECT (self, "Pre loading the timeline.");
 
+        ges_demux_create_timeline (self, uri, &error);
+        if (error)
           goto error;
-        }
 
       done:
         g_free (filename);
         g_free (uri);
         g_close (f, NULL);
         return ret;
+
       error:
         ret = FALSE;
+        gst_element_post_message (GST_ELEMENT (self),
+            gst_message_new_error (parent, error,
+                "Could not create timeline from description"));
+        g_clear_error (&error);
+
         goto done;
       } else {
         GST_ELEMENT_ERROR (self, RESOURCE, READ,