diff options
author | Thibault Saunier <tsaunier@gnome.org> | 2015-03-18 20:23:55 +0100 |
---|---|---|
committer | Thibault Saunier <tsaunier@gnome.org> | 2015-03-18 20:23:55 +0100 |
commit | 9fe15ef4354dc1d878dbdec80908ac8541bc6131 (patch) | |
tree | 52a05875b9ee0914764f139fe6b38028aa9033a3 /ges | |
parent | f21132c3d586669a42bdbaf0a5cd6806d88da92f (diff) |
ges: Move the notion of children properties to GESTimelineElement
Summary:
Deprecate the old GESTrackElement children property handling API.
New APIs:
* 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
Deprecated APIs:
* ges_track_element_list_children_properties
* ges_track_element_lookup_child
* ges_track_element_get_child_property_by_pspec
* ges_track_element_get_child_property_valist
* ges_track_element_get_child_properties
* ges_track_element_set_child_property_valist
* ges_track_element_set_child_property_by_pspec
* ges_track_element_set_child_properties
* ges_track_element_set_child_property
* ges_track_element_get_child_property
* ges_track_element_add_child_property
Reviewers: Mathieu_Du
Reviewed By: Mathieu_Du
Differential Revision: http://phabricator.freedesktop.org/D40
Diffstat (limited to 'ges')
-rw-r--r-- | ges/ges-container.c | 86 | ||||
-rw-r--r-- | ges/ges-timeline-element.c | 539 | ||||
-rw-r--r-- | ges/ges-timeline-element.h | 59 | ||||
-rw-r--r-- | ges/ges-timeline.c | 31 | ||||
-rw-r--r-- | ges/ges-timeline.h | 1 | ||||
-rw-r--r-- | ges/ges-track-element.c | 418 | ||||
-rw-r--r-- | ges/ges-track-element.h | 4 |
7 files changed, 795 insertions, 343 deletions
diff --git a/ges/ges-container.c b/ges/ges-container.c index c4010591..7b26f89e 100644 --- a/ges/ges-container.c +++ b/ges/ges-container.c @@ -185,6 +185,86 @@ _set_duration (GESTimelineElement * element, GstClockTime duration) return TRUE; } +static void +_ges_container_add_child_properties (GESContainer * container, + GESTimelineElement * child) +{ + guint n_props, i; + + GParamSpec **child_props = + ges_timeline_element_list_children_properties (child, + &n_props); + + for (i = 0; i < n_props; i++) { + GObject *prop_child; + + if (ges_timeline_element_lookup_child (child, child_props[i]->name, + &prop_child, NULL)) { + ges_timeline_element_add_child_property (GES_TIMELINE_ELEMENT (container), + child_props[i], prop_child); + + } + + g_param_spec_unref (child_props[i]); + } + + g_free (child_props); +} + +static void +_ges_container_remove_child_properties (GESContainer * container, + GESTimelineElement * child) +{ + guint n_props, i; + + GParamSpec **child_props = + ges_timeline_element_list_children_properties (child, + &n_props); + + for (i = 0; i < n_props; i++) { + GObject *prop_child; + + if (ges_timeline_element_lookup_child (child, child_props[i]->name, + &prop_child, NULL)) { + ges_timeline_element_remove_child_property (GES_TIMELINE_ELEMENT + (container), child_props[i]); + + } + + g_param_spec_unref (child_props[i]); + } + + g_free (child_props); +} + +static GParamSpec ** +_list_children_properties (GESTimelineElement * self, guint * n_properties) +{ + GList *tmp; + + for (tmp = GES_CONTAINER_CHILDREN (self); tmp; tmp = tmp->next) + _ges_container_add_child_properties (GES_CONTAINER (self), tmp->data); + + return + GES_TIMELINE_ELEMENT_CLASS + (ges_container_parent_class)->list_children_properties (self, + n_properties); +} + +static gboolean +_lookup_child (GESTimelineElement * self, const gchar * prop_name, + GObject ** child, GParamSpec ** pspec) +{ + GList *tmp; + + for (tmp = GES_CONTAINER_CHILDREN (self); tmp; tmp = tmp->next) + _ges_container_add_child_properties (GES_CONTAINER (self), tmp->data); + + return + GES_TIMELINE_ELEMENT_CLASS (ges_container_parent_class)->lookup_child + (self, prop_name, child, pspec); +} + /****************************************** * * * GObject virtual methods implementation * @@ -281,6 +361,8 @@ ges_container_class_init (GESContainerClass * klass) element_class->set_start = _set_start; element_class->set_duration = _set_duration; element_class->set_inpoint = _set_inpoint; + element_class->list_children_properties = _list_children_properties; + element_class->lookup_child = _lookup_child; /* No default implementations */ klass->remove_child = NULL; @@ -558,6 +640,8 @@ ges_container_add (GESContainer * container, GESTimelineElement * child) return FALSE; } + _ges_container_add_child_properties (container, child); + g_signal_emit (container, ges_container_signals[CHILD_ADDED_SIGNAL], 0, child); @@ -602,6 +686,8 @@ ges_container_remove (GESContainer * container, GESTimelineElement * child) /* Let it live removing from our mappings */ g_hash_table_remove (priv->mappings, child); + _ges_container_remove_child_properties (container, child); + g_signal_emit (container, ges_container_signals[CHILD_REMOVED_SIGNAL], 0, child); gst_object_unref (child); diff --git a/ges/ges-timeline-element.c b/ges/ges-timeline-element.c index 3ace821a..0ddd28d9 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 <string.h> +#include <gobject/gvaluecollector.h> /* 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 d787d668..ba0d5615 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-timeline.c b/ges/ges-timeline.c index b753f9e2..5b67253a 100644 --- a/ges/ges-timeline.c +++ b/ges/ges-timeline.c @@ -3214,3 +3214,34 @@ ges_timeline_is_empty (GESTimeline * timeline) return TRUE; } + +/** + * ges_timeline_get_layer: + * @timeline: The #GESTimeline to retrive a layer from + * @priority: The priority of the layer to find + * + * Retrieve the layer with @priority as a priority + * + * Returns: A #GESLayer or %NULL if no layer with @priority was found + * + * Since 1.6 + */ +GESLayer * +ges_timeline_get_layer (GESTimeline * timeline, guint priority) +{ + GList *tmp; + GESLayer *layer = NULL; + + for (tmp = timeline->layers; tmp; tmp = tmp->next) { + GESLayer *tmp_layer = GES_LAYER (tmp->data); + guint tmp_priority; + + g_object_get (tmp_layer, "priority", &tmp_priority, NULL); + if (tmp_priority == priority) { + layer = gst_object_ref (tmp_layer); + break; + } + } + + return layer; +} diff --git a/ges/ges-timeline.h b/ges/ges-timeline.h index bbcc83aa..fd5e6ec2 100644 --- a/ges/ges-timeline.h +++ b/ges/ges-timeline.h @@ -109,6 +109,7 @@ gboolean ges_timeline_add_layer (GESTimeline *timeline, GESLayer *layer); GESLayer * ges_timeline_append_layer (GESTimeline * timeline); gboolean ges_timeline_remove_layer (GESTimeline *timeline, GESLayer *layer); GList* ges_timeline_get_layers (GESTimeline *timeline); +GESLayer* ges_timeline_get_layer (GESTimeline *timeline, guint priority); gboolean ges_timeline_add_track (GESTimeline *timeline, GESTrack *track); gboolean ges_timeline_remove_track (GESTimeline *timeline, GESTrack *track); diff --git a/ges/ges-track-element.c b/ges/ges-track-element.c index fdeaa8ac..dab9a7ef 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 <gobject/gvaluecollector.h> 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,42 +112,27 @@ 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; - } - } + 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; } - g_strfreev (names); - return res; + return FALSE; } - static void ges_track_element_get_property (GObject * object, guint property_id, GValue * value, GParamSpec * pspec) @@ -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); @@ -278,21 +249,6 @@ ges_track_element_class_init (GESTrackElementClass * klass) 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 * @control_binding: the #GstControlBinding that has been added @@ -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 67249ec3..370a0831 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, |