1 /* GStreamer Editing Services
2 * Copyright (C) 2009 Edward Hervey <edward.hervey@collabora.co.uk>
3 * 2009 Nokia Corporation
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
22 * SECTION:gestrackelement
23 * @title: GESTrackElement
24 * @short_description: Base Class for objects contained in a GESTrack
26 * #GESTrackElement is the Base Class for any object that can be contained in a
29 * It contains the basic information as to the location of the object within
30 * its container, like the start position, the inpoint, the duration and the
33 #include "ges-internal.h"
34 #include "ges-extractable.h"
35 #include "ges-track-element.h"
37 #include "ges-meta-container.h"
39 G_DEFINE_ABSTRACT_TYPE (GESTrackElement, ges_track_element,
40 GES_TYPE_TIMELINE_ELEMENT);
42 struct _GESTrackElementPrivate
44 GESTrackType track_type;
46 GstElement *nleobject; /* The NleObject */
47 GstElement *element; /* The element contained in the nleobject (can be NULL) */
51 gboolean locked; /* If TRUE, then moves in sync with its controlling
54 GHashTable *bindings_hashtable; /* We need this if we want to be able to serialize
55 and deserialize keyframes */
67 static GParamSpec *properties[PROP_LAST];
71 CONTROL_BINDING_ADDED,
72 CONTROL_BINDING_REMOVED,
76 static guint ges_track_element_signals[LAST_SIGNAL] = { 0 };
78 static GstElement *ges_track_element_create_gnl_object_func (GESTrackElement *
81 static gboolean _set_start (GESTimelineElement * element, GstClockTime start);
82 static gboolean _set_inpoint (GESTimelineElement * element,
83 GstClockTime inpoint);
84 static gboolean _set_duration (GESTimelineElement * element,
85 GstClockTime duration);
86 static gboolean _set_priority (GESTimelineElement * element, guint32 priority);
87 GESTrackType _get_track_types (GESTimelineElement * object);
89 static GParamSpec **default_list_children_properties (GESTrackElement * object,
90 guint * n_properties);
93 _update_control_bindings (GESTimelineElement * element, GstClockTime inpoint,
94 GstClockTime duration);
97 _lookup_child (GESTrackElement * object,
98 const gchar * prop_name, GstElement ** element, GParamSpec ** pspec)
101 GES_TIMELINE_ELEMENT_GET_CLASS (object)->lookup_child
102 (GES_TIMELINE_ELEMENT (object), prop_name, (GObject **) element, pspec);
106 strv_find_str (const gchar ** strv, const char *str)
113 for (i = 0; strv[i]; i++) {
114 if (g_strcmp0 (strv[i], str) == 0)
122 ges_track_element_get_property (GObject * object, guint property_id,
123 GValue * value, GParamSpec * pspec)
125 GESTrackElement *track_element = GES_TRACK_ELEMENT (object);
127 switch (property_id) {
129 g_value_set_boolean (value, ges_track_element_is_active (track_element));
131 case PROP_TRACK_TYPE:
132 g_value_set_flags (value, track_element->priv->track_type);
135 g_value_set_object (value, track_element->priv->track);
138 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
143 ges_track_element_set_property (GObject * object, guint property_id,
144 const GValue * value, GParamSpec * pspec)
146 GESTrackElement *track_element = GES_TRACK_ELEMENT (object);
148 switch (property_id) {
150 ges_track_element_set_active (track_element, g_value_get_boolean (value));
152 case PROP_TRACK_TYPE:
153 track_element->priv->track_type = g_value_get_flags (value);
156 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
161 ges_track_element_dispose (GObject * object)
163 GESTrackElement *element = GES_TRACK_ELEMENT (object);
164 GESTrackElementPrivate *priv = element->priv;
166 if (priv->bindings_hashtable)
167 g_hash_table_destroy (priv->bindings_hashtable);
169 if (priv->nleobject) {
172 if (priv->track != NULL) {
173 g_error ("%p Still in %p, this means that you forgot"
174 " to remove it from the GESTrack it is contained in. You always need"
175 " to remove a GESTrackElement from its track before dropping the last"
177 "This problem may also be caused by a refcounting bug in"
178 " the application or GES itself.", object, priv->track);
179 gst_element_get_state (priv->nleobject, &cstate, NULL, 0);
180 if (cstate != GST_STATE_NULL)
181 gst_element_set_state (priv->nleobject, GST_STATE_NULL);
184 g_object_set_qdata (G_OBJECT (priv->nleobject),
185 NLE_OBJECT_TRACK_ELEMENT_QUARK, NULL);
186 gst_object_unref (priv->nleobject);
187 priv->nleobject = NULL;
190 G_OBJECT_CLASS (ges_track_element_parent_class)->dispose (object);
194 ges_track_element_constructed (GObject * gobject)
196 GESTrackElementClass *class;
197 GstElement *nleobject;
198 gdouble media_duration_factor;
200 GESTrackElement *object = GES_TRACK_ELEMENT (gobject);
202 GST_DEBUG_OBJECT (object, "Creating NleObject");
204 class = GES_TRACK_ELEMENT_GET_CLASS (object);
205 g_assert (class->create_gnl_object);
207 nleobject = class->create_gnl_object (object);
208 if (G_UNLIKELY (nleobject == NULL)) {
209 GST_ERROR_OBJECT (object, "Could not create NleObject");
214 tmp = g_strdup_printf ("%s:%s", G_OBJECT_TYPE_NAME (object),
215 GST_OBJECT_NAME (nleobject));
216 gst_object_set_name (GST_OBJECT (nleobject), tmp);
219 GST_DEBUG_OBJECT (object, "Got a valid NleObject, now filling it in");
221 object->priv->nleobject = gst_object_ref (nleobject);
222 g_object_set_qdata (G_OBJECT (nleobject), NLE_OBJECT_TRACK_ELEMENT_QUARK,
225 /* Set some properties on the NleObject */
226 g_object_set (object->priv->nleobject,
227 "start", GES_TIMELINE_ELEMENT_START (object),
228 "inpoint", GES_TIMELINE_ELEMENT_INPOINT (object),
229 "duration", GES_TIMELINE_ELEMENT_DURATION (object),
230 "priority", GES_TIMELINE_ELEMENT_PRIORITY (object),
231 "active", object->active, NULL);
233 media_duration_factor =
234 ges_timeline_element_get_media_duration_factor (GES_TIMELINE_ELEMENT
236 g_object_set (object->priv->nleobject,
237 "media-duration-factor", media_duration_factor, NULL);
239 G_OBJECT_CLASS (ges_track_element_parent_class)->constructed (gobject);
243 ges_track_element_class_init (GESTrackElementClass * klass)
245 GObjectClass *object_class = G_OBJECT_CLASS (klass);
246 GESTimelineElementClass *element_class = GES_TIMELINE_ELEMENT_CLASS (klass);
248 g_type_class_add_private (klass, sizeof (GESTrackElementPrivate));
250 object_class->get_property = ges_track_element_get_property;
251 object_class->set_property = ges_track_element_set_property;
252 object_class->dispose = ges_track_element_dispose;
253 object_class->constructed = ges_track_element_constructed;
257 * GESTrackElement:active:
259 * Whether the object should be taken into account in the #GESTrack output.
260 * If #FALSE, then its contents will not be used in the resulting track.
262 properties[PROP_ACTIVE] =
263 g_param_spec_boolean ("active", "Active", "Use object in output", TRUE,
265 g_object_class_install_property (object_class, PROP_ACTIVE,
266 properties[PROP_ACTIVE]);
268 properties[PROP_TRACK_TYPE] = g_param_spec_flags ("track-type", "Track Type",
269 "The track type of the object", GES_TYPE_TRACK_TYPE,
270 GES_TRACK_TYPE_UNKNOWN, G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
271 g_object_class_install_property (object_class, PROP_TRACK_TYPE,
272 properties[PROP_TRACK_TYPE]);
274 properties[PROP_TRACK] = g_param_spec_object ("track", "Track",
275 "The track the object is in", GES_TYPE_TRACK, G_PARAM_READABLE);
276 g_object_class_install_property (object_class, PROP_TRACK,
277 properties[PROP_TRACK]);
280 * GESTrackElement::control-binding-added:
281 * @track_element: a #GESTrackElement
282 * @control_binding: the #GstControlBinding that has been added
284 * The control-binding-added signal is emitted each time a control binding
285 * is added for a child property of @track_element
287 ges_track_element_signals[CONTROL_BINDING_ADDED] =
288 g_signal_new ("control-binding-added", G_TYPE_FROM_CLASS (klass),
289 G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_generic,
290 G_TYPE_NONE, 1, GST_TYPE_CONTROL_BINDING);
293 * GESTrackElement::control-binding-removed:
294 * @track_element: a #GESTrackElement
295 * @control_binding: the #GstControlBinding that has been removed
297 * The control-binding-removed signal is emitted each time a control binding
298 * is removed for a child property of @track_element
300 ges_track_element_signals[CONTROL_BINDING_REMOVED] =
301 g_signal_new ("control-binding-removed", G_TYPE_FROM_CLASS (klass),
302 G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_generic,
303 G_TYPE_NONE, 1, GST_TYPE_CONTROL_BINDING);
305 element_class->set_start = _set_start;
306 element_class->set_duration = _set_duration;
307 element_class->set_inpoint = _set_inpoint;
308 element_class->set_priority = _set_priority;
309 element_class->get_track_types = _get_track_types;
310 element_class->deep_copy = ges_track_element_copy_properties;
312 klass->create_gnl_object = ges_track_element_create_gnl_object_func;
313 klass->list_children_properties = default_list_children_properties;
314 klass->lookup_child = _lookup_child;
318 ges_track_element_init (GESTrackElement * self)
320 GESTrackElementPrivate *priv = self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
321 GES_TYPE_TRACK_ELEMENT, GESTrackElementPrivate);
323 /* Sane default values */
324 GES_TIMELINE_ELEMENT_START (self) = 0;
325 GES_TIMELINE_ELEMENT_INPOINT (self) = 0;
326 GES_TIMELINE_ELEMENT_DURATION (self) = GST_SECOND;
327 GES_TIMELINE_ELEMENT_PRIORITY (self) = 0;
330 priv->bindings_hashtable = g_hash_table_new_full (g_str_hash, g_str_equal,
335 interpolate_values_for_position (GstTimedValue * first_value,
336 GstTimedValue * second_value, guint64 position, gboolean absolute)
339 GstClockTime interval;
342 g_assert (second_value || first_value);
344 if (first_value == NULL)
345 return second_value->value;
347 if (second_value == NULL)
348 return first_value->value;
350 diff = second_value->value - first_value->value;
351 interval = second_value->timestamp - first_value->timestamp;
353 if (position > first_value->timestamp)
355 first_value->value + ((float) (position -
356 first_value->timestamp) / (float) interval) * diff;
359 first_value->value - ((float) (first_value->timestamp -
360 position) / (float) interval) * diff;
363 value_at_pos = CLAMP (value_at_pos, 0.0, 1.0);
369 _update_control_bindings (GESTimelineElement * element, GstClockTime inpoint,
370 GstClockTime duration)
374 GstControlBinding *binding;
375 GstTimedValueControlSource *source;
376 GESTrackElement *self = GES_TRACK_ELEMENT (element);
378 specs = ges_track_element_list_children_properties (self, &n_specs);
380 for (n = 0; n < n_specs; ++n) {
383 GstTimedValue *last, *first, *prev = NULL, *next = NULL;
386 binding = ges_track_element_get_control_binding (self, specs[n]->name);
391 g_object_get (binding, "control_source", &source, NULL);
393 g_object_get (binding, "absolute", &absolute, NULL);
395 gst_timed_value_control_source_unset_all (GST_TIMED_VALUE_CONTROL_SOURCE
401 gst_timed_value_control_source_get_all (GST_TIMED_VALUE_CONTROL_SOURCE
404 if (g_list_length (values) == 0)
407 first = values->data;
409 for (tmp = values->next; tmp; tmp = tmp->next) {
412 if (next->timestamp > inpoint)
417 interpolate_values_for_position (first, next, inpoint, absolute);
418 gst_timed_value_control_source_unset (source, first->timestamp);
419 gst_timed_value_control_source_set (source, inpoint, value_at_pos);
422 gst_timed_value_control_source_get_all (GST_TIMED_VALUE_CONTROL_SOURCE
425 if (duration != GST_CLOCK_TIME_NONE) {
426 last = g_list_last (values)->data;
428 for (tmp = g_list_last (values)->prev; tmp; tmp = tmp->prev) {
431 if (prev->timestamp < duration + inpoint)
436 interpolate_values_for_position (prev, last, duration + inpoint,
439 gst_timed_value_control_source_unset (source, last->timestamp);
440 gst_timed_value_control_source_set (source, duration + inpoint,
443 gst_timed_value_control_source_get_all (GST_TIMED_VALUE_CONTROL_SOURCE
447 for (tmp = values; tmp; tmp = tmp->next) {
448 GstTimedValue *value = tmp->data;
449 if (value->timestamp < inpoint)
450 gst_timed_value_control_source_unset (source, value->timestamp);
451 else if (duration != GST_CLOCK_TIME_NONE
452 && value->timestamp > duration + inpoint)
453 gst_timed_value_control_source_unset (source, value->timestamp);
461 _set_start (GESTimelineElement * element, GstClockTime start)
463 GESTrackElement *object = GES_TRACK_ELEMENT (element);
465 g_return_val_if_fail (object->priv->nleobject, FALSE);
467 if (G_UNLIKELY (start == _START (object)))
470 g_object_set (object->priv->nleobject, "start", start, NULL);
476 _set_inpoint (GESTimelineElement * element, GstClockTime inpoint)
478 GESTrackElement *object = GES_TRACK_ELEMENT (element);
480 g_return_val_if_fail (object->priv->nleobject, FALSE);
482 if (G_UNLIKELY (inpoint == _INPOINT (object)))
486 g_object_set (object->priv->nleobject, "inpoint", inpoint, NULL);
487 _update_control_bindings (element, inpoint, GST_CLOCK_TIME_NONE);
493 _set_duration (GESTimelineElement * element, GstClockTime duration)
495 GESTrackElement *object = GES_TRACK_ELEMENT (element);
496 GESTrackElementPrivate *priv = object->priv;
498 g_return_val_if_fail (object->priv->nleobject, FALSE);
500 if (GST_CLOCK_TIME_IS_VALID (_MAXDURATION (element)) &&
501 duration > _INPOINT (object) + _MAXDURATION (element))
502 duration = _MAXDURATION (element) - _INPOINT (object);
504 if (G_UNLIKELY (duration == _DURATION (object)))
507 g_object_set (priv->nleobject, "duration", duration, NULL);
509 _update_control_bindings (element, ges_timeline_element_get_inpoint (element),
516 _set_priority (GESTimelineElement * element, guint32 priority)
518 GESTrackElement *object = GES_TRACK_ELEMENT (element);
520 g_return_val_if_fail (object->priv->nleobject, FALSE);
522 if (priority < MIN_NLE_PRIO) {
523 GST_INFO_OBJECT (element, "Priority (%d) < MIN_NLE_PRIO, setting it to %d",
524 priority, MIN_NLE_PRIO);
525 priority = MIN_NLE_PRIO;
528 GST_DEBUG_OBJECT (object, "priority:%" G_GUINT32_FORMAT, priority);
530 if (G_UNLIKELY (priority == _PRIORITY (object)))
533 g_object_set (object->priv->nleobject, "priority", priority, NULL);
539 _get_track_types (GESTimelineElement * object)
541 return ges_track_element_get_track_type (GES_TRACK_ELEMENT (object));
545 * ges_track_element_set_active:
546 * @object: a #GESTrackElement
547 * @active: visibility
549 * Sets the usage of the @object. If @active is %TRUE, the object will be used for
550 * playback and rendering, else it will be ignored.
552 * Returns: %TRUE if the property was toggled, else %FALSE
555 ges_track_element_set_active (GESTrackElement * object, gboolean active)
557 g_return_val_if_fail (GES_IS_TRACK_ELEMENT (object), FALSE);
558 g_return_val_if_fail (object->priv->nleobject, FALSE);
560 GST_DEBUG_OBJECT (object, "object:%p, active:%d", object, active);
562 if (G_UNLIKELY (active == object->active))
565 g_object_set (object->priv->nleobject, "active", active, NULL);
567 if (active != object->active) {
568 object->active = active;
569 if (GES_TRACK_ELEMENT_GET_CLASS (object)->active_changed)
570 GES_TRACK_ELEMENT_GET_CLASS (object)->active_changed (object, active);
577 ges_track_element_set_track_type (GESTrackElement * object, GESTrackType type)
579 g_return_if_fail (GES_IS_TRACK_ELEMENT (object));
581 if (object->priv->track_type != type) {
582 object->priv->track_type = type;
583 g_object_notify_by_pspec (G_OBJECT (object), properties[PROP_TRACK_TYPE]);
588 ges_track_element_get_track_type (GESTrackElement * object)
590 g_return_val_if_fail (GES_IS_TRACK_ELEMENT (object), GES_TRACK_TYPE_UNKNOWN);
592 return object->priv->track_type;
595 /* default 'create_gnl_object' virtual method implementation */
597 ges_track_element_create_gnl_object_func (GESTrackElement * self)
599 GESTrackElementClass *klass = NULL;
600 GstElement *child = NULL;
601 GstElement *nleobject;
603 klass = GES_TRACK_ELEMENT_GET_CLASS (self);
605 if (G_UNLIKELY (self->priv->nleobject != NULL))
606 goto already_have_nleobject;
608 if (G_UNLIKELY (klass->nleobject_factorytype == NULL))
611 GST_DEBUG ("Creating a supporting nleobject of type '%s'",
612 klass->nleobject_factorytype);
614 nleobject = gst_element_factory_make (klass->nleobject_factorytype, NULL);
616 if (G_UNLIKELY (nleobject == NULL))
619 if (klass->create_element) {
620 GST_DEBUG ("Calling subclass 'create_element' vmethod");
621 child = klass->create_element (self);
623 if (G_UNLIKELY (!child))
626 if (!gst_bin_add (GST_BIN (nleobject), child))
629 GST_DEBUG ("Succesfully got the element to put in the nleobject");
630 self->priv->element = child;
639 already_have_nleobject:
641 GST_ERROR ("Already controlling a NleObject %s",
642 GST_ELEMENT_NAME (self->priv->nleobject));
648 GST_ERROR ("No GESTrackElement::nleobject_factorytype implementation!");
654 GST_ERROR ("Error creating a nleobject of type '%s'",
655 klass->nleobject_factorytype);
661 GST_ERROR ("create_element returned NULL");
662 gst_object_unref (nleobject);
668 GST_ERROR ("Error adding the contents to the nleobject");
669 gst_object_unref (child);
670 gst_object_unref (nleobject);
676 * ges_track_element_add_children_props:
677 * @self: The #GESTrackElement to set chidlren props on
678 * @element: The GstElement to retrieve properties from
679 * @wanted_categories: (array zero-terminated=1) (transfer none) (allow-none):
680 * An array of categories of GstElement to
681 * take into account (as defined in the factory meta "klass" field)
682 * @blacklist: (array zero-terminated=1) (transfer none) (allow-none): A
683 * blacklist of elements factory names to not take into account
684 * @whitelist: (array zero-terminated=1) (transfer none) (allow-none): A list
685 * of propery names to add as children properties
687 * Looks for the properties defines with the various parametters and add
688 * them to the hashtable of children properties.
690 * To be used by subclasses only
693 ges_track_element_add_children_props (GESTrackElement * self,
694 GstElement * element, const gchar ** wanted_categories,
695 const gchar ** blacklist, const gchar ** whitelist)
697 GValue item = { 0, };
702 GstElementFactory *factory;
703 gboolean done = FALSE;
705 if (!GST_IS_BIN (element)) {
709 GObjectClass *class = G_OBJECT_GET_CLASS (element);
711 for (i = 0; whitelist[i]; i++) {
713 pspec = g_object_class_find_property (class, whitelist[i]);
715 GST_WARNING ("no such property : %s in element : %s", whitelist[i],
716 gst_element_get_name (element));
721 ges_timeline_element_add_child_property (GES_TIMELINE_ELEMENT (self),
722 pspec, G_OBJECT (element));
723 GST_LOG_OBJECT (self,
724 "added property %s to controllable properties successfully !",
728 ("the property %s for element %s exists but is not writable",
729 whitelist[i], gst_element_get_name (element));
735 /* We go over child elements recursivly, and add writable properties to the
737 it = gst_bin_iterate_recurse (GST_BIN (element));
739 switch (gst_iterator_next (it, &item)) {
740 case GST_ITERATOR_OK:
744 GstElement *child = g_value_get_object (&item);
746 factory = gst_element_get_factory (child);
747 klass = gst_element_factory_get_metadata (factory,
748 GST_ELEMENT_METADATA_KLASS);
750 if (strv_find_str (blacklist, GST_OBJECT_NAME (factory))) {
751 GST_DEBUG_OBJECT (self, "%s blacklisted", GST_OBJECT_NAME (factory));
755 GST_DEBUG ("Looking at element '%s' of klass '%s'",
756 GST_ELEMENT_NAME (child), klass);
758 categories = g_strsplit (klass, "/", 0);
760 for (i = 0; categories[i]; i++) {
761 if ((!wanted_categories ||
762 strv_find_str (wanted_categories, categories[i]))) {
765 class = G_OBJECT_GET_CLASS (child);
766 parray = g_object_class_list_properties (class, &nb_specs);
767 for (i = 0; i < nb_specs; i++) {
768 if ((parray[i]->flags & G_PARAM_WRITABLE) &&
769 (!whitelist || strv_find_str (whitelist, parray[i]->name))) {
770 ges_timeline_element_add_child_property (GES_TIMELINE_ELEMENT
771 (self), parray[i], G_OBJECT (child));
777 ("%d configurable properties of '%s' added to property hashtable",
778 nb_specs, GST_ELEMENT_NAME (child));
783 g_strfreev (categories);
784 g_value_reset (&item);
787 case GST_ITERATOR_RESYNC:
788 /* FIXME, properly restart the process */
789 GST_DEBUG ("iterator resync");
790 gst_iterator_resync (it);
793 case GST_ITERATOR_DONE:
794 GST_DEBUG ("iterator done");
801 g_value_unset (&item);
803 gst_iterator_free (it);
808 ges_track_element_set_track (GESTrackElement * object, GESTrack * track)
812 g_return_val_if_fail (object->priv->nleobject, FALSE);
814 GST_DEBUG_OBJECT (object, "new track: %" GST_PTR_FORMAT, track);
816 object->priv->track = track;
818 if (object->priv->track) {
819 ges_track_element_set_track_type (object, track->type);
821 g_object_set (object->priv->nleobject,
822 "caps", ges_track_get_caps (object->priv->track), NULL);
825 g_object_notify_by_pspec (G_OBJECT (object), properties[PROP_TRACK]);
830 * ges_track_element_get_all_control_bindings
831 * @trackelement: The #TrackElement from which to get all set bindings
833 * Returns: (element-type gchar* GstControlBinding)(transfer none): A
834 * #GHashTable containing all property_name: GstControlBinding
837 ges_track_element_get_all_control_bindings (GESTrackElement * trackelement)
839 GESTrackElementPrivate *priv = GES_TRACK_ELEMENT (trackelement)->priv;
841 return priv->bindings_hashtable;
845 _ges_track_element_get_layer_priority (GESTrackElement * element)
847 if (_PRIORITY (element) < LAYER_HEIGHT + MIN_NLE_PRIO)
850 return (_PRIORITY (element) - MIN_NLE_PRIO) / LAYER_HEIGHT;
854 * ges_track_element_get_track:
855 * @object: a #GESTrackElement
857 * Get the #GESTrack to which this object belongs.
859 * Returns: (transfer none) (nullable): The #GESTrack to which this object
860 * belongs. Can be %NULL if it is not in any track
863 ges_track_element_get_track (GESTrackElement * object)
865 g_return_val_if_fail (GES_IS_TRACK_ELEMENT (object), NULL);
867 return object->priv->track;
871 * ges_track_element_get_gnlobject:
872 * @object: a #GESTrackElement
874 * Get the NleObject object this object is controlling.
876 * Returns: (transfer none): the NleObject object this object is controlling.
878 * Deprecated: use #ges_track_element_get_nleobject instead.
881 ges_track_element_get_gnlobject (GESTrackElement * object)
883 g_return_val_if_fail (GES_IS_TRACK_ELEMENT (object), NULL);
885 return object->priv->nleobject;
889 * ges_track_element_get_nleobject:
890 * @object: a #GESTrackElement
892 * Get the GNonLin object this object is controlling.
894 * Returns: (transfer none): the GNonLin object this object is controlling.
899 ges_track_element_get_nleobject (GESTrackElement * object)
901 g_return_val_if_fail (GES_IS_TRACK_ELEMENT (object), NULL);
903 return object->priv->nleobject;
907 * ges_track_element_get_element:
908 * @object: a #GESTrackElement
910 * Get the #GstElement this track element is controlling within GNonLin.
912 * Returns: (transfer none): the #GstElement this track element is controlling
916 ges_track_element_get_element (GESTrackElement * object)
918 g_return_val_if_fail (GES_IS_TRACK_ELEMENT (object), NULL);
920 return object->priv->element;
924 * ges_track_element_is_active:
925 * @object: a #GESTrackElement
927 * Lets you know if @object will be used for playback and rendering,
930 * Returns: %TRUE if @object is active, %FALSE otherwize
933 ges_track_element_is_active (GESTrackElement * object)
935 g_return_val_if_fail (GES_IS_TRACK_ELEMENT (object), FALSE);
936 g_return_val_if_fail (object->priv->nleobject, FALSE);
938 return object->active;
942 * ges_track_element_lookup_child:
943 * @object: object to lookup the property in
944 * @prop_name: name of the property to look up. You can specify the name of the
945 * class as such: "ClassName::property-name", to guarantee that you get the
946 * proper GParamSpec in case various GstElement-s contain the same property
947 * name. If you don't do so, you will get the first element found, having
948 * this property and the and the corresponding GParamSpec.
949 * @element: (out) (allow-none) (transfer full): pointer to a #GstElement that
950 * takes the real object to set property on
951 * @pspec: (out) (allow-none) (transfer full): pointer to take the #GParamSpec
952 * describing the property
954 * Looks up which @element and @pspec would be effected by the given @name. If various
955 * contained elements have this property name you will get the first one, unless you
956 * specify the class name in @name.
958 * Returns: TRUE if @element and @pspec could be found. FALSE otherwise. In that
959 * case the values for @pspec and @element are not modified. Unref @element after
962 * Deprecated: Use #ges_timeline_element_lookup_child
965 ges_track_element_lookup_child (GESTrackElement * object,
966 const gchar * prop_name, GstElement ** element, GParamSpec ** pspec)
968 return ges_timeline_element_lookup_child (GES_TIMELINE_ELEMENT (object),
969 prop_name, ((GObject **) element), pspec);
973 * ges_track_element_set_child_property_by_pspec: (skip):
974 * @object: a #GESTrackElement
975 * @pspec: The #GParamSpec that specifies the property you want to set
978 * Sets a property of a child of @object.
980 * Deprecated: Use #ges_timeline_element_set_child_property_by_spec
983 ges_track_element_set_child_property_by_pspec (GESTrackElement * object,
984 GParamSpec * pspec, GValue * value)
986 g_return_if_fail (GES_IS_TRACK_ELEMENT (object));
988 ges_timeline_element_set_child_property_by_pspec (GES_TIMELINE_ELEMENT
989 (object), pspec, value);
995 * ges_track_element_set_child_property_valist: (skip):
996 * @object: The #GESTrackElement parent object
997 * @first_property_name: The name of the first property to set
998 * @var_args: value for the first property, followed optionally by more
999 * name/return location pairs, followed by NULL
1001 * Sets a property of a child of @object. If there are various child elements
1002 * that have the same property name, you can distinguish them using the following
1003 * syntax: 'ClasseName::property_name' as property name. If you don't, the
1004 * corresponding property of the first element found will be set.
1006 * Deprecated: Use #ges_timeline_element_set_child_property_valist
1009 ges_track_element_set_child_property_valist (GESTrackElement * object,
1010 const gchar * first_property_name, va_list var_args)
1012 ges_timeline_element_set_child_property_valist (GES_TIMELINE_ELEMENT (object),
1013 first_property_name, var_args);
1017 * ges_track_element_set_child_properties: (skip):
1018 * @object: The #GESTrackElement parent object
1019 * @first_property_name: The name of the first property to set
1020 * @...: value for the first property, followed optionally by more
1021 * name/return location pairs, followed by NULL
1023 * Sets a property of a child of @object. If there are various child elements
1024 * that have the same property name, you can distinguish them using the following
1025 * syntax: 'ClasseName::property_name' as property name. If you don't, the
1026 * corresponding property of the first element found will be set.
1028 * Deprecated: Use #ges_timeline_element_set_child_properties
1031 ges_track_element_set_child_properties (GESTrackElement * object,
1032 const gchar * first_property_name, ...)
1036 g_return_if_fail (GES_IS_TRACK_ELEMENT (object));
1038 va_start (var_args, first_property_name);
1039 ges_track_element_set_child_property_valist (object, first_property_name,
1045 * ges_track_element_get_child_property_valist: (skip):
1046 * @object: The #GESTrackElement parent object
1047 * @first_property_name: The name of the first property to get
1048 * @var_args: value for the first property, followed optionally by more
1049 * name/return location pairs, followed by NULL
1051 * Gets a property of a child of @object. If there are various child elements
1052 * that have the same property name, you can distinguish them using the following
1053 * syntax: 'ClasseName::property_name' as property name. If you don't, the
1054 * corresponding property of the first element found will be set.
1056 * Deprecated: Use #ges_timeline_element_get_child_property_valist
1059 ges_track_element_get_child_property_valist (GESTrackElement * object,
1060 const gchar * first_property_name, va_list var_args)
1062 ges_timeline_element_get_child_property_valist (GES_TIMELINE_ELEMENT (object),
1063 first_property_name, var_args);
1067 * ges_track_element_list_children_properties:
1068 * @object: The #GESTrackElement to get the list of children properties from
1069 * @n_properties: (out): return location for the length of the returned array
1071 * Gets an array of #GParamSpec* for all configurable properties of the
1072 * children of @object.
1074 * Returns: (transfer full) (array length=n_properties): an array of #GParamSpec* which should be freed after use or
1075 * %NULL if something went wrong
1077 * Deprecated: Use #ges_timeline_element_list_children_properties
1080 ges_track_element_list_children_properties (GESTrackElement * object,
1081 guint * n_properties)
1084 ges_timeline_element_list_children_properties (GES_TIMELINE_ELEMENT
1085 (object), n_properties);
1089 * ges_track_element_get_child_properties: (skip):
1090 * @object: The origin #GESTrackElement
1091 * @first_property_name: The name of the first property to get
1092 * @...: return location for the first property, followed optionally by more
1093 * name/return location pairs, followed by NULL
1095 * Gets properties of a child of @object.
1097 * Deprecated: Use #ges_timeline_element_get_child_properties
1100 ges_track_element_get_child_properties (GESTrackElement * object,
1101 const gchar * first_property_name, ...)
1105 g_return_if_fail (GES_IS_TRACK_ELEMENT (object));
1107 va_start (var_args, first_property_name);
1108 ges_track_element_get_child_property_valist (object, first_property_name,
1114 * ges_track_element_get_child_property_by_pspec: (skip):
1115 * @object: a #GESTrackElement
1116 * @pspec: The #GParamSpec that specifies the property you want to get
1117 * @value: (out): return location for the value
1119 * Gets a property of a child of @object.
1121 * Deprecated: Use #ges_timeline_element_get_child_property_by_pspec
1124 ges_track_element_get_child_property_by_pspec (GESTrackElement * object,
1125 GParamSpec * pspec, GValue * value)
1127 ges_timeline_element_get_child_property_by_pspec (GES_TIMELINE_ELEMENT
1128 (object), pspec, value);
1132 * ges_track_element_set_child_property: (skip):
1133 * @object: The origin #GESTrackElement
1134 * @property_name: The name of the property
1137 * Sets a property of a GstElement contained in @object.
1139 * Note that #ges_track_element_set_child_property is really
1140 * intended for language bindings, #ges_track_element_set_child_properties
1141 * is much more convenient for C programming.
1143 * Returns: %TRUE if the property was set, %FALSE otherwize
1145 * Deprecated: use #ges_timeline_element_set_child_property instead
1148 ges_track_element_set_child_property (GESTrackElement * object,
1149 const gchar * property_name, GValue * value)
1151 return ges_timeline_element_set_child_property (GES_TIMELINE_ELEMENT (object),
1152 property_name, value);
1156 * ges_track_element_get_child_property: (skip):
1157 * @object: The origin #GESTrackElement
1158 * @property_name: The name of the property
1159 * @value: (out): return location for the property value, it will
1160 * be initialized if it is initialized with 0
1162 * In general, a copy is made of the property contents and
1163 * the caller is responsible for freeing the memory by calling
1166 * Gets a property of a GstElement contained in @object.
1168 * Note that #ges_track_element_get_child_property is really
1169 * intended for language bindings, #ges_track_element_get_child_properties
1170 * is much more convenient for C programming.
1172 * Returns: %TRUE if the property was found, %FALSE otherwize
1174 * Deprecated: Use #ges_timeline_element_get_child_property
1177 ges_track_element_get_child_property (GESTrackElement * object,
1178 const gchar * property_name, GValue * value)
1180 return ges_timeline_element_get_child_property (GES_TIMELINE_ELEMENT (object),
1181 property_name, value);
1184 static GParamSpec **
1185 default_list_children_properties (GESTrackElement * object,
1186 guint * n_properties)
1189 GES_TIMELINE_ELEMENT_GET_CLASS (object)->list_children_properties
1190 (GES_TIMELINE_ELEMENT (object), n_properties);
1194 ges_track_element_copy_properties (GESTimelineElement * element,
1195 GESTimelineElement * elementcopy)
1200 GESTrackElement *copy = GES_TRACK_ELEMENT (elementcopy);
1203 ges_track_element_list_children_properties (GES_TRACK_ELEMENT (element),
1205 for (n = 0; n < n_specs; ++n) {
1206 if (!(specs[n]->flags & G_PARAM_WRITABLE))
1208 g_value_init (&val, specs[n]->value_type);
1209 ges_track_element_get_child_property_by_pspec (GES_TRACK_ELEMENT (element),
1211 ges_track_element_set_child_property_by_pspec (copy, specs[n], &val);
1212 g_value_unset (&val);
1219 _split_binding (GESTrackElement * element, GESTrackElement * new_element,
1220 guint64 position, GstTimedValueControlSource * source,
1221 GstTimedValueControlSource * new_source, gboolean absolute)
1223 GstTimedValue *last_value = NULL;
1224 gboolean past_position = FALSE;
1225 GList *values, *tmp;
1228 gst_timed_value_control_source_get_all (GST_TIMED_VALUE_CONTROL_SOURCE
1231 for (tmp = values; tmp; tmp = tmp->next) {
1232 GstTimedValue *value = tmp->data;
1234 if (value->timestamp > position && !past_position) {
1235 gfloat value_at_pos;
1237 /* FIXME We should be able to use gst_control_source_get_value so
1238 * all modes are handled. Right now that method only works if the value
1239 * we are looking for is between two actual keyframes which is not enough
1240 * in our case. bug #706621 */
1242 interpolate_values_for_position (last_value, value, position,
1245 past_position = TRUE;
1247 gst_timed_value_control_source_set (new_source, position, value_at_pos);
1248 gst_timed_value_control_source_set (new_source, value->timestamp,
1251 gst_timed_value_control_source_unset (source, value->timestamp);
1252 gst_timed_value_control_source_set (source, position, value_at_pos);
1253 } else if (past_position) {
1254 gst_timed_value_control_source_set (new_source, value->timestamp,
1256 gst_timed_value_control_source_unset (source, value->timestamp);
1264 _copy_binding (GESTrackElement * element, GESTrackElement * new_element,
1265 guint64 position, GstTimedValueControlSource * source,
1266 GstTimedValueControlSource * new_source, gboolean absolute)
1268 GList *values, *tmp;
1271 gst_timed_value_control_source_get_all (GST_TIMED_VALUE_CONTROL_SOURCE
1273 for (tmp = values; tmp; tmp = tmp->next) {
1274 GstTimedValue *value = tmp->data;
1276 gst_timed_value_control_source_set (new_source, value->timestamp,
1281 /* position == GST_CLOCK_TIME_NONE means that we do a simple copy
1282 * other position means that the function will do a splitting
1283 * and thus interpollate the values in the element and new_element
1286 ges_track_element_copy_bindings (GESTrackElement * element,
1287 GESTrackElement * new_element, guint64 position)
1292 GstControlBinding *binding;
1293 GstTimedValueControlSource *source, *new_source;
1296 ges_track_element_list_children_properties (GES_TRACK_ELEMENT (element),
1298 for (n = 0; n < n_specs; ++n) {
1299 GstInterpolationMode mode;
1301 binding = ges_track_element_get_control_binding (element, specs[n]->name);
1305 /* FIXME : this should work as well with other types of control sources */
1306 g_object_get (binding, "control_source", &source, NULL);
1307 if (!GST_IS_TIMED_VALUE_CONTROL_SOURCE (source))
1310 g_object_get (binding, "absolute", &absolute, NULL);
1311 g_object_get (source, "mode", &mode, NULL);
1314 GST_TIMED_VALUE_CONTROL_SOURCE (gst_interpolation_control_source_new
1316 g_object_set (new_source, "mode", mode, NULL);
1318 if (GST_CLOCK_TIME_IS_VALID (position))
1319 _split_binding (element, new_element, position, source, new_source,
1322 _copy_binding (element, new_element, position, source, new_source,
1325 /* We only manage direct (absolute) bindings, see TODO in set_control_source */
1327 ges_track_element_set_control_source (new_element,
1328 GST_CONTROL_SOURCE (new_source), specs[n]->name, "direct-absolute");
1330 ges_track_element_set_control_source (new_element,
1331 GST_CONTROL_SOURCE (new_source), specs[n]->name, "direct");
1338 * ges_track_element_edit:
1339 * @object: the #GESTrackElement to edit
1340 * @layers: (element-type GESLayer): The layers you want the edit to
1341 * happen in, %NULL means that the edition is done in all the
1342 * #GESLayers contained in the current timeline.
1343 * FIXME: This is not implemented yet.
1344 * @mode: The #GESEditMode in which the edition will happen.
1345 * @edge: The #GESEdge the edit should happen on.
1346 * @position: The position at which to edit @object (in nanosecond)
1348 * Edit @object in the different exisiting #GESEditMode modes. In the case of
1349 * slide, and roll, you need to specify a #GESEdge
1351 * Returns: %TRUE if the object as been edited properly, %FALSE if an error
1355 ges_track_element_edit (GESTrackElement * object,
1356 GList * layers, GESEditMode mode, GESEdge edge, guint64 position)
1358 GESTrack *track = ges_track_element_get_track (object);
1359 GESTimeline *timeline;
1361 g_return_val_if_fail (GES_IS_TRACK_ELEMENT (object), FALSE);
1363 if (G_UNLIKELY (!track)) {
1364 GST_WARNING_OBJECT (object, "Trying to edit in %d mode but not in "
1365 "any Track yet.", mode);
1369 timeline = GES_TIMELINE (ges_track_get_timeline (track));
1371 if (G_UNLIKELY (!timeline)) {
1372 GST_WARNING_OBJECT (object, "Trying to edit in %d mode but "
1373 "track %p is not in any timeline yet.", mode, track);
1378 case GES_EDIT_MODE_NORMAL:
1379 return timeline_move_object (timeline, object, layers, edge, position);
1381 case GES_EDIT_MODE_TRIM:
1382 return timeline_trim_object (timeline, object, layers, edge, position);
1384 case GES_EDIT_MODE_RIPPLE:
1385 return timeline_ripple_object (timeline, object, layers, edge, position);
1387 case GES_EDIT_MODE_ROLL:
1388 return timeline_roll_object (timeline, object, layers, edge, position);
1390 case GES_EDIT_MODE_SLIDE:
1391 return timeline_slide_object (timeline, object, layers, edge, position);
1394 GST_ERROR ("Unkown edit mode: %d", mode);
1402 * ges_track_element_remove_control_binding:
1403 * @object: the #GESTrackElement on which to set a control binding
1404 * @property_name: The name of the property to control.
1406 * Removes a #GstControlBinding from @object.
1408 * Returns: %TRUE if the binding could be removed, %FALSE if an error
1412 ges_track_element_remove_control_binding (GESTrackElement * object,
1413 const gchar * property_name)
1415 GESTrackElementPrivate *priv;
1416 GstControlBinding *binding;
1419 g_return_val_if_fail (GES_IS_TRACK_ELEMENT (object), FALSE);
1421 priv = GES_TRACK_ELEMENT (object)->priv;
1423 (GstControlBinding *) g_hash_table_lookup (priv->bindings_hashtable,
1427 g_object_get (binding, "object", &target, NULL);
1428 GST_DEBUG_OBJECT (object, "Removing binding %p for property %s", binding,
1431 gst_object_ref (binding);
1432 gst_object_remove_control_binding (target, binding);
1434 g_signal_emit (object, ges_track_element_signals[CONTROL_BINDING_REMOVED],
1437 gst_object_unref (target);
1438 gst_object_unref (binding);
1439 g_hash_table_remove (priv->bindings_hashtable, property_name);
1448 * ges_track_element_set_control_source:
1449 * @object: the #GESTrackElement on which to set a control binding
1450 * @source: the #GstControlSource to set on the binding.
1451 * @property_name: The name of the property to control.
1452 * @binding_type: The type of binding to create. Only "direct" is available for now.
1454 * Creates a #GstControlBinding and adds it to the #GstElement concerned by the
1455 * property. Use the same syntax as #ges_track_element_lookup_child for
1456 * the property name.
1458 * Returns: %TRUE if the binding could be created and added, %FALSE if an error
1462 ges_track_element_set_control_source (GESTrackElement * object,
1463 GstControlSource * source,
1464 const gchar * property_name, const gchar * binding_type)
1466 GESTrackElementPrivate *priv;
1467 GstElement *element;
1469 GstControlBinding *binding;
1470 gboolean direct, direct_absolute;
1472 g_return_val_if_fail (GES_IS_TRACK_ELEMENT (object), FALSE);
1473 priv = GES_TRACK_ELEMENT (object)->priv;
1475 if (G_UNLIKELY (!(GST_IS_CONTROL_SOURCE (source)))) {
1477 ("You need to provide a non-null control source to build a new control binding");
1481 if (!ges_track_element_lookup_child (object, property_name, &element, &pspec)) {
1482 GST_WARNING ("You need to provide a valid and controllable property name");
1486 /* TODO : update this according to new types of bindings */
1487 direct = !g_strcmp0 (binding_type, "direct");
1488 direct_absolute = !g_strcmp0 (binding_type, "direct-absolute");
1490 if (direct || direct_absolute) {
1491 /* First remove existing binding */
1493 (GstControlBinding *) g_hash_table_lookup (priv->bindings_hashtable,
1496 GST_LOG ("Removing old binding %p for property %s", binding,
1498 gst_object_remove_control_binding (GST_OBJECT (element), binding);
1501 if (direct_absolute)
1503 gst_direct_control_binding_new_absolute (GST_OBJECT (element),
1504 property_name, source);
1507 gst_direct_control_binding_new (GST_OBJECT (element), property_name,
1510 gst_object_add_control_binding (GST_OBJECT (element), binding);
1511 g_hash_table_insert (priv->bindings_hashtable, g_strdup (property_name),
1513 g_signal_emit (object, ges_track_element_signals[CONTROL_BINDING_ADDED],
1518 GST_WARNING ("Binding type must be in [direct]");
1524 * ges_track_element_get_control_binding:
1525 * @object: the #GESTrackElement in which to lookup the bindings.
1526 * @property_name: The property_name to which the binding is associated.
1528 * Looks up the various controlled properties for that #GESTrackElement,
1529 * and returns the #GstControlBinding which controls @property_name.
1531 * Returns: (transfer none) (nullable): the #GstControlBinding associated with
1532 * @property_name, or %NULL if that property is not controlled.
1535 ges_track_element_get_control_binding (GESTrackElement * object,
1536 const gchar * property_name)
1538 GESTrackElementPrivate *priv;
1539 GstControlBinding *binding;
1541 g_return_val_if_fail (GES_IS_TRACK_ELEMENT (object), NULL);
1543 priv = GES_TRACK_ELEMENT (object)->priv;
1546 (GstControlBinding *) g_hash_table_lookup (priv->bindings_hashtable,