diff --git a/docs/libs/ges-sections.txt b/docs/libs/ges-sections.txt index 1d467dc93c..eee72efe0d 100644 --- a/docs/libs/ges-sections.txt +++ b/docs/libs/ges-sections.txt @@ -452,6 +452,18 @@ ges_timeline_element_get_toplevel_parent ges_timeline_element_copy ges_timeline_element_get_name ges_timeline_element_set_name +ges_timeline_element_list_children_properties +ges_timeline_element_lookup_child +ges_timeline_element_get_child_property_by_pspec +ges_timeline_element_get_child_property_valist +ges_timeline_element_get_child_properties +ges_timeline_element_set_child_property_valist +ges_timeline_element_set_child_property_by_pspec +ges_timeline_element_set_child_properties +ges_timeline_element_set_child_property +ges_timeline_element_get_child_property +ges_timeline_element_add_child_property +ges_timeline_element_remove_child_property GES_TIMELINE_ELEMENT_PARENT GES_TIMELINE_ELEMENT_TIMELINE GES_TIMELINE_ELEMENT_START diff --git a/ges/ges-timeline-element.c b/ges/ges-timeline-element.c index 3ace821a2f..0ddd28d989 100644 --- a/ges/ges-timeline-element.c +++ b/ges/ges-timeline-element.c @@ -26,11 +26,14 @@ * responsible for controlling its timing properties. */ +#include "ges-utils.h" #include "ges-timeline-element.h" #include "ges-extractable.h" #include "ges-meta-container.h" #include "ges-internal.h" + #include +#include /* maps type name quark => count */ static GData *object_name_counts = NULL; @@ -67,13 +70,90 @@ enum PROP_LAST }; +enum +{ + DEEP_NOTIFY, + LAST_SIGNAL +}; + +static guint ges_timeline_element_signals[LAST_SIGNAL] = { 0 }; + static GParamSpec *properties[PROP_LAST] = { NULL, }; struct _GESTimelineElementPrivate { gboolean serialize; + + /* We keep a link between properties name and elements internally + * The hashtable should look like + * {GParamaSpec ---> child}*/ + GHashTable *children_props; }; +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; + + classename = NULL; + res = FALSE; + + names = g_strsplit (prop_name, "::", 2); + if (names[1] != NULL) { + classename = names[0]; + name = names[1]; + } 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) { + if (classename == NULL || + g_strcmp0 (G_OBJECT_TYPE_NAME (G_OBJECT (value)), classename) == 0) { + GST_DEBUG_OBJECT (self, "The %s property from %s has been found", name, + classename); + if (child) + *child = gst_object_ref (value); + + if (pspec) + *pspec = g_param_spec_ref (key); + res = TRUE; + break; + } + } + } + g_strfreev (names); + + return res; +} + +static GParamSpec ** +default_list_children_properties (GESTimelineElement * self, + guint * n_properties) +{ + GParamSpec **pspec, *spec; + GHashTableIter iter; + gpointer key, value; + + guint i = 0; + + *n_properties = g_hash_table_size (self->priv->children_props); + 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++; + } + + return pspec; +} + static void _get_property (GObject * object, guint property_id, GValue * value, GParamSpec * pspec) @@ -169,6 +249,10 @@ ges_timeline_element_init (GESTimelineElement * self) GES_TYPE_TIMELINE_ELEMENT, GESTimelineElementPrivate); 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, gst_object_unref); } static void @@ -268,6 +352,21 @@ ges_timeline_element_class_init (GESTimelineElementClass * klass) g_object_class_install_properties (object_class, PROP_LAST, properties); + /** + * GESTimelineElement::deep-notify: + * @timeline_element: a #GESTtimelineElement + * @prop_object: the object that originated the signal + * @prop: the property that changed + * + * The deep notify signal is used to be notified of property changes of all + * the childs of @timeline_element + */ + ges_timeline_element_signals[DEEP_NOTIFY] = + g_signal_new ("deep-notify", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED | + G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_generic, + G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_PARAM); + object_class->finalize = ges_timeline_element_finalize; klass->set_parent = NULL; @@ -282,6 +381,9 @@ ges_timeline_element_class_init (GESTimelineElementClass * klass) klass->roll_start = NULL; klass->roll_end = NULL; klass->trim = NULL; + + klass->list_children_properties = default_list_children_properties; + klass->lookup_child = _lookup_child; } static void @@ -1082,3 +1184,440 @@ had_timeline: return FALSE; } } + +static void +child_prop_changed_cb (GObject * child, GParamSpec * arg + G_GNUC_UNUSED, GESTimelineElement * self) +{ + g_signal_emit (self, ges_timeline_element_signals[DEEP_NOTIFY], 0, + child, arg); +} + +gboolean +ges_timeline_element_add_child_property (GESTimelineElement * self, + GParamSpec * pspec, GObject * child) +{ + GST_DEBUG_OBJECT (self, "Adding child property: %" GST_PTR_FORMAT "::%s", + child, pspec->name); + + if (g_hash_table_insert (self->priv->children_props, + g_param_spec_ref (pspec), gst_object_ref (child))) { + gchar *signame = g_strconcat ("notify::", pspec->name, NULL); + + g_signal_connect (child, signame, G_CALLBACK (child_prop_changed_cb), self); + + g_free (signame); + + return TRUE; + } + + return FALSE; +} + +/** + * ges_track_element_get_child_property_by_pspec: + * @self: a #GESTrackElement + * @pspec: The #GParamSpec that specifies the property you want to get + * @value: (out): return location for the value + * + * Gets a property of a child of @self. + */ +void +ges_timeline_element_get_child_property_by_pspec (GESTimelineElement * self, + GParamSpec * pspec, GValue * value) +{ + GstElement *element; + + g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self)); + + element = g_hash_table_lookup (self->priv->children_props, pspec); + if (!element) + goto not_found; + + g_object_get_property (G_OBJECT (element), pspec->name, value); + + return; + +not_found: + { + GST_ERROR_OBJECT (self, "The %s property doesn't exist", pspec->name); + return; + } +} + +/** + * ges_timeline_element_set_child_property_by_pspec: + * @self: a #GESTimelineElement + * @pspec: The #GParamSpec that specifies the property you want to set + * @value: the value + * + * Sets a property of a child of @self. + */ +void +ges_timeline_element_set_child_property_by_pspec (GESTimelineElement * self, + GParamSpec * pspec, GValue * value) +{ + GObject *child; + + g_return_if_fail (GES_IS_TRACK_ELEMENT (self)); + + if (!ges_timeline_element_lookup_child (self, pspec->name, &child, &pspec)) + goto not_found; + + g_object_set_property (child, pspec->name, value); + + return; + +not_found: + { + GST_ERROR ("The %s property doesn't exist", pspec->name); + return; + } +} + +/** + * ges_timeline_element_set_child_property: + * @self: The origin #GESTimelineElement + * @property_name: The name of the property + * @value: the value + * + * Sets a property of a child of @self + * + * Note that #ges_timeline_element_set_child_property is really + * intended for language bindings, #ges_timeline_element_set_child_properties + * is much more convenient for C programming. + * + * Returns: %TRUE if the property was set, %FALSE otherwize + */ +gboolean +ges_timeline_element_set_child_property (GESTimelineElement * self, + const gchar * property_name, GValue * value) +{ + GParamSpec *pspec; + GObject *child; + + g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE); + + if (!ges_timeline_element_lookup_child (self, property_name, &child, &pspec)) + goto not_found; + + g_object_set_property (child, pspec->name, value); + + gst_object_unref (child); + g_param_spec_unref (pspec); + + return TRUE; + +not_found: + { + GST_WARNING_OBJECT (self, "The %s property doesn't exist", property_name); + + return FALSE; + } +} + +/** +* ges_timeline_element_get_child_property: +* @object: The origin #GESTimelineElement +* @property_name: The name of the property +* @value: (out): return location for the property value, it will +* be initialized if it is initialized with 0 +* +* In general, a copy is made of the property contents and +* the caller is responsible for freeing the memory by calling +* g_value_unset(). +* +* Gets a property of a GstElement contained in @object. +* +* Note that #ges_timeline_element_get_child_property is really +* intended for language bindings, #ges_timeline_element_get_child_properties +* is much more convenient for C programming. +* +* Returns: %TRUE if the property was found, %FALSE otherwize +*/ +gboolean +ges_timeline_element_get_child_property (GESTimelineElement * self, + const gchar * property_name, GValue * value) +{ + GParamSpec *pspec; + GObject *child; + + g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE); + + if (!ges_timeline_element_lookup_child (self, property_name, &child, &pspec)) + goto not_found; + + if (G_VALUE_TYPE (value) == G_TYPE_INVALID) + g_value_init (value, pspec->value_type); + + g_object_get_property (child, pspec->name, value); + + gst_object_unref (child); + g_param_spec_unref (pspec); + + return TRUE; + +not_found: + { + GST_WARNING_OBJECT (self, "The %s property doesn't exist", property_name); + + return FALSE; + } +} + +/** + * ges_timeline_element_lookup_child: + * @self: object to lookup the property in + * @prop_name: name of the property to look up. You can specify the name of the + * class as such: "ClassName::property-name", to guarantee that you get the + * proper GParamSpec in case various GstElement-s contain the same property + * name. If you don't do so, you will get the first element found, having + * this property and the and the corresponding GParamSpec. + * @element: (out) (allow-none) (transfer full): pointer to a #GstElement that + * takes the real object to set property on + * @pspec: (out) (allow-none) (transfer full): pointer to take the #GParamSpec + * describing the property + * + * Looks up which @element and @pspec would be effected by the given @name. If various + * contained elements have this property name you will get the first one, unless you + * specify the class name in @name. + * + * Returns: TRUE if @element and @pspec could be found. FALSE otherwise. In that + * case the values for @pspec and @element are not modified. Unref @element after + * usage. + */ +gboolean +ges_timeline_element_lookup_child (GESTimelineElement * self, + const gchar * prop_name, GObject ** child, GParamSpec ** pspec) +{ + GESTimelineElementClass *class; + + g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE); + class = GES_TIMELINE_ELEMENT_GET_CLASS (self); + g_return_val_if_fail (class->lookup_child, FALSE); + + return class->lookup_child (self, prop_name, child, pspec); +} + +/** + * ges_timeline_element_set_child_property_valist: + * @self: The #GESTimelineElement parent object + * @first_property_name: The name of the first property to set + * @var_args: value for the first property, followed optionally by more + * name/return location pairs, followed by NULL + * + * Sets a property of a child of @self. If there are various child elements + * that have the same property name, you can distinguish them using the following + * syntax: 'ClasseName::property_name' as property name. If you don't, the + * corresponding property of the first element found will be set. + */ +void +ges_timeline_element_set_child_property_valist (GESTimelineElement * self, + const gchar * first_property_name, va_list var_args) +{ + const gchar *name; + GParamSpec *pspec; + GObject *child; + + gchar *error = NULL; + GValue value = { 0, }; + + g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self)); + + name = first_property_name; + + /* Note: This part is in big part copied from the gst_child_object_set_valist + * method. */ + + /* iterate over pairs */ + while (name) { + if (!ges_timeline_element_lookup_child (self, name, &child, &pspec)) + goto not_found; + + G_VALUE_COLLECT_INIT (&value, pspec->value_type, var_args, + G_VALUE_NOCOPY_CONTENTS, &error); + + if (error) + goto cant_copy; + + g_object_set_property (child, pspec->name, &value); + + gst_object_unref (child); + g_value_unset (&value); + + name = va_arg (var_args, gchar *); + } + return; + +not_found: + { + GST_WARNING_OBJECT (self, "No property %s in OBJECT\n", name); + return; + } +cant_copy: + { + GST_WARNING_OBJECT (self, "error copying value %s in %p: %s", pspec->name, + self, error); + + g_value_unset (&value); + return; + } +} + +/** + * ges_timeline_element_set_child_properties: + * @self: The #GESTimelineElement parent object + * @first_property_name: The name of the first property to set + * @...: value for the first property, followed optionally by more + * name/return location pairs, followed by NULL + * + * Sets a property of a child of @self. If there are various child elements + * that have the same property name, you can distinguish them using the following + * syntax: 'ClasseName::property_name' as property name. If you don't, the + * corresponding property of the first element found will be set. + */ +void +ges_timeline_element_set_child_properties (GESTimelineElement * self, + const gchar * first_property_name, ...) +{ + va_list var_args; + + g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self)); + + va_start (var_args, first_property_name); + ges_timeline_element_set_child_property_valist (self, first_property_name, + var_args); + va_end (var_args); +} + +/** + * ges_timeline_element_get_child_property_valist: + * @self: The #GESTimelineElement parent object + * @first_property_name: The name of the first property to get + * @var_args: value for the first property, followed optionally by more + * name/return location pairs, followed by NULL + * + * Gets a property of a child of @self. If there are various child elements + * that have the same property name, you can distinguish them using the following + * syntax: 'ClasseName::property_name' as property name. If you don't, the + * corresponding property of the first element found will be set. + */ +void +ges_timeline_element_get_child_property_valist (GESTimelineElement * self, + const gchar * first_property_name, va_list var_args) +{ + const gchar *name; + gchar *error = NULL; + GValue value = { 0, }; + GParamSpec *pspec; + GObject *child; + + g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self)); + + name = first_property_name; + + /* This part is in big part copied from the gst_child_object_get_valist method */ + while (name) { + if (!ges_timeline_element_lookup_child (self, name, &child, &pspec)) + goto not_found; + + g_value_init (&value, pspec->value_type); + g_object_get_property (child, pspec->name, &value); + gst_object_unref (child); + + G_VALUE_LCOPY (&value, var_args, 0, &error); + if (error) + goto cant_copy; + g_value_unset (&value); + name = va_arg (var_args, gchar *); + } + return; + +not_found: + { + GST_WARNING_OBJECT (self, "no child property %s", name); + return; + } +cant_copy: + { + GST_WARNING_OBJECT (self, "error copying value %s in %s", pspec->name, + error); + + g_value_unset (&value); + return; + } +} + +static gint +compare_gparamspec (GParamSpec ** a, GParamSpec ** b, gpointer udata) +{ + return g_strcmp0 ((*a)->name, (*b)->name); +} + + +/** + * ges_timeline_element_list_children_properties: + * @self: The #GESTimelineElement to get the list of children properties from + * @n_properties: (out): return location for the length of the returned array + * + * Gets an array of #GParamSpec* for all configurable properties of the + * children of @self. + * + * Returns: (transfer full) (array length=n_properties): an array of #GParamSpec* which should be freed after use or + * %NULL if something went wrong + */ +GParamSpec ** +ges_timeline_element_list_children_properties (GESTimelineElement * self, + guint * n_properties) +{ + GParamSpec **ret; + GESTimelineElementClass *class; + + g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), NULL); + + class = GES_TIMELINE_ELEMENT_GET_CLASS (self); + + if (!class->list_children_properties) { + GST_INFO_OBJECT (self, "No %s->list_children_properties implementation", + G_OBJECT_TYPE_NAME (self)); + + *n_properties = 0; + return NULL; + } + + ret = class->list_children_properties (self, n_properties); + g_qsort_with_data (ret, *n_properties, sizeof (GParamSpec *), + (GCompareDataFunc) compare_gparamspec, NULL); + + return ret; +} + +/** + * ges_timeline_element_get_child_properties: + * @self: The origin #GESTimelineElement + * @first_property_name: The name of the first property to get + * @...: return location for the first property, followed optionally by more + * name/return location pairs, followed by NULL + * + * Gets properties of a child of @self. + */ +void +ges_timeline_element_get_child_properties (GESTimelineElement * self, + const gchar * first_property_name, ...) +{ + va_list var_args; + + g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self)); + + va_start (var_args, first_property_name); + ges_timeline_element_get_child_property_valist (self, first_property_name, + var_args); + va_end (var_args); +} + +gboolean +ges_timeline_element_remove_child_property (GESTimelineElement * self, + GParamSpec * pspec) +{ + return g_hash_table_remove (self->priv->children_props, pspec); +} diff --git a/ges/ges-timeline-element.h b/ges/ges-timeline-element.h index d787d66819..ba0d5615c5 100644 --- a/ges/ges-timeline-element.h +++ b/ges/ges-timeline-element.h @@ -185,11 +185,15 @@ struct _GESTimelineElementClass gboolean (*roll_start) (GESTimelineElement *self, guint64 start); gboolean (*roll_end) (GESTimelineElement *self, guint64 end); gboolean (*trim) (GESTimelineElement *self, guint64 start); - void (*deep_copy) (GESTimelineElement *self, GESTimelineElement *copy); + void (*deep_copy) (GESTimelineElement *self, GESTimelineElement *copy); + + GParamSpec** (*list_children_properties) (GESTimelineElement * self, guint *n_properties); + gboolean (*lookup_child) (GESTimelineElement *self, const gchar *prop_name, + GObject **child, GParamSpec **pspec); /*< private > */ /* Padding for API extension */ - gpointer _ges_reserved[GES_PADDING_LARGE]; + gpointer _ges_reserved[GES_PADDING_LARGE - 2]; }; GType ges_timeline_element_get_type (void) G_GNUC_CONST; @@ -220,6 +224,57 @@ gboolean ges_timeline_element_trim (GESTimelineElement *self, GESTimelineElement * ges_timeline_element_copy (GESTimelineElement *self, gboolean deep); gchar * ges_timeline_element_get_name (GESTimelineElement *self); gboolean ges_timeline_element_set_name (GESTimelineElement *self, const gchar *name); +GParamSpec ** +ges_timeline_element_list_children_properties (GESTimelineElement *self, + guint *n_properties); + +gboolean ges_timeline_element_lookup_child (GESTimelineElement *self, + const gchar *prop_name, + GObject **child, + GParamSpec **pspec); + +void +ges_timeline_element_get_child_property_by_pspec (GESTimelineElement * self, + GParamSpec * pspec, + GValue * value); + +void +ges_timeline_element_get_child_property_valist (GESTimelineElement * self, + const gchar * first_property_name, + va_list var_args); + +void ges_timeline_element_get_child_properties (GESTimelineElement *self, + const gchar * first_property_name, + ...) G_GNUC_NULL_TERMINATED; + +void +ges_timeline_element_set_child_property_valist (GESTimelineElement * self, + const gchar * first_property_name, + va_list var_args); + +void +ges_timeline_element_set_child_property_by_pspec (GESTimelineElement * self, + GParamSpec * pspec, + GValue * value); + +void ges_timeline_element_set_child_properties (GESTimelineElement * self, + const gchar * first_property_name, + ...) G_GNUC_NULL_TERMINATED; + +gboolean ges_timeline_element_set_child_property (GESTimelineElement *self, + const gchar *property_name, + GValue * value); + +gboolean ges_timeline_element_get_child_property (GESTimelineElement *self, + const gchar *property_name, + GValue * value); + +gboolean ges_timeline_element_add_child_property (GESTimelineElement * self, + GParamSpec *pspec, + GObject *child); + +gboolean ges_timeline_element_remove_child_property(GESTimelineElement * self, + GParamSpec *pspec); G_END_DECLS diff --git a/ges/ges-track-element.c b/ges/ges-track-element.c index fdeaa8ac03..dab9a7efc5 100644 --- a/ges/ges-track-element.c +++ b/ges/ges-track-element.c @@ -29,13 +29,11 @@ * its container, like the start position, the inpoint, the duration and the * priority. */ -#include "ges-utils.h" #include "ges-internal.h" #include "ges-extractable.h" #include "ges-track-element.h" #include "ges-clip.h" #include "ges-meta-container.h" -#include G_DEFINE_ABSTRACT_TYPE (GESTrackElement, ges_track_element, GES_TYPE_TIMELINE_ELEMENT); @@ -54,11 +52,6 @@ struct _GESTrackElementPrivate GstElement *nleobject; /* The NleObject */ GstElement *element; /* The element contained in the nleobject (can be NULL) */ - /* We keep a link between properties name and elements internally - * The hashtable should look like - * {GParamaSpec ---> element,}*/ - GHashTable *children_props; - GESTrack *track; gboolean valid; @@ -92,7 +85,6 @@ static GParamSpec *properties[PROP_LAST]; enum { - DEEP_NOTIFY, CONTROL_BINDING_ADDED, LAST_SIGNAL }; @@ -102,11 +94,6 @@ static guint ges_track_element_signals[LAST_SIGNAL] = { 0 }; static GstElement *ges_track_element_create_nle_object_func (GESTrackElement * object); -static void connect_properties_signals (GESTrackElement * object); -static void connect_signal (gpointer key, gpointer value, gpointer user_data); -static void gst_element_prop_changed_cb (GstElement * element, GParamSpec * arg - G_GNUC_UNUSED, GESTrackElement * track_element); - static gboolean _set_start (GESTimelineElement * element, GstClockTime start); static gboolean _set_inpoint (GESTimelineElement * element, GstClockTime inpoint); @@ -125,41 +112,26 @@ static gboolean _lookup_child (GESTrackElement * object, const gchar * prop_name, GstElement ** element, GParamSpec ** pspec) { - GHashTableIter iter; - gpointer key, value; - gchar **names, *name, *classename; - gboolean res; - - classename = NULL; - res = FALSE; - - names = g_strsplit (prop_name, "::", 2); - if (names[1] != NULL) { - classename = names[0]; - name = names[1]; - } else - name = names[0]; - - g_hash_table_iter_init (&iter, object->priv->children_props); - while (g_hash_table_iter_next (&iter, &key, &value)) { - if (g_strcmp0 (G_PARAM_SPEC (key)->name, name) == 0) { - if (classename == NULL || - g_strcmp0 (G_OBJECT_TYPE_NAME (G_OBJECT (value)), classename) == 0) { - GST_DEBUG ("The %s property from %s has been found", name, classename); - if (element) - *element = gst_object_ref (value); - - *pspec = g_param_spec_ref (key); - res = TRUE; - break; - } - } - } - g_strfreev (names); - - return res; + return + GES_TIMELINE_ELEMENT_GET_CLASS (object)->lookup_child + (GES_TIMELINE_ELEMENT (object), prop_name, (GObject **) element, pspec); } +static gboolean +strv_find_str (const gchar ** strv, const char *str) +{ + guint i; + + if (strv == NULL) + return FALSE; + + for (i = 0; strv[i]; i++) { + if (g_strcmp0 (strv[i], str) == 0) + return TRUE; + } + + return FALSE; +} static void ges_track_element_get_property (GObject * object, guint property_id, @@ -206,7 +178,6 @@ ges_track_element_dispose (GObject * object) GESTrackElement *element = GES_TRACK_ELEMENT (object); GESTrackElementPrivate *priv = element->priv; - g_hash_table_destroy (priv->children_props); if (priv->bindings_hashtable) g_hash_table_destroy (priv->bindings_hashtable); @@ -277,21 +248,6 @@ ges_track_element_class_init (GESTrackElementClass * klass) g_object_class_install_property (object_class, PROP_TRACK, properties[PROP_TRACK]); - /** - * GESTrackElement::deep-notify: - * @track_element: a #GESTrackElement - * @prop_object: the object that originated the signal - * @prop: the property that changed - * - * The deep notify signal is used to be notified of property changes of all - * the childs of @track_element - */ - ges_track_element_signals[DEEP_NOTIFY] = - g_signal_new ("deep-notify", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED | - G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_generic, - G_TYPE_NONE, 2, GST_TYPE_ELEMENT, G_TYPE_PARAM); - /** * GESTrackElement::control-binding-added: * @track_element: a #GESTrackElement @@ -330,16 +286,6 @@ ges_track_element_init (GESTrackElement * self) priv->pending_active = TRUE; priv->bindings_hashtable = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - priv->children_props = - g_hash_table_new_full ((GHashFunc) ges_pspec_hash, ges_pspec_equal, - (GDestroyNotify) g_param_spec_unref, gst_object_unref); - -} - -static gint -compare_gparamspec (GParamSpec ** a, GParamSpec ** b, gpointer udata) -{ - return g_strcmp0 ((*a)->name, (*b)->name); } static gfloat @@ -591,33 +537,6 @@ ges_track_element_get_track_type (GESTrackElement * object) return object->priv->track_type; } -static void -gst_element_prop_changed_cb (GstElement * element, GParamSpec * arg - G_GNUC_UNUSED, GESTrackElement * track_element) -{ - g_signal_emit (track_element, ges_track_element_signals[DEEP_NOTIFY], 0, - GST_ELEMENT (element), arg); -} - -static void -connect_signal (gpointer key, gpointer value, gpointer user_data) -{ - gchar *signame = g_strconcat ("notify::", G_PARAM_SPEC (key)->name, NULL); - - g_signal_connect (G_OBJECT (value), - signame, G_CALLBACK (gst_element_prop_changed_cb), - GES_TRACK_ELEMENT (user_data)); - - g_free (signame); -} - -static void -connect_properties_signals (GESTrackElement * object) -{ - g_hash_table_foreach (object->priv->children_props, - (GHFunc) connect_signal, object); -} - /* default 'create_nle_object' virtual method implementation */ static GstElement * ges_track_element_create_nle_object_func (GESTrackElement * self) @@ -768,22 +687,6 @@ done: return res; } -static gboolean -strv_find_str (const gchar ** strv, const char *str) -{ - guint i; - - if (strv == NULL) - return FALSE; - - for (i = 0; strv[i]; i++) { - if (g_strcmp0 (strv[i], str) == 0) - return TRUE; - } - - return FALSE; -} - /** * ges_track_element_add_children_props: * @self: The #GESTrackElement to set chidlren props on @@ -830,8 +733,8 @@ ges_track_element_add_children_props (GESTrackElement * self, } if (pspec->flags & G_PARAM_WRITABLE) { - g_hash_table_insert (self->priv->children_props, - g_param_spec_ref (pspec), gst_object_ref (element)); + ges_timeline_element_add_child_property (GES_TIMELINE_ELEMENT (self), + pspec, G_OBJECT (element)); GST_LOG_OBJECT (self, "added property %s to controllable properties successfully !", whitelist[i]); @@ -841,8 +744,6 @@ ges_track_element_add_children_props (GESTrackElement * self, whitelist[i], gst_element_get_name (element)); } - - connect_properties_signals (self); return; } @@ -881,8 +782,8 @@ ges_track_element_add_children_props (GESTrackElement * self, for (i = 0; i < nb_specs; i++) { if ((parray[i]->flags & G_PARAM_WRITABLE) && (!whitelist || strv_find_str (whitelist, parray[i]->name))) { - g_hash_table_insert (self->priv->children_props, - g_param_spec_ref (parray[i]), gst_object_ref (child)); + ges_timeline_element_add_child_property (GES_TIMELINE_ELEMENT + (self), parray[i], G_OBJECT (child)); } } g_free (parray); @@ -915,8 +816,6 @@ ges_track_element_add_children_props (GESTrackElement * self, g_value_unset (&item); } gst_iterator_free (it); - - connect_properties_signals (self); } /* INTERNAL USAGE */ @@ -1080,18 +979,15 @@ ges_track_element_is_active (GESTrackElement * object) * Returns: TRUE if @element and @pspec could be found. FALSE otherwise. In that * case the values for @pspec and @element are not modified. Unref @element after * usage. + * + * Deprecated: Use #ges_timeline_element_lookup_child */ gboolean ges_track_element_lookup_child (GESTrackElement * object, const gchar * prop_name, GstElement ** element, GParamSpec ** pspec) { - GESTrackElementClass *class; - - g_return_val_if_fail (GES_IS_TRACK_ELEMENT (object), FALSE); - class = GES_TRACK_ELEMENT_GET_CLASS (object); - g_return_val_if_fail (class->lookup_child, FALSE); - - return class->lookup_child (object, prop_name, element, pspec); + return ges_timeline_element_lookup_child (GES_TIMELINE_ELEMENT (object), + prop_name, ((GObject **) element), pspec); } /** @@ -1101,26 +997,19 @@ ges_track_element_lookup_child (GESTrackElement * object, * @value: the value * * Sets a property of a child of @object. + * + * Deprecated: Use #ges_timeline_element_set_child_property_by_spec */ void ges_track_element_set_child_property_by_pspec (GESTrackElement * object, GParamSpec * pspec, GValue * value) { - GstElement *element; g_return_if_fail (GES_IS_TRACK_ELEMENT (object)); - if (!ges_track_element_lookup_child (object, pspec->name, &element, &pspec)) - goto not_found; - - g_object_set_property (G_OBJECT (element), pspec->name, value); + ges_timeline_element_set_child_property_by_pspec (GES_TIMELINE_ELEMENT + (object), pspec, value); return; - -not_found: - { - GST_ERROR ("The %s property doesn't exist", pspec->name); - return; - } } /** @@ -1134,62 +1023,15 @@ not_found: * that have the same property name, you can distinguish them using the following * syntax: 'ClasseName::property_name' as property name. If you don't, the * corresponding property of the first element found will be set. + * + * Deprecated: Use #ges_timeline_element_set_child_property_valist */ void ges_track_element_set_child_property_valist (GESTrackElement * object, const gchar * first_property_name, va_list var_args) { - const gchar *name; - GParamSpec *pspec; - GstElement *element; - - gchar *error = NULL; - GValue value = { 0, }; - - g_return_if_fail (GES_IS_TRACK_ELEMENT (object)); - - name = first_property_name; - - /* Note: This part is in big part copied from the gst_child_object_set_valist - * method. */ - - /* iterate over pairs */ - while (name) { - if (!ges_track_element_lookup_child (object, name, &element, &pspec)) - goto not_found; - -#if GLIB_CHECK_VERSION(2,23,3) - G_VALUE_COLLECT_INIT (&value, pspec->value_type, var_args, - G_VALUE_NOCOPY_CONTENTS, &error); -#else - g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec)); - G_VALUE_COLLECT (&value, var_args, G_VALUE_NOCOPY_CONTENTS, &error); -#endif - - if (error) - goto cant_copy; - - g_object_set_property (G_OBJECT (element), pspec->name, &value); - - gst_object_unref (element); - g_value_unset (&value); - - name = va_arg (var_args, gchar *); - } - return; - -not_found: - { - GST_WARNING ("No property %s in OBJECT\n", name); - return; - } -cant_copy: - { - GST_WARNING ("error copying value %s in object %p: %s", pspec->name, object, - error); - g_value_unset (&value); - return; - } + ges_timeline_element_set_child_property_valist (GES_TIMELINE_ELEMENT (object), + first_property_name, var_args); } /** @@ -1203,6 +1045,8 @@ cant_copy: * that have the same property name, you can distinguish them using the following * syntax: 'ClasseName::property_name' as property name. If you don't, the * corresponding property of the first element found will be set. + * + * Deprecated: Use #ges_timeline_element_set_child_properties */ void ges_track_element_set_child_properties (GESTrackElement * object, @@ -1229,50 +1073,15 @@ ges_track_element_set_child_properties (GESTrackElement * object, * that have the same property name, you can distinguish them using the following * syntax: 'ClasseName::property_name' as property name. If you don't, the * corresponding property of the first element found will be set. + * + * Deprecated: Use #ges_timeline_element_get_child_property_valist */ void ges_track_element_get_child_property_valist (GESTrackElement * object, const gchar * first_property_name, va_list var_args) { - const gchar *name; - gchar *error = NULL; - GValue value = { 0, }; - GParamSpec *pspec; - GstElement *element; - - g_return_if_fail (G_IS_OBJECT (object)); - - name = first_property_name; - - /* This part is in big part copied from the gst_child_object_get_valist method */ - while (name) { - if (!ges_track_element_lookup_child (object, name, &element, &pspec)) - goto not_found; - - g_value_init (&value, pspec->value_type); - g_object_get_property (G_OBJECT (element), pspec->name, &value); - gst_object_unref (element); - - G_VALUE_LCOPY (&value, var_args, 0, &error); - if (error) - goto cant_copy; - g_value_unset (&value); - name = va_arg (var_args, gchar *); - } - return; - -not_found: - { - GST_WARNING ("no property %s in object", name); - return; - } -cant_copy: - { - GST_WARNING ("error copying value %s in object %p: %s", pspec->name, object, - error); - g_value_unset (&value); - return; - } + ges_timeline_element_get_child_property_valist (GES_TIMELINE_ELEMENT (object), + first_property_name, var_args); } /** @@ -1285,23 +1094,16 @@ cant_copy: * * Returns: (transfer full) (array length=n_properties): an array of #GParamSpec* which should be freed after use or * %NULL if something went wrong + * + * Deprecated: Use #ges_timeline_element_list_children_properties */ GParamSpec ** ges_track_element_list_children_properties (GESTrackElement * object, guint * n_properties) { - GParamSpec **ret; - GESTrackElementClass *class; - - g_return_val_if_fail (GES_IS_TRACK_ELEMENT (object), NULL); - - class = GES_TRACK_ELEMENT_GET_CLASS (object); - - ret = class->list_children_properties (object, n_properties); - g_qsort_with_data (ret, *n_properties, sizeof (GParamSpec *), - (GCompareDataFunc) compare_gparamspec, NULL); - - return ret; + return + ges_timeline_element_list_children_properties (GES_TIMELINE_ELEMENT + (object), n_properties); } /** @@ -1312,6 +1114,8 @@ ges_track_element_list_children_properties (GESTrackElement * object, * name/return location pairs, followed by NULL * * Gets properties of a child of @object. + * + * Deprecated: Use #ges_timeline_element_get_child_properties */ void ges_track_element_get_child_properties (GESTrackElement * object, @@ -1334,28 +1138,15 @@ ges_track_element_get_child_properties (GESTrackElement * object, * @value: (out): return location for the value * * Gets a property of a child of @object. + * + * Deprecated: Use #ges_timeline_element_get_child_property_by_pspec */ void ges_track_element_get_child_property_by_pspec (GESTrackElement * object, GParamSpec * pspec, GValue * value) { - GstElement *element; - - g_return_if_fail (GES_IS_TRACK_ELEMENT (object)); - - element = g_hash_table_lookup (object->priv->children_props, pspec); - if (!element) - goto not_found; - - g_object_get_property (G_OBJECT (element), pspec->name, value); - - return; - -not_found: - { - GST_ERROR ("The %s property doesn't exist", pspec->name); - return; - } + ges_timeline_element_get_child_property_by_pspec (GES_TIMELINE_ELEMENT + (object), pspec, value); } /** @@ -1371,104 +1162,53 @@ not_found: * is much more convenient for C programming. * * Returns: %TRUE if the property was set, %FALSE otherwize + * + * Deprecated: use #ges_timeline_element_set_child_property instead */ gboolean ges_track_element_set_child_property (GESTrackElement * object, const gchar * property_name, GValue * value) { - GParamSpec *pspec; - GstElement *element; - - g_return_val_if_fail (GES_IS_TRACK_ELEMENT (object), FALSE); - - if (!ges_track_element_lookup_child (object, property_name, &element, &pspec)) - goto not_found; - - g_object_set_property (G_OBJECT (element), pspec->name, value); - - gst_object_unref (element); - g_param_spec_unref (pspec); - - return TRUE; - -not_found: - { - GST_WARNING_OBJECT (object, "The %s property doesn't exist", property_name); - - return FALSE; - } + return ges_timeline_element_set_child_property (GES_TIMELINE_ELEMENT (object), + property_name, value); } /** -* ges_track_element_get_child_property: -* @object: The origin #GESTrackElement -* @property_name: The name of the property -* @value: (out): return location for the property value, it will -* be initialized if it is initialized with 0 -* -* In general, a copy is made of the property contents and -* the caller is responsible for freeing the memory by calling -* g_value_unset(). -* -* Gets a property of a GstElement contained in @object. -* -* Note that #ges_track_element_get_child_property is really -* intended for language bindings, #ges_track_element_get_child_properties -* is much more convenient for C programming. -* -* Returns: %TRUE if the property was found, %FALSE otherwize -*/ + * ges_track_element_get_child_property: + * @object: The origin #GESTrackElement + * @property_name: The name of the property + * @value: (out): return location for the property value, it will + * be initialized if it is initialized with 0 + * + * In general, a copy is made of the property contents and + * the caller is responsible for freeing the memory by calling + * g_value_unset(). + * + * Gets a property of a GstElement contained in @object. + * + * Note that #ges_track_element_get_child_property is really + * intended for language bindings, #ges_track_element_get_child_properties + * is much more convenient for C programming. + * + * Returns: %TRUE if the property was found, %FALSE otherwize + * + * Deprecated: Use #ges_timeline_element_get_child_property + */ gboolean ges_track_element_get_child_property (GESTrackElement * object, const gchar * property_name, GValue * value) { - GParamSpec *pspec; - GstElement *element; - - g_return_val_if_fail (GES_IS_TRACK_ELEMENT (object), FALSE); - - if (!ges_track_element_lookup_child (object, property_name, &element, &pspec)) - goto not_found; - - if (G_VALUE_TYPE (value) == G_TYPE_INVALID) - g_value_init (value, pspec->value_type); - - g_object_get_property (G_OBJECT (element), pspec->name, value); - - gst_object_unref (element); - g_param_spec_unref (pspec); - - return TRUE; - -not_found: - { - GST_WARNING_OBJECT (object, "The %s property doesn't exist", property_name); - - return FALSE; - } + return ges_timeline_element_get_child_property (GES_TIMELINE_ELEMENT (object), + property_name, value); } static GParamSpec ** default_list_children_properties (GESTrackElement * object, guint * n_properties) { - GParamSpec **pspec, *spec; - GHashTableIter iter; - gpointer key, value; - - guint i = 0; - - *n_properties = g_hash_table_size (object->priv->children_props); - pspec = g_new (GParamSpec *, *n_properties); - - g_hash_table_iter_init (&iter, object->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++; - } - - return pspec; + return + GES_TIMELINE_ELEMENT_GET_CLASS (object)->list_children_properties + (GES_TIMELINE_ELEMENT (object), n_properties); } void diff --git a/ges/ges-track-element.h b/ges/ges-track-element.h index 67249ec313..370a08312d 100644 --- a/ges/ges-track-element.h +++ b/ges/ges-track-element.h @@ -80,6 +80,7 @@ struct _GESTrackElement { * The default implementation will create an object * of type @nleobject_factorytype and call * @create_element. + * DeprecatedUse: GESTimelineElement.list_children_properties instead * @lookup_child: method letting subclasses look for a child, overriding the * simple standard behaviour. This vmethod can be used for example * in the case where you want the name of a child property to be @@ -90,6 +91,7 @@ struct _GESTrackElement { * has been overriden so that we tweak the name passed has parametter * to rename "background" to "foreground-backend" making our API * understandable. + * Deprecated: use GESTimelineElement.lookup_child instead * * Subclasses can override the @create_nle_object method to override what type * of GNonLin object will be created. @@ -114,8 +116,6 @@ struct _GESTrackElementClass { /* virtual methods for subclasses */ GParamSpec** (*list_children_properties) (GESTrackElement * object, guint *n_properties); - - gboolean (*lookup_child) (GESTrackElement *object, const gchar *prop_name, GstElement **element, diff --git a/tests/check/ges/effects.c b/tests/check/ges/effects.c index 00bd4a25e5..3bd7280fc1 100644 --- a/tests/check/ges/effects.c +++ b/tests/check/ges/effects.c @@ -354,7 +354,7 @@ GST_START_TEST (test_effect_set_properties) GESLayer *layer; GESTrack *track_video; GESEffectClip *effect_clip; - GESTrackElement *effect; + GESTimelineElement *effect; guint scratch_line, n_props, i; gboolean color_aging; GParamSpec **pspecs, *spec; @@ -377,21 +377,21 @@ GST_START_TEST (test_effect_set_properties) ges_layer_add_clip (layer, (GESClip *) effect_clip); - effect = GES_TRACK_ELEMENT (ges_effect_new ("agingtv")); + effect = GES_TIMELINE_ELEMENT (ges_effect_new ("agingtv")); fail_unless (ges_container_add (GES_CONTAINER (effect_clip), GES_TIMELINE_ELEMENT (effect))); fail_unless (ges_track_element_get_track (GES_TRACK_ELEMENT (effect)) == track_video); - ges_track_element_set_child_properties (effect, + ges_timeline_element_set_child_properties (effect, "GstAgingTV::scratch-lines", 17, "color-aging", FALSE, NULL); - ges_track_element_get_child_properties (effect, + ges_timeline_element_get_child_properties (effect, "GstAgingTV::scratch-lines", &scratch_line, "color-aging", &color_aging, NULL); fail_unless (scratch_line == 17); fail_unless (color_aging == FALSE); - pspecs = ges_track_element_list_children_properties (effect, &n_props); + pspecs = ges_timeline_element_list_children_properties (effect, &n_props); fail_unless (n_props == 7); spec = pspecs[0]; @@ -404,8 +404,8 @@ GST_START_TEST (test_effect_set_properties) g_value_init (&nval, G_TYPE_UINT); g_value_set_uint (&val, 10); - ges_track_element_set_child_property_by_pspec (effect, spec, &val); - ges_track_element_get_child_property_by_pspec (effect, spec, &nval); + ges_timeline_element_set_child_property_by_pspec (effect, spec, &val); + ges_timeline_element_get_child_property_by_pspec (effect, spec, &nval); fail_unless (g_value_get_uint (&nval) == 10); for (i = 0; i < n_props; i++) { @@ -444,7 +444,7 @@ GST_START_TEST (test_clip_signals) GESLayer *layer; GESTrack *track_video; GESEffectClip *effect_clip; - GESEffect *effect; + GESTimelineElement *effect; GValue val = { 0, }; gboolean effect_added = FALSE; @@ -466,9 +466,8 @@ GST_START_TEST (test_clip_signals) ges_layer_add_clip (layer, (GESClip *) effect_clip); - effect = ges_effect_new ("agingtv"); - fail_unless (ges_container_add (GES_CONTAINER (effect_clip), - GES_TIMELINE_ELEMENT (effect))); + effect = GES_TIMELINE_ELEMENT (ges_effect_new ("agingtv")); + fail_unless (ges_container_add (GES_CONTAINER (effect_clip), effect)); fail_unless (effect_added); g_signal_handlers_disconnect_by_func (effect_clip, effect_added_cb, &effect_added); @@ -477,11 +476,11 @@ GST_START_TEST (test_clip_signals) g_signal_connect (effect, "deep-notify", (GCallback) deep_prop_changed_cb, effect); - ges_track_element_set_child_properties (GES_TRACK_ELEMENT (effect), + ges_timeline_element_set_child_properties (effect, "GstAgingTV::scratch-lines", 17, NULL); g_value_init (&val, G_TYPE_UINT); - ges_track_element_get_child_property (GES_TRACK_ELEMENT (effect), + ges_timeline_element_get_child_property (effect, "GstAgingTV::scratch-lines", &val); fail_unless (G_VALUE_HOLDS_UINT (&val)); g_value_unset (&val); diff --git a/tests/check/ges/project.c b/tests/check/ges/project.c index 7325e5b040..13f8df7a76 100644 --- a/tests/check/ges/project.c +++ b/tests/check/ges/project.c @@ -249,7 +249,7 @@ _test_project (GESProject * project, GESTimeline * timeline) if (GES_IS_BASE_EFFECT (trackelement)) { guint nb_scratch_lines; - ges_track_element_get_child_properties (trackelement, + ges_timeline_element_get_child_properties (tmptrackelement->data, "scratch-lines", &nb_scratch_lines, NULL); assert_equals_int (nb_scratch_lines, 12); @@ -339,10 +339,10 @@ _add_properties (GESTimeline * timeline) /* Adding children properties */ else if (GES_IS_VIDEO_SOURCE (element)) { gint64 posx = 42; - ges_track_element_set_child_properties (element, "posx", posx, - NULL); - ges_track_element_get_child_properties (element, "posx", &posx, - NULL); + ges_timeline_element_set_child_properties (GES_TIMELINE_ELEMENT + (element), "posx", posx, NULL); + ges_timeline_element_get_child_properties (GES_TIMELINE_ELEMENT + (element), "posx", &posx, NULL); fail_unless_equals_int64 (posx, 42); } } @@ -406,8 +406,8 @@ _check_properties (GESTimeline * timeline) else if (GES_IS_VIDEO_SOURCE (element)) { /* Init 'posx' with a wrong value */ gint64 posx = 27; - ges_track_element_get_child_properties (element, "posx", &posx, - NULL); + ges_timeline_element_get_child_properties (GES_TIMELINE_ELEMENT + (element), "posx", &posx, NULL); fail_unless_equals_int64 (posx, 42); } } diff --git a/tests/check/ges/timelineedition.c b/tests/check/ges/timelineedition.c index 714c4fa86a..34e34e2c32 100644 --- a/tests/check/ges/timelineedition.c +++ b/tests/check/ges/timelineedition.c @@ -1265,9 +1265,11 @@ _set_track_element_width_height (GESTrackElement * trksrc, gint wvalue, g_value_set_int (&width, wvalue); g_value_set_int (&height, hvalue); if (wvalue >= 0) - ges_track_element_set_child_property (trksrc, "width", &width); + ges_timeline_element_set_child_property (GES_TIMELINE_ELEMENT (trksrc), + "width", &width); if (hvalue >= 0) - ges_track_element_set_child_property (trksrc, "height", &height); + ges_timeline_element_set_child_property (GES_TIMELINE_ELEMENT (trksrc), + "height", &height); } static gboolean @@ -1285,8 +1287,10 @@ check_frame_positionner_size (GESClip * clip, gint width, gint height) g_value_init (&val_width, G_TYPE_INT); g_value_init (&val_height, G_TYPE_INT); - ges_track_element_get_child_property (trksrc, "width", &val_width); - ges_track_element_get_child_property (trksrc, "height", &val_height); + ges_timeline_element_get_child_property (GES_TIMELINE_ELEMENT (trksrc), + "width", &val_width); + ges_timeline_element_get_child_property (GES_TIMELINE_ELEMENT (trksrc), + "height", &val_height); real_width = g_value_get_int (&val_width); real_height = g_value_get_int (&val_height);