From 6d895ea11143a6786945c2fd2fb84de4a31556d3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 14 Jun 2019 23:48:20 -0400 Subject: [PATCH] demux: Create timeline from the streaming thread 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 | 100 +++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 65 deletions(-) diff --git a/plugins/ges/gesdemux.c b/plugins/ges/gesdemux.c index 4985378e20..6e191ce495 100644 --- a/plugins/ges/gesdemux.c +++ b/plugins/ges/gesdemux.c @@ -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.error_sigid) + g_signal_handler_disconnect (project, data.error_sigid); - if (data->loaded_sigid) - g_signal_handler_disconnect (project, data->loaded_sigid); + g_clear_object (&project); - if (data->error_sigid) - g_signal_handler_disconnect (project, data->error_sigid); + GST_INFO_OBJECT (self, "Timeline properly loaded: %" GST_PTR_FORMAT, + data.timeline); + ges_base_bin_set_timeline (GES_BASE_BIN (self), data.timeline); - gst_clear_object (&project); - - 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,