TrackObject: Small cleanup
[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   GESTimelineObject *timelineobj;
53   GESTrack *track;
54
55   gboolean valid;
56
57   gboolean locked;              /* If TRUE, then moves in sync with its controlling
58                                  * GESTimelineObject */
59 };
60
61 enum
62 {
63   PROP_0,
64   PROP_START,
65   PROP_INPOINT,
66   PROP_DURATION,
67   PROP_PRIORITY,
68   PROP_ACTIVE,
69   PROP_LAST
70 };
71
72 static GParamSpec *properties[PROP_LAST];
73
74 static GstElement *ges_track_object_create_gnl_object_func (GESTrackObject *
75     object);
76
77 void gnlobject_start_cb (GstElement * gnlobject, GParamSpec * arg
78     G_GNUC_UNUSED, GESTrackObject * obj);
79
80 void gnlobject_media_start_cb (GstElement * gnlobject, GParamSpec * arg
81     G_GNUC_UNUSED, GESTrackObject * obj);
82
83 void gnlobject_priority_cb (GstElement * gnlobject, GParamSpec * arg
84     G_GNUC_UNUSED, GESTrackObject * obj);
85
86 void gnlobject_duration_cb (GstElement * gnlobject, GParamSpec * arg
87     G_GNUC_UNUSED, GESTrackObject * obj);
88
89 void gnlobject_active_cb (GstElement * gnlobject, GParamSpec * arg
90     G_GNUC_UNUSED, GESTrackObject * obj);
91
92 static inline gboolean
93 ges_track_object_set_start_internal (GESTrackObject * object, guint64 start);
94 static inline gboolean
95 ges_track_object_set_inpoint_internal (GESTrackObject * object,
96     guint64 inpoint);
97 static inline gboolean ges_track_object_set_duration_internal (GESTrackObject *
98     object, guint64 duration);
99 static inline gboolean ges_track_object_set_priority_internal (GESTrackObject *
100     object, guint32 priority);
101
102 static void
103 ges_track_object_get_property (GObject * object, guint property_id,
104     GValue * value, GParamSpec * pspec)
105 {
106   GESTrackObject *tobj = GES_TRACK_OBJECT (object);
107
108   switch (property_id) {
109     case PROP_START:
110       g_value_set_uint64 (value, tobj->start);
111       break;
112     case PROP_INPOINT:
113       g_value_set_uint64 (value, tobj->inpoint);
114       break;
115     case PROP_DURATION:
116       g_value_set_uint64 (value, tobj->duration);
117       break;
118     case PROP_PRIORITY:
119       g_value_set_uint (value, tobj->priority);
120       break;
121     case PROP_ACTIVE:
122       g_value_set_boolean (value, tobj->active);
123       break;
124     default:
125       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
126   }
127 }
128
129 static void
130 ges_track_object_set_property (GObject * object, guint property_id,
131     const GValue * value, GParamSpec * pspec)
132 {
133   GESTrackObject *tobj = GES_TRACK_OBJECT (object);
134
135   switch (property_id) {
136     case PROP_START:
137       ges_track_object_set_start_internal (tobj, g_value_get_uint64 (value));
138       break;
139     case PROP_INPOINT:
140       ges_track_object_set_inpoint_internal (tobj, g_value_get_uint64 (value));
141       break;
142     case PROP_DURATION:
143       ges_track_object_set_duration_internal (tobj, g_value_get_uint64 (value));
144       break;
145     case PROP_PRIORITY:
146       ges_track_object_set_priority_internal (tobj, g_value_get_uint (value));
147       break;
148     case PROP_ACTIVE:
149       ges_track_object_set_active (tobj, g_value_get_boolean (value));
150       break;
151     default:
152       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
153   }
154 }
155
156 static void
157 ges_track_object_dispose (GObject * object)
158 {
159   G_OBJECT_CLASS (ges_track_object_parent_class)->dispose (object);
160 }
161
162 static void
163 ges_track_object_finalize (GObject * object)
164 {
165   G_OBJECT_CLASS (ges_track_object_parent_class)->finalize (object);
166 }
167
168 static void
169 ges_track_object_class_init (GESTrackObjectClass * klass)
170 {
171   GObjectClass *object_class = G_OBJECT_CLASS (klass);
172
173   g_type_class_add_private (klass, sizeof (GESTrackObjectPrivate));
174
175   object_class->get_property = ges_track_object_get_property;
176   object_class->set_property = ges_track_object_set_property;
177   object_class->dispose = ges_track_object_dispose;
178   object_class->finalize = ges_track_object_finalize;
179
180   /**
181    * GESTrackObject:start
182    *
183    * The position of the object in the container #GESTrack (in nanoseconds).
184    */
185   properties[PROP_START] = g_param_spec_uint64 ("start", "Start",
186       "The position in the container", 0, G_MAXUINT64, 0, G_PARAM_READWRITE);
187   g_object_class_install_property (object_class, PROP_START,
188       properties[PROP_START]);
189
190   /**
191    * GESTrackObject:in-point
192    *
193    * The in-point at which this #GESTrackObject will start outputting data
194    * from its contents (in nanoseconds).
195    *
196    * Ex : an in-point of 5 seconds means that the first outputted buffer will
197    * be the one located 5 seconds in the controlled resource.
198    */
199   properties[PROP_INPOINT] =
200       g_param_spec_uint64 ("in-point", "In-point", "The in-point", 0,
201       G_MAXUINT64, 0, G_PARAM_READWRITE);
202   g_object_class_install_property (object_class, PROP_INPOINT,
203       properties[PROP_INPOINT]);
204
205   /**
206    * GESTrackObject:duration
207    *
208    * The duration (in nanoseconds) which will be used in the container #GESTrack
209    * starting from 'in-point'.
210    *
211    */
212   properties[PROP_DURATION] =
213       g_param_spec_uint64 ("duration", "Duration", "The duration to use", 0,
214       G_MAXUINT64, GST_SECOND, G_PARAM_READWRITE);
215   g_object_class_install_property (object_class, PROP_DURATION,
216       properties[PROP_DURATION]);
217
218   /**
219    * GESTrackObject:priority
220    *
221    * The priority of the object within the containing #GESTrack.
222    * If two objects intersect over the same region of time, the @priority
223    * property is used to decide which one takes precedence.
224    *
225    * The highest priority (that supercedes everything) is 0, and then lowering
226    * priorities go in increasing numerical value (with #G_MAXUINT64 being the
227    * lowest priority).
228    */
229   properties[PROP_PRIORITY] = g_param_spec_uint ("priority", "Priority",
230       "The priority of the object", 0, G_MAXUINT, 0, G_PARAM_READWRITE);
231   g_object_class_install_property (object_class, PROP_PRIORITY,
232       properties[PROP_PRIORITY]);
233
234   /**
235    * GESTrackObject:active
236    *
237    * Whether the object should be taken into account in the #GESTrack output.
238    * If #FALSE, then its contents will not be used in the resulting track.
239    */
240   properties[PROP_ACTIVE] =
241       g_param_spec_boolean ("active", "Active", "Use object in output", TRUE,
242       G_PARAM_READWRITE);
243   g_object_class_install_property (object_class, PROP_ACTIVE,
244       properties[PROP_ACTIVE]);
245
246   klass->create_gnl_object = ges_track_object_create_gnl_object_func;
247 }
248
249 static void
250 ges_track_object_init (GESTrackObject * self)
251 {
252   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
253       GES_TYPE_TRACK_OBJECT, GESTrackObjectPrivate);
254
255   /* Sane default values */
256   self->priv->pending_start = 0;
257   self->priv->pending_inpoint = 0;
258   self->priv->pending_duration = GST_SECOND;
259   self->priv->pending_priority = 1;
260   self->priv->pending_active = TRUE;
261   self->priv->locked = TRUE;
262 }
263
264 static inline gboolean
265 ges_track_object_set_start_internal (GESTrackObject * object, guint64 start)
266 {
267   GST_DEBUG ("object:%p, start:%" GST_TIME_FORMAT,
268       object, GST_TIME_ARGS (start));
269
270   if (object->priv->gnlobject != NULL) {
271     if (G_UNLIKELY (start == object->start))
272       return FALSE;
273
274     g_object_set (object->priv->gnlobject, "start", start, NULL);
275   } else
276     object->priv->pending_start = start;
277   return TRUE;
278 };
279
280 /**
281  * ges_track_object_set_start:
282  * @object: a #GESTrackObject
283  * @start: the start position (in #GstClockTime)
284  *
285  * Sets the position of the object in the container #GESTrack.
286  */
287 void
288 ges_track_object_set_start (GESTrackObject * object, guint64 start)
289 {
290   if (ges_track_object_set_start_internal (object, start))
291 #if GLIB_CHECK_VERSION(2,26,0)
292     g_object_notify_by_pspec (G_OBJECT (object), properties[PROP_START]);
293 #else
294     g_object_notify (G_OBJECT (object), "start");
295 #endif
296 }
297
298 static inline gboolean
299 ges_track_object_set_inpoint_internal (GESTrackObject * object, guint64 inpoint)
300 {
301
302   GST_DEBUG ("object:%p, inpoint:%" GST_TIME_FORMAT,
303       object, GST_TIME_ARGS (inpoint));
304
305   if (object->priv->gnlobject != NULL) {
306     if (G_UNLIKELY (inpoint == object->inpoint))
307       return FALSE;
308
309     g_object_set (object->priv->gnlobject, "media-start", inpoint, NULL);
310   } else
311     object->priv->pending_inpoint = inpoint;
312
313   return TRUE;
314 }
315
316 /**
317  * ges_track_object_set_inpoint:
318  * @object: a #GESTrackObject
319  * @inpoint: the in-point (in #GstClockTime)
320  *
321  * Set the offset within the contents of this #GESTrackObject
322  */
323 void
324 ges_track_object_set_inpoint (GESTrackObject * object, guint64 inpoint)
325 {
326   if (ges_track_object_set_inpoint_internal (object, inpoint))
327 #if GLIB_CHECK_VERSION(2,26,0)
328     g_object_notify_by_pspec (G_OBJECT (object), properties[PROP_INPOINT]);
329 #else
330     g_object_notify (G_OBJECT (object), "in-point");
331 #endif
332 }
333
334 static inline gboolean
335 ges_track_object_set_duration_internal (GESTrackObject * object,
336     guint64 duration)
337 {
338   GST_DEBUG ("object:%p, duration:%" GST_TIME_FORMAT,
339       object, GST_TIME_ARGS (duration));
340
341   if (object->priv->gnlobject != NULL) {
342     if (G_UNLIKELY (duration == object->duration))
343       return FALSE;
344
345     g_object_set (object->priv->gnlobject, "duration", duration,
346         "media-duration", duration, NULL);
347   } else
348     object->priv->pending_duration = duration;
349   return TRUE;
350 }
351
352 /**
353  * ges_track_object_set_duration:
354  * @object: a #GESTrackObject
355  * @duration: the duration (in #GstClockTime)
356  *
357  * Set the duration which will be used in the container #GESTrack
358  * starting from the 'in-point'
359  */
360 void
361 ges_track_object_set_duration (GESTrackObject * object, guint64 duration)
362 {
363   if (ges_track_object_set_duration_internal (object, duration))
364 #if GLIB_CHECK_VERSION(2,26,0)
365     g_object_notify_by_pspec (G_OBJECT (object), properties[PROP_DURATION]);
366 #else
367     g_object_notify (G_OBJECT (object), "duration");
368 #endif
369 }
370
371 static inline gboolean
372 ges_track_object_set_priority_internal (GESTrackObject * object,
373     guint32 priority)
374 {
375   GST_DEBUG ("object:%p, priority:%" GST_TIME_FORMAT,
376       object, GST_TIME_ARGS (priority));
377
378   if (object->priv->gnlobject != NULL) {
379     if (G_UNLIKELY (priority == object->priority))
380       return FALSE;
381
382     g_object_set (object->priv->gnlobject, "priority", priority, NULL);
383   } else
384     object->priv->pending_priority = priority;
385   return TRUE;
386 }
387
388 /**
389  * ges_track_object_set_priority:
390  * @object: a #GESTrackObject
391  * @priority: the priority
392  *
393  * Sets the priority of the object withing the containing #GESTrack.
394  * If two objects intersect over the same region of time, the priority
395  * property is used to decide which one takes precedence.
396  *
397  * The highest priority (that supercedes everything) is 0, and then
398  * lowering priorities go in increasing numerical value (with G_MAXUINT32
399  * being the lowest priority).
400  */
401 void
402 ges_track_object_set_priority (GESTrackObject * object, guint32 priority)
403 {
404   if (ges_track_object_set_priority_internal (object, priority))
405 #if GLIB_CHECK_VERSION(2,26,0)
406     g_object_notify_by_pspec (G_OBJECT (object), properties[PROP_PRIORITY]);
407 #else
408     g_object_notify (G_OBJECT (object), "priority");
409 #endif
410 }
411
412
413 /**
414  * ges_track_object_set_active:
415  * @object: a #GESTrackObject
416  * @active: visibility
417  *
418  * Sets the usage of the @object. If @active is %TRUE, the object will be used for
419  * playback and rendering, else it will be ignored.
420  *
421  * Returns: %TRUE if the property was toggled, else %FALSE
422  */
423 gboolean
424 ges_track_object_set_active (GESTrackObject * object, gboolean active)
425 {
426   GST_DEBUG ("object:%p, active:%d", object, active);
427
428   if (object->priv->gnlobject != NULL) {
429     if (G_UNLIKELY (active == object->active))
430       return FALSE;
431
432     g_object_set (object->priv->gnlobject, "active", active, NULL);
433   } else
434     object->priv->pending_active = active;
435   return TRUE;
436 }
437
438 /* Callbacks from the GNonLin object */
439 void
440 gnlobject_start_cb (GstElement * gnlobject, GParamSpec * arg G_GNUC_UNUSED,
441     GESTrackObject * obj)
442 {
443   guint64 start;
444   GESTrackObjectClass *klass;
445
446   klass = GES_TRACK_OBJECT_GET_CLASS (obj);
447
448   g_object_get (gnlobject, "start", &start, NULL);
449
450   GST_DEBUG ("gnlobject start : %" GST_TIME_FORMAT " current : %"
451       GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (obj->start));
452
453   if (start != obj->start) {
454     obj->start = start;
455     if (klass->start_changed)
456       klass->start_changed (obj, start);
457   }
458 }
459
460 /* Callbacks from the GNonLin object */
461 void
462 gnlobject_media_start_cb (GstElement * gnlobject,
463     GParamSpec * arg G_GNUC_UNUSED, GESTrackObject * obj)
464 {
465   guint64 start;
466   GESTrackObjectClass *klass;
467
468   klass = GES_TRACK_OBJECT_GET_CLASS (obj);
469
470   g_object_get (gnlobject, "media-start", &start, NULL);
471
472   GST_DEBUG ("gnlobject in-point : %" GST_TIME_FORMAT " current : %"
473       GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (obj->inpoint));
474
475   if (start != obj->inpoint) {
476     obj->inpoint = start;
477     if (klass->media_start_changed)
478       klass->media_start_changed (obj, start);
479   }
480 }
481
482 void
483 gnlobject_priority_cb (GstElement * gnlobject, GParamSpec * arg G_GNUC_UNUSED,
484     GESTrackObject * obj)
485 {
486   guint32 priority;
487   GESTrackObjectClass *klass;
488
489   klass = GES_TRACK_OBJECT_GET_CLASS (obj);
490
491   g_object_get (gnlobject, "priority", &priority, NULL);
492
493   GST_DEBUG ("gnlobject priority : %d current : %d", priority, obj->priority);
494
495   if (priority != obj->priority) {
496     obj->priority = priority;
497     if (klass->gnl_priority_changed)
498       klass->gnl_priority_changed (obj, priority);
499   }
500 }
501
502 void
503 gnlobject_duration_cb (GstElement * gnlobject, GParamSpec * arg G_GNUC_UNUSED,
504     GESTrackObject * obj)
505 {
506   guint64 duration;
507   GESTrackObjectClass *klass;
508
509   klass = GES_TRACK_OBJECT_GET_CLASS (obj);
510
511   g_object_get (gnlobject, "duration", &duration, NULL);
512
513   GST_DEBUG ("gnlobject duration : %" GST_TIME_FORMAT " current : %"
514       GST_TIME_FORMAT, GST_TIME_ARGS (duration), GST_TIME_ARGS (obj->duration));
515
516   if (duration != obj->duration) {
517     obj->duration = duration;
518     if (klass->duration_changed)
519       klass->duration_changed (obj, duration);
520   }
521 }
522
523 void
524 gnlobject_active_cb (GstElement * gnlobject, GParamSpec * arg G_GNUC_UNUSED,
525     GESTrackObject * obj)
526 {
527   gboolean active;
528   GESTrackObjectClass *klass;
529
530   klass = GES_TRACK_OBJECT_GET_CLASS (obj);
531
532   g_object_get (gnlobject, "active", &active, NULL);
533
534   GST_DEBUG ("gnlobject active : %d current : %d", active, obj->active);
535
536   if (active != obj->active) {
537     obj->active = active;
538     if (klass->active_changed)
539       klass->active_changed (obj, active);
540   }
541 }
542
543
544 /* default 'create_gnl_object' virtual method implementation */
545 static GstElement *
546 ges_track_object_create_gnl_object_func (GESTrackObject * self)
547 {
548   GESTrackObjectClass *klass = NULL;
549   GstElement *child = NULL;
550   GstElement *gnlobject;
551
552   klass = GES_TRACK_OBJECT_GET_CLASS (self);
553
554   if (G_UNLIKELY (self->priv->gnlobject != NULL))
555     goto already_have_gnlobject;
556
557   if (G_UNLIKELY (klass->gnlobject_factorytype == NULL))
558     goto no_gnlfactory;
559
560   GST_DEBUG ("Creating a supporting gnlobject of type '%s'",
561       klass->gnlobject_factorytype);
562
563   gnlobject = gst_element_factory_make (klass->gnlobject_factorytype, NULL);
564
565   if (G_UNLIKELY (gnlobject == NULL))
566     goto no_gnlobject;
567
568   if (klass->create_element) {
569     GST_DEBUG ("Calling subclass 'create_element' vmethod");
570     child = klass->create_element (self);
571
572     if (G_UNLIKELY (!child))
573       goto child_failure;
574
575     if (!gst_bin_add (GST_BIN (gnlobject), child))
576       goto add_failure;
577
578     GST_DEBUG ("Succesfully got the element to put in the gnlobject");
579     self->priv->element = child;
580   }
581
582   GST_DEBUG ("done");
583   return gnlobject;
584
585
586   /* ERROR CASES */
587
588 already_have_gnlobject:
589   {
590     GST_ERROR ("Already controlling a GnlObject %s",
591         GST_ELEMENT_NAME (self->priv->gnlobject));
592     return NULL;
593   }
594
595 no_gnlfactory:
596   {
597     GST_ERROR ("No GESTrackObject::gnlobject_factorytype implementation!");
598     return NULL;
599   }
600
601 no_gnlobject:
602   {
603     GST_ERROR ("Error creating a gnlobject of type '%s'",
604         klass->gnlobject_factorytype);
605     return NULL;
606   }
607
608 child_failure:
609   {
610     GST_ERROR ("create_element returned NULL");
611     gst_object_unref (gnlobject);
612     return NULL;
613   }
614
615 add_failure:
616   {
617     GST_ERROR ("Error adding the contents to the gnlobject");
618     gst_object_unref (child);
619     gst_object_unref (gnlobject);
620     return NULL;
621   }
622 }
623
624 static gboolean
625 ensure_gnl_object (GESTrackObject * object)
626 {
627   GESTrackObjectClass *class;
628   GstElement *gnlobject;
629   gboolean res = FALSE;
630
631   if (object->priv->gnlobject && object->priv->valid)
632     return FALSE;
633
634   /* 1. Create the GnlObject */
635   GST_DEBUG ("Creating GnlObject");
636
637   class = GES_TRACK_OBJECT_GET_CLASS (object);
638
639   if (G_UNLIKELY (class->create_gnl_object == NULL)) {
640     GST_ERROR ("No 'create_gnl_object' implementation !");
641     goto done;
642   }
643
644   GST_DEBUG ("Calling virtual method");
645
646   /* call the create_gnl_object virtual method */
647   gnlobject = class->create_gnl_object (object);
648
649   if (G_UNLIKELY (gnlobject == NULL)) {
650     GST_ERROR
651         ("'create_gnl_object' implementation returned TRUE but no GnlObject is available");
652     goto done;
653   }
654
655   object->priv->gnlobject = gnlobject;
656
657   /* 2. Fill in the GnlObject */
658   if (gnlobject) {
659     GST_DEBUG ("Got a valid GnlObject, now filling it in");
660
661     res =
662         ges_timeline_object_fill_track_object (object->priv->timelineobj,
663         object, object->priv->gnlobject);
664     if (res) {
665       /* Connect to property notifications */
666       /* FIXME : remember the signalids so we can remove them later on !!! */
667       g_signal_connect (G_OBJECT (object->priv->gnlobject), "notify::start",
668           G_CALLBACK (gnlobject_start_cb), object);
669       g_signal_connect (G_OBJECT (object->priv->gnlobject),
670           "notify::media-start", G_CALLBACK (gnlobject_media_start_cb), object);
671       g_signal_connect (G_OBJECT (object->priv->gnlobject), "notify::duration",
672           G_CALLBACK (gnlobject_duration_cb), object);
673       g_signal_connect (G_OBJECT (object->priv->gnlobject), "notify::priority",
674           G_CALLBACK (gnlobject_priority_cb), object);
675       g_signal_connect (G_OBJECT (object->priv->gnlobject), "notify::active",
676           G_CALLBACK (gnlobject_active_cb), object);
677
678       /* Set some properties on the GnlObject */
679       g_object_set (object->priv->gnlobject,
680           "caps", ges_track_get_caps (object->priv->track),
681           "duration", object->priv->pending_duration,
682           "media-duration", object->priv->pending_duration,
683           "start", object->priv->pending_start,
684           "media-start", object->priv->pending_inpoint,
685           "priority", object->priv->pending_priority,
686           "active", object->priv->pending_active, NULL);
687
688     }
689   }
690
691 done:
692   object->priv->valid = res;
693
694   GST_DEBUG ("Returning res:%d", res);
695
696   return res;
697 }
698
699 /* INTERNAL USAGE */
700 gboolean
701 ges_track_object_set_track (GESTrackObject * object, GESTrack * track)
702 {
703   GST_DEBUG ("object:%p, track:%p", object, track);
704
705   object->priv->track = track;
706
707   if (object->priv->track)
708     return ensure_gnl_object (object);
709
710   return TRUE;
711 }
712
713 /**
714  * ges_track_object_get_track:
715  * @object: a #GESTrackObject
716  *
717  * Returns: (transfer none): The #GESTrack to which this object belongs. Can be %NULL if it
718  * is not in any track
719  */
720 GESTrack *
721 ges_track_object_get_track (GESTrackObject * object)
722 {
723   g_return_val_if_fail (GES_IS_TRACK_OBJECT (object), NULL);
724
725   return object->priv->track;
726 }
727
728
729 void
730 ges_track_object_set_timeline_object (GESTrackObject * object,
731     GESTimelineObject * tlobj)
732 {
733   GST_DEBUG ("object:%p, timeline-object:%p", object, tlobj);
734
735   object->priv->timelineobj = tlobj;
736 }
737
738 /**
739  * ges_track_object_get_timeline_object:
740  * @object: a #GESTrackObject
741  *
742  * Returns: (transfer none): the #GESTimelineObject which is controlling
743  * this track object
744  */
745 GESTimelineObject *
746 ges_track_object_get_timeline_object (GESTrackObject * object)
747 {
748   g_return_val_if_fail (GES_IS_TRACK_OBJECT (object), NULL);
749
750   return object->priv->timelineobj;
751 }
752
753 /**
754  * ges_track_object_get_gnlobject:
755  * @object: a #GESTrackObject
756  *
757  * Returns: (transfer none): the GNonLin object this object is controlling.
758  */
759 GstElement *
760 ges_track_object_get_gnlobject (GESTrackObject * object)
761 {
762   return object->priv->gnlobject;
763 }
764
765 /**
766  * ges_track_object_get_element:
767  * @object: a #GESTrackObject
768  *
769  * Returns: (transfer none): the #GstElement this track object is controlling
770  * within GNonLin.
771  */
772 GstElement *
773 ges_track_object_get_element (GESTrackObject * object)
774 {
775   return object->priv->element;
776 }
777
778 /**
779  * ges_track_object_set_locked:
780  * @object: a #GESTrackObject
781  * @locked: whether the object is lock to its parent
782  *
783  * Set the locking status of the @object in relationship to its controlling
784  * #GESTimelineObject. If @locked is %TRUE, then this object will move synchronously
785  * with its controlling #GESTimelineObject.
786 */
787 void
788 ges_track_object_set_locked (GESTrackObject * object, gboolean locked)
789 {
790   object->priv->locked = locked;
791 }
792
793 /**
794  * ges_track_object_is_locked:
795  * @object: a #GESTrackObject
796  *
797  * Returns: %TRUE if the object is moving synchronously to its controlling
798  * #GESTimelineObject, else %FALSE.
799  */
800 gboolean
801 ges_track_object_is_locked (GESTrackObject * object)
802 {
803   return object->priv->locked;
804 }