1 /* GStreamer Editing Services
2 * Copyright (C) 2009 Edward Hervey <edward.hervey@collabora.co.uk>
3 * 2009 Nokia Corporation
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * SECTION:ges-track-object
23 * @short_description: Base Class for objects contained in a #GESTrack
25 * #GESTrackObject is the Base Class for any object that can be contained in a
28 * It contains the basic information as to the location of the object within
29 * its container, like the start position, the in-point, the duration and the
33 #include "ges-internal.h"
34 #include "ges-track-object.h"
35 #include "ges-timeline-object.h"
37 static GQuark _start_quark;
38 static GQuark _inpoint_quark;
39 static GQuark _duration_quark;
40 static GQuark _priority_quark;
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"); \
50 G_DEFINE_TYPE_WITH_CODE (GESTrackObject, ges_track_object, G_TYPE_OBJECT,
65 ges_track_object_create_gnl_object_func (GESTrackObject * object);
67 void gnlobject_start_cb (GstElement * gnlobject, GParamSpec * arg
68 G_GNUC_UNUSED, GESTrackObject * obj);
70 void gnlobject_media_start_cb (GstElement * gnlobject, GParamSpec * arg
71 G_GNUC_UNUSED, GESTrackObject * obj);
73 void gnlobject_priority_cb (GstElement * gnlobject, GParamSpec * arg
74 G_GNUC_UNUSED, GESTrackObject * obj);
76 void gnlobject_duration_cb (GstElement * gnlobject, GParamSpec * arg
77 G_GNUC_UNUSED, GESTrackObject * obj);
79 void gnlobject_active_cb (GstElement * gnlobject, GParamSpec * arg
80 G_GNUC_UNUSED, GESTrackObject * obj);
82 static gboolean ges_track_object_update_priority (GESTrackObject * object);
85 ges_track_object_get_property (GObject * object, guint property_id,
86 GValue * value, GParamSpec * pspec)
88 GESTrackObject *tobj = GES_TRACK_OBJECT (object);
90 switch (property_id) {
92 g_value_set_uint64 (value, tobj->start);
95 g_value_set_uint64 (value, tobj->inpoint);
98 g_value_set_uint64 (value, tobj->duration);
101 g_value_set_uint (value, tobj->base_priority);
103 case PROP_PRIORITY_OFFSET:
104 g_value_set_uint (value, tobj->priority_offset);
107 g_value_set_boolean (value, tobj->active);
110 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
115 ges_track_object_set_property (GObject * object, guint property_id,
116 const GValue * value, GParamSpec * pspec)
118 GESTrackObject *tobj = GES_TRACK_OBJECT (object);
120 switch (property_id) {
122 ges_track_object_set_start_internal (tobj, g_value_get_uint64 (value));
125 ges_track_object_set_inpoint_internal (tobj, g_value_get_uint64 (value));
128 ges_track_object_set_duration_internal (tobj, g_value_get_uint64 (value));
131 ges_track_object_set_priority_internal (tobj, g_value_get_uint (value));
133 case PROP_PRIORITY_OFFSET:
134 ges_track_object_set_priority_offset_internal (tobj, g_value_get_uint
138 ges_track_object_set_active (tobj, g_value_get_boolean (value));
141 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
146 ges_track_object_dispose (GObject * object)
148 G_OBJECT_CLASS (ges_track_object_parent_class)->dispose (object);
152 ges_track_object_finalize (GObject * object)
154 G_OBJECT_CLASS (ges_track_object_parent_class)->finalize (object);
158 ges_track_object_class_init (GESTrackObjectClass * klass)
160 GObjectClass *object_class = G_OBJECT_CLASS (klass);
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;
168 * GESTrackObject:start
170 * The position of the object in the container #GESTrack (in nanoseconds).
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,
178 * GESTrackObject:in-point
180 * The in-point at which this #GESTrackObject will start outputting data
181 * from its contents (in nanoseconds).
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.
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));
191 * GESTrackObject:duration
193 * The duration (in nanoseconds) which will be used in the container #GESTrack
194 * starting from 'in-point'.
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));
202 * GESTrackObject:priority
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.
208 * The highest priority (that supercedes everything) is 0, and then lowering
209 * priorities go in increasing numerical value (with #G_MAXUINT64 being the
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));
217 * GESTrackObject:priority-offset
219 * The priority of the object relative to its parent track object.
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,
227 * GESTrackObject:active
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.
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));
236 klass->create_gnl_object = ges_track_object_create_gnl_object_func;
240 ges_track_object_init (GESTrackObject * self)
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;
251 ges_track_object_set_start_internal (GESTrackObject * object, guint64 start)
253 GST_DEBUG ("object:%p, start:%" GST_TIME_FORMAT,
254 object, GST_TIME_ARGS (start));
256 if (object->gnlobject != NULL) {
257 if (G_UNLIKELY (start == object->start))
260 g_object_set (object->gnlobject, "start", start, NULL);
262 object->pending_start = start;
267 ges_track_object_set_inpoint_internal (GESTrackObject * object, guint64 inpoint)
270 GST_DEBUG ("object:%p, inpoint:%" GST_TIME_FORMAT,
271 object, GST_TIME_ARGS (inpoint));
273 if (object->gnlobject != NULL) {
274 if (G_UNLIKELY (inpoint == object->inpoint))
277 g_object_set (object->gnlobject, "media-start", inpoint, NULL);
279 object->pending_inpoint = inpoint;
285 ges_track_object_set_duration_internal (GESTrackObject * object,
288 GST_DEBUG ("object:%p, duration:%" GST_TIME_FORMAT,
289 object, GST_TIME_ARGS (duration));
291 if (object->gnlobject != NULL) {
292 if (G_UNLIKELY (duration == object->duration))
295 g_object_set (object->gnlobject, "duration", duration, "media-duration",
298 object->pending_duration = duration;
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
309 ges_track_object_set_priority_internal (GESTrackObject * object,
313 save = object->base_priority;
314 GST_DEBUG ("object:%p, priority:%d", object, priority);
316 object->base_priority = priority;
317 if (!ges_track_object_update_priority (object)) {
318 object->base_priority = save;
325 ges_track_object_set_priority_offset_internal (GESTrackObject * object,
326 guint32 priority_offset)
329 save = object->priority_offset;
330 GST_DEBUG ("object:%p, offset:%d", object, priority_offset);
332 object->priority_offset = priority_offset;
333 if (!ges_track_object_update_priority (object)) {
334 object->base_priority = save;
341 ges_track_object_update_priority (GESTrackObject * object)
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,
350 if (object->gnlobject != NULL) {
351 if (G_UNLIKELY (gnl == object->gnl_priority))
354 g_object_set (object->gnlobject, "priority", gnl, NULL);
356 object->pending_gnl_priority = gnl;
361 ges_track_object_set_active (GESTrackObject * object, gboolean active)
363 GST_DEBUG ("object:%p, active:%d", object, active);
365 if (object->gnlobject != NULL) {
366 if (G_UNLIKELY (active == object->active))
369 g_object_set (object->gnlobject, "active", active, NULL);
371 object->pending_active = active;
375 /* Callbacks from the GNonLin object */
377 gnlobject_start_cb (GstElement * gnlobject, GParamSpec * arg G_GNUC_UNUSED,
378 GESTrackObject * obj)
381 GESTrackObjectClass *klass;
383 klass = GES_TRACK_OBJECT_GET_CLASS (obj);
385 g_object_get (gnlobject, "start", &start, NULL);
387 GST_DEBUG ("gnlobject start : %" GST_TIME_FORMAT " current : %"
388 GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (obj->start));
390 if (start != obj->start) {
392 if (klass->start_changed)
393 klass->start_changed (obj, start);
394 /* FIXME : emit changed */
398 /* Callbacks from the GNonLin object */
400 gnlobject_media_start_cb (GstElement * gnlobject,
401 GParamSpec * arg G_GNUC_UNUSED, GESTrackObject * obj)
404 GESTrackObjectClass *klass;
406 klass = GES_TRACK_OBJECT_GET_CLASS (obj);
408 g_object_get (gnlobject, "media-start", &start, NULL);
410 GST_DEBUG ("gnlobject in-point : %" GST_TIME_FORMAT " current : %"
411 GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (obj->inpoint));
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 */
422 gnlobject_priority_cb (GstElement * gnlobject, GParamSpec * arg G_GNUC_UNUSED,
423 GESTrackObject * obj)
426 GESTrackObjectClass *klass;
428 klass = GES_TRACK_OBJECT_GET_CLASS (obj);
430 g_object_get (gnlobject, "priority", &priority, NULL);
432 GST_DEBUG ("gnlobject priority : %d current : %d", priority,
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 */
444 gnlobject_duration_cb (GstElement * gnlobject, GParamSpec * arg G_GNUC_UNUSED,
445 GESTrackObject * obj)
448 GESTrackObjectClass *klass;
450 klass = GES_TRACK_OBJECT_GET_CLASS (obj);
452 g_object_get (gnlobject, "duration", &duration, NULL);
454 GST_DEBUG ("gnlobject duration : %" GST_TIME_FORMAT " current : %"
455 GST_TIME_FORMAT, GST_TIME_ARGS (duration), GST_TIME_ARGS (obj->duration));
457 if (duration != obj->duration) {
458 obj->duration = duration;
459 if (klass->duration_changed)
460 klass->duration_changed (obj, duration);
461 /* FIXME : emit changed */
466 gnlobject_active_cb (GstElement * gnlobject, GParamSpec * arg G_GNUC_UNUSED,
467 GESTrackObject * obj)
470 GESTrackObjectClass *klass;
472 klass = GES_TRACK_OBJECT_GET_CLASS (obj);
474 g_object_get (gnlobject, "active", &active, NULL);
476 GST_DEBUG ("gnlobject active : %d current : %d", active, obj->active);
478 if (active != obj->active) {
479 obj->active = active;
480 if (klass->active_changed)
481 klass->active_changed (obj, active);
482 /* FIXME : emit changed */
487 /* default 'create_gnl_object' virtual method implementation */
489 ges_track_object_create_gnl_object_func (GESTrackObject * object)
496 ensure_gnl_object (GESTrackObject * object)
498 GESTrackObjectClass *class;
501 if (object->gnlobject && object->valid)
504 /* 1. Create the GnlObject */
505 GST_DEBUG ("Creating GnlObject");
507 class = GES_TRACK_OBJECT_GET_CLASS (object);
509 if (G_UNLIKELY (class->create_gnl_object == NULL)) {
510 GST_ERROR ("No 'create_gnl_object' implementation !");
514 GST_DEBUG ("Calling virtual method");
516 /* call the create_gnl_object virtual method */
517 res = class->create_gnl_object (object);
519 if (G_UNLIKELY (res && (object->gnlobject == NULL))) {
521 ("'create_gnl_object' implementation returned TRUE but no GnlObject is available");
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);
537 /* 2. Fill in the GnlObject */
539 GST_DEBUG ("Got a valid GnlObject, now filling it in");
542 ges_timeline_object_fill_track_object (object->timelineobj, object,
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);
560 GST_DEBUG ("Returning res:%d", res);
566 ges_track_object_set_track (GESTrackObject * object, GESTrack * track)
568 GST_DEBUG ("object:%p, track:%p", object, track);
570 object->track = track;
573 return ensure_gnl_object (object);
579 ges_track_object_set_timeline_object (GESTrackObject * object,
580 GESTimelineObject * tlobj)
582 GST_DEBUG ("object:%p, timeline-object:%p", object, tlobj);
584 object->timelineobj = tlobj;