From 38d60c9f43f29c2af6c9b6d45539edc8e4ddf70f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 1 May 2020 11:33:38 -0400 Subject: [PATCH] ges: Also track children props 'duplicates' in TimelineElement We used to only track the first one but this was wrong, so we start tracking all the children properties here, adapting the test which was already thought for this to be implemented. At the same time add some flags to determine how children properties need to be handled adding a mode that means that all duplicated children props will be set together when the user sets that particular child property. This is going to be tested in a following commit. Part-of: --- .../gst-editing-services/ges/ges-container.c | 59 ++-- .../gst-editing-services/ges/ges-internal.h | 20 +- .../gst-editing-services/ges/ges-test-clip.c | 4 +- .../ges/ges-timeline-element.c | 263 +++++++++++------- .../ges/ges-track-element.c | 5 +- .../tests/check/ges/group.c | 91 +++--- 6 files changed, 250 insertions(+), 192 deletions(-) diff --git a/subprojects/gst-editing-services/ges/ges-container.c b/subprojects/gst-editing-services/ges/ges-container.c index f0177a4ddb..45a7b4f978 100644 --- a/subprojects/gst-editing-services/ges/ges-container.c +++ b/subprojects/gst-editing-services/ges/ges-container.c @@ -211,7 +211,8 @@ _add_childs_child_property (GESTimelineElement * container_child, * instance who the property comes from */ gboolean res = ges_timeline_element_add_child_property_full (GES_TIMELINE_ELEMENT - (container), container_child, property, prop_child); + (container), container_child, property, prop_child, + GES_TIMELINE_ELEMENT_CHILD_PROP_FLAG_INHERIT); if (!res) GST_INFO_OBJECT (container, "Could not register the child property '%s' " "of our child %" GES_FORMAT " for the object %" GST_PTR_FORMAT, @@ -233,10 +234,14 @@ _ges_container_add_child_properties (GESContainer * container, for (i = 0; i < n_props; i++) { GParamSpec *property = child_props[i]; - GObject *prop_child = - ges_timeline_element_get_child_from_child_property (child, property); - if (prop_child) - _add_childs_child_property (child, prop_child, property, container); + GList *tmp, *children = + ges_timeline_element_get_children_from_child_property (child, property); + + for (tmp = children; tmp; tmp = tmp->next) + ges_timeline_element_add_child_property_full (GES_TIMELINE_ELEMENT + (container), child, property, tmp->data, + GES_TIMELINE_ELEMENT_CHILD_PROP_FLAG_INHERIT); + g_list_free (children); g_param_spec_unref (property); } @@ -247,37 +252,8 @@ static void _remove_childs_child_property (GESTimelineElement * container_child, GObject * prop_child, GParamSpec * property, GESContainer * container) { - /* NOTE: some children may share the same GParamSpec. Currently, only - * the first such child added will have its children properties - * successfully registered for the container (even though the GObject - * child who the properties belong to will be a different instance). As - * such, we only want to remove the child property if it corresponds to - * the same instance that the parent container has. - * E.g. if we add child1 and child2, that have the same (or some - * overlapping) children properties. And child1 is added before child2, - * then child2's overlapping children properties would not be registered. - * If we remove child2, we do *not* want to removed the child properties - * for child1 because they belong to a GObject instance that we still - * have in our control. - * If we remove child1, we *do* want to remove the child properties for - * child1, even though child2 may overlap with some of them, because we - * are loosing the specific GObject instance that it belongs to! - * We could try and register the ones that match for the other children. - * However, it is probably simpler to change - * ges_timeline_element_add_child_property_full to accept the same - * GParamSpec, for different instances. - */ - GESTimelineElement *element = GES_TIMELINE_ELEMENT (container); - GObject *our_prop_child = - ges_timeline_element_get_child_from_child_property (element, property); - if (our_prop_child == prop_child) - ges_timeline_element_remove_child_property (element, property); - else - GST_INFO_OBJECT (container, "Not removing child property '%s' for child" - " %" GES_FORMAT " because it derives from the object %" GST_PTR_FORMAT - "(%p) rather than the object %" GST_PTR_FORMAT "(%p)", property->name, - GES_ARGS (container_child), prop_child, prop_child, our_prop_child, - our_prop_child); + ges_timeline_element_remove_child_property_full (GES_TIMELINE_ELEMENT + (container), property, prop_child); } static void @@ -295,10 +271,13 @@ _ges_container_remove_child_properties (GESContainer * container, for (i = 0; i < n_props; i++) { GParamSpec *property = child_props[i]; - GObject *prop_child = - ges_timeline_element_get_child_from_child_property (child, property); - if (prop_child) - _remove_childs_child_property (child, prop_child, property, container); + GList *tmp, *children = + ges_timeline_element_get_children_from_child_property (child, property); + + for (tmp = children; tmp; tmp = tmp->next) + ges_timeline_element_remove_child_property_full (GES_TIMELINE_ELEMENT + (container), property, tmp->data); + g_list_free (children); g_param_spec_unref (property); } diff --git a/subprojects/gst-editing-services/ges/ges-internal.h b/subprojects/gst-editing-services/ges/ges-internal.h index 2cb5eb0c50..da7e10fc0f 100644 --- a/subprojects/gst-editing-services/ges/ges-internal.h +++ b/subprojects/gst-editing-services/ges/ges-internal.h @@ -551,18 +551,32 @@ typedef enum } GESTimelineElementFlags; G_GNUC_INTERNAL GESTimelineElement * ges_timeline_element_peak_toplevel (GESTimelineElement * self); + +typedef enum +{ + GES_TIMELINE_ELEMENT_CHILD_PROP_FLAG_NONE = (1 << 0), + /* Inherit flags from the owner child property registration */ + GES_TIMELINE_ELEMENT_CHILD_PROP_FLAG_INHERIT = (1 << 1), + /* When setting child property, ensure to set value on every registered instances */ + GES_TIMELINE_ELEMENT_CHILD_PROP_FLAG_SET_ON_ALL_INSTANCES = (1 << 2), +} GESTimelineElementChildPropertyFlags; + G_GNUC_INTERNAL GESTimelineElement * ges_timeline_element_get_copied_from (GESTimelineElement *self); G_GNUC_INTERNAL GESTimelineElementFlags ges_timeline_element_flags (GESTimelineElement *self); G_GNUC_INTERNAL void ges_timeline_element_set_flags (GESTimelineElement *self, GESTimelineElementFlags flags); G_GNUC_INTERNAL gboolean ges_timeline_element_add_child_property_full (GESTimelineElement *self, GESTimelineElement *owner, GParamSpec *pspec, - GObject *child); + GObject *child, + GESTimelineElementChildPropertyFlags flags); -G_GNUC_INTERNAL GObject * ges_timeline_element_get_child_from_child_property (GESTimelineElement * self, - GParamSpec * pspec); +G_GNUC_INTERNAL GList * ges_timeline_element_get_children_from_child_property (GESTimelineElement * self, + GParamSpec * pspec); G_GNUC_INTERNAL GParamSpec ** ges_timeline_element_get_children_properties (GESTimelineElement * self, guint * n_properties); +G_GNUC_INTERNAL gboolean ges_timeline_element_remove_child_property_full (GESTimelineElement * self, + GParamSpec * pspec, + GObject *child); #define ELEMENT_FLAGS(obj) (ges_timeline_element_flags (GES_TIMELINE_ELEMENT(obj))) #define ELEMENT_SET_FLAG(obj,flag) (ges_timeline_element_set_flags(GES_TIMELINE_ELEMENT(obj), (ELEMENT_FLAGS(obj) | (flag)))) diff --git a/subprojects/gst-editing-services/ges/ges-test-clip.c b/subprojects/gst-editing-services/ges/ges-test-clip.c index 0eba35920a..d83b18cf5d 100644 --- a/subprojects/gst-editing-services/ges/ges-test-clip.c +++ b/subprojects/gst-editing-services/ges/ges-test-clip.c @@ -301,7 +301,7 @@ static void ges_test_clip_class_init (GESTestClipClass * klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - GESClipClass *timobj_class = GES_CLIP_CLASS (klass); + GESClipClass *clip_class = GES_CLIP_CLASS (klass); object_class->get_property = ges_test_clip_get_property; object_class->set_property = ges_test_clip_set_property; @@ -347,7 +347,7 @@ ges_test_clip_class_init (GESTestClipClass * klass) g_param_spec_boolean ("mute", "Mute", "Mute audio track", FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - timobj_class->create_track_element = ges_test_clip_create_track_element; + clip_class->create_track_element = ges_test_clip_create_track_element; } static void diff --git a/subprojects/gst-editing-services/ges/ges-timeline-element.c b/subprojects/gst-editing-services/ges/ges-timeline-element.c index caa8b5bbc5..3bb80ae0f3 100644 --- a/subprojects/gst-editing-services/ges/ges-timeline-element.c +++ b/subprojects/gst-editing-services/ges/ges-timeline-element.c @@ -165,19 +165,18 @@ static GParamSpec *properties[PROP_LAST] = { NULL, }; typedef struct { GObject *child; + GParamSpec *pspec; GESTimelineElement *owner; gulong handler_id; GESTimelineElement *self; -} ChildPropHandler; + GESTimelineElementChildPropertyFlags flags; +} ChildPropSpec; struct _GESTimelineElementPrivate { gboolean serialize; - /* We keep a link between properties name and elements internally - * The hashtable should look like - * {GParamaSpec ---> child}*/ - GHashTable *children_props; + GArray *children_props; GESTimelineElement *copied_from; @@ -210,6 +209,31 @@ _set_child_property (GESTimelineElement * self G_GNUC_UNUSED, GObject * child, g_object_set_property (child, pspec->name, value); } +static ChildPropSpec * +_find_child_prop (GESTimelineElement * self, + GParamSpec * pspec, GObject * child, gint * index) +{ + gint i; + + for (i = 0; i < self->priv->children_props->len; i++) { + ChildPropSpec *childprop = + &g_array_index (self->priv->children_props, ChildPropSpec, i); + + if (child && childprop->child != child) { + continue; + } + + if (ges_pspec_hash (childprop->pspec) == ges_pspec_hash (pspec)) { + if (index) + *index = i; + + return childprop; + } + } + + return NULL; +} + static gboolean _set_child_property_full (GESTimelineElement * self, GObject * child, GParamSpec * pspec, const GValue * value, GError ** error) @@ -223,10 +247,9 @@ static gboolean _lookup_child (GESTimelineElement * self, const gchar * prop_name, GObject ** child, GParamSpec ** pspec) { - GHashTableIter iter; - gpointer key, value; gchar **names, *name, *classename; gboolean res; + gint i; classename = NULL; res = FALSE; @@ -238,22 +261,22 @@ _lookup_child (GESTimelineElement * self, const gchar * prop_name, } else name = names[0]; - 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 (handler->child)), - classename) == 0 || - g_strcmp0 (g_type_name (G_PARAM_SPEC (key)->owner_type), + for (i = 0; i < self->priv->children_props->len; i++) { + ChildPropSpec *childprop = + &g_array_index (self->priv->children_props, ChildPropSpec, i); + if (g_strcmp0 (childprop->pspec->name, name) == 0) { + if (classename == NULL + || g_strcmp0 (G_OBJECT_TYPE_NAME (G_OBJECT (childprop->child)), + classename) == 0 + || g_strcmp0 (g_type_name (childprop->pspec->owner_type), classename) == 0) { GST_DEBUG_OBJECT (self, "The %s property from %s has been found", name, classename); if (child) - *child = gst_object_ref (handler->child); + *child = gst_object_ref (childprop->child); if (pspec) - *pspec = g_param_spec_ref (key); + *pspec = g_param_spec_ref (childprop->pspec); res = TRUE; break; } @@ -268,20 +291,17 @@ GParamSpec ** ges_timeline_element_get_children_properties (GESTimelineElement * self, guint * n_properties) { - GParamSpec **pspec, *spec; - GHashTableIter iter; - gpointer key, value; + GParamSpec **pspec; guint i = 0; - *n_properties = g_hash_table_size (self->priv->children_props); + *n_properties = self->priv->children_props->len; pspec = g_new (GParamSpec *, *n_properties); - g_hash_table_iter_init (&iter, self->priv->children_props); - while (g_hash_table_iter_next (&iter, &key, &value)) { - spec = G_PARAM_SPEC (key); - pspec[i] = g_param_spec_ref (spec); - i++; + for (i = 0; i < *n_properties; i++) { + pspec[i] = + g_param_spec_ref (g_array_index (self->priv->children_props, + ChildPropSpec, i).pspec); } return pspec; @@ -370,10 +390,7 @@ ges_timeline_element_dispose (GObject * object) { GESTimelineElement *self = GES_TIMELINE_ELEMENT (object); - if (self->priv->children_props) { - g_hash_table_unref (self->priv->children_props); - self->priv->children_props = NULL; - } + g_clear_pointer (&self->priv->children_props, g_array_unref); g_clear_object (&self->priv->copied_from); @@ -391,12 +408,12 @@ ges_timeline_element_finalize (GObject * self) } static void -_child_prop_handler_free (ChildPropHandler * handler) +_child_prop_spec (ChildPropSpec * childprop) { - 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); + g_object_freeze_notify (childprop->child); + if (childprop->handler_id) + g_signal_handler_disconnect (childprop->child, childprop->handler_id); + g_object_thaw_notify (childprop->child); if (handler->child != (GObject *) handler->self && handler->child != (GObject *) handler->owner) @@ -420,10 +437,9 @@ ges_timeline_element_init (GESTimelineElement * self) self->priv->serialize = TRUE; - self->priv->children_props = - g_hash_table_new_full ((GHashFunc) ges_pspec_hash, ges_pspec_equal, - (GDestroyNotify) g_param_spec_unref, - (GDestroyNotify) _child_prop_handler_free); + self->priv->children_props = g_array_new (TRUE, TRUE, sizeof (ChildPropSpec)); + g_array_set_clear_func (self->priv->children_props, + (GDestroyNotify) _child_prop_spec); } static void @@ -792,52 +808,92 @@ child_prop_changed_cb (GObject * child, GParamSpec * arg, } static gboolean -set_child_property_by_pspec (GESTimelineElement * self, - GParamSpec * pspec, const GValue * value, GError ** error) +set_child_property (GESTimelineElement * self, ChildPropSpec * childprop, + const GValue * value, GError **error) { - GESTimelineElementClass *klass; GESTimelineElement *setter = self; - ChildPropHandler *handler = - g_hash_table_lookup (self->priv->children_props, pspec); + GESTimelineElementClass *klass; - if (!handler) { - GST_ERROR_OBJECT (self, "The %s property doesn't exist", pspec->name); - return FALSE; - } - - if (handler->owner) { - klass = GES_TIMELINE_ELEMENT_GET_CLASS (handler->owner); - setter = handler->owner; + if (childprop->owner) { + klass = GES_TIMELINE_ELEMENT_GET_CLASS (childprop->owner); + setter = childprop->owner; } else { klass = GES_TIMELINE_ELEMENT_GET_CLASS (self); } if (klass->set_child_property_full) - return klass->set_child_property_full (setter, handler->child, pspec, - value, error); + return klass->set_child_property_full (setter, childprop->child, + childprop->pspec, value, error); g_assert (klass->set_child_property); - klass->set_child_property (setter, handler->child, pspec, (GValue *) value); + klass->set_child_property (setter, childprop->child, childprop->pspec, + (GValue *) value); return TRUE; } +static gboolean +set_child_property_by_pspec (GESTimelineElement * self, + GParamSpec * pspec, const GValue * value, GError ** error) +{ + gint i; + ChildPropSpec *childprop; + + gboolean found = FALSE, res = TRUE; + + for (i = 0; i < self->priv->children_props->len; i++) { + childprop = &g_array_index (self->priv->children_props, ChildPropSpec, i); + + if (ges_pspec_hash (childprop->pspec) != ges_pspec_hash (pspec)) + continue; + + found = TRUE; + res &= set_child_property (self, childprop, value, error); + if (!(childprop->flags & + GES_TIMELINE_ELEMENT_CHILD_PROP_FLAG_SET_ON_ALL_INSTANCES)) + break; + } + + if (!found) { + GST_ERROR_OBJECT (self, "The %s property doesn't exist", pspec->name); + return FALSE; + } + GST_DEBUG_OBJECT (self, "Set child property %s", pspec->name); + + return res; +} + gboolean ges_timeline_element_add_child_property_full (GESTimelineElement * self, - GESTimelineElement * owner, GParamSpec * pspec, GObject * child) + GESTimelineElement * owner, GParamSpec * pspec, GObject * child, + GESTimelineElementChildPropertyFlags flags) { gchar *signame; - ChildPropHandler *handler; + ChildPropSpec childprop, *prev; - /* FIXME: allow the same pspec, provided the child is different. This - * is important for containers that may have duplicate children - * If this is changed, _remove_childs_child_property in ges-container.c - * should be changed to reflect this. - * We could hack around this by copying the pspec into a new instance - * of GParamSpec, but there is no such GLib method, and it would break - * the usage of get_..._from_pspec and set_..._from_pspec */ - if (g_hash_table_contains (self->priv->children_props, pspec)) { + if (_find_child_prop (self, pspec, child, NULL)) { GST_INFO_OBJECT (self, "Child property already exists: %s", pspec->name); + + return FALSE; + } + + prev = _find_child_prop (self, pspec, NULL, NULL); + if (flags & GES_TIMELINE_ELEMENT_CHILD_PROP_FLAG_INHERIT) { + if (!owner) { + g_warning ("Trying to inherit child property flags without an owner"); + } else { + ChildPropSpec *owner_prop = _find_child_prop (owner, pspec, NULL, NULL); + + g_return_val_if_fail (owner_prop, FALSE); + flags |= owner_prop->flags; + } + } + + if (prev && prev->flags != flags) { + GST_ERROR_OBJECT (self, + "Trying to add child property with flags %d but the same" + " property had flags %d - this is not supported", flags, prev->flags); + return FALSE; } @@ -848,15 +904,16 @@ ges_timeline_element_add_child_property_full (GESTimelineElement * self, handler = (ChildPropHandler *) g_new0 (ChildPropHandler, 1); handler->self = self; if (child == G_OBJECT (self) || child == G_OBJECT (owner)) - handler->child = child; + childprop.child = child; else - handler->child = gst_object_ref (child); - handler->owner = owner; - handler->handler_id = + childprop.child = gst_object_ref (child); + childprop.pspec = g_param_spec_ref (pspec); + childprop.owner = owner; + childprop.flags = flags; + childprop.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_array_append_val (self->priv->children_props, childprop); g_signal_emit (self, ges_timeline_element_signals[CHILD_PROPERTY_ADDED], 0, child, pspec); @@ -865,15 +922,22 @@ ges_timeline_element_add_child_property_full (GESTimelineElement * self, return TRUE; } -GObject * -ges_timeline_element_get_child_from_child_property (GESTimelineElement * self, - GParamSpec * pspec) +GList * +ges_timeline_element_get_children_from_child_property (GESTimelineElement * + self, GParamSpec * pspec) { - ChildPropHandler *handler = - g_hash_table_lookup (self->priv->children_props, pspec); - if (handler) - return handler->child; - return NULL; + gint i; + GList *res = NULL; + + for (i = 0; i < self->priv->children_props->len; i++) { + ChildPropSpec *childprop = + &g_array_index (self->priv->children_props, ChildPropSpec, i); + + if (ges_pspec_hash (childprop->pspec) == ges_pspec_hash (pspec)) + res = g_list_append (res, childprop->child); + } + + return res; } @@ -1778,7 +1842,7 @@ ges_timeline_element_add_child_property (GESTimelineElement * self, g_return_val_if_fail (G_IS_OBJECT (child), FALSE); return ges_timeline_element_add_child_property_full (self, NULL, pspec, - child); + child, 0); } /** @@ -1795,16 +1859,16 @@ void ges_timeline_element_get_child_property_by_pspec (GESTimelineElement * self, GParamSpec * pspec, GValue * value) { - ChildPropHandler *handler; + ChildPropSpec *childprop; g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self)); g_return_if_fail (G_IS_PARAM_SPEC (pspec)); - handler = g_hash_table_lookup (self->priv->children_props, pspec); - if (!handler) + childprop = _find_child_prop (self, pspec, NULL, NULL); + if (!childprop) goto not_found; - g_object_get_property (G_OBJECT (handler->child), pspec->name, value); + g_object_get_property (G_OBJECT (childprop->child), pspec->name, value); return; @@ -2232,28 +2296,37 @@ gboolean ges_timeline_element_remove_child_property (GESTimelineElement * self, GParamSpec * pspec) { - gpointer key, value; - GParamSpec *found_pspec; - ChildPropHandler *handler; + return ges_timeline_element_remove_child_property_full (self, pspec, NULL); +} + +gboolean +ges_timeline_element_remove_child_property_full (GESTimelineElement * self, + GParamSpec * pspec, GObject * child) +{ + gint index; + ChildPropSpec *childprop, handler_copy; g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE); g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE); + g_return_val_if_fail ((!child || G_IS_OBJECT (child)), FALSE); - if (!g_hash_table_lookup_extended (self->priv->children_props, pspec, - &key, &value)) { + if (!(childprop = _find_child_prop (self, pspec, child, &index))) { GST_WARNING_OBJECT (self, "No child property with pspec %p (%s) found", pspec, pspec->name); return FALSE; } - g_hash_table_steal (self->priv->children_props, pspec); - found_pspec = G_PARAM_SPEC (key); - handler = (ChildPropHandler *) value; + + GST_DEBUG_OBJECT (child, "Removing %s", pspec->name); + handler_copy = *childprop; + g_array_set_clear_func (self->priv->children_props, NULL); + g_array_remove_index (self->priv->children_props, index); + g_array_set_clear_func (self->priv->children_props, + (GDestroyNotify) _child_prop_spec); g_signal_emit (self, ges_timeline_element_signals[CHILD_PROPERTY_REMOVED], 0, - handler->child, found_pspec); + handler_copy.child, handler_copy.pspec); - g_param_spec_unref (found_pspec); - _child_prop_handler_free (handler); + _child_prop_spec (&handler_copy); return TRUE; } diff --git a/subprojects/gst-editing-services/ges/ges-track-element.c b/subprojects/gst-editing-services/ges/ges-track-element.c index 60c0691974..d80c1de0f2 100644 --- a/subprojects/gst-editing-services/ges/ges-track-element.c +++ b/subprojects/gst-editing-services/ges/ges-track-element.c @@ -279,9 +279,9 @@ ges_track_element_dispose (GObject * object) static void ges_track_element_set_asset (GESExtractable * extractable, GESAsset * asset) { + gchar *tmp; GESTrackElementClass *class; GstElement *nleobject; - gchar *tmp; GESTrackElement *object = GES_TRACK_ELEMENT (extractable); if (ges_track_element_get_track_type (object) == GES_TRACK_TYPE_UNKNOWN) { @@ -300,8 +300,7 @@ ges_track_element_set_asset (GESExtractable * extractable, GESAsset * asset) return; } - tmp = g_strdup_printf ("%s:%s", G_OBJECT_TYPE_NAME (object), - GST_OBJECT_NAME (nleobject)); + tmp = g_strdup_printf ("nleges%s", GES_TIMELINE_ELEMENT_NAME (object)); gst_object_set_name (GST_OBJECT (nleobject), tmp); g_free (tmp); diff --git a/subprojects/gst-editing-services/tests/check/ges/group.c b/subprojects/gst-editing-services/tests/check/ges/group.c index 6c6002b243..caad249ce4 100644 --- a/subprojects/gst-editing-services/tests/check/ges/group.c +++ b/subprojects/gst-editing-services/tests/check/ges/group.c @@ -635,7 +635,6 @@ static void project_loaded_cb (GESProject * project, GESTimeline * timeline, GMainLoop * mainloop) { - GST_ERROR ("LOADED!"); g_main_loop_quit (mainloop); } @@ -728,7 +727,7 @@ GST_START_TEST (test_children_properties_contain) GESTimeline *timeline; GESLayer *layer; GESAsset *asset; - GESTimelineElement *c1, *c2, *c3, *g1, *g2; + GESTimelineElement *audioc0, *videoc, *audioc1, *g1, *g2; GParamSpec **child_props1, **child_props2; guint num_props1, num_props2; @@ -739,99 +738,92 @@ GST_START_TEST (test_children_properties_contain) asset = ges_asset_request (GES_TYPE_TEST_CLIP, NULL, NULL); /* choose one audio and one video to give them different properties */ - c1 = GES_TIMELINE_ELEMENT (ges_layer_add_asset (layer, asset, 0, 0, 10, + audioc0 = GES_TIMELINE_ELEMENT (ges_layer_add_asset (layer, asset, 0, 0, 10, GES_TRACK_TYPE_AUDIO)); - c2 = GES_TIMELINE_ELEMENT (ges_layer_add_asset (layer, asset, 20, 0, 10, + videoc = GES_TIMELINE_ELEMENT (ges_layer_add_asset (layer, asset, 20, 0, 10, GES_TRACK_TYPE_VIDEO)); - /* but c3 will have the same child properties as c1! */ - c3 = GES_TIMELINE_ELEMENT (ges_layer_add_asset (layer, asset, 40, 0, 10, + /* but audioc1 will have the same child properties as audioc0! */ + audioc1 = GES_TIMELINE_ELEMENT (ges_layer_add_asset (layer, asset, 40, 0, 10, GES_TRACK_TYPE_AUDIO)); - fail_unless (c1); - fail_unless (c2); + fail_unless (audioc0); + fail_unless (videoc); g1 = GES_TIMELINE_ELEMENT (ges_group_new ()); g2 = GES_TIMELINE_ELEMENT (ges_group_new ()); /* group should have the same as its children */ - fail_unless (ges_container_add (GES_CONTAINER (g1), c1)); + fail_unless (ges_container_add (GES_CONTAINER (g1), audioc0)); num_props1 = 0; - child_props1 = append_children_properties (NULL, c1, &num_props1); + child_props1 = append_children_properties (NULL, audioc0, &num_props1); num_props2 = 0; child_props2 = append_children_properties (NULL, g1, &num_props2); + /* audioc0 VS g1 */ assert_property_list_match (child_props1, num_props1, child_props2, num_props2); /* add next child and gain its children properties as well */ - fail_unless (ges_container_add (GES_CONTAINER (g1), c2)); + fail_unless (ges_container_add (GES_CONTAINER (g1), videoc)); - /* add the child properties of c2 to the existing list for c1 */ - child_props1 = append_children_properties (child_props1, c2, &num_props1); + /* add the child properties of videoc to the existing list for audioc0 */ + child_props1 = append_children_properties (child_props1, videoc, &num_props1); free_children_properties (child_props2, num_props2); num_props2 = 0; child_props2 = append_children_properties (NULL, g1, &num_props2); + /* audioc0+videoc VS g1 */ assert_property_list_match (child_props1, num_props1, child_props2, num_props2); - /* FIXME: if c1 and c3 have the same child properties (they use the - * same GParamSpec) then ges_timeline_element_add_child_property_full - * will fail, even though the corresponding GObject child is not the - * same instance */ - - fail_unless (ges_container_add (GES_CONTAINER (g1), c3)); - - /* FIXME: regarding the above comment, ideally we would append the - * children properties for c3 to child_props1, so that its children - * properties appear twice in the list: - * child_props1 = - * append_children_properties (child_props1, c3, &num_props1); */ + fail_unless (ges_container_add (GES_CONTAINER (g1), audioc1)); + child_props1 = + append_children_properties (child_props1, audioc1, &num_props1); free_children_properties (child_props2, num_props2); num_props2 = 0; child_props2 = append_children_properties (NULL, g1, &num_props2); + /* audioc0+videoc+audioc1 VS g1 */ assert_property_list_match (child_props1, num_props1, child_props2, num_props2); - /* remove c3 */ - fail_unless (ges_container_remove (GES_CONTAINER (g1), c3)); - - /* FIXME: regarding the above comment, ideally we would reset - * child_props1 to only contain the child properties for c1 and c2 - * Currently, we at least want to make sure that the child properties - * for c1 remain. - * Currently, if we removed c1 first, all its children properties would - * be removed from g1, and this would *not* automatically register the - * children properties for c3. */ - - free_children_properties (child_props2, num_props2); - num_props2 = 0; - child_props2 = append_children_properties (NULL, g1, &num_props2); - - assert_property_list_match (child_props1, num_props1, - child_props2, num_props2); - - /* remove c1 */ - fail_unless (ges_container_remove (GES_CONTAINER (g1), c1)); + /* remove audioc1 */ + fail_unless (ges_container_remove (GES_CONTAINER (g1), audioc1)); free_children_properties (child_props1, num_props1); num_props1 = 0; - child_props1 = append_children_properties (NULL, c2, &num_props1); + child_props1 = append_children_properties (NULL, audioc0, &num_props1); + child_props1 = append_children_properties (child_props1, videoc, &num_props1); free_children_properties (child_props2, num_props2); num_props2 = 0; child_props2 = append_children_properties (NULL, g1, &num_props2); + /* audioc0+videoc VS g1 */ assert_property_list_match (child_props1, num_props1, child_props2, num_props2); - /* add g1 and c1 to g2 */ + /* remove audioc0 */ + fail_unless (ges_container_remove (GES_CONTAINER (g1), audioc0)); + + free_children_properties (child_props1, num_props1); + num_props1 = 0; + child_props1 = append_children_properties (NULL, videoc, &num_props1); + + free_children_properties (child_props2, num_props2); + num_props2 = 0; + child_props2 = append_children_properties (NULL, g1, &num_props2); + + /* videoc VS g1 */ + assert_property_list_match (child_props1, num_props1, + child_props2, num_props2); + + /* add g1 and audioc0 to g2 */ fail_unless (ges_container_add (GES_CONTAINER (g2), g1)); - fail_unless (ges_container_add (GES_CONTAINER (g2), c1)); + fail_unless (ges_container_add (GES_CONTAINER (g2), audioc0)); free_children_properties (child_props1, num_props1); num_props1 = 0; @@ -839,9 +831,10 @@ GST_START_TEST (test_children_properties_contain) free_children_properties (child_props2, num_props2); num_props2 = 0; - child_props2 = append_children_properties (NULL, c1, &num_props2); + child_props2 = append_children_properties (NULL, audioc0, &num_props2); child_props2 = append_children_properties (child_props2, g1, &num_props2); + /* g2+audioc0 VS g2 */ assert_property_list_match (child_props1, num_props1, child_props2, num_props2);