mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-20 04:56:24 +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, };
|
static GParamSpec *properties[PROP_LAST] = { NULL, };
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
GObject *child;
|
||||||
|
gulong handler_id;
|
||||||
|
} ChildPropHandler;
|
||||||
|
|
||||||
struct _GESTimelineElementPrivate
|
struct _GESTimelineElementPrivate
|
||||||
{
|
{
|
||||||
gboolean serialize;
|
gboolean serialize;
|
||||||
|
@ -112,12 +118,14 @@ _lookup_child (GESTimelineElement * self, const gchar * prop_name,
|
||||||
g_hash_table_iter_init (&iter, self->priv->children_props);
|
g_hash_table_iter_init (&iter, self->priv->children_props);
|
||||||
while (g_hash_table_iter_next (&iter, &key, &value)) {
|
while (g_hash_table_iter_next (&iter, &key, &value)) {
|
||||||
if (g_strcmp0 (G_PARAM_SPEC (key)->name, name) == 0) {
|
if (g_strcmp0 (G_PARAM_SPEC (key)->name, name) == 0) {
|
||||||
|
ChildPropHandler *handler = (ChildPropHandler *) value;
|
||||||
if (classename == NULL ||
|
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,
|
GST_DEBUG_OBJECT (self, "The %s property from %s has been found", name,
|
||||||
classename);
|
classename);
|
||||||
if (child)
|
if (child)
|
||||||
*child = gst_object_ref (value);
|
*child = gst_object_ref (handler->child);
|
||||||
|
|
||||||
if (pspec)
|
if (pspec)
|
||||||
*pspec = g_param_spec_ref (key);
|
*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);
|
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
|
static void
|
||||||
ges_timeline_element_init (GESTimelineElement * self)
|
ges_timeline_element_init (GESTimelineElement * self)
|
||||||
{
|
{
|
||||||
|
@ -252,7 +271,8 @@ ges_timeline_element_init (GESTimelineElement * self)
|
||||||
|
|
||||||
self->priv->children_props =
|
self->priv->children_props =
|
||||||
g_hash_table_new_full ((GHashFunc) ges_pspec_hash, ges_pspec_equal,
|
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
|
static void
|
||||||
|
@ -1198,6 +1218,7 @@ ges_timeline_element_add_child_property (GESTimelineElement * self,
|
||||||
GParamSpec * pspec, GObject * child)
|
GParamSpec * pspec, GObject * child)
|
||||||
{
|
{
|
||||||
gchar *signame = g_strconcat ("notify::", pspec->name, NULL);
|
gchar *signame = g_strconcat ("notify::", pspec->name, NULL);
|
||||||
|
ChildPropHandler *handler;
|
||||||
|
|
||||||
if (g_hash_table_contains (self->priv->children_props, pspec)) {
|
if (g_hash_table_contains (self->priv->children_props, pspec)) {
|
||||||
GST_INFO_OBJECT (self, "Child property already exists: %s", pspec->name);
|
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",
|
GST_DEBUG_OBJECT (self, "Adding child property: %" GST_PTR_FORMAT "::%s",
|
||||||
child, pspec->name);
|
child, pspec->name);
|
||||||
|
|
||||||
g_hash_table_insert (self->priv->children_props,
|
handler = (ChildPropHandler *) g_slice_new0 (ChildPropHandler);
|
||||||
g_param_spec_ref (pspec), gst_object_ref (child));
|
handler->child = gst_object_ref (child);
|
||||||
signame = g_strconcat ("notify::", pspec->name, NULL);
|
handler->handler_id =
|
||||||
|
g_signal_connect (child, signame, G_CALLBACK (child_prop_changed_cb),
|
||||||
g_signal_connect (child, signame, G_CALLBACK (child_prop_changed_cb), self);
|
self);
|
||||||
|
g_hash_table_insert (self->priv->children_props, g_param_spec_ref (pspec),
|
||||||
|
handler);
|
||||||
|
|
||||||
g_free (signame);
|
g_free (signame);
|
||||||
|
|
||||||
|
@ -1231,15 +1254,15 @@ void
|
||||||
ges_timeline_element_get_child_property_by_pspec (GESTimelineElement * self,
|
ges_timeline_element_get_child_property_by_pspec (GESTimelineElement * self,
|
||||||
GParamSpec * pspec, GValue * value)
|
GParamSpec * pspec, GValue * value)
|
||||||
{
|
{
|
||||||
GstElement *element;
|
ChildPropHandler *handler;
|
||||||
|
|
||||||
g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
|
g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
|
||||||
|
|
||||||
element = g_hash_table_lookup (self->priv->children_props, pspec);
|
handler = g_hash_table_lookup (self->priv->children_props, pspec);
|
||||||
if (!element)
|
if (!handler)
|
||||||
goto not_found;
|
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;
|
return;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue