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., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * SECTION:ges-track-object
23 * @short_description: Base Class for objects contained in a #GESTrack
25 * #GESTrackObject is the Base Class for any object that can be contained in a
28 * It contains the basic information as to the location of the object within
29 * its container, like the start position, the in-point, the duration and the
33 #include "ges-internal.h"
34 #include "ges-track-object.h"
35 #include "ges-timeline-object.h"
36 #include <gobject/gvaluecollector.h>
38 G_DEFINE_ABSTRACT_TYPE (GESTrackObject, ges_track_object,
39 G_TYPE_INITIALLY_UNOWNED);
41 struct _GESTrackObjectPrivate
43 /* These fields are only used before the gnlobject is available */
44 guint64 pending_start;
45 guint64 pending_inpoint;
46 guint64 pending_duration;
47 guint32 pending_priority;
48 gboolean pending_active;
50 GstElement *gnlobject; /* The GnlObject */
51 GstElement *element; /* The element contained in the gnlobject (can be NULL) */
53 /* We keep a link between properties name and elements internally
54 * The hashtable should look like
55 * {GParamaSpec ---> element,}*/
56 GHashTable *properties_hashtable;
58 GESTimelineObject *timelineobj;
63 gboolean locked; /* If TRUE, then moves in sync with its controlling
64 * GESTimelineObject */
79 static GParamSpec *properties[PROP_LAST];
87 static guint ges_track_object_signals[LAST_SIGNAL] = { 0 };
89 static GstElement *ges_track_object_create_gnl_object_func (GESTrackObject *
92 static void gnlobject_start_cb (GstElement * gnlobject, GParamSpec * arg
93 G_GNUC_UNUSED, GESTrackObject * obj);
95 static void gnlobject_media_start_cb (GstElement * gnlobject, GParamSpec * arg
96 G_GNUC_UNUSED, GESTrackObject * obj);
98 static void gnlobject_priority_cb (GstElement * gnlobject, GParamSpec * arg
99 G_GNUC_UNUSED, GESTrackObject * obj);
101 static void gnlobject_duration_cb (GstElement * gnlobject, GParamSpec * arg
102 G_GNUC_UNUSED, GESTrackObject * obj);
104 static void gnlobject_active_cb (GstElement * gnlobject, GParamSpec * arg
105 G_GNUC_UNUSED, GESTrackObject * obj);
107 static void connect_properties_signals (GESTrackObject * object);
108 static void connect_signal (gpointer key, gpointer value, gpointer user_data);
109 static void gst_element_prop_changed_cb (GstElement * element, GParamSpec * arg
110 G_GNUC_UNUSED, GESTrackObject * obj);
112 static inline gboolean
113 ges_track_object_set_start_internal (GESTrackObject * object, guint64 start);
114 static inline gboolean
115 ges_track_object_set_inpoint_internal (GESTrackObject * object,
117 static inline gboolean ges_track_object_set_duration_internal (GESTrackObject *
118 object, guint64 duration);
119 static inline gboolean ges_track_object_set_priority_internal (GESTrackObject *
120 object, guint32 priority);
122 ges_track_object_set_locked_internal (GESTrackObject * object, gboolean locked);
124 static GParamSpec **default_list_children_properties (GESTrackObject * object,
125 guint * n_properties);
128 ges_track_object_get_property (GObject * object, guint property_id,
129 GValue * value, GParamSpec * pspec)
131 GESTrackObject *tobj = GES_TRACK_OBJECT (object);
133 switch (property_id) {
135 g_value_set_uint64 (value, ges_track_object_get_start (tobj));
138 g_value_set_uint64 (value, ges_track_object_get_inpoint (tobj));
141 g_value_set_uint64 (value, ges_track_object_get_duration (tobj));
144 g_value_set_uint (value, ges_track_object_get_priority (tobj));
147 g_value_set_boolean (value, ges_track_object_is_active (tobj));
150 g_value_set_boolean (value, ges_track_object_is_locked (tobj));
153 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
158 ges_track_object_set_property (GObject * object, guint property_id,
159 const GValue * value, GParamSpec * pspec)
161 GESTrackObject *tobj = GES_TRACK_OBJECT (object);
163 switch (property_id) {
165 ges_track_object_set_start_internal (tobj, g_value_get_uint64 (value));
168 ges_track_object_set_inpoint_internal (tobj, g_value_get_uint64 (value));
171 ges_track_object_set_duration_internal (tobj, g_value_get_uint64 (value));
174 ges_track_object_set_priority_internal (tobj, g_value_get_uint (value));
177 ges_track_object_set_active (tobj, g_value_get_boolean (value));
180 ges_track_object_set_locked_internal (tobj, g_value_get_boolean (value));
183 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
188 ges_track_object_dispose (GObject * object)
190 GESTrackObjectPrivate *priv = GES_TRACK_OBJECT (object)->priv;
191 if (priv->properties_hashtable)
192 g_hash_table_destroy (priv->properties_hashtable);
194 G_OBJECT_CLASS (ges_track_object_parent_class)->dispose (object);
198 ges_track_object_finalize (GObject * object)
200 G_OBJECT_CLASS (ges_track_object_parent_class)->finalize (object);
204 ges_track_object_class_init (GESTrackObjectClass * klass)
206 GObjectClass *object_class = G_OBJECT_CLASS (klass);
208 g_type_class_add_private (klass, sizeof (GESTrackObjectPrivate));
210 object_class->get_property = ges_track_object_get_property;
211 object_class->set_property = ges_track_object_set_property;
212 object_class->dispose = ges_track_object_dispose;
213 object_class->finalize = ges_track_object_finalize;
216 * GESTrackObject:start
218 * The position of the object in the container #GESTrack (in nanoseconds).
220 properties[PROP_START] = g_param_spec_uint64 ("start", "Start",
221 "The position in the container", 0, G_MAXUINT64, 0, G_PARAM_READWRITE);
222 g_object_class_install_property (object_class, PROP_START,
223 properties[PROP_START]);
226 * GESTrackObject:in-point
228 * The in-point at which this #GESTrackObject will start outputting data
229 * from its contents (in nanoseconds).
231 * Ex: an in-point of 5 seconds means that the first outputted buffer will
232 * be the one located 5 seconds in the controlled resource.
234 properties[PROP_INPOINT] =
235 g_param_spec_uint64 ("in-point", "In-point", "The in-point", 0,
236 G_MAXUINT64, 0, G_PARAM_READWRITE);
237 g_object_class_install_property (object_class, PROP_INPOINT,
238 properties[PROP_INPOINT]);
241 * GESTrackObject:duration
243 * The duration (in nanoseconds) which will be used in the container #GESTrack
244 * starting from 'in-point'.
247 properties[PROP_DURATION] =
248 g_param_spec_uint64 ("duration", "Duration", "The duration to use", 0,
249 G_MAXUINT64, GST_SECOND, G_PARAM_READWRITE);
250 g_object_class_install_property (object_class, PROP_DURATION,
251 properties[PROP_DURATION]);
254 * GESTrackObject:priority
256 * The priority of the object within the containing #GESTrack.
257 * If two objects intersect over the same region of time, the @priority
258 * property is used to decide which one takes precedence.
260 * The highest priority (that supercedes everything) is 0, and then lowering
261 * priorities go in increasing numerical value (with #G_MAXUINT64 being the
264 properties[PROP_PRIORITY] = g_param_spec_uint ("priority", "Priority",
265 "The priority of the object", 0, G_MAXUINT, 0, G_PARAM_READWRITE);
266 g_object_class_install_property (object_class, PROP_PRIORITY,
267 properties[PROP_PRIORITY]);
270 * GESTrackObject:active
272 * Whether the object should be taken into account in the #GESTrack output.
273 * If #FALSE, then its contents will not be used in the resulting track.
275 properties[PROP_ACTIVE] =
276 g_param_spec_boolean ("active", "Active", "Use object in output", TRUE,
278 g_object_class_install_property (object_class, PROP_ACTIVE,
279 properties[PROP_ACTIVE]);
282 * GESTrackObject:locked
284 * If %TRUE, then moves in sync with its controlling #GESTimelineObject
286 properties[PROP_LOCKED] =
287 g_param_spec_boolean ("locked", "Locked",
288 "Moves in sync with its controling TimelineObject", TRUE,
290 g_object_class_install_property (object_class, PROP_LOCKED,
291 properties[PROP_LOCKED]);
294 * GESTrackObject::deep-notify:
295 * @track_object: a #GESTrackObject
296 * @prop_object: the object that originated the signal
297 * @prop: the property that changed
299 * The deep notify signal is used to be notified of property changes of all
300 * the childs of @track_object
304 ges_track_object_signals[DEEP_NOTIFY] =
305 g_signal_new ("deep-notify", G_TYPE_FROM_CLASS (klass),
306 G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED |
307 G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_generic,
308 G_TYPE_NONE, 2, GST_TYPE_ELEMENT, G_TYPE_PARAM);
310 klass->create_gnl_object = ges_track_object_create_gnl_object_func;
311 /* There is no 'get_props_hashtable' default implementation */
312 klass->get_props_hastable = NULL;
313 klass->list_children_properties = default_list_children_properties;
317 ges_track_object_init (GESTrackObject * self)
319 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
320 GES_TYPE_TRACK_OBJECT, GESTrackObjectPrivate);
322 /* Sane default values */
323 self->priv->pending_start = 0;
324 self->priv->pending_inpoint = 0;
325 self->priv->pending_duration = GST_SECOND;
326 self->priv->pending_priority = 1;
327 self->priv->pending_active = TRUE;
328 self->priv->locked = TRUE;
329 self->priv->properties_hashtable = NULL;
332 static inline gboolean
333 ges_track_object_set_start_internal (GESTrackObject * object, guint64 start)
335 GST_DEBUG ("object:%p, start:%" GST_TIME_FORMAT,
336 object, GST_TIME_ARGS (start));
338 if (object->priv->gnlobject != NULL) {
339 if (G_UNLIKELY (start == object->start))
342 g_object_set (object->priv->gnlobject, "start", start, NULL);
344 object->priv->pending_start = start;
349 * ges_track_object_set_start:
350 * @object: a #GESTrackObject
351 * @start: the start position (in #GstClockTime)
353 * Sets the position of the object in the container #GESTrack.
356 ges_track_object_set_start (GESTrackObject * object, guint64 start)
358 if (ges_track_object_set_start_internal (object, start))
359 #if GLIB_CHECK_VERSION(2,26,0)
360 g_object_notify_by_pspec (G_OBJECT (object), properties[PROP_START]);
362 g_object_notify (G_OBJECT (object), "start");
366 static inline gboolean
367 ges_track_object_set_inpoint_internal (GESTrackObject * object, guint64 inpoint)
370 GST_DEBUG ("object:%p, inpoint:%" GST_TIME_FORMAT,
371 object, GST_TIME_ARGS (inpoint));
373 if (object->priv->gnlobject != NULL) {
374 if (G_UNLIKELY (inpoint == object->inpoint))
377 g_object_set (object->priv->gnlobject, "media-start", inpoint, NULL);
379 object->priv->pending_inpoint = inpoint;
385 * ges_track_object_set_inpoint:
386 * @object: a #GESTrackObject
387 * @inpoint: the in-point (in #GstClockTime)
389 * Set the offset within the contents of this #GESTrackObject
392 ges_track_object_set_inpoint (GESTrackObject * object, guint64 inpoint)
394 if (ges_track_object_set_inpoint_internal (object, inpoint))
395 #if GLIB_CHECK_VERSION(2,26,0)
396 g_object_notify_by_pspec (G_OBJECT (object), properties[PROP_INPOINT]);
398 g_object_notify (G_OBJECT (object), "in-point");
402 static inline gboolean
403 ges_track_object_set_duration_internal (GESTrackObject * object,
406 GST_DEBUG ("object:%p, duration:%" GST_TIME_FORMAT,
407 object, GST_TIME_ARGS (duration));
409 if (object->priv->gnlobject != NULL) {
410 if (G_UNLIKELY (duration == object->duration))
413 g_object_set (object->priv->gnlobject, "duration", duration,
414 "media-duration", duration, NULL);
416 object->priv->pending_duration = duration;
421 * ges_track_object_set_duration:
422 * @object: a #GESTrackObject
423 * @duration: the duration (in #GstClockTime)
425 * Set the duration which will be used in the container #GESTrack
426 * starting from the 'in-point'
429 ges_track_object_set_duration (GESTrackObject * object, guint64 duration)
431 if (ges_track_object_set_duration_internal (object, duration))
432 #if GLIB_CHECK_VERSION(2,26,0)
433 g_object_notify_by_pspec (G_OBJECT (object), properties[PROP_DURATION]);
435 g_object_notify (G_OBJECT (object), "duration");
439 static inline gboolean
440 ges_track_object_set_priority_internal (GESTrackObject * object,
443 GST_DEBUG ("object:%p, priority:%" G_GUINT32_FORMAT, object, priority);
445 if (object->priv->gnlobject != NULL) {
446 if (G_UNLIKELY (priority == object->priority))
449 g_object_set (object->priv->gnlobject, "priority", priority, NULL);
451 object->priv->pending_priority = priority;
456 * ges_track_object_set_priority:
457 * @object: a #GESTrackObject
458 * @priority: the priority
460 * Sets the priority of the object withing the containing #GESTrack.
461 * If two objects intersect over the same region of time, the priority
462 * property is used to decide which one takes precedence.
464 * The highest priority (that supercedes everything) is 0, and then
465 * lowering priorities go in increasing numerical value (with G_MAXUINT32
466 * being the lowest priority).
469 ges_track_object_set_priority (GESTrackObject * object, guint32 priority)
471 if (ges_track_object_set_priority_internal (object, priority))
472 #if GLIB_CHECK_VERSION(2,26,0)
473 g_object_notify_by_pspec (G_OBJECT (object), properties[PROP_PRIORITY]);
475 g_object_notify (G_OBJECT (object), "priority");
481 * ges_track_object_set_active:
482 * @object: a #GESTrackObject
483 * @active: visibility
485 * Sets the usage of the @object. If @active is %TRUE, the object will be used for
486 * playback and rendering, else it will be ignored.
488 * Returns: %TRUE if the property was toggled, else %FALSE
491 ges_track_object_set_active (GESTrackObject * object, gboolean active)
493 GST_DEBUG ("object:%p, active:%d", object, active);
495 if (object->priv->gnlobject != NULL) {
496 if (G_UNLIKELY (active == object->active))
499 g_object_set (object->priv->gnlobject, "active", active, NULL);
501 object->priv->pending_active = active;
505 /* Callbacks from the GNonLin object */
507 gnlobject_start_cb (GstElement * gnlobject, GParamSpec * arg G_GNUC_UNUSED,
508 GESTrackObject * obj)
511 GESTrackObjectClass *klass;
513 klass = GES_TRACK_OBJECT_GET_CLASS (obj);
515 g_object_get (gnlobject, "start", &start, NULL);
517 GST_DEBUG ("gnlobject start : %" GST_TIME_FORMAT " current : %"
518 GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (obj->start));
520 if (start != obj->start) {
522 if (klass->start_changed)
523 klass->start_changed (obj, start);
528 gst_element_prop_changed_cb (GstElement * element, GParamSpec * arg
529 G_GNUC_UNUSED, GESTrackObject * obj)
531 g_signal_emit (obj, ges_track_object_signals[DEEP_NOTIFY], 0,
532 GST_ELEMENT (element), arg);
536 connect_signal (gpointer key, gpointer value, gpointer user_data)
538 gchar *signame = g_strconcat ("notify::", G_PARAM_SPEC (key)->name, NULL);
540 g_signal_connect (G_OBJECT (value),
541 signame, G_CALLBACK (gst_element_prop_changed_cb),
542 GES_TRACK_OBJECT (user_data));
548 connect_properties_signals (GESTrackObject * object)
550 if (G_UNLIKELY (!object->priv->properties_hashtable)) {
551 GST_WARNING ("The properties_hashtable hasn't been set");
555 g_hash_table_foreach (object->priv->properties_hashtable,
556 (GHFunc) connect_signal, object);
560 /* Callbacks from the GNonLin object */
562 gnlobject_media_start_cb (GstElement * gnlobject,
563 GParamSpec * arg G_GNUC_UNUSED, GESTrackObject * obj)
566 GESTrackObjectClass *klass;
568 klass = GES_TRACK_OBJECT_GET_CLASS (obj);
570 g_object_get (gnlobject, "media-start", &start, NULL);
572 GST_DEBUG ("gnlobject in-point : %" GST_TIME_FORMAT " current : %"
573 GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (obj->inpoint));
575 if (start != obj->inpoint) {
576 obj->inpoint = start;
577 if (klass->media_start_changed)
578 klass->media_start_changed (obj, start);
583 gnlobject_priority_cb (GstElement * gnlobject, GParamSpec * arg G_GNUC_UNUSED,
584 GESTrackObject * obj)
587 GESTrackObjectClass *klass;
589 klass = GES_TRACK_OBJECT_GET_CLASS (obj);
591 g_object_get (gnlobject, "priority", &priority, NULL);
593 GST_DEBUG ("gnlobject priority : %d current : %d", priority, obj->priority);
595 if (priority != obj->priority) {
596 obj->priority = priority;
597 if (klass->gnl_priority_changed)
598 klass->gnl_priority_changed (obj, priority);
603 gnlobject_duration_cb (GstElement * gnlobject, GParamSpec * arg G_GNUC_UNUSED,
604 GESTrackObject * obj)
607 GESTrackObjectClass *klass;
609 klass = GES_TRACK_OBJECT_GET_CLASS (obj);
611 g_object_get (gnlobject, "duration", &duration, NULL);
613 GST_DEBUG ("gnlobject duration : %" GST_TIME_FORMAT " current : %"
614 GST_TIME_FORMAT, GST_TIME_ARGS (duration), GST_TIME_ARGS (obj->duration));
616 if (duration != obj->duration) {
617 obj->duration = duration;
618 if (klass->duration_changed)
619 klass->duration_changed (obj, duration);
624 gnlobject_active_cb (GstElement * gnlobject, GParamSpec * arg G_GNUC_UNUSED,
625 GESTrackObject * obj)
628 GESTrackObjectClass *klass;
630 klass = GES_TRACK_OBJECT_GET_CLASS (obj);
632 g_object_get (gnlobject, "active", &active, NULL);
634 GST_DEBUG ("gnlobject active : %d current : %d", active, obj->active);
636 if (active != obj->active) {
637 obj->active = active;
638 if (klass->active_changed)
639 klass->active_changed (obj, active);
644 /* default 'create_gnl_object' virtual method implementation */
646 ges_track_object_create_gnl_object_func (GESTrackObject * self)
648 GESTrackObjectClass *klass = NULL;
649 GstElement *child = NULL;
650 GstElement *gnlobject;
652 klass = GES_TRACK_OBJECT_GET_CLASS (self);
654 if (G_UNLIKELY (self->priv->gnlobject != NULL))
655 goto already_have_gnlobject;
657 if (G_UNLIKELY (klass->gnlobject_factorytype == NULL))
660 GST_DEBUG ("Creating a supporting gnlobject of type '%s'",
661 klass->gnlobject_factorytype);
663 gnlobject = gst_element_factory_make (klass->gnlobject_factorytype, NULL);
665 if (G_UNLIKELY (gnlobject == NULL))
668 if (klass->create_element) {
669 GST_DEBUG ("Calling subclass 'create_element' vmethod");
670 child = klass->create_element (self);
672 if (G_UNLIKELY (!child))
675 if (!gst_bin_add (GST_BIN (gnlobject), child))
678 GST_DEBUG ("Succesfully got the element to put in the gnlobject");
679 self->priv->element = child;
688 already_have_gnlobject:
690 GST_ERROR ("Already controlling a GnlObject %s",
691 GST_ELEMENT_NAME (self->priv->gnlobject));
697 GST_ERROR ("No GESTrackObject::gnlobject_factorytype implementation!");
703 GST_ERROR ("Error creating a gnlobject of type '%s'",
704 klass->gnlobject_factorytype);
710 GST_ERROR ("create_element returned NULL");
711 gst_object_unref (gnlobject);
717 GST_ERROR ("Error adding the contents to the gnlobject");
718 gst_object_unref (child);
719 gst_object_unref (gnlobject);
725 ensure_gnl_object (GESTrackObject * object)
727 GESTrackObjectClass *class;
728 GstElement *gnlobject;
729 GHashTable *props_hash;
732 if (object->priv->gnlobject && object->priv->valid)
735 /* 1. Create the GnlObject */
736 GST_DEBUG ("Creating GnlObject");
738 class = GES_TRACK_OBJECT_GET_CLASS (object);
740 if (G_UNLIKELY (class->create_gnl_object == NULL)) {
741 GST_ERROR ("No 'create_gnl_object' implementation !");
745 GST_DEBUG ("Calling virtual method");
747 /* call the create_gnl_object virtual method */
748 gnlobject = class->create_gnl_object (object);
750 if (G_UNLIKELY (gnlobject == NULL)) {
752 ("'create_gnl_object' implementation returned TRUE but no GnlObject is available");
756 object->priv->gnlobject = gnlobject;
758 /* 2. Fill in the GnlObject */
760 GST_DEBUG ("Got a valid GnlObject, now filling it in");
762 if (object->priv->timelineobj)
763 res = ges_timeline_object_fill_track_object (object->priv->timelineobj,
764 object, object->priv->gnlobject);
769 /* Connect to property notifications */
770 /* FIXME : remember the signalids so we can remove them later on !!! */
771 g_signal_connect (G_OBJECT (object->priv->gnlobject), "notify::start",
772 G_CALLBACK (gnlobject_start_cb), object);
773 g_signal_connect (G_OBJECT (object->priv->gnlobject),
774 "notify::media-start", G_CALLBACK (gnlobject_media_start_cb), object);
775 g_signal_connect (G_OBJECT (object->priv->gnlobject), "notify::duration",
776 G_CALLBACK (gnlobject_duration_cb), object);
777 g_signal_connect (G_OBJECT (object->priv->gnlobject), "notify::priority",
778 G_CALLBACK (gnlobject_priority_cb), object);
779 g_signal_connect (G_OBJECT (object->priv->gnlobject), "notify::active",
780 G_CALLBACK (gnlobject_active_cb), object);
782 /* Set some properties on the GnlObject */
783 g_object_set (object->priv->gnlobject,
784 "caps", ges_track_get_caps (object->priv->track),
785 "duration", object->priv->pending_duration,
786 "media-duration", object->priv->pending_duration,
787 "start", object->priv->pending_start,
788 "media-start", object->priv->pending_inpoint,
789 "priority", object->priv->pending_priority,
790 "active", object->priv->pending_active, NULL);
792 /* We feed up the props_hashtable if possible */
793 if (class->get_props_hastable) {
794 props_hash = class->get_props_hastable (object);
796 if (props_hash == NULL) {
797 GST_DEBUG ("'get_props_hastable' implementation returned TRUE but no"
798 "properties_hashtable is available");
800 object->priv->properties_hashtable = props_hash;
801 connect_properties_signals (object);
808 object->priv->valid = res;
810 GST_DEBUG ("Returning res:%d", res);
817 ges_track_object_set_track (GESTrackObject * object, GESTrack * track)
819 GST_DEBUG ("object:%p, track:%p", object, track);
821 object->priv->track = track;
823 if (object->priv->track)
824 return ensure_gnl_object (object);
830 * ges_track_object_get_track:
831 * @object: a #GESTrackObject
833 * Get the #GESTrack to which this object belongs.
835 * Returns: (transfer none): The #GESTrack to which this object belongs. Can be %NULL if it
836 * is not in any track
839 ges_track_object_get_track (GESTrackObject * object)
841 g_return_val_if_fail (GES_IS_TRACK_OBJECT (object), NULL);
843 return object->priv->track;
848 ges_track_object_set_timeline_object (GESTrackObject * object,
849 GESTimelineObject * tlobj)
851 GST_DEBUG ("object:%p, timeline-object:%p", object, tlobj);
853 object->priv->timelineobj = tlobj;
857 * ges_track_object_get_timeline_object:
858 * @object: a #GESTrackObject
860 * Get the #GESTimelineObject which is controlling this track object
862 * Returns: (transfer none): the #GESTimelineObject which is controlling
866 ges_track_object_get_timeline_object (GESTrackObject * object)
868 g_return_val_if_fail (GES_IS_TRACK_OBJECT (object), NULL);
870 return object->priv->timelineobj;
874 * ges_track_object_get_gnlobject:
875 * @object: a #GESTrackObject
877 * Get the GNonLin object this object is controlling.
879 * Returns: (transfer none): the GNonLin object this object is controlling.
882 ges_track_object_get_gnlobject (GESTrackObject * object)
884 return object->priv->gnlobject;
888 * ges_track_object_get_element:
889 * @object: a #GESTrackObject
891 * Get the #GstElement this track object is controlling within GNonLin.
893 * Returns: (transfer none): the #GstElement this track object is controlling
897 ges_track_object_get_element (GESTrackObject * object)
899 return object->priv->element;
903 ges_track_object_set_locked_internal (GESTrackObject * object, gboolean locked)
905 object->priv->locked = locked;
909 * ges_track_object_set_locked:
910 * @object: a #GESTrackObject
911 * @locked: whether the object is lock to its parent
913 * Set the locking status of the @object in relationship to its controlling
914 * #GESTimelineObject. If @locked is %TRUE, then this object will move synchronously
915 * with its controlling #GESTimelineObject.
918 ges_track_object_set_locked (GESTrackObject * object, gboolean locked)
920 g_return_if_fail (GES_IS_TRACK_OBJECT (object));
922 GST_DEBUG_OBJECT (object, "%s object", locked ? "Locking" : "Unlocking");
924 ges_track_object_set_locked_internal (object, locked);
925 #if GLIB_CHECK_VERSION(2,26,0)
926 g_object_notify_by_pspec (G_OBJECT (object), properties[PROP_LOCKED]);
928 g_object_notify (G_OBJECT (object), "locked");
934 * ges_track_object_is_locked:
935 * @object: a #GESTrackObject
937 * Let you know if object us locked or not (moving synchronously).
939 * Returns: %TRUE if the object is moving synchronously to its controlling
940 * #GESTimelineObject, else %FALSE.
943 ges_track_object_is_locked (GESTrackObject * object)
945 return object->priv->locked;
949 * ges_track_object_get_start:
950 * @object: a #GESTrackObject
952 * Get the position of the object in the container #GESTrack.
954 * Returns: the start position (in #GstClockTime)
959 ges_track_object_get_start (GESTrackObject * object)
961 if (G_UNLIKELY (object->priv->gnlobject == NULL))
962 return object->priv->pending_start;
964 return object->start;
968 * ges_track_object_get_inpoint:
969 * @object: a #GESTrackObject
971 * Get the offset within the contents of this #GESTrackObject
973 * Returns: the in-point (in #GstClockTime)
978 ges_track_object_get_inpoint (GESTrackObject * object)
980 if (G_UNLIKELY (object->priv->gnlobject == NULL))
981 return object->priv->pending_inpoint;
983 return object->inpoint;
987 * ges_track_object_get_duration:
988 * @object: a #GESTrackObject
990 * Get the duration which will be used in the container #GESTrack
991 * starting from the 'in-point'
993 * Returns: the duration (in #GstClockTime)
998 ges_track_object_get_duration (GESTrackObject * object)
1000 if (G_UNLIKELY (object->priv->gnlobject == NULL))
1001 return object->priv->pending_duration;
1003 return object->duration;
1007 * ges_track_object_get_priority:
1008 * @object: a #GESTrackObject
1010 * Get the priority of the object withing the containing #GESTrack.
1012 * Returns: the priority of @object
1017 ges_track_object_get_priority (GESTrackObject * object)
1019 if (G_UNLIKELY (object->priv->gnlobject == NULL))
1020 return object->priv->pending_priority;
1022 return object->priority;
1026 * ges_track_object_is_active:
1027 * @object: a #GESTrackObject
1029 * Lets you know if @object will be used for playback and rendering,
1032 * Returns: %TRUE if @object is active, %FALSE otherwize
1037 ges_track_object_is_active (GESTrackObject * object)
1039 if (G_UNLIKELY (object->priv->gnlobject == NULL))
1040 return object->priv->pending_active;
1042 return object->active;
1046 * ges_track_object_lookup_child:
1047 * @object: object to lookup the property in
1048 * @prop_name: name of the property to look up. You can specify the name of the
1049 * class as such: "ClassName::property-name", to guarantee that you get the
1050 * proper GParamSpec in case various GstElement-s contain the same property
1051 * name. If you don't do so, you will get the first element found, having
1052 * this property and the and the corresponding GParamSpec.
1053 * @element: (out) (allow-none) (transfer full): pointer to a #GstElement that
1054 * takes the real object to set property on
1055 * @pspec: (out) (allow-none) (transfer full): pointer to take the #GParamSpec
1056 * describing the property
1058 * Looks up which @element and @pspec would be effected by the given @name. If various
1059 * contained elements have this property name you will get the first one, unless you
1060 * specify the class name in @name.
1062 * Returns: TRUE if @element and @pspec could be found. FALSE otherwise. In that
1063 * case the values for @pspec and @element are not modified. Unref @element after
1069 ges_track_object_lookup_child (GESTrackObject * object, const gchar * prop_name,
1070 GstElement ** element, GParamSpec ** pspec)
1072 GHashTableIter iter;
1073 gpointer key, value;
1074 gchar **names, *name, *classename;
1076 GESTrackObjectPrivate *priv = object->priv;
1081 names = g_strsplit (prop_name, "::", 2);
1082 if (names[1] != NULL) {
1083 classename = names[0];
1088 g_hash_table_iter_init (&iter, priv->properties_hashtable);
1089 while (g_hash_table_iter_next (&iter, &key, &value)) {
1090 if (g_strcmp0 (G_PARAM_SPEC (key)->name, name) == 0) {
1091 if (classename == NULL ||
1092 g_strcmp0 (G_OBJECT_TYPE_NAME (G_OBJECT (value)), classename) == 0) {
1093 GST_DEBUG ("The %s property from %s has been found", name, classename);
1095 *element = g_object_ref (value);
1097 *pspec = g_param_spec_ref (key);
1109 * ges_track_object_set_child_property_by_pspec:
1110 * @object: a #GESTrackObject
1111 * @pspec: The #GParamSpec that specifies the property you want to set
1114 * Sets a property of a child of @object.
1119 ges_track_object_set_child_property_by_pspec (GESTrackObject * object,
1120 GParamSpec * pspec, GValue * value)
1122 GstElement *element;
1124 GESTrackObjectPrivate *priv = object->priv;
1126 if (!priv->properties_hashtable)
1127 goto prop_hash_not_set;
1129 element = g_hash_table_lookup (priv->properties_hashtable, pspec);
1133 g_object_set_property (G_OBJECT (element), pspec->name, value);
1139 GST_ERROR ("The %s property doesn't exist", pspec->name);
1144 GST_DEBUG ("The child properties haven't been set on %p", object);
1150 * ges_track_object_set_child_property_valist:
1151 * @object: The #GESTrackObject parent object
1152 * @first_property_name: The name of the first property to set
1153 * @var_args: value for the first property, followed optionally by more
1154 * name/return location pairs, followed by NULL
1156 * Sets a property of a child of @object. If there are various child elements
1157 * that have the same property name, you can distinguish them using the following
1158 * syntax: 'ClasseName::property_name' as property name. If you don't, the
1159 * corresponding property of the first element found will be set.
1164 ges_track_object_set_child_property_valist (GESTrackObject * object,
1165 const gchar * first_property_name, va_list var_args)
1169 GstElement *element;
1171 gchar *error = NULL;
1172 GValue value = { 0, };
1174 g_return_if_fail (G_IS_OBJECT (object));
1176 name = first_property_name;
1178 /* Note: This part is in big part copied from the gst_child_object_set_valist
1181 /* iterate over pairs */
1183 if (!ges_track_object_lookup_child (object, name, &element, &pspec))
1186 #if GLIB_CHECK_VERSION(2,23,3)
1187 G_VALUE_COLLECT_INIT (&value, pspec->value_type, var_args,
1188 G_VALUE_NOCOPY_CONTENTS, &error);
1190 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1191 G_VALUE_COLLECT (&value, var_args, G_VALUE_NOCOPY_CONTENTS, &error);
1197 g_object_set_property (G_OBJECT (element), pspec->name, &value);
1199 g_object_unref (element);
1200 g_value_unset (&value);
1202 name = va_arg (var_args, gchar *);
1208 GST_WARNING ("No property %s in OBJECT\n", name);
1213 GST_WARNING ("error copying value %s in object %p: %s", pspec->name, object,
1215 g_value_unset (&value);
1221 * ges_track_object_set_child_property:
1222 * @object: The #GESTrackObject parent object
1223 * @first_property_name: The name of the first property to set
1224 * @...: value for the first property, followed optionally by more
1225 * name/return location pairs, followed by NULL
1227 * Sets a property of a child of @object. If there are various child elements
1228 * that have the same property name, you can distinguish them using the following
1229 * syntax: 'ClasseName::property_name' as property name. If you don't, the
1230 * corresponding property of the first element found will be set.
1235 ges_track_object_set_child_property (GESTrackObject * object,
1236 const gchar * first_property_name, ...)
1240 va_start (var_args, first_property_name);
1241 ges_track_object_set_child_property_valist (object, first_property_name,
1247 * ges_track_object_get_child_property_valist:
1248 * @object: The #GESTrackObject parent object
1249 * @first_property_name: The name of the first property to get
1250 * @var_args: value for the first property, followed optionally by more
1251 * name/return location pairs, followed by NULL
1253 * Gets a property of a child of @object. If there are various child elements
1254 * that have the same property name, you can distinguish them using the following
1255 * syntax: 'ClasseName::property_name' as property name. If you don't, the
1256 * corresponding property of the first element found will be set.
1261 ges_track_object_get_child_property_valist (GESTrackObject * object,
1262 const gchar * first_property_name, va_list var_args)
1265 gchar *error = NULL;
1266 GValue value = { 0, };
1268 GstElement *element;
1270 g_return_if_fail (G_IS_OBJECT (object));
1272 name = first_property_name;
1274 /* This part is in big part copied from the gst_child_object_get_valist method */
1276 if (!ges_track_object_lookup_child (object, name, &element, &pspec))
1279 g_value_init (&value, pspec->value_type);
1280 g_object_get_property (G_OBJECT (element), pspec->name, &value);
1281 g_object_unref (element);
1283 G_VALUE_LCOPY (&value, var_args, 0, &error);
1286 g_value_unset (&value);
1287 name = va_arg (var_args, gchar *);
1293 GST_WARNING ("no property %s in object", name);
1298 GST_WARNING ("error copying value %s in object %p: %s", pspec->name, object,
1300 g_value_unset (&value);
1306 * ges_track_object_list_children_properties:
1307 * @object: The #GESTrackObject to get the list of children properties from
1308 * @n_properties: return location for the length of the returned array
1310 * Gets an array of #GParamSpec* for all configurable properties of the
1311 * children of @object.
1313 * Returns: (transfer full) (array): an array of #GParamSpec* which should be freed after use or
1314 * %NULL if something went wrong
1319 ges_track_object_list_children_properties (GESTrackObject * object,
1320 guint * n_properties)
1322 GESTrackObjectClass *class;
1324 g_return_val_if_fail (GES_IS_TRACK_OBJECT (object), NULL);
1326 class = GES_TRACK_OBJECT_GET_CLASS (object);
1328 return class->list_children_properties (object, n_properties);
1332 * ges_track_object_get_child_property:
1333 * @object: The origin #GESTrackObject
1334 * @first_property_name: The name of the first property to get
1335 * @...: return location for the first property, followed optionally by more
1336 * name/return location pairs, followed by NULL
1338 * Gets properties of a child of @object.
1343 ges_track_object_get_child_property (GESTrackObject * object,
1344 const gchar * first_property_name, ...)
1348 va_start (var_args, first_property_name);
1349 ges_track_object_get_child_property_valist (object, first_property_name,
1355 * ges_track_object_get_child_property_by_pspec:
1356 * @object: a #GESTrackObject
1357 * @pspec: The #GParamSpec that specifies the property you want to get
1358 * @value: return location for the value
1360 * Gets a property of a child of @object.
1365 ges_track_object_get_child_property_by_pspec (GESTrackObject * object,
1366 GParamSpec * pspec, GValue * value)
1368 GstElement *element;
1370 GESTrackObjectPrivate *priv = object->priv;
1372 if (!priv->properties_hashtable)
1373 goto prop_hash_not_set;
1375 element = g_hash_table_lookup (priv->properties_hashtable, pspec);
1379 g_object_get_property (G_OBJECT (element), pspec->name, value);
1385 GST_ERROR ("The %s property doesn't exist", pspec->name);
1390 GST_ERROR ("The child properties haven't been set on %p", object);
1395 static GParamSpec **
1396 default_list_children_properties (GESTrackObject * object, guint * n_properties)
1398 GParamSpec **pspec, *spec;
1399 GHashTableIter iter;
1400 gpointer key, value;
1404 if (!object->priv->properties_hashtable)
1405 goto prop_hash_not_set;
1407 *n_properties = g_hash_table_size (object->priv->properties_hashtable);
1408 pspec = g_new (GParamSpec *, *n_properties);
1410 g_hash_table_iter_init (&iter, object->priv->properties_hashtable);
1411 while (g_hash_table_iter_next (&iter, &key, &value)) {
1412 spec = G_PARAM_SPEC (key);
1413 pspec[i] = g_param_spec_ref (spec);
1422 GST_ERROR ("The child properties haven't been set on %p", object);