mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-05 06:58:56 +00:00
GESTimeline: Lock object discovery list
TimelineFileSource objects are asynchronously discovered with discoverer with such objects being added to a pendingobjects list. If one were to remove a layer before an object in said layer had been discovered, a segfault could occur. As such, management of the list has been made more robust with the addition of a mutex and removal of the object from the pendingobjects list upon layer removal.
This commit is contained in:
parent
d1de4b2114
commit
fc97c16e7e
1 changed files with 56 additions and 1 deletions
|
@ -46,6 +46,13 @@
|
||||||
|
|
||||||
G_DEFINE_TYPE (GESTimeline, ges_timeline, GST_TYPE_BIN);
|
G_DEFINE_TYPE (GESTimeline, ges_timeline, GST_TYPE_BIN);
|
||||||
|
|
||||||
|
#define GES_TIMELINE_PENDINGOBJS_GET_LOCK(timeline) \
|
||||||
|
(GES_TIMELINE(timeline)->priv->pendingobjects_lock)
|
||||||
|
#define GES_TIMELINE_PENDINGOBJS_LOCK(timeline) \
|
||||||
|
(g_mutex_lock(GES_TIMELINE_PENDINGOBJS_GET_LOCK (timeline)))
|
||||||
|
#define GES_TIMELINE_PENDINGOBJS_UNLOCK(timeline) \
|
||||||
|
(g_mutex_unlock(GES_TIMELINE_PENDINGOBJS_GET_LOCK (timeline)))
|
||||||
|
|
||||||
struct _GESTimelinePrivate
|
struct _GESTimelinePrivate
|
||||||
{
|
{
|
||||||
GList *layers; /* A list of GESTimelineLayer sorted by priority */
|
GList *layers; /* A list of GESTimelineLayer sorted by priority */
|
||||||
|
@ -53,8 +60,10 @@ struct _GESTimelinePrivate
|
||||||
|
|
||||||
/* discoverer used for virgin sources */
|
/* discoverer used for virgin sources */
|
||||||
GstDiscoverer *discoverer;
|
GstDiscoverer *discoverer;
|
||||||
/* Objects that are being discovered FIXME : LOCK ! */
|
|
||||||
GList *pendingobjects;
|
GList *pendingobjects;
|
||||||
|
/* lock to avoid discovery of objects that will be removed */
|
||||||
|
GMutex *pendingobjects_lock;
|
||||||
|
|
||||||
/* Whether we are changing state asynchronously or not */
|
/* Whether we are changing state asynchronously or not */
|
||||||
gboolean async_pending;
|
gboolean async_pending;
|
||||||
};
|
};
|
||||||
|
@ -143,6 +152,10 @@ ges_timeline_dispose (GObject * object)
|
||||||
static void
|
static void
|
||||||
ges_timeline_finalize (GObject * object)
|
ges_timeline_finalize (GObject * object)
|
||||||
{
|
{
|
||||||
|
GESTimeline *timeline = GES_TIMELINE (object);
|
||||||
|
|
||||||
|
g_mutex_free (timeline->priv->pendingobjects_lock);
|
||||||
|
|
||||||
G_OBJECT_CLASS (ges_timeline_parent_class)->finalize (object);
|
G_OBJECT_CLASS (ges_timeline_parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,6 +236,7 @@ ges_timeline_init (GESTimeline * self)
|
||||||
self->priv->layers = NULL;
|
self->priv->layers = NULL;
|
||||||
self->priv->tracks = NULL;
|
self->priv->tracks = NULL;
|
||||||
|
|
||||||
|
self->priv->pendingobjects_lock = g_mutex_new ();
|
||||||
/* New discoverer with a 15s timeout */
|
/* New discoverer with a 15s timeout */
|
||||||
self->priv->discoverer = gst_discoverer_new (15 * GST_SECOND, NULL);
|
self->priv->discoverer = gst_discoverer_new (15 * GST_SECOND, NULL);
|
||||||
g_signal_connect (self->priv->discoverer, "finished",
|
g_signal_connect (self->priv->discoverer, "finished",
|
||||||
|
@ -443,6 +457,8 @@ discoverer_discovered_cb (GstDiscoverer * discoverer,
|
||||||
|
|
||||||
GST_DEBUG ("Discovered uri %s", uri);
|
GST_DEBUG ("Discovered uri %s", uri);
|
||||||
|
|
||||||
|
GES_TIMELINE_PENDINGOBJS_LOCK (timeline);
|
||||||
|
|
||||||
/* Find corresponding TimelineFileSource in the sources */
|
/* Find corresponding TimelineFileSource in the sources */
|
||||||
for (tmp = priv->pendingobjects; tmp; tmp = tmp->next) {
|
for (tmp = priv->pendingobjects; tmp; tmp = tmp->next) {
|
||||||
tfs = (GESTimelineFileSource *) tmp->data;
|
tfs = (GESTimelineFileSource *) tmp->data;
|
||||||
|
@ -457,8 +473,13 @@ discoverer_discovered_cb (GstDiscoverer * discoverer,
|
||||||
GList *stream_list;
|
GList *stream_list;
|
||||||
GESTrackType tfs_supportedformats;
|
GESTrackType tfs_supportedformats;
|
||||||
|
|
||||||
|
/* The timeline file source will be updated with discovered information
|
||||||
|
* so it needs to not be finalized during this process */
|
||||||
|
g_object_ref (tfs);
|
||||||
|
|
||||||
/* Remove object from list */
|
/* Remove object from list */
|
||||||
priv->pendingobjects = g_list_delete_link (priv->pendingobjects, tmp);
|
priv->pendingobjects = g_list_delete_link (priv->pendingobjects, tmp);
|
||||||
|
GES_TIMELINE_PENDINGOBJS_UNLOCK (timeline);
|
||||||
|
|
||||||
/* FIXME : Handle errors in discovery */
|
/* FIXME : Handle errors in discovery */
|
||||||
stream_list = gst_discoverer_info_get_stream_list (info);
|
stream_list = gst_discoverer_info_get_stream_list (info);
|
||||||
|
@ -503,6 +524,11 @@ discoverer_discovered_cb (GstDiscoverer * discoverer,
|
||||||
|
|
||||||
/* Continue the processing on tfs */
|
/* Continue the processing on tfs */
|
||||||
add_object_to_tracks (timeline, GES_TIMELINE_OBJECT (tfs));
|
add_object_to_tracks (timeline, GES_TIMELINE_OBJECT (tfs));
|
||||||
|
|
||||||
|
/* Remove the ref as the timeline file source is no longer needed here */
|
||||||
|
g_object_unref (tfs);
|
||||||
|
} else {
|
||||||
|
GES_TIMELINE_PENDINGOBJS_UNLOCK (timeline);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -514,9 +540,13 @@ ges_timeline_change_state (GstElement * element, GstStateChange transition)
|
||||||
|
|
||||||
switch (transition) {
|
switch (transition) {
|
||||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
||||||
|
GES_TIMELINE_PENDINGOBJS_LOCK (timeline);
|
||||||
if (timeline->priv->pendingobjects) {
|
if (timeline->priv->pendingobjects) {
|
||||||
|
GES_TIMELINE_PENDINGOBJS_UNLOCK (timeline);
|
||||||
do_async_start (timeline);
|
do_async_start (timeline);
|
||||||
ret = GST_STATE_CHANGE_ASYNC;
|
ret = GST_STATE_CHANGE_ASYNC;
|
||||||
|
} else {
|
||||||
|
GES_TIMELINE_PENDINGOBJS_UNLOCK (timeline);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -567,8 +597,12 @@ layer_object_added_cb (GESTimelineLayer * layer, GESTimelineObject * object,
|
||||||
tfs_maxdur == GST_CLOCK_TIME_NONE || object->duration == 0) {
|
tfs_maxdur == GST_CLOCK_TIME_NONE || object->duration == 0) {
|
||||||
GST_LOG ("Incomplete TimelineFileSource, discovering it");
|
GST_LOG ("Incomplete TimelineFileSource, discovering it");
|
||||||
tfs_uri = ges_timeline_filesource_get_uri (tfs);
|
tfs_uri = ges_timeline_filesource_get_uri (tfs);
|
||||||
|
|
||||||
|
GES_TIMELINE_PENDINGOBJS_LOCK (timeline);
|
||||||
timeline->priv->pendingobjects =
|
timeline->priv->pendingobjects =
|
||||||
g_list_append (timeline->priv->pendingobjects, object);
|
g_list_append (timeline->priv->pendingobjects, object);
|
||||||
|
GES_TIMELINE_PENDINGOBJS_UNLOCK (timeline);
|
||||||
|
|
||||||
gst_discoverer_discover_uri_async (timeline->priv->discoverer, tfs_uri);
|
gst_discoverer_discover_uri_async (timeline->priv->discoverer, tfs_uri);
|
||||||
} else
|
} else
|
||||||
add_object_to_tracks (timeline, object);
|
add_object_to_tracks (timeline, object);
|
||||||
|
@ -610,6 +644,27 @@ layer_object_removed_cb (GESTimelineLayer * layer, GESTimelineObject * object,
|
||||||
}
|
}
|
||||||
g_list_free (trackobjects);
|
g_list_free (trackobjects);
|
||||||
|
|
||||||
|
/* if the object is a timeline file source that has not yet been discovered,
|
||||||
|
* it no longer needs to be discovered so remove it from the pendingobjects
|
||||||
|
* list if it belongs to this layer */
|
||||||
|
if (GES_IS_TIMELINE_FILE_SOURCE (object)) {
|
||||||
|
GList *pendingobjects;
|
||||||
|
|
||||||
|
GES_TIMELINE_PENDINGOBJS_LOCK (timeline);
|
||||||
|
pendingobjects = timeline->priv->pendingobjects;
|
||||||
|
|
||||||
|
tmp = pendingobjects;
|
||||||
|
while (tmp) {
|
||||||
|
GList *next = tmp->next;
|
||||||
|
|
||||||
|
if (layer == (GESTimelineLayer *) ((GESTimelineObject *) tmp->data)->priv)
|
||||||
|
pendingobjects = g_list_delete_link (pendingobjects, tmp);
|
||||||
|
tmp = next;
|
||||||
|
}
|
||||||
|
timeline->priv->pendingobjects = pendingobjects;
|
||||||
|
GES_TIMELINE_PENDINGOBJS_UNLOCK (timeline);
|
||||||
|
}
|
||||||
|
|
||||||
GST_DEBUG ("Done");
|
GST_DEBUG ("Done");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue