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);