GESTrackObject: Fix debug statement
[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 static GQuark _start_quark;
38 static GQuark _inpoint_quark;
39 static GQuark _duration_quark;
40 static GQuark _priority_quark;
41
42 #define _do_init \
43 { \
44   _start_quark = g_quark_from_static_string ("start"); \
45   _inpoint_quark = g_quark_from_static_string ("inpoint"); \
46   _duration_quark = g_quark_from_static_string ("duration"); \
47   _priority_quark = g_quark_from_static_string ("priority"); \
48 }
49
50 G_DEFINE_TYPE_WITH_CODE (GESTrackObject, ges_track_object, G_TYPE_OBJECT,
51     _do_init);
52
53 enum
54 {
55   PROP_0,
56   PROP_START,
57   PROP_INPOINT,
58   PROP_DURATION,
59   PROP_PRIORITY,
60   PROP_PRIORITY_OFFSET,
61   PROP_ACTIVE
62 };
63
64 static gboolean
65 ges_track_object_create_gnl_object_func (GESTrackObject * object);
66
67 void gnlobject_start_cb (GstElement * gnlobject, GParamSpec * arg
68     G_GNUC_UNUSED, GESTrackObject * obj);
69
70 void gnlobject_media_start_cb (GstElement * gnlobject, GParamSpec * arg
71     G_GNUC_UNUSED, GESTrackObject * obj);
72
73 void gnlobject_priority_cb (GstElement * gnlobject, GParamSpec * arg
74     G_GNUC_UNUSED, GESTrackObject * obj);
75
76 void gnlobject_duration_cb (GstElement * gnlobject, GParamSpec * arg
77     G_GNUC_UNUSED, GESTrackObject * obj);
78
79 void gnlobject_active_cb (GstElement * gnlobject, GParamSpec * arg
80     G_GNUC_UNUSED, GESTrackObject * obj);
81
82 static gboolean ges_track_object_update_priority (GESTrackObject * object);
83
84 static void
85 ges_track_object_get_property (GObject * object, guint property_id,
86     GValue * value, GParamSpec * pspec)
87 {
88   GESTrackObject *tobj = GES_TRACK_OBJECT (object);
89
90   switch (property_id) {
91     case PROP_START:
92       g_value_set_uint64 (value, tobj->start);
93       break;
94     case PROP_INPOINT:
95       g_value_set_uint64 (value, tobj->inpoint);
96       break;
97     case PROP_DURATION:
98       g_value_set_uint64 (value, tobj->duration);
99       break;
100     case PROP_PRIORITY:
101       g_value_set_uint (value, tobj->base_priority);
102       break;
103     case PROP_PRIORITY_OFFSET:
104       g_value_set_uint (value, tobj->priority_offset);
105       break;
106     case PROP_ACTIVE:
107       g_value_set_boolean (value, tobj->active);
108       break;
109     default:
110       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
111   }
112 }
113
114 static void
115 ges_track_object_set_property (GObject * object, guint property_id,
116     const GValue * value, GParamSpec * pspec)
117 {
118   GESTrackObject *tobj = GES_TRACK_OBJECT (object);
119
120   switch (property_id) {
121     case PROP_START:
122       ges_track_object_set_start_internal (tobj, g_value_get_uint64 (value));
123       break;
124     case PROP_INPOINT:
125       ges_track_object_set_inpoint_internal (tobj, g_value_get_uint64 (value));
126       break;
127     case PROP_DURATION:
128       ges_track_object_set_duration_internal (tobj, g_value_get_uint64 (value));
129       break;
130     case PROP_PRIORITY:
131       ges_track_object_set_priority_internal (tobj, g_value_get_uint (value));
132       break;
133     case PROP_PRIORITY_OFFSET:
134       ges_track_object_set_priority_offset_internal (tobj, g_value_get_uint
135           (value));
136       break;
137     case PROP_ACTIVE:
138       ges_track_object_set_active (tobj, g_value_get_boolean (value));
139       break;
140     default:
141       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
142   }
143 }
144
145 static void
146 ges_track_object_dispose (GObject * object)
147 {
148   G_OBJECT_CLASS (ges_track_object_parent_class)->dispose (object);
149 }
150
151 static void
152 ges_track_object_finalize (GObject * object)
153 {
154   G_OBJECT_CLASS (ges_track_object_parent_class)->finalize (object);
155 }
156
157 static void
158 ges_track_object_class_init (GESTrackObjectClass * klass)
159 {
160   GObjectClass *object_class = G_OBJECT_CLASS (klass);
161
162   object_class->get_property = ges_track_object_get_property;
163   object_class->set_property = ges_track_object_set_property;
164   object_class->dispose = ges_track_object_dispose;
165   object_class->finalize = ges_track_object_finalize;
166
167   /**
168    * GESTrackObject:start
169    *
170    * The position of the object in the container #GESTrack (in nanoseconds).
171    */
172   g_object_class_install_property (object_class, PROP_START,
173       g_param_spec_uint64 ("start", "Start",
174           "The position in the container", 0, G_MAXUINT64, 0,
175           G_PARAM_READWRITE));
176
177   /**
178    * GESTrackObject:in-point
179    *
180    * The in-point at which this #GESTrackObject will start outputting data
181    * from its contents (in nanoseconds).
182    *
183    * Ex : an in-point of 5 seconds means that the first outputted buffer will
184    * be the one located 5 seconds in the controlled resource.
185    */
186   g_object_class_install_property (object_class, PROP_INPOINT,
187       g_param_spec_uint64 ("in-point", "In-point", "The in-point", 0,
188           G_MAXUINT64, 0, G_PARAM_READWRITE));
189
190   /**
191    * GESTrackObject:duration
192    *
193    * The duration (in nanoseconds) which will be used in the container #GESTrack
194    * starting from 'in-point'.
195    *
196    */
197   g_object_class_install_property (object_class, PROP_DURATION,
198       g_param_spec_uint64 ("duration", "Duration", "The duration to use",
199           0, G_MAXUINT64, GST_SECOND, G_PARAM_READWRITE));
200
201   /**
202    * GESTrackObject:priority
203    *
204    * The priority of the object within the containing #GESTrack.
205    * If two objects intersect over the same region of time, the @priority
206    * property is used to decide which one takes precedence.
207    *
208    * The highest priority (that supercedes everything) is 0, and then lowering
209    * priorities go in increasing numerical value (with #G_MAXUINT64 being the
210    * lowest priority).
211    */
212   g_object_class_install_property (object_class, PROP_PRIORITY,
213       g_param_spec_uint ("priority", "Priority",
214           "The priority of the object", 0, G_MAXUINT, 0, G_PARAM_READWRITE));
215
216   /**
217    * GESTrackObject:priority-offset
218    *
219    * The priority of the object relative to its parent track object.
220    */
221   g_object_class_install_property (object_class, PROP_PRIORITY_OFFSET,
222       g_param_spec_uint ("priority-offset", "Priority Offset",
223           "An offset from the base priority", 0, G_MAXUINT, 0,
224           G_PARAM_READWRITE));
225
226   /**
227    * GESTrackObject:active
228    *
229    * Whether the object should be taken into account in the #GESTrack output.
230    * If #FALSE, then its contents will not be used in the resulting track.
231    */
232   g_object_class_install_property (object_class, PROP_ACTIVE,
233       g_param_spec_boolean ("active", "Active", "Use object in output",
234           TRUE, G_PARAM_READWRITE));
235
236   klass->create_gnl_object = ges_track_object_create_gnl_object_func;
237 }
238
239 static void
240 ges_track_object_init (GESTrackObject * self)
241 {
242   /* Sane default values */
243   self->pending_start = 0;
244   self->pending_inpoint = 0;
245   self->pending_duration = GST_SECOND;
246   self->pending_gnl_priority = 1;
247   self->pending_active = TRUE;
248 }
249
250 gboolean
251 ges_track_object_set_start_internal (GESTrackObject * object, guint64 start)
252 {
253   GST_DEBUG ("object:%p, start:%" GST_TIME_FORMAT,
254       object, GST_TIME_ARGS (start));
255
256   if (object->gnlobject != NULL) {
257     if (G_UNLIKELY (start == object->start))
258       return FALSE;
259
260     g_object_set (object->gnlobject, "start", start, NULL);
261   } else
262     object->pending_start = start;
263   return TRUE;
264 };
265
266 gboolean
267 ges_track_object_set_inpoint_internal (GESTrackObject * object, guint64 inpoint)
268 {
269
270   GST_DEBUG ("object:%p, inpoint:%" GST_TIME_FORMAT,
271       object, GST_TIME_ARGS (inpoint));
272
273   if (object->gnlobject != NULL) {
274     if (G_UNLIKELY (inpoint == object->inpoint))
275       return FALSE;
276
277     g_object_set (object->gnlobject, "media-start", inpoint, NULL);
278   } else
279     object->pending_inpoint = inpoint;
280
281   return TRUE;
282 }
283
284 gboolean
285 ges_track_object_set_duration_internal (GESTrackObject * object,
286     guint64 duration)
287 {
288   GST_DEBUG ("object:%p, duration:%" GST_TIME_FORMAT,
289       object, GST_TIME_ARGS (duration));
290
291   if (object->gnlobject != NULL) {
292     if (G_UNLIKELY (duration == object->duration))
293       return FALSE;
294
295     g_object_set (object->gnlobject, "duration", duration, "media-duration",
296         duration, NULL);
297   } else
298     object->pending_duration = duration;
299   return TRUE;
300 }
301
302 /* NOTE: we handle priority differently than other properties! the gnlpriority
303  * is object->base_priority + object->priority_offset! A change to either one
304  * will trigger an update to the gnonlin priority and a subsequent property
305  * notification. 
306  */
307
308 gboolean
309 ges_track_object_set_priority_internal (GESTrackObject * object,
310     guint32 priority)
311 {
312   guint32 save;
313   save = object->base_priority;
314   GST_DEBUG ("object:%p, priority:%d", object, priority);
315
316   object->base_priority = priority;
317   if (!ges_track_object_update_priority (object)) {
318     object->base_priority = save;
319     return FALSE;
320   }
321   return TRUE;
322 }
323
324 gboolean
325 ges_track_object_set_priority_offset_internal (GESTrackObject * object,
326     guint32 priority_offset)
327 {
328   guint32 save;
329   save = object->priority_offset;
330   GST_DEBUG ("object:%p, offset:%d", object, priority_offset);
331
332   object->priority_offset = priority_offset;
333   if (!ges_track_object_update_priority (object)) {
334     object->base_priority = save;
335     return FALSE;
336   }
337   return TRUE;
338 }
339
340 static gboolean
341 ges_track_object_update_priority (GESTrackObject * object)
342 {
343   guint32 priority, offset, gnl;
344   priority = object->base_priority;
345   offset = object->priority_offset;
346   gnl = priority + offset;
347   GST_DEBUG ("object:%p, base:%d, offset:%d: gnl:%d", object, priority, offset,
348       gnl);
349
350   if (object->gnlobject != NULL) {
351     if (G_UNLIKELY (gnl == object->gnl_priority))
352       return FALSE;
353
354     g_object_set (object->gnlobject, "priority", gnl, NULL);
355   } else
356     object->pending_gnl_priority = gnl;
357   return TRUE;
358 }
359
360 gboolean
361 ges_track_object_set_active (GESTrackObject * object, gboolean active)
362 {
363   GST_DEBUG ("object:%p, active:%d", object, active);
364
365   if (object->gnlobject != NULL) {
366     if (G_UNLIKELY (active == object->active))
367       return FALSE;
368
369     g_object_set (object->gnlobject, "active", active, NULL);
370   } else
371     object->pending_active = active;
372   return TRUE;
373 }
374
375 /* Callbacks from the GNonLin object */
376 void
377 gnlobject_start_cb (GstElement * gnlobject, GParamSpec * arg G_GNUC_UNUSED,
378     GESTrackObject * obj)
379 {
380   guint64 start;
381   GESTrackObjectClass *klass;
382
383   klass = GES_TRACK_OBJECT_GET_CLASS (obj);
384
385   g_object_get (gnlobject, "start", &start, NULL);
386
387   GST_DEBUG ("gnlobject start : %" GST_TIME_FORMAT " current : %"
388       GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (obj->start));
389
390   if (start != obj->start) {
391     obj->start = start;
392     if (klass->start_changed)
393       klass->start_changed (obj, start);
394     /* FIXME : emit changed */
395   }
396 }
397
398 /* Callbacks from the GNonLin object */
399 void
400 gnlobject_media_start_cb (GstElement * gnlobject,
401     GParamSpec * arg G_GNUC_UNUSED, GESTrackObject * obj)
402 {
403   guint64 start;
404   GESTrackObjectClass *klass;
405
406   klass = GES_TRACK_OBJECT_GET_CLASS (obj);
407
408   g_object_get (gnlobject, "media-start", &start, NULL);
409
410   GST_DEBUG ("gnlobject in-point : %" GST_TIME_FORMAT " current : %"
411       GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (obj->inpoint));
412
413   if (start != obj->inpoint) {
414     obj->inpoint = start;
415     if (klass->media_start_changed)
416       klass->media_start_changed (obj, start);
417     /* FIXME : emit changed */
418   }
419 }
420
421 void
422 gnlobject_priority_cb (GstElement * gnlobject, GParamSpec * arg G_GNUC_UNUSED,
423     GESTrackObject * obj)
424 {
425   guint32 priority;
426   GESTrackObjectClass *klass;
427
428   klass = GES_TRACK_OBJECT_GET_CLASS (obj);
429
430   g_object_get (gnlobject, "priority", &priority, NULL);
431
432   GST_DEBUG ("gnlobject priority : %d current : %d", priority,
433       obj->gnl_priority);
434
435   if (priority != obj->gnl_priority) {
436     obj->gnl_priority = priority;
437     if (klass->gnl_priority_changed)
438       klass->gnl_priority_changed (obj, priority);
439     /* FIXME : emit changed */
440   }
441 }
442
443 void
444 gnlobject_duration_cb (GstElement * gnlobject, GParamSpec * arg G_GNUC_UNUSED,
445     GESTrackObject * obj)
446 {
447   guint64 duration;
448   GESTrackObjectClass *klass;
449
450   klass = GES_TRACK_OBJECT_GET_CLASS (obj);
451
452   g_object_get (gnlobject, "duration", &duration, NULL);
453
454   GST_DEBUG ("gnlobject duration : %" GST_TIME_FORMAT " current : %"
455       GST_TIME_FORMAT, GST_TIME_ARGS (duration), GST_TIME_ARGS (obj->duration));
456
457   if (duration != obj->duration) {
458     obj->duration = duration;
459     if (klass->duration_changed)
460       klass->duration_changed (obj, duration);
461     /* FIXME : emit changed */
462   }
463 }
464
465 void
466 gnlobject_active_cb (GstElement * gnlobject, GParamSpec * arg G_GNUC_UNUSED,
467     GESTrackObject * obj)
468 {
469   gboolean active;
470   GESTrackObjectClass *klass;
471
472   klass = GES_TRACK_OBJECT_GET_CLASS (obj);
473
474   g_object_get (gnlobject, "active", &active, NULL);
475
476   GST_DEBUG ("gnlobject active : %d current : %d", active, obj->active);
477
478   if (active != obj->active) {
479     obj->active = active;
480     if (klass->active_changed)
481       klass->active_changed (obj, active);
482     /* FIXME : emit changed */
483   }
484 }
485
486
487 /* default 'create_gnl_object' virtual method implementation */
488 static gboolean
489 ges_track_object_create_gnl_object_func (GESTrackObject * object)
490 {
491
492   return FALSE;
493 }
494
495 static gboolean
496 ensure_gnl_object (GESTrackObject * object)
497 {
498   GESTrackObjectClass *class;
499   gboolean res;
500
501   if (object->gnlobject && object->valid)
502     return TRUE;
503
504   /* 1. Create the GnlObject */
505   GST_DEBUG ("Creating GnlObject");
506
507   class = GES_TRACK_OBJECT_GET_CLASS (object);
508
509   if (G_UNLIKELY (class->create_gnl_object == NULL)) {
510     GST_ERROR ("No 'create_gnl_object' implementation !");
511     return FALSE;
512   }
513
514   GST_DEBUG ("Calling virtual method");
515
516   /* call the create_gnl_object virtual method */
517   res = class->create_gnl_object (object);
518
519   if (G_UNLIKELY (res && (object->gnlobject == NULL))) {
520     GST_ERROR
521         ("'create_gnl_object' implementation returned TRUE but no GnlObject is available");
522     return FALSE;
523   }
524
525   /* Connect to property notifications */
526   g_signal_connect (G_OBJECT (object->gnlobject), "notify::start",
527       G_CALLBACK (gnlobject_start_cb), object);
528   g_signal_connect (G_OBJECT (object->gnlobject), "notify::media-start",
529       G_CALLBACK (gnlobject_media_start_cb), object);
530   g_signal_connect (G_OBJECT (object->gnlobject), "notify::duration",
531       G_CALLBACK (gnlobject_duration_cb), object);
532   g_signal_connect (G_OBJECT (object->gnlobject), "notify::priority",
533       G_CALLBACK (gnlobject_priority_cb), object);
534   g_signal_connect (G_OBJECT (object->gnlobject), "notify::active",
535       G_CALLBACK (gnlobject_active_cb), object);
536
537   /* 2. Fill in the GnlObject */
538   if (res) {
539     GST_DEBUG ("Got a valid GnlObject, now filling it in");
540
541     res =
542         ges_timeline_object_fill_track_object (object->timelineobj, object,
543         object->gnlobject);
544     if (res) {
545       /* Set some properties on the GnlObject */
546       g_object_set (object->gnlobject,
547           "caps", object->track->caps,
548           "duration", object->pending_duration,
549           "media-duration", object->pending_duration,
550           "start", object->pending_start,
551           "media-start", object->pending_inpoint,
552           "priority", object->pending_gnl_priority,
553           "active", object->pending_active, NULL);
554
555     }
556   }
557
558   object->valid = res;
559
560   GST_DEBUG ("Returning res:%d", res);
561
562   return res;
563 }
564
565 gboolean
566 ges_track_object_set_track (GESTrackObject * object, GESTrack * track)
567 {
568   GST_DEBUG ("object:%p, track:%p", object, track);
569
570   object->track = track;
571
572   if (object->track)
573     return ensure_gnl_object (object);
574
575   return TRUE;
576 }
577
578 void
579 ges_track_object_set_timeline_object (GESTrackObject * object,
580     GESTimelineObject * tlobj)
581 {
582   GST_DEBUG ("object:%p, timeline-object:%p", object, tlobj);
583
584   object->timelineobj = tlobj;
585 }