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 "gesmarshal.h"
35 #include "ges-track-object.h"
36 #include "ges-timeline-object.h"
37 #include <gobject/gvaluecollector.h>
39 G_DEFINE_ABSTRACT_TYPE (GESTrackObject, ges_track_object,
40 G_TYPE_INITIALLY_UNOWNED);
42 struct _GESTrackObjectPrivate
44 /* These fields are only used before the gnlobject is available */
45 guint64 pending_start;
46 guint64 pending_inpoint;
47 guint64 pending_duration;
48 guint32 pending_priority;
49 gboolean pending_active;
51 GstElement *gnlobject; /* The GnlObject */
52 GstElement *element; /* The element contained in the gnlobject (can be NULL) */
54 /* We keep a link between properties name and elements internally
55 * The hashtable should look like
56 * {GParamaSpec ---> element,}*/
57 GHashTable *properties_hashtable;
59 GESTimelineObject *timelineobj;
64 gboolean locked; /* If TRUE, then moves in sync with its controlling
65 * 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 GParamSpec **default_list_children_properties (GESTrackObject * object,
123 guint * n_properties);
126 ges_track_object_get_property (GObject * object, guint property_id,
127 GValue * value, GParamSpec * pspec)
129 GESTrackObject *tobj = GES_TRACK_OBJECT (object);
131 switch (property_id) {
133 g_value_set_uint64 (value, ges_track_object_get_start (tobj));
136 g_value_set_uint64 (value, ges_track_object_get_inpoint (tobj));
139 g_value_set_uint64 (value, ges_track_object_get_duration (tobj));
142 g_value_set_uint (value, ges_track_object_get_priority (tobj));
145 g_value_set_boolean (value, ges_track_object_is_active (tobj));
148 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
153 ges_track_object_set_property (GObject * object, guint property_id,
154 const GValue * value, GParamSpec * pspec)
156 GESTrackObject *tobj = GES_TRACK_OBJECT (object);
158 switch (property_id) {
160 ges_track_object_set_start_internal (tobj, g_value_get_uint64 (value));
163 ges_track_object_set_inpoint_internal (tobj, g_value_get_uint64 (value));
166 ges_track_object_set_duration_internal (tobj, g_value_get_uint64 (value));
169 ges_track_object_set_priority_internal (tobj, g_value_get_uint (value));
172 ges_track_object_set_active (tobj, g_value_get_boolean (value));
175 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
180 ges_track_object_dispose (GObject * object)
182 GESTrackObjectPrivate *priv = GES_TRACK_OBJECT (object)->priv;
183 if (priv->properties_hashtable)
184 g_hash_table_destroy (priv->properties_hashtable);
186 G_OBJECT_CLASS (ges_track_object_parent_class)->dispose (object);
190 ges_track_object_finalize (GObject * object)
192 G_OBJECT_CLASS (ges_track_object_parent_class)->finalize (object);
196 ges_track_object_class_init (GESTrackObjectClass * klass)
198 GObjectClass *object_class = G_OBJECT_CLASS (klass);
200 g_type_class_add_private (klass, sizeof (GESTrackObjectPrivate));
202 object_class->get_property = ges_track_object_get_property;
203 object_class->set_property = ges_track_object_set_property;
204 object_class->dispose = ges_track_object_dispose;
205 object_class->finalize = ges_track_object_finalize;
208 * GESTrackObject:start
210 * The position of the object in the container #GESTrack (in nanoseconds).
212 properties[PROP_START] = g_param_spec_uint64 ("start", "Start",
213 "The position in the container", 0, G_MAXUINT64, 0, G_PARAM_READWRITE);
214 g_object_class_install_property (object_class, PROP_START,
215 properties[PROP_START]);
218 * GESTrackObject:in-point
220 * The in-point at which this #GESTrackObject will start outputting data
221 * from its contents (in nanoseconds).
223 * Ex : an in-point of 5 seconds means that the first outputted buffer will
224 * be the one located 5 seconds in the controlled resource.
226 properties[PROP_INPOINT] =
227 g_param_spec_uint64 ("in-point", "In-point", "The in-point", 0,
228 G_MAXUINT64, 0, G_PARAM_READWRITE);
229 g_object_class_install_property (object_class, PROP_INPOINT,
230 properties[PROP_INPOINT]);
233 * GESTrackObject:duration
235 * The duration (in nanoseconds) which will be used in the container #GESTrack
236 * starting from 'in-point'.
239 properties[PROP_DURATION] =
240 g_param_spec_uint64 ("duration", "Duration", "The duration to use", 0,
241 G_MAXUINT64, GST_SECOND, G_PARAM_READWRITE);
242 g_object_class_install_property (object_class, PROP_DURATION,
243 properties[PROP_DURATION]);
246 * GESTrackObject:priority
248 * The priority of the object within the containing #GESTrack.
249 * If two objects intersect over the same region of time, the @priority
250 * property is used to decide which one takes precedence.
252 * The highest priority (that supercedes everything) is 0, and then lowering
253 * priorities go in increasing numerical value (with #G_MAXUINT64 being the
256 properties[PROP_PRIORITY] = g_param_spec_uint ("priority", "Priority",
257 "The priority of the object", 0, G_MAXUINT, 0, G_PARAM_READWRITE);
258 g_object_class_install_property (object_class, PROP_PRIORITY,
259 properties[PROP_PRIORITY]);
262 * GESTrackObject:active
264 * Whether the object should be taken into account in the #GESTrack output.
265 * If #FALSE, then its contents will not be used in the resulting track.
267 properties[PROP_ACTIVE] =
268 g_param_spec_boolean ("active", "Active", "Use object in output", TRUE,
270 g_object_class_install_property (object_class, PROP_ACTIVE,
271 properties[PROP_ACTIVE]);
274 * GESTrackObject::deep-notify:
275 * @track_object: a #GESTrackObject
276 * @prop_object: the object that originated the signal
277 * @prop: the property that changed
279 * The deep notify signal is used to be notified of property changes of all
280 * the childs of @track_object
282 ges_track_object_signals[DEEP_NOTIFY] =
283 g_signal_new ("deep-notify", G_TYPE_FROM_CLASS (klass),
284 G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED |
285 G_SIGNAL_NO_HOOKS, 0, NULL, NULL, gst_marshal_VOID__OBJECT_PARAM,
286 G_TYPE_NONE, 2, GST_TYPE_ELEMENT, G_TYPE_PARAM);
288 klass->create_gnl_object = ges_track_object_create_gnl_object_func;
289 /* There is no 'get_props_hastable' default implementation */
290 klass->get_props_hastable = NULL;
291 klass->list_children_properties = default_list_children_properties;
295 ges_track_object_init (GESTrackObject * self)
297 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
298 GES_TYPE_TRACK_OBJECT, GESTrackObjectPrivate);
300 /* Sane default values */
301 self->priv->pending_start = 0;
302 self->priv->pending_inpoint = 0;
303 self->priv->pending_duration = GST_SECOND;
304 self->priv->pending_priority = 1;
305 self->priv->pending_active = TRUE;
306 self->priv->locked = TRUE;
307 self->priv->properties_hashtable = NULL;
310 static inline gboolean
311 ges_track_object_set_start_internal (GESTrackObject * object, guint64 start)
313 GST_DEBUG ("object:%p, start:%" GST_TIME_FORMAT,
314 object, GST_TIME_ARGS (start));
316 if (object->priv->gnlobject != NULL) {
317 if (G_UNLIKELY (start == object->start))
320 g_object_set (object->priv->gnlobject, "start", start, NULL);
322 object->priv->pending_start = start;
327 * ges_track_object_set_start:
328 * @object: a #GESTrackObject
329 * @start: the start position (in #GstClockTime)
331 * Sets the position of the object in the container #GESTrack.
334 ges_track_object_set_start (GESTrackObject * object, guint64 start)
336 if (ges_track_object_set_start_internal (object, start))
337 #if GLIB_CHECK_VERSION(2,26,0)
338 g_object_notify_by_pspec (G_OBJECT (object), properties[PROP_START]);
340 g_object_notify (G_OBJECT (object), "start");
344 static inline gboolean
345 ges_track_object_set_inpoint_internal (GESTrackObject * object, guint64 inpoint)
348 GST_DEBUG ("object:%p, inpoint:%" GST_TIME_FORMAT,
349 object, GST_TIME_ARGS (inpoint));
351 if (object->priv->gnlobject != NULL) {
352 if (G_UNLIKELY (inpoint == object->inpoint))
355 g_object_set (object->priv->gnlobject, "media-start", inpoint, NULL);
357 object->priv->pending_inpoint = inpoint;
363 * ges_track_object_set_inpoint:
364 * @object: a #GESTrackObject
365 * @inpoint: the in-point (in #GstClockTime)
367 * Set the offset within the contents of this #GESTrackObject
370 ges_track_object_set_inpoint (GESTrackObject * object, guint64 inpoint)
372 if (ges_track_object_set_inpoint_internal (object, inpoint))
373 #if GLIB_CHECK_VERSION(2,26,0)
374 g_object_notify_by_pspec (G_OBJECT (object), properties[PROP_INPOINT]);
376 g_object_notify (G_OBJECT (object), "in-point");
380 static inline gboolean
381 ges_track_object_set_duration_internal (GESTrackObject * object,
384 GST_DEBUG ("object:%p, duration:%" GST_TIME_FORMAT,
385 object, GST_TIME_ARGS (duration));
387 if (object->priv->gnlobject != NULL) {
388 if (G_UNLIKELY (duration == object->duration))
391 g_object_set (object->priv->gnlobject, "duration", duration,
392 "media-duration", duration, NULL);
394 object->priv->pending_duration = duration;
399 * ges_track_object_set_duration:
400 * @object: a #GESTrackObject
401 * @duration: the duration (in #GstClockTime)
403 * Set the duration which will be used in the container #GESTrack
404 * starting from the 'in-point'
407 ges_track_object_set_duration (GESTrackObject * object, guint64 duration)
409 if (ges_track_object_set_duration_internal (object, duration))
410 #if GLIB_CHECK_VERSION(2,26,0)
411 g_object_notify_by_pspec (G_OBJECT (object), properties[PROP_DURATION]);
413 g_object_notify (G_OBJECT (object), "duration");
417 static inline gboolean
418 ges_track_object_set_priority_internal (GESTrackObject * object,
421 GST_DEBUG ("object:%p, priority:%" G_GUINT32_FORMAT, object, priority);
423 if (object->priv->gnlobject != NULL) {
424 if (G_UNLIKELY (priority == object->priority))
427 g_object_set (object->priv->gnlobject, "priority", priority, NULL);
429 object->priv->pending_priority = priority;
434 * ges_track_object_set_priority:
435 * @object: a #GESTrackObject
436 * @priority: the priority
438 * Sets the priority of the object withing the containing #GESTrack.
439 * If two objects intersect over the same region of time, the priority
440 * property is used to decide which one takes precedence.
442 * The highest priority (that supercedes everything) is 0, and then
443 * lowering priorities go in increasing numerical value (with G_MAXUINT32
444 * being the lowest priority).
447 ges_track_object_set_priority (GESTrackObject * object, guint32 priority)
449 if (ges_track_object_set_priority_internal (object, priority))
450 #if GLIB_CHECK_VERSION(2,26,0)
451 g_object_notify_by_pspec (G_OBJECT (object), properties[PROP_PRIORITY]);
453 g_object_notify (G_OBJECT (object), "priority");
459 * ges_track_object_set_active:
460 * @object: a #GESTrackObject
461 * @active: visibility
463 * Sets the usage of the @object. If @active is %TRUE, the object will be used for
464 * playback and rendering, else it will be ignored.
466 * Returns: %TRUE if the property was toggled, else %FALSE
469 ges_track_object_set_active (GESTrackObject * object, gboolean active)
471 GST_DEBUG ("object:%p, active:%d", object, active);
473 if (object->priv->gnlobject != NULL) {
474 if (G_UNLIKELY (active == object->active))
477 g_object_set (object->priv->gnlobject, "active", active, NULL);
479 object->priv->pending_active = active;
483 /* Callbacks from the GNonLin object */
485 gnlobject_start_cb (GstElement * gnlobject, GParamSpec * arg G_GNUC_UNUSED,
486 GESTrackObject * obj)
489 GESTrackObjectClass *klass;
491 klass = GES_TRACK_OBJECT_GET_CLASS (obj);
493 g_object_get (gnlobject, "start", &start, NULL);
495 GST_DEBUG ("gnlobject start : %" GST_TIME_FORMAT " current : %"
496 GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (obj->start));
498 if (start != obj->start) {
500 if (klass->start_changed)
501 klass->start_changed (obj, start);
506 gst_element_prop_changed_cb (GstElement * element, GParamSpec * arg
507 G_GNUC_UNUSED, GESTrackObject * obj)
509 g_signal_emit (obj, ges_track_object_signals[DEEP_NOTIFY], 0,
510 GST_ELEMENT (element), arg);
514 connect_signal (gpointer key, gpointer value, gpointer user_data)
516 gchar *signame = g_strconcat ("notify::", G_PARAM_SPEC (key)->name, NULL);
518 g_signal_connect (G_OBJECT (value),
519 signame, G_CALLBACK (gst_element_prop_changed_cb),
520 GES_TRACK_OBJECT (user_data));
526 connect_properties_signals (GESTrackObject * object)
528 if (G_UNLIKELY (!object->priv->properties_hashtable)) {
529 GST_WARNING ("The properties_hashtable hasn't been set");
533 g_hash_table_foreach (object->priv->properties_hashtable,
534 (GHFunc) connect_signal, object);
538 /* Callbacks from the GNonLin object */
540 gnlobject_media_start_cb (GstElement * gnlobject,
541 GParamSpec * arg G_GNUC_UNUSED, GESTrackObject * obj)
544 GESTrackObjectClass *klass;
546 klass = GES_TRACK_OBJECT_GET_CLASS (obj);
548 g_object_get (gnlobject, "media-start", &start, NULL);
550 GST_DEBUG ("gnlobject in-point : %" GST_TIME_FORMAT " current : %"
551 GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (obj->inpoint));
553 if (start != obj->inpoint) {
554 obj->inpoint = start;
555 if (klass->media_start_changed)
556 klass->media_start_changed (obj, start);
561 gnlobject_priority_cb (GstElement * gnlobject, GParamSpec * arg G_GNUC_UNUSED,
562 GESTrackObject * obj)
565 GESTrackObjectClass *klass;
567 klass = GES_TRACK_OBJECT_GET_CLASS (obj);
569 g_object_get (gnlobject, "priority", &priority, NULL);
571 GST_DEBUG ("gnlobject priority : %d current : %d", priority, obj->priority);
573 if (priority != obj->priority) {
574 obj->priority = priority;
575 if (klass->gnl_priority_changed)
576 klass->gnl_priority_changed (obj, priority);
581 gnlobject_duration_cb (GstElement * gnlobject, GParamSpec * arg G_GNUC_UNUSED,
582 GESTrackObject * obj)
585 GESTrackObjectClass *klass;
587 klass = GES_TRACK_OBJECT_GET_CLASS (obj);
589 g_object_get (gnlobject, "duration", &duration, NULL);
591 GST_DEBUG ("gnlobject duration : %" GST_TIME_FORMAT " current : %"
592 GST_TIME_FORMAT, GST_TIME_ARGS (duration), GST_TIME_ARGS (obj->duration));
594 if (duration != obj->duration) {
595 obj->duration = duration;
596 if (klass->duration_changed)
597 klass->duration_changed (obj, duration);
602 gnlobject_active_cb (GstElement * gnlobject, GParamSpec * arg G_GNUC_UNUSED,
603 GESTrackObject * obj)
606 GESTrackObjectClass *klass;
608 klass = GES_TRACK_OBJECT_GET_CLASS (obj);
610 g_object_get (gnlobject, "active", &active, NULL);
612 GST_DEBUG ("gnlobject active : %d current : %d", active, obj->active);
614 if (active != obj->active) {
615 obj->active = active;
616 if (klass->active_changed)
617 klass->active_changed (obj, active);
622 /* default 'create_gnl_object' virtual method implementation */
624 ges_track_object_create_gnl_object_func (GESTrackObject * self)
626 GESTrackObjectClass *klass = NULL;
627 GstElement *child = NULL;
628 GstElement *gnlobject;
630 klass = GES_TRACK_OBJECT_GET_CLASS (self);
632 if (G_UNLIKELY (self->priv->gnlobject != NULL))
633 goto already_have_gnlobject;
635 if (G_UNLIKELY (klass->gnlobject_factorytype == NULL))
638 GST_DEBUG ("Creating a supporting gnlobject of type '%s'",
639 klass->gnlobject_factorytype);
641 gnlobject = gst_element_factory_make (klass->gnlobject_factorytype, NULL);
643 if (G_UNLIKELY (gnlobject == NULL))
646 if (klass->create_element) {
647 GST_DEBUG ("Calling subclass 'create_element' vmethod");
648 child = klass->create_element (self);
650 if (G_UNLIKELY (!child))
653 if (!gst_bin_add (GST_BIN (gnlobject), child))
656 GST_DEBUG ("Succesfully got the element to put in the gnlobject");
657 self->priv->element = child;
666 already_have_gnlobject:
668 GST_ERROR ("Already controlling a GnlObject %s",
669 GST_ELEMENT_NAME (self->priv->gnlobject));
675 GST_ERROR ("No GESTrackObject::gnlobject_factorytype implementation!");
681 GST_ERROR ("Error creating a gnlobject of type '%s'",
682 klass->gnlobject_factorytype);
688 GST_ERROR ("create_element returned NULL");
689 gst_object_unref (gnlobject);
695 GST_ERROR ("Error adding the contents to the gnlobject");
696 gst_object_unref (child);
697 gst_object_unref (gnlobject);
703 ensure_gnl_object (GESTrackObject * object)
705 GESTrackObjectClass *class;
706 GstElement *gnlobject;
707 GHashTable *props_hash;
708 gboolean res = FALSE;
710 if (object->priv->gnlobject && object->priv->valid)
713 /* 1. Create the GnlObject */
714 GST_DEBUG ("Creating GnlObject");
716 class = GES_TRACK_OBJECT_GET_CLASS (object);
718 if (G_UNLIKELY (class->create_gnl_object == NULL)) {
719 GST_ERROR ("No 'create_gnl_object' implementation !");
723 GST_DEBUG ("Calling virtual method");
725 /* call the create_gnl_object virtual method */
726 gnlobject = class->create_gnl_object (object);
728 if (G_UNLIKELY (gnlobject == NULL)) {
730 ("'create_gnl_object' implementation returned TRUE but no GnlObject is available");
734 object->priv->gnlobject = gnlobject;
736 /* 2. Fill in the GnlObject */
738 GST_DEBUG ("Got a valid GnlObject, now filling it in");
741 ges_timeline_object_fill_track_object (object->priv->timelineobj,
742 object, object->priv->gnlobject);
744 /* Connect to property notifications */
745 /* FIXME : remember the signalids so we can remove them later on !!! */
746 g_signal_connect (G_OBJECT (object->priv->gnlobject), "notify::start",
747 G_CALLBACK (gnlobject_start_cb), object);
748 g_signal_connect (G_OBJECT (object->priv->gnlobject),
749 "notify::media-start", G_CALLBACK (gnlobject_media_start_cb), object);
750 g_signal_connect (G_OBJECT (object->priv->gnlobject), "notify::duration",
751 G_CALLBACK (gnlobject_duration_cb), object);
752 g_signal_connect (G_OBJECT (object->priv->gnlobject), "notify::priority",
753 G_CALLBACK (gnlobject_priority_cb), object);
754 g_signal_connect (G_OBJECT (object->priv->gnlobject), "notify::active",
755 G_CALLBACK (gnlobject_active_cb), object);
757 /* Set some properties on the GnlObject */
758 g_object_set (object->priv->gnlobject,
759 "caps", ges_track_get_caps (object->priv->track),
760 "duration", object->priv->pending_duration,
761 "media-duration", object->priv->pending_duration,
762 "start", object->priv->pending_start,
763 "media-start", object->priv->pending_inpoint,
764 "priority", object->priv->pending_priority,
765 "active", object->priv->pending_active, NULL);
767 /* We feed up the props_hashtable if possible */
768 if (class->get_props_hastable) {
769 props_hash = class->get_props_hastable (object);
771 if (props_hash == NULL) {
772 GST_DEBUG ("'get_props_hastable' implementation returned TRUE but no"
773 "properties_hashtable is available");
775 object->priv->properties_hashtable = props_hash;
776 connect_properties_signals (object);
783 object->priv->valid = res;
785 GST_DEBUG ("Returning res:%d", res);
792 ges_track_object_set_track (GESTrackObject * object, GESTrack * track)
794 GST_DEBUG ("object:%p, track:%p", object, track);
796 object->priv->track = track;
798 if (object->priv->track)
799 return ensure_gnl_object (object);
805 * ges_track_object_get_track:
806 * @object: a #GESTrackObject
808 * Get the #GESTrack to which this object belongs.
810 * Returns: (transfer none): The #GESTrack to which this object belongs. Can be %NULL if it
811 * is not in any track
814 ges_track_object_get_track (GESTrackObject * object)
816 g_return_val_if_fail (GES_IS_TRACK_OBJECT (object), NULL);
818 return object->priv->track;
823 ges_track_object_set_timeline_object (GESTrackObject * object,
824 GESTimelineObject * tlobj)
826 GST_DEBUG ("object:%p, timeline-object:%p", object, tlobj);
828 object->priv->timelineobj = tlobj;
832 * ges_track_object_get_timeline_object:
833 * @object: a #GESTrackObject
835 * Get the #GESTimelineObject which is controlling this track object
837 * Returns: (transfer none): the #GESTimelineObject which is controlling
841 ges_track_object_get_timeline_object (GESTrackObject * object)
843 g_return_val_if_fail (GES_IS_TRACK_OBJECT (object), NULL);
845 return object->priv->timelineobj;
849 * ges_track_object_get_gnlobject:
850 * @object: a #GESTrackObject
852 * Get the GNonLin object this object is controlling.
854 * Returns: (transfer none): the GNonLin object this object is controlling.
857 ges_track_object_get_gnlobject (GESTrackObject * object)
859 return object->priv->gnlobject;
863 * ges_track_object_get_element:
864 * @object: a #GESTrackObject
866 * Get the #GstElement this track object is controlling within GNonLin.
868 * Returns: (transfer none): the #GstElement this track object is controlling
872 ges_track_object_get_element (GESTrackObject * object)
874 return object->priv->element;
878 * ges_track_object_set_locked:
879 * @object: a #GESTrackObject
880 * @locked: whether the object is lock to its parent
882 * Set the locking status of the @object in relationship to its controlling
883 * #GESTimelineObject. If @locked is %TRUE, then this object will move synchronously
884 * with its controlling #GESTimelineObject.
887 ges_track_object_set_locked (GESTrackObject * object, gboolean locked)
889 object->priv->locked = locked;
893 * ges_track_object_is_locked:
894 * @object: a #GESTrackObject
896 * Let you know if object us locked or not (moving synchronously).
898 * Returns: %TRUE if the object is moving synchronously to its controlling
899 * #GESTimelineObject, else %FALSE.
902 ges_track_object_is_locked (GESTrackObject * object)
904 return object->priv->locked;
908 * ges_track_object_get_start:
909 * @object: a #GESTrackObject
911 * Get the position of the object in the container #GESTrack.
913 * Returns: the start position (in #GstClockTime)
916 ges_track_object_get_start (GESTrackObject * object)
918 if (G_UNLIKELY (object->priv->gnlobject == NULL))
919 return object->priv->pending_start;
921 return object->start;
925 * ges_track_object_get_inpoint:
926 * @object: a #GESTrackObject
928 * Get the offset within the contents of this #GESTrackObject
930 * Returns: the in-point (in #GstClockTime)
933 ges_track_object_get_inpoint (GESTrackObject * object)
935 if (G_UNLIKELY (object->priv->gnlobject == NULL))
936 return object->priv->pending_inpoint;
938 return object->inpoint;
942 * ges_track_object_get_duration:
943 * @object: a #GESTrackObject
945 * Get the duration which will be used in the container #GESTrack
946 * starting from the 'in-point'
948 * Returns: the duration (in #GstClockTime)
951 ges_track_object_get_duration (GESTrackObject * object)
953 if (G_UNLIKELY (object->priv->gnlobject == NULL))
954 return object->priv->pending_duration;
956 return object->duration;
960 * ges_track_object_get_priority:
961 * @object: a #GESTrackObject
963 * Get the priority of the object withing the containing #GESTrack.
965 * Returns: the priority of @object
968 ges_track_object_get_priority (GESTrackObject * object)
970 if (G_UNLIKELY (object->priv->gnlobject == NULL))
971 return object->priv->pending_priority;
973 return object->priority;
977 * ges_track_object_is_active:
978 * @object: a #GESTrackObject
980 * Lets you know if @object will be used for playback and rendering,
983 * Returns: %TRUE if @object is active, %FALSE otherwize
986 ges_track_object_is_active (GESTrackObject * object)
988 if (G_UNLIKELY (object->priv->gnlobject == NULL))
989 return object->priv->pending_active;
991 return object->active;
995 * ges_track_object_lookup_child:
996 * @object: object to lookup the property in
997 * @prop_name: name of the property to look up. You can specify the name of the
998 * class as such: ClassName::property-name, to guarantee that you get the
999 * proper GParamSpec in case various GstElement-s contain the same property
1000 * name. If you don't do so, you will get the first element found, having
1001 * this property and the and the corresponding GParamSpec.
1002 * @element: (out) (allow-none) (transfer full): pointer to a #GstElement that
1003 * takes the real object to set property on
1004 * @pspec: (out) (allow-none) (transfer full): pointer to take the #GParamSpec
1005 * describing the property
1007 * Looks up which @element and @pspec would be effected by the given @name. If various
1008 * contained elements have this property name you will get the first one, unless you
1009 * specify the class name in @name.
1011 * Returns: TRUE if @element and @pspec could be found. FALSE otherwise. In that
1012 * case the values for @pspec and @element are not modified. Unref @element after
1016 ges_track_object_lookup_child (GESTrackObject * object, const gchar * prop_name,
1017 GstElement ** element, GParamSpec ** pspec)
1019 GHashTableIter iter;
1020 gpointer key, value;
1021 gchar **names, *name, *classename;
1023 GESTrackObjectPrivate *priv = object->priv;
1028 names = g_strsplit (prop_name, "::", 2);
1029 if (names[1] != NULL) {
1030 classename = names[0];
1035 g_hash_table_iter_init (&iter, priv->properties_hashtable);
1036 while (g_hash_table_iter_next (&iter, &key, &value)) {
1037 if (g_strcmp0 (G_PARAM_SPEC (key)->name, name) == 0) {
1038 if (classename == NULL ||
1039 g_strcmp0 (G_OBJECT_TYPE_NAME (G_OBJECT (value)), classename) == 0) {
1040 GST_DEBUG ("The %s property from %s has been found in %s", name,
1041 classename, GST_OBJECT_NAME (GST_OBJECT (element)));
1043 *element = g_object_ref (value);
1045 *pspec = g_param_spec_ref (key);
1057 * ges_track_object_set_child_property_by_pspec:
1058 * @object: a #GESTrackObject
1059 * @pspec: The #GParamSpec that specifies the property you want to set
1062 * Sets a property of a child of @object.
1065 ges_track_object_set_child_property_by_pspec (GESTrackObject * object,
1066 GParamSpec * pspec, GValue * value)
1068 GstElement *element;
1070 GESTrackObjectPrivate *priv = object->priv;
1072 if (!priv->properties_hashtable)
1073 goto prop_hash_not_set;
1075 element = g_hash_table_lookup (priv->properties_hashtable, pspec);
1079 g_object_set_property (G_OBJECT (element), pspec->name, value);
1085 GST_ERROR ("The %s property doesn't exist", pspec->name);
1090 GST_DEBUG ("The child properties haven't been set on %p", object);
1096 * ges_track_object_set_child_property_valist:
1097 * @object: The #GESTrackObject parent object
1098 * @first_property_name: The name of the first property to set
1099 * @var_args: value for the first property, followed optionally by more
1100 * name/return location pairs, followed by NULL
1102 * Sets a property of a child of @object. If there are various child elements
1103 * that have the same property name, you can distinguish them using the following
1104 * synthaxe: 'ClasseName::property_name' as property name. If you don't, the
1105 * corresponding property of the first element found will be set.
1108 ges_track_object_set_child_property_valist (GESTrackObject * object,
1109 const gchar * first_property_name, va_list var_args)
1113 GstElement *element;
1115 gchar *error = NULL;
1116 GValue value = { 0, };
1118 g_return_if_fail (G_IS_OBJECT (object));
1120 name = first_property_name;
1122 /* Note: This part is in big part copied from the gst_child_object_set_valist
1125 /* iterate over pairs */
1127 if (!ges_track_object_lookup_child (object, name, &element, &pspec))
1130 #if GLIB_CHECK_VERSION(2,23,3)
1131 G_VALUE_COLLECT_INIT (&value, pspec->value_type, var_args,
1132 G_VALUE_NOCOPY_CONTENTS, &error);
1134 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1135 G_VALUE_COLLECT (&value, var_args, G_VALUE_NOCOPY_CONTENTS, &error);
1141 g_object_set_property (G_OBJECT (element), pspec->name, &value);
1143 g_object_unref (element);
1144 g_value_unset (&value);
1146 name = va_arg (var_args, gchar *);
1152 GST_WARNING ("No property %s in OBJECT\n", name);
1157 GST_WARNING ("error copying value %s in object %p: %s", pspec->name, object,
1159 g_value_unset (&value);
1165 * ges_track_object_set_child_property:
1166 * @object: The #GESTrackObject parent object
1167 * @first_property_name: The name of the first property to set
1168 * @...: value for the first property, followed optionally by more
1169 * name/return location pairs, followed by NULL
1171 * Sets a property of a child of @object. If there are various child elements
1172 * that have the same property name, you can distinguish them using the following
1173 * synthaxe: 'ClasseName::property_name' as property name. If you don't, the
1174 * corresponding property of the first element found will be set.
1177 ges_track_object_set_child_property (GESTrackObject * object,
1178 const gchar * first_property_name, ...)
1182 va_start (var_args, first_property_name);
1183 ges_track_object_set_child_property_valist (object, first_property_name,
1189 * ges_track_object_get_child_property_valist:
1190 * @object: The #GESTrackObject parent object
1191 * @first_property_name: The name of the first property to get
1192 * @var_args: value for the first property, followed optionally by more
1193 * name/return location pairs, followed by NULL
1195 * Gets a property of a child of @object. If there are various child elements
1196 * that have the same property name, you can distinguish them using the following
1197 * synthaxe: 'ClasseName::property_name' as property name. If you don't, the
1198 * corresponding property of the first element found will be set.
1201 ges_track_object_get_child_property_valist (GESTrackObject * object,
1202 const gchar * first_property_name, va_list var_args)
1205 gchar *error = NULL;
1206 GValue value = { 0, };
1208 GstElement *element;
1210 g_return_if_fail (G_IS_OBJECT (object));
1212 name = first_property_name;
1214 /* This part is in big part copied from the gst_child_object_get_valist method */
1216 if (!ges_track_object_lookup_child (object, name, &element, &pspec))
1219 g_value_init (&value, pspec->value_type);
1220 g_object_get_property (G_OBJECT (element), pspec->name, &value);
1221 g_object_unref (element);
1223 G_VALUE_LCOPY (&value, var_args, 0, &error);
1226 g_value_unset (&value);
1227 name = va_arg (var_args, gchar *);
1233 GST_WARNING ("no property %s in object", name);
1238 GST_WARNING ("error copying value %s in object %p: %s", pspec->name, object,
1240 g_value_unset (&value);
1246 * ges_track_object_list_children_properties:
1247 * @object: The #GESTrackObject to get the list of children properties from
1248 * @n_properties: return location for the length of the returned array
1250 * Gets an array of #GParamSpec* for all configurable properties of the
1251 * children of @object.
1253 * Returns: an array of #GParamSpec* which should be freed after use or %NULL
1254 * if something went wrong
1257 ges_track_object_list_children_properties (GESTrackObject * object,
1258 guint * n_properties)
1260 GESTrackObjectClass *class;
1261 class = GES_TRACK_OBJECT_GET_CLASS (object);
1263 return class->list_children_properties (object, n_properties);
1267 * ges_track_object_get_child_property:
1268 * @object: The origin #GESTrackObject
1269 * @first_property_name: The name of the first property to get
1270 * @...: return location for the first property, followed optionally by more
1271 * name/return location pairs, followed by NULL
1273 * Gets properties of a child of @object.
1276 ges_track_object_get_child_property (GESTrackObject * object,
1277 const gchar * first_property_name, ...)
1281 va_start (var_args, first_property_name);
1282 ges_track_object_get_child_property_valist (object, first_property_name,
1288 * ges_track_object_get_child_property_by_pspec:
1289 * @object: a #GESTrackObject
1290 * @pspec: The #GParamSpec that specifies the property you want to get
1291 * @value: return location for the value
1293 * Gets a property of a child of @object.
1296 ges_track_object_get_child_property_by_pspec (GESTrackObject * object,
1297 GParamSpec * pspec, GValue * value)
1299 GstElement *element;
1301 GESTrackObjectPrivate *priv = object->priv;
1303 if (!priv->properties_hashtable)
1304 goto prop_hash_not_set;
1306 element = g_hash_table_lookup (priv->properties_hashtable, pspec);
1310 g_object_get_property (G_OBJECT (element), pspec->name, value);
1316 GST_ERROR ("The %s property doesn't exist", pspec->name);
1321 GST_ERROR ("The child properties haven't been set on %p", object);
1327 default_list_children_properties (GESTrackObject * object, guint * n_properties)
1329 GParamSpec **pspec, *spec;
1330 GHashTableIter iter;
1331 gpointer key, value;
1335 if (!object->priv->properties_hashtable)
1336 goto prop_hash_not_set;
1338 *n_properties = g_hash_table_size (object->priv->properties_hashtable);
1339 pspec = g_new (GParamSpec *, *n_properties);
1341 g_hash_table_iter_init (&iter, object->priv->properties_hashtable);
1342 while (g_hash_table_iter_next (&iter, &key, &value)) {
1343 spec = G_PARAM_SPEC (key);
1344 pspec[i] = g_param_spec_ref (spec);
1352 GST_ERROR ("The child properties haven't been set on %p", object);