GesTrackObject: add the ges_track_object_get_child_property method
[platform/upstream/gstreamer.git] / ges / ges-track-object.c
1 /* GStreamer Editing Services
2  * Copyright (C) 2009 Edward Hervey <edward.hervey@collabora.co.uk>
3  *               2009 Nokia Corporation
4  *
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.
9  *
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.
14  *
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.
19  */
20
21 /**
22  * SECTION:ges-track-object
23  * @short_description: Base Class for objects contained in a #GESTrack
24  *
25  * #GESTrackObject is the Base Class for any object that can be contained in a
26  * #GESTrack.
27  *
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
30  * priority.
31  */
32
33 #include "ges-internal.h"
34 #include "ges-track-object.h"
35 #include "ges-timeline-object.h"
36
37 G_DEFINE_ABSTRACT_TYPE (GESTrackObject, ges_track_object,
38     G_TYPE_INITIALLY_UNOWNED);
39
40 struct _GESTrackObjectPrivate
41 {
42   /* These fields are only used before the gnlobject is available */
43   guint64 pending_start;
44   guint64 pending_inpoint;
45   guint64 pending_duration;
46   guint32 pending_priority;
47   gboolean pending_active;
48
49   GstElement *gnlobject;        /* The GnlObject */
50   GstElement *element;          /* The element contained in the gnlobject (can be NULL) */
51
52   /* We keep a link between properties name and elements internally
53    * The hashtable should look like
54    * {'ClassName-propertyName' ---> element,}*/
55   GHashTable *properties_hashtable;
56
57   GESTimelineObject *timelineobj;
58   GESTrack *track;
59
60   gboolean valid;
61
62   gboolean locked;              /* If TRUE, then moves in sync with its controlling
63                                  * GESTimelineObject */
64 };
65
66 enum
67 {
68   PROP_0,
69   PROP_START,
70   PROP_INPOINT,
71   PROP_DURATION,
72   PROP_PRIORITY,
73   PROP_ACTIVE,
74   PROP_LAST
75 };
76
77 static GParamSpec *properties[PROP_LAST];
78
79 static GstElement *ges_track_object_create_gnl_object_func (GESTrackObject *
80     object);
81
82 static void gnlobject_start_cb (GstElement * gnlobject, GParamSpec * arg
83     G_GNUC_UNUSED, GESTrackObject * obj);
84
85 static void gnlobject_media_start_cb (GstElement * gnlobject, GParamSpec * arg
86     G_GNUC_UNUSED, GESTrackObject * obj);
87
88 static void gnlobject_priority_cb (GstElement * gnlobject, GParamSpec * arg
89     G_GNUC_UNUSED, GESTrackObject * obj);
90
91 static void gnlobject_duration_cb (GstElement * gnlobject, GParamSpec * arg
92     G_GNUC_UNUSED, GESTrackObject * obj);
93
94 static void gnlobject_active_cb (GstElement * gnlobject, GParamSpec * arg
95     G_GNUC_UNUSED, GESTrackObject * obj);
96
97 static inline gboolean
98 ges_track_object_set_start_internal (GESTrackObject * object, guint64 start);
99 static inline gboolean
100 ges_track_object_set_inpoint_internal (GESTrackObject * object,
101     guint64 inpoint);
102 static inline gboolean ges_track_object_set_duration_internal (GESTrackObject *
103     object, guint64 duration);
104 static inline gboolean ges_track_object_set_priority_internal (GESTrackObject *
105     object, guint32 priority);
106
107 static void
108 ges_track_object_get_property (GObject * object, guint property_id,
109     GValue * value, GParamSpec * pspec)
110 {
111   GESTrackObject *tobj = GES_TRACK_OBJECT (object);
112
113   switch (property_id) {
114     case PROP_START:
115       g_value_set_uint64 (value, ges_track_object_get_start (tobj));
116       break;
117     case PROP_INPOINT:
118       g_value_set_uint64 (value, ges_track_object_get_inpoint (tobj));
119       break;
120     case PROP_DURATION:
121       g_value_set_uint64 (value, ges_track_object_get_duration (tobj));
122       break;
123     case PROP_PRIORITY:
124       g_value_set_uint (value, ges_track_object_get_priority (tobj));
125       break;
126     case PROP_ACTIVE:
127       g_value_set_boolean (value, ges_track_object_is_active (tobj));
128       break;
129     default:
130       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
131   }
132 }
133
134 static void
135 ges_track_object_set_property (GObject * object, guint property_id,
136     const GValue * value, GParamSpec * pspec)
137 {
138   GESTrackObject *tobj = GES_TRACK_OBJECT (object);
139
140   switch (property_id) {
141     case PROP_START:
142       ges_track_object_set_start_internal (tobj, g_value_get_uint64 (value));
143       break;
144     case PROP_INPOINT:
145       ges_track_object_set_inpoint_internal (tobj, g_value_get_uint64 (value));
146       break;
147     case PROP_DURATION:
148       ges_track_object_set_duration_internal (tobj, g_value_get_uint64 (value));
149       break;
150     case PROP_PRIORITY:
151       ges_track_object_set_priority_internal (tobj, g_value_get_uint (value));
152       break;
153     case PROP_ACTIVE:
154       ges_track_object_set_active (tobj, g_value_get_boolean (value));
155       break;
156     default:
157       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
158   }
159 }
160
161 static void
162 ges_track_object_dispose (GObject * object)
163 {
164   GESTrackObjectPrivate *priv = GES_TRACK_OBJECT (object)->priv;
165   if (priv->properties_hashtable)
166     g_hash_table_destroy (priv->properties_hashtable);
167
168   G_OBJECT_CLASS (ges_track_object_parent_class)->dispose (object);
169 }
170
171 static void
172 ges_track_object_finalize (GObject * object)
173 {
174   G_OBJECT_CLASS (ges_track_object_parent_class)->finalize (object);
175 }
176
177 static void
178 ges_track_object_class_init (GESTrackObjectClass * klass)
179 {
180   GObjectClass *object_class = G_OBJECT_CLASS (klass);
181
182   g_type_class_add_private (klass, sizeof (GESTrackObjectPrivate));
183
184   object_class->get_property = ges_track_object_get_property;
185   object_class->set_property = ges_track_object_set_property;
186   object_class->dispose = ges_track_object_dispose;
187   object_class->finalize = ges_track_object_finalize;
188
189   /**
190    * GESTrackObject:start
191    *
192    * The position of the object in the container #GESTrack (in nanoseconds).
193    */
194   properties[PROP_START] = g_param_spec_uint64 ("start", "Start",
195       "The position in the container", 0, G_MAXUINT64, 0, G_PARAM_READWRITE);
196   g_object_class_install_property (object_class, PROP_START,
197       properties[PROP_START]);
198
199   /**
200    * GESTrackObject:in-point
201    *
202    * The in-point at which this #GESTrackObject will start outputting data
203    * from its contents (in nanoseconds).
204    *
205    * Ex : an in-point of 5 seconds means that the first outputted buffer will
206    * be the one located 5 seconds in the controlled resource.
207    */
208   properties[PROP_INPOINT] =
209       g_param_spec_uint64 ("in-point", "In-point", "The in-point", 0,
210       G_MAXUINT64, 0, G_PARAM_READWRITE);
211   g_object_class_install_property (object_class, PROP_INPOINT,
212       properties[PROP_INPOINT]);
213
214   /**
215    * GESTrackObject:duration
216    *
217    * The duration (in nanoseconds) which will be used in the container #GESTrack
218    * starting from 'in-point'.
219    *
220    */
221   properties[PROP_DURATION] =
222       g_param_spec_uint64 ("duration", "Duration", "The duration to use", 0,
223       G_MAXUINT64, GST_SECOND, G_PARAM_READWRITE);
224   g_object_class_install_property (object_class, PROP_DURATION,
225       properties[PROP_DURATION]);
226
227   /**
228    * GESTrackObject:priority
229    *
230    * The priority of the object within the containing #GESTrack.
231    * If two objects intersect over the same region of time, the @priority
232    * property is used to decide which one takes precedence.
233    *
234    * The highest priority (that supercedes everything) is 0, and then lowering
235    * priorities go in increasing numerical value (with #G_MAXUINT64 being the
236    * lowest priority).
237    */
238   properties[PROP_PRIORITY] = g_param_spec_uint ("priority", "Priority",
239       "The priority of the object", 0, G_MAXUINT, 0, G_PARAM_READWRITE);
240   g_object_class_install_property (object_class, PROP_PRIORITY,
241       properties[PROP_PRIORITY]);
242
243   /**
244    * GESTrackObject:active
245    *
246    * Whether the object should be taken into account in the #GESTrack output.
247    * If #FALSE, then its contents will not be used in the resulting track.
248    */
249   properties[PROP_ACTIVE] =
250       g_param_spec_boolean ("active", "Active", "Use object in output", TRUE,
251       G_PARAM_READWRITE);
252   g_object_class_install_property (object_class, PROP_ACTIVE,
253       properties[PROP_ACTIVE]);
254
255   klass->create_gnl_object = ges_track_object_create_gnl_object_func;
256 }
257
258 static void
259 ges_track_object_init (GESTrackObject * self)
260 {
261   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
262       GES_TYPE_TRACK_OBJECT, GESTrackObjectPrivate);
263
264   /* Sane default values */
265   self->priv->pending_start = 0;
266   self->priv->pending_inpoint = 0;
267   self->priv->pending_duration = GST_SECOND;
268   self->priv->pending_priority = 1;
269   self->priv->pending_active = TRUE;
270   self->priv->locked = TRUE;
271   self->priv->properties_hashtable = NULL;
272 }
273
274 static inline gboolean
275 ges_track_object_set_start_internal (GESTrackObject * object, guint64 start)
276 {
277   GST_DEBUG ("object:%p, start:%" GST_TIME_FORMAT,
278       object, GST_TIME_ARGS (start));
279
280   if (object->priv->gnlobject != NULL) {
281     if (G_UNLIKELY (start == object->start))
282       return FALSE;
283
284     g_object_set (object->priv->gnlobject, "start", start, NULL);
285   } else
286     object->priv->pending_start = start;
287   return TRUE;
288 };
289
290 /**
291  * ges_track_object_set_start:
292  * @object: a #GESTrackObject
293  * @start: the start position (in #GstClockTime)
294  *
295  * Sets the position of the object in the container #GESTrack.
296  */
297 void
298 ges_track_object_set_start (GESTrackObject * object, guint64 start)
299 {
300   if (ges_track_object_set_start_internal (object, start))
301 #if GLIB_CHECK_VERSION(2,26,0)
302     g_object_notify_by_pspec (G_OBJECT (object), properties[PROP_START]);
303 #else
304     g_object_notify (G_OBJECT (object), "start");
305 #endif
306 }
307
308 static inline gboolean
309 ges_track_object_set_inpoint_internal (GESTrackObject * object, guint64 inpoint)
310 {
311
312   GST_DEBUG ("object:%p, inpoint:%" GST_TIME_FORMAT,
313       object, GST_TIME_ARGS (inpoint));
314
315   if (object->priv->gnlobject != NULL) {
316     if (G_UNLIKELY (inpoint == object->inpoint))
317       return FALSE;
318
319     g_object_set (object->priv->gnlobject, "media-start", inpoint, NULL);
320   } else
321     object->priv->pending_inpoint = inpoint;
322
323   return TRUE;
324 }
325
326 /**
327  * ges_track_object_set_inpoint:
328  * @object: a #GESTrackObject
329  * @inpoint: the in-point (in #GstClockTime)
330  *
331  * Set the offset within the contents of this #GESTrackObject
332  */
333 void
334 ges_track_object_set_inpoint (GESTrackObject * object, guint64 inpoint)
335 {
336   if (ges_track_object_set_inpoint_internal (object, inpoint))
337 #if GLIB_CHECK_VERSION(2,26,0)
338     g_object_notify_by_pspec (G_OBJECT (object), properties[PROP_INPOINT]);
339 #else
340     g_object_notify (G_OBJECT (object), "in-point");
341 #endif
342 }
343
344 static inline gboolean
345 ges_track_object_set_duration_internal (GESTrackObject * object,
346     guint64 duration)
347 {
348   GST_DEBUG ("object:%p, duration:%" GST_TIME_FORMAT,
349       object, GST_TIME_ARGS (duration));
350
351   if (object->priv->gnlobject != NULL) {
352     if (G_UNLIKELY (duration == object->duration))
353       return FALSE;
354
355     g_object_set (object->priv->gnlobject, "duration", duration,
356         "media-duration", duration, NULL);
357   } else
358     object->priv->pending_duration = duration;
359   return TRUE;
360 }
361
362 /**
363  * ges_track_object_set_duration:
364  * @object: a #GESTrackObject
365  * @duration: the duration (in #GstClockTime)
366  *
367  * Set the duration which will be used in the container #GESTrack
368  * starting from the 'in-point'
369  */
370 void
371 ges_track_object_set_duration (GESTrackObject * object, guint64 duration)
372 {
373   if (ges_track_object_set_duration_internal (object, duration))
374 #if GLIB_CHECK_VERSION(2,26,0)
375     g_object_notify_by_pspec (G_OBJECT (object), properties[PROP_DURATION]);
376 #else
377     g_object_notify (G_OBJECT (object), "duration");
378 #endif
379 }
380
381 static inline gboolean
382 ges_track_object_set_priority_internal (GESTrackObject * object,
383     guint32 priority)
384 {
385   GST_DEBUG ("object:%p, priority:%" G_GUINT32_FORMAT, object, priority);
386
387   if (object->priv->gnlobject != NULL) {
388     if (G_UNLIKELY (priority == object->priority))
389       return FALSE;
390
391     g_object_set (object->priv->gnlobject, "priority", priority, NULL);
392   } else
393     object->priv->pending_priority = priority;
394   return TRUE;
395 }
396
397 /**
398  * ges_track_object_set_priority:
399  * @object: a #GESTrackObject
400  * @priority: the priority
401  *
402  * Sets the priority of the object withing the containing #GESTrack.
403  * If two objects intersect over the same region of time, the priority
404  * property is used to decide which one takes precedence.
405  *
406  * The highest priority (that supercedes everything) is 0, and then
407  * lowering priorities go in increasing numerical value (with G_MAXUINT32
408  * being the lowest priority).
409  */
410 void
411 ges_track_object_set_priority (GESTrackObject * object, guint32 priority)
412 {
413   if (ges_track_object_set_priority_internal (object, priority))
414 #if GLIB_CHECK_VERSION(2,26,0)
415     g_object_notify_by_pspec (G_OBJECT (object), properties[PROP_PRIORITY]);
416 #else
417     g_object_notify (G_OBJECT (object), "priority");
418 #endif
419 }
420
421
422 /**
423  * ges_track_object_set_active:
424  * @object: a #GESTrackObject
425  * @active: visibility
426  *
427  * Sets the usage of the @object. If @active is %TRUE, the object will be used for
428  * playback and rendering, else it will be ignored.
429  *
430  * Returns: %TRUE if the property was toggled, else %FALSE
431  */
432 gboolean
433 ges_track_object_set_active (GESTrackObject * object, gboolean active)
434 {
435   GST_DEBUG ("object:%p, active:%d", object, active);
436
437   if (object->priv->gnlobject != NULL) {
438     if (G_UNLIKELY (active == object->active))
439       return FALSE;
440
441     g_object_set (object->priv->gnlobject, "active", active, NULL);
442   } else
443     object->priv->pending_active = active;
444   return TRUE;
445 }
446
447 /* Callbacks from the GNonLin object */
448 static void
449 gnlobject_start_cb (GstElement * gnlobject, GParamSpec * arg G_GNUC_UNUSED,
450     GESTrackObject * obj)
451 {
452   guint64 start;
453   GESTrackObjectClass *klass;
454
455   klass = GES_TRACK_OBJECT_GET_CLASS (obj);
456
457   g_object_get (gnlobject, "start", &start, NULL);
458
459   GST_DEBUG ("gnlobject start : %" GST_TIME_FORMAT " current : %"
460       GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (obj->start));
461
462   if (start != obj->start) {
463     obj->start = start;
464     if (klass->start_changed)
465       klass->start_changed (obj, start);
466   }
467 }
468
469 /* Callbacks from the GNonLin object */
470 static void
471 gnlobject_media_start_cb (GstElement * gnlobject,
472     GParamSpec * arg G_GNUC_UNUSED, GESTrackObject * obj)
473 {
474   guint64 start;
475   GESTrackObjectClass *klass;
476
477   klass = GES_TRACK_OBJECT_GET_CLASS (obj);
478
479   g_object_get (gnlobject, "media-start", &start, NULL);
480
481   GST_DEBUG ("gnlobject in-point : %" GST_TIME_FORMAT " current : %"
482       GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (obj->inpoint));
483
484   if (start != obj->inpoint) {
485     obj->inpoint = start;
486     if (klass->media_start_changed)
487       klass->media_start_changed (obj, start);
488   }
489 }
490
491 static void
492 gnlobject_priority_cb (GstElement * gnlobject, GParamSpec * arg G_GNUC_UNUSED,
493     GESTrackObject * obj)
494 {
495   guint32 priority;
496   GESTrackObjectClass *klass;
497
498   klass = GES_TRACK_OBJECT_GET_CLASS (obj);
499
500   g_object_get (gnlobject, "priority", &priority, NULL);
501
502   GST_DEBUG ("gnlobject priority : %d current : %d", priority, obj->priority);
503
504   if (priority != obj->priority) {
505     obj->priority = priority;
506     if (klass->gnl_priority_changed)
507       klass->gnl_priority_changed (obj, priority);
508   }
509 }
510
511 static void
512 gnlobject_duration_cb (GstElement * gnlobject, GParamSpec * arg G_GNUC_UNUSED,
513     GESTrackObject * obj)
514 {
515   guint64 duration;
516   GESTrackObjectClass *klass;
517
518   klass = GES_TRACK_OBJECT_GET_CLASS (obj);
519
520   g_object_get (gnlobject, "duration", &duration, NULL);
521
522   GST_DEBUG ("gnlobject duration : %" GST_TIME_FORMAT " current : %"
523       GST_TIME_FORMAT, GST_TIME_ARGS (duration), GST_TIME_ARGS (obj->duration));
524
525   if (duration != obj->duration) {
526     obj->duration = duration;
527     if (klass->duration_changed)
528       klass->duration_changed (obj, duration);
529   }
530 }
531
532 static void
533 gnlobject_active_cb (GstElement * gnlobject, GParamSpec * arg G_GNUC_UNUSED,
534     GESTrackObject * obj)
535 {
536   gboolean active;
537   GESTrackObjectClass *klass;
538
539   klass = GES_TRACK_OBJECT_GET_CLASS (obj);
540
541   g_object_get (gnlobject, "active", &active, NULL);
542
543   GST_DEBUG ("gnlobject active : %d current : %d", active, obj->active);
544
545   if (active != obj->active) {
546     obj->active = active;
547     if (klass->active_changed)
548       klass->active_changed (obj, active);
549   }
550 }
551
552
553 /* default 'create_gnl_object' virtual method implementation */
554 static GstElement *
555 ges_track_object_create_gnl_object_func (GESTrackObject * self)
556 {
557   GESTrackObjectClass *klass = NULL;
558   GstElement *child = NULL;
559   GstElement *gnlobject;
560
561   klass = GES_TRACK_OBJECT_GET_CLASS (self);
562
563   if (G_UNLIKELY (self->priv->gnlobject != NULL))
564     goto already_have_gnlobject;
565
566   if (G_UNLIKELY (klass->gnlobject_factorytype == NULL))
567     goto no_gnlfactory;
568
569   GST_DEBUG ("Creating a supporting gnlobject of type '%s'",
570       klass->gnlobject_factorytype);
571
572   gnlobject = gst_element_factory_make (klass->gnlobject_factorytype, NULL);
573
574   if (G_UNLIKELY (gnlobject == NULL))
575     goto no_gnlobject;
576
577   if (klass->create_element) {
578     GST_DEBUG ("Calling subclass 'create_element' vmethod");
579     child = klass->create_element (self);
580
581     if (G_UNLIKELY (!child))
582       goto child_failure;
583
584     if (!gst_bin_add (GST_BIN (gnlobject), child))
585       goto add_failure;
586
587     GST_DEBUG ("Succesfully got the element to put in the gnlobject");
588     self->priv->element = child;
589   }
590
591   GST_DEBUG ("done");
592   return gnlobject;
593
594
595   /* ERROR CASES */
596
597 already_have_gnlobject:
598   {
599     GST_ERROR ("Already controlling a GnlObject %s",
600         GST_ELEMENT_NAME (self->priv->gnlobject));
601     return NULL;
602   }
603
604 no_gnlfactory:
605   {
606     GST_ERROR ("No GESTrackObject::gnlobject_factorytype implementation!");
607     return NULL;
608   }
609
610 no_gnlobject:
611   {
612     GST_ERROR ("Error creating a gnlobject of type '%s'",
613         klass->gnlobject_factorytype);
614     return NULL;
615   }
616
617 child_failure:
618   {
619     GST_ERROR ("create_element returned NULL");
620     gst_object_unref (gnlobject);
621     return NULL;
622   }
623
624 add_failure:
625   {
626     GST_ERROR ("Error adding the contents to the gnlobject");
627     gst_object_unref (child);
628     gst_object_unref (gnlobject);
629     return NULL;
630   }
631 }
632
633 static gboolean
634 ensure_gnl_object (GESTrackObject * object)
635 {
636   GESTrackObjectClass *class;
637   GstElement *gnlobject;
638   GHashTable *props_hash;
639   gboolean res = FALSE;
640
641   if (object->priv->gnlobject && object->priv->valid)
642     return FALSE;
643
644   /* 1. Create the GnlObject */
645   GST_DEBUG ("Creating GnlObject");
646
647   class = GES_TRACK_OBJECT_GET_CLASS (object);
648
649   if (G_UNLIKELY (class->create_gnl_object == NULL)) {
650     GST_ERROR ("No 'create_gnl_object' implementation !");
651     goto done;
652   }
653
654   GST_DEBUG ("Calling virtual method");
655
656   /* call the create_gnl_object virtual method */
657   gnlobject = class->create_gnl_object (object);
658
659   if (G_UNLIKELY (gnlobject == NULL)) {
660     GST_ERROR
661         ("'create_gnl_object' implementation returned TRUE but no GnlObject is available");
662     goto done;
663   }
664
665   object->priv->gnlobject = gnlobject;
666
667   /* 2. Fill in the GnlObject */
668   if (gnlobject) {
669     GST_DEBUG ("Got a valid GnlObject, now filling it in");
670
671     res =
672         ges_timeline_object_fill_track_object (object->priv->timelineobj,
673         object, object->priv->gnlobject);
674     if (res) {
675       /* Connect to property notifications */
676       /* FIXME : remember the signalids so we can remove them later on !!! */
677       g_signal_connect (G_OBJECT (object->priv->gnlobject), "notify::start",
678           G_CALLBACK (gnlobject_start_cb), object);
679       g_signal_connect (G_OBJECT (object->priv->gnlobject),
680           "notify::media-start", G_CALLBACK (gnlobject_media_start_cb), object);
681       g_signal_connect (G_OBJECT (object->priv->gnlobject), "notify::duration",
682           G_CALLBACK (gnlobject_duration_cb), object);
683       g_signal_connect (G_OBJECT (object->priv->gnlobject), "notify::priority",
684           G_CALLBACK (gnlobject_priority_cb), object);
685       g_signal_connect (G_OBJECT (object->priv->gnlobject), "notify::active",
686           G_CALLBACK (gnlobject_active_cb), object);
687
688       /* Set some properties on the GnlObject */
689       g_object_set (object->priv->gnlobject,
690           "caps", ges_track_get_caps (object->priv->track),
691           "duration", object->priv->pending_duration,
692           "media-duration", object->priv->pending_duration,
693           "start", object->priv->pending_start,
694           "media-start", object->priv->pending_inpoint,
695           "priority", object->priv->pending_priority,
696           "active", object->priv->pending_active, NULL);
697
698       /*  We feed up the props_hashtable if possible */
699       if (class->get_props_hastable) {
700         props_hash = class->get_props_hastable (object);
701
702         if (props_hash == NULL) {
703           GST_DEBUG ("'get_props_hastable' implementation returned TRUE but no\
704                  properties_hashtable is available");
705         } else {
706           object->priv->properties_hashtable = props_hash;
707         }
708       }
709     }
710   }
711
712 done:
713   object->priv->valid = res;
714
715   GST_DEBUG ("Returning res:%d", res);
716
717   return res;
718 }
719
720 /* INTERNAL USAGE */
721 gboolean
722 ges_track_object_set_track (GESTrackObject * object, GESTrack * track)
723 {
724   GST_DEBUG ("object:%p, track:%p", object, track);
725
726   object->priv->track = track;
727
728   if (object->priv->track)
729     return ensure_gnl_object (object);
730
731   return TRUE;
732 }
733
734 /**
735  * ges_track_object_get_track:
736  * @object: a #GESTrackObject
737  *
738  * Get the #GESTrack to which this object belongs. 
739  *
740  * Returns: (transfer none): The #GESTrack to which this object belongs. Can be %NULL if it
741  * is not in any track
742  */
743 GESTrack *
744 ges_track_object_get_track (GESTrackObject * object)
745 {
746   g_return_val_if_fail (GES_IS_TRACK_OBJECT (object), NULL);
747
748   return object->priv->track;
749 }
750
751
752 void
753 ges_track_object_set_timeline_object (GESTrackObject * object,
754     GESTimelineObject * tlobj)
755 {
756   GST_DEBUG ("object:%p, timeline-object:%p", object, tlobj);
757
758   object->priv->timelineobj = tlobj;
759 }
760
761 /**
762  * ges_track_object_get_timeline_object:
763  * @object: a #GESTrackObject
764  *
765  * Get the #GESTimelineObject which is controlling this track object
766  *
767  * Returns: (transfer none): the #GESTimelineObject which is controlling
768  * this track object
769  */
770 GESTimelineObject *
771 ges_track_object_get_timeline_object (GESTrackObject * object)
772 {
773   g_return_val_if_fail (GES_IS_TRACK_OBJECT (object), NULL);
774
775   return object->priv->timelineobj;
776 }
777
778 /**
779  * ges_track_object_get_gnlobject:
780  * @object: a #GESTrackObject
781  *
782  * Get the GNonLin object this object is controlling.
783  *
784  * Returns: (transfer none): the GNonLin object this object is controlling.
785  */
786 GstElement *
787 ges_track_object_get_gnlobject (GESTrackObject * object)
788 {
789   return object->priv->gnlobject;
790 }
791
792 /**
793  * ges_track_object_get_element:
794  * @object: a #GESTrackObject
795  *
796  * Get the #GstElement this track object is controlling within GNonLin.
797  *
798  * Returns: (transfer none): the #GstElement this track object is controlling
799  * within GNonLin.
800  */
801 GstElement *
802 ges_track_object_get_element (GESTrackObject * object)
803 {
804   return object->priv->element;
805 }
806
807 /**
808  * ges_track_object_set_locked:
809  * @object: a #GESTrackObject
810  * @locked: whether the object is lock to its parent
811  *
812  * Set the locking status of the @object in relationship to its controlling
813  * #GESTimelineObject. If @locked is %TRUE, then this object will move synchronously
814  * with its controlling #GESTimelineObject.
815 */
816 void
817 ges_track_object_set_locked (GESTrackObject * object, gboolean locked)
818 {
819   object->priv->locked = locked;
820 }
821
822 /**
823  * ges_track_object_is_locked:
824  * @object: a #GESTrackObject
825  *
826  * Let you know if object us locked or not (moving synchronously).
827  *
828  * Returns: %TRUE if the object is moving synchronously to its controlling
829  * #GESTimelineObject, else %FALSE.
830  */
831 gboolean
832 ges_track_object_is_locked (GESTrackObject * object)
833 {
834   return object->priv->locked;
835 }
836
837 /**
838  * ges_track_object_get_start:
839  * @object: a #GESTrackObject
840  *
841  * Get the position of the object in the container #GESTrack.
842  *
843  * Returns: the start position (in #GstClockTime)
844  */
845 guint64
846 ges_track_object_get_start (GESTrackObject * object)
847 {
848   if (G_UNLIKELY (object->priv->gnlobject == NULL))
849     return object->priv->pending_start;
850   else
851     return object->start;
852 }
853
854 /**
855  * ges_track_object_get_inpoint:
856  * @object: a #GESTrackObject
857  *
858  * Get the offset within the contents of this #GESTrackObject
859  *
860  * Returns: the in-point (in #GstClockTime)
861  */
862 guint64
863 ges_track_object_get_inpoint (GESTrackObject * object)
864 {
865   if (G_UNLIKELY (object->priv->gnlobject == NULL))
866     return object->priv->pending_inpoint;
867   else
868     return object->inpoint;
869 }
870
871 /**
872  * ges_track_object_get_duration:
873  * @object: a #GESTrackObject
874  *
875  * Get the duration which will be used in the container #GESTrack
876  * starting from the 'in-point'
877  *
878  * Returns: the duration (in #GstClockTime)
879  */
880 guint64
881 ges_track_object_get_duration (GESTrackObject * object)
882 {
883   if (G_UNLIKELY (object->priv->gnlobject == NULL))
884     return object->priv->pending_duration;
885   else
886     return object->duration;
887 }
888
889 /**
890  * ges_track_object_get_priority:
891  * @object: a #GESTrackObject
892  *
893  * Get the priority of the object withing the containing #GESTrack.
894  *
895  * Returns: the priority of @object
896  */
897 guint32
898 ges_track_object_get_priority (GESTrackObject * object)
899 {
900   if (G_UNLIKELY (object->priv->gnlobject == NULL))
901     return object->priv->pending_priority;
902   else
903     return object->priority;
904 }
905
906 /**
907  * ges_track_object_is_active:
908  * @object: a #GESTrackObject
909  *
910  * Lets you know if @object will be used for playback and rendering,
911  * or not.
912  *
913  * Returns: %TRUE if @object is active, %FALSE otherwize
914  */
915 gboolean
916 ges_track_object_is_active (GESTrackObject * object)
917 {
918   if (G_UNLIKELY (object->priv->gnlobject == NULL))
919     return object->priv->pending_active;
920   else
921     return object->active;
922 }
923
924 /**
925  * ges_track_object_set_child_property:
926  * @object: a #GESTrackObject
927  * @property_name: The name of the property to set
928  * @value: the value
929  *
930  * Sets a property of a child of @object. The property name
931  * should look like ClasseName-property-name
932  */
933 void
934 ges_track_object_set_child_property (GESTrackObject * object,
935     const gchar * property_name, GValue * value)
936 {
937   GESTrackObjectPrivate *priv = object->priv;
938
939   if (priv->properties_hashtable) {
940     GstElement *element;
941     gchar **prop_name;
942
943     element = g_hash_table_lookup (priv->properties_hashtable, property_name);
944     if (element) {
945       prop_name = g_strsplit (property_name, "-", 2);
946       g_object_set_property (G_OBJECT (element), prop_name[1], value);
947       g_strfreev (prop_name);
948     } else {
949       GST_ERROR ("The %s property doesn't exist", property_name);
950     }
951   } else {
952     GST_DEBUG ("The child properties haven't been set on %p", object);
953   }
954 }
955
956 /**
957 * ges_track_object_get_child_property:
958 * @object: The origin #GESTrackObject
959 * @property_name: The name of the property
960 * @value: return location for the property value
961 *
962 * Gets a property of a child of @object.
963 */
964 void
965 ges_track_object_get_child_property (GESTrackObject * object,
966     const gchar * property_name, gpointer value)
967 {
968   GESTrackObjectPrivate *priv = object->priv;
969
970   if (priv->properties_hashtable) {
971     GstElement *element;
972     gchar **prop_name;
973
974     element = g_hash_table_lookup (priv->properties_hashtable, property_name);
975     if (element) {
976       prop_name = g_strsplit (property_name, "-", 2);
977       g_object_get (G_OBJECT (element), prop_name[1], value, NULL);
978       g_strfreev (prop_name);
979     } else {
980       GST_ERROR ("The %s property doesn't exist", property_name);
981     }
982   } else {
983     GST_DEBUG ("The child properties haven't been set on %p", object);
984   }
985 }