mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-17 11:45:25 +00:00
timeline-element: Disconnect child properties handlers.
Summary: + And freeze notifies while doing so. We had a race with GstController which isn't MT safe, we can fix it by propertly disconnecting signals, and making sure no notifies are emitted while doing so. Reviewers: thiblahute Differential Revision: http://phabricator.freedesktop.org/D64
This commit is contained in:
parent
1ea442a021
commit
e89dccc9aa
1 changed files with 35 additions and 12 deletions
|
@ -80,6 +80,12 @@ static guint ges_timeline_element_signals[LAST_SIGNAL] = { 0 };
|
|||
|
||||
static GParamSpec *properties[PROP_LAST] = { NULL, };
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GObject *child;
|
||||
gulong handler_id;
|
||||
} ChildPropHandler;
|
||||
|
||||
struct _GESTimelineElementPrivate
|
||||
{
|
||||
gboolean serialize;
|
||||
|
@ -112,12 +118,14 @@ _lookup_child (GESTimelineElement * self, const gchar * prop_name,
|
|||
g_hash_table_iter_init (&iter, self->priv->children_props);
|
||||
while (g_hash_table_iter_next (&iter, &key, &value)) {
|
||||
if (g_strcmp0 (G_PARAM_SPEC (key)->name, name) == 0) {
|
||||
ChildPropHandler *handler = (ChildPropHandler *) value;
|
||||
if (classename == NULL ||
|
||||
g_strcmp0 (G_OBJECT_TYPE_NAME (G_OBJECT (value)), classename) == 0) {
|
||||
g_strcmp0 (G_OBJECT_TYPE_NAME (G_OBJECT (handler->child)),
|
||||
classename) == 0) {
|
||||
GST_DEBUG_OBJECT (self, "The %s property from %s has been found", name,
|
||||
classename);
|
||||
if (child)
|
||||
*child = gst_object_ref (value);
|
||||
*child = gst_object_ref (handler->child);
|
||||
|
||||
if (pspec)
|
||||
*pspec = g_param_spec_ref (key);
|
||||
|
@ -242,6 +250,17 @@ ges_timeline_element_finalize (GObject * self)
|
|||
G_OBJECT_CLASS (ges_timeline_element_parent_class)->finalize (self);
|
||||
}
|
||||
|
||||
static void
|
||||
_child_prop_handler_free (ChildPropHandler * handler)
|
||||
{
|
||||
g_object_freeze_notify (handler->child);
|
||||
if (handler->handler_id)
|
||||
g_signal_handler_disconnect (handler->child, handler->handler_id);
|
||||
g_object_thaw_notify (handler->child);
|
||||
gst_object_unref (handler->child);
|
||||
g_slice_free (ChildPropHandler, handler);
|
||||
}
|
||||
|
||||
static void
|
||||
ges_timeline_element_init (GESTimelineElement * self)
|
||||
{
|
||||
|
@ -252,7 +271,8 @@ ges_timeline_element_init (GESTimelineElement * self)
|
|||
|
||||
self->priv->children_props =
|
||||
g_hash_table_new_full ((GHashFunc) ges_pspec_hash, ges_pspec_equal,
|
||||
(GDestroyNotify) g_param_spec_unref, gst_object_unref);
|
||||
(GDestroyNotify) g_param_spec_unref,
|
||||
(GDestroyNotify) _child_prop_handler_free);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1198,6 +1218,7 @@ ges_timeline_element_add_child_property (GESTimelineElement * self,
|
|||
GParamSpec * pspec, GObject * child)
|
||||
{
|
||||
gchar *signame = g_strconcat ("notify::", pspec->name, NULL);
|
||||
ChildPropHandler *handler;
|
||||
|
||||
if (g_hash_table_contains (self->priv->children_props, pspec)) {
|
||||
GST_INFO_OBJECT (self, "Child property already exists: %s", pspec->name);
|
||||
|
@ -1208,11 +1229,13 @@ ges_timeline_element_add_child_property (GESTimelineElement * self,
|
|||
GST_DEBUG_OBJECT (self, "Adding child property: %" GST_PTR_FORMAT "::%s",
|
||||
child, pspec->name);
|
||||
|
||||
g_hash_table_insert (self->priv->children_props,
|
||||
g_param_spec_ref (pspec), gst_object_ref (child));
|
||||
signame = g_strconcat ("notify::", pspec->name, NULL);
|
||||
|
||||
g_signal_connect (child, signame, G_CALLBACK (child_prop_changed_cb), self);
|
||||
handler = (ChildPropHandler *) g_slice_new0 (ChildPropHandler);
|
||||
handler->child = gst_object_ref (child);
|
||||
handler->handler_id =
|
||||
g_signal_connect (child, signame, G_CALLBACK (child_prop_changed_cb),
|
||||
self);
|
||||
g_hash_table_insert (self->priv->children_props, g_param_spec_ref (pspec),
|
||||
handler);
|
||||
|
||||
g_free (signame);
|
||||
|
||||
|
@ -1231,15 +1254,15 @@ void
|
|||
ges_timeline_element_get_child_property_by_pspec (GESTimelineElement * self,
|
||||
GParamSpec * pspec, GValue * value)
|
||||
{
|
||||
GstElement *element;
|
||||
ChildPropHandler *handler;
|
||||
|
||||
g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
|
||||
|
||||
element = g_hash_table_lookup (self->priv->children_props, pspec);
|
||||
if (!element)
|
||||
handler = g_hash_table_lookup (self->priv->children_props, pspec);
|
||||
if (!handler)
|
||||
goto not_found;
|
||||
|
||||
g_object_get_property (G_OBJECT (element), pspec->name, value);
|
||||
g_object_get_property (G_OBJECT (handler->child), pspec->name, value);
|
||||
|
||||
return;
|
||||
|
||||
|
|
Loading…
Reference in a new issue