Commit 6d895ea1 authored by Thibault Saunier's avatar Thibault Saunier 🌵

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
parent 61c952c7
......@@ -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); = 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->error_sigid =
g_signal_connect (project, "error-loading-asset",
G_CALLBACK (error_loading_asset_cb), 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 (;
g_main_loop_unref (;
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,
ges_base_bin_set_timeline (GES_BASE_BIN (self), data.timeline);
GST_INFO_OBJECT (data->self, "Timeline properly loaded: %" GST_PTR_FORMAT,
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);
......@@ -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) {
......@@ -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) {
("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;
g_free (filename);
g_free (uri);
g_close (f, NULL);
return ret;
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 {
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment