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., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 /**
22 * SECTION:gestrackelement
23 * @title: GESTrackElement
24 * @short_description: Base Class for objects contained in a GESTrack
25 *
26 * #GESTrackElement is the Base Class for any object that can be contained in a
27 * #GESTrack.
28 *
29 * It contains the basic information as to the location of the object within
30 * its container, like the start position, the inpoint, the duration and the
31 * priority.
32 */
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36
37 #include "ges-internal.h"
38 #include "ges-extractable.h"
39 #include "ges-track-element.h"
40 #include "ges-clip.h"
41 #include "ges-meta-container.h"
42
43 struct _GESTrackElementPrivate
44 {
45 GESTrackType track_type;
46
47 GstElement *nleobject; /* The NleObject */
48 GstElement *element; /* The element contained in the nleobject (can be NULL) */
49
50 GESTrack *track;
51
52 gboolean locked; /* If TRUE, then moves in sync with its controlling
53 * GESClip */
54
55 GHashTable *bindings_hashtable; /* We need this if we want to be able to serialize
56 and deserialize keyframes */
57 };
58
59 enum
60 {
61 PROP_0,
62 PROP_ACTIVE,
63 PROP_TRACK_TYPE,
64 PROP_TRACK,
65 PROP_LAST
66 };
67
68 static GParamSpec *properties[PROP_LAST];
69
70 enum
71 {
72 CONTROL_BINDING_ADDED,
73 CONTROL_BINDING_REMOVED,
74 LAST_SIGNAL
75 };
76
77 static guint ges_track_element_signals[LAST_SIGNAL] = { 0 };
78
79 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GESTrackElement, ges_track_element,
80 GES_TYPE_TIMELINE_ELEMENT);
81
82 static GstElement *ges_track_element_create_gnl_object_func (GESTrackElement *
83 object);
84
85 static gboolean _set_start (GESTimelineElement * element, GstClockTime start);
86 static gboolean _set_inpoint (GESTimelineElement * element,
87 GstClockTime inpoint);
88 static gboolean _set_duration (GESTimelineElement * element,
89 GstClockTime duration);
90 static gboolean _set_priority (GESTimelineElement * element, guint32 priority);
91 GESTrackType _get_track_types (GESTimelineElement * object);
92
93 static GParamSpec **default_list_children_properties (GESTrackElement * object,
94 guint * n_properties);
95
96 static void
97 _update_control_bindings (GESTimelineElement * element, GstClockTime inpoint,
98 GstClockTime duration);
99
100 static gboolean
_lookup_child(GESTrackElement * object,const gchar * prop_name,GstElement ** element,GParamSpec ** pspec)101 _lookup_child (GESTrackElement * object,
102 const gchar * prop_name, GstElement ** element, GParamSpec ** pspec)
103 {
104 return
105 GES_TIMELINE_ELEMENT_GET_CLASS (object)->lookup_child
106 (GES_TIMELINE_ELEMENT (object), prop_name, (GObject **) element, pspec);
107 }
108
109 static gboolean
strv_find_str(const gchar ** strv,const char * str)110 strv_find_str (const gchar ** strv, const char *str)
111 {
112 guint i;
113
114 if (strv == NULL)
115 return FALSE;
116
117 for (i = 0; strv[i]; i++) {
118 if (g_strcmp0 (strv[i], str) == 0)
119 return TRUE;
120 }
121
122 return FALSE;
123 }
124
125 static guint32
_get_layer_priority(GESTimelineElement * element)126 _get_layer_priority (GESTimelineElement * element)
127 {
128 if (!element->parent)
129 return GES_TIMELINE_ELEMENT_NO_LAYER_PRIORITY;
130
131 return ges_timeline_element_get_layer_priority (element->parent);
132 }
133
134 static void
ges_track_element_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)135 ges_track_element_get_property (GObject * object, guint property_id,
136 GValue * value, GParamSpec * pspec)
137 {
138 GESTrackElement *track_element = GES_TRACK_ELEMENT (object);
139
140 switch (property_id) {
141 case PROP_ACTIVE:
142 g_value_set_boolean (value, ges_track_element_is_active (track_element));
143 break;
144 case PROP_TRACK_TYPE:
145 g_value_set_flags (value, track_element->priv->track_type);
146 break;
147 case PROP_TRACK:
148 g_value_set_object (value, track_element->priv->track);
149 break;
150 default:
151 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
152 }
153 }
154
155 static void
ges_track_element_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)156 ges_track_element_set_property (GObject * object, guint property_id,
157 const GValue * value, GParamSpec * pspec)
158 {
159 GESTrackElement *track_element = GES_TRACK_ELEMENT (object);
160
161 switch (property_id) {
162 case PROP_ACTIVE:
163 ges_track_element_set_active (track_element, g_value_get_boolean (value));
164 break;
165 case PROP_TRACK_TYPE:
166 track_element->priv->track_type = g_value_get_flags (value);
167 break;
168 default:
169 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
170 }
171 }
172
173 static void
ges_track_element_dispose(GObject * object)174 ges_track_element_dispose (GObject * object)
175 {
176 GESTrackElement *element = GES_TRACK_ELEMENT (object);
177 GESTrackElementPrivate *priv = element->priv;
178
179 if (priv->bindings_hashtable)
180 g_hash_table_destroy (priv->bindings_hashtable);
181
182 if (priv->nleobject) {
183 GstState cstate;
184
185 if (priv->track != NULL) {
186 g_error ("%p Still in %p, this means that you forgot"
187 " to remove it from the GESTrack it is contained in. You always need"
188 " to remove a GESTrackElement from its track before dropping the last"
189 " reference\n"
190 "This problem may also be caused by a refcounting bug in"
191 " the application or GES itself.", object, priv->track);
192 gst_element_get_state (priv->nleobject, &cstate, NULL, 0);
193 if (cstate != GST_STATE_NULL)
194 gst_element_set_state (priv->nleobject, GST_STATE_NULL);
195 }
196
197 g_object_set_qdata (G_OBJECT (priv->nleobject),
198 NLE_OBJECT_TRACK_ELEMENT_QUARK, NULL);
199 gst_object_unref (priv->nleobject);
200 priv->nleobject = NULL;
201 }
202
203 G_OBJECT_CLASS (ges_track_element_parent_class)->dispose (object);
204 }
205
206 static void
ges_track_element_constructed(GObject * gobject)207 ges_track_element_constructed (GObject * gobject)
208 {
209 GESTrackElementClass *class;
210 GstElement *nleobject;
211 gdouble media_duration_factor;
212 gchar *tmp;
213 GESTrackElement *object = GES_TRACK_ELEMENT (gobject);
214
215 GST_DEBUG_OBJECT (object, "Creating NleObject");
216
217 class = GES_TRACK_ELEMENT_GET_CLASS (object);
218 g_assert (class->create_gnl_object);
219
220 nleobject = class->create_gnl_object (object);
221 if (G_UNLIKELY (nleobject == NULL)) {
222 GST_ERROR_OBJECT (object, "Could not create NleObject");
223
224 return;
225 }
226
227 tmp = g_strdup_printf ("%s:%s", G_OBJECT_TYPE_NAME (object),
228 GST_OBJECT_NAME (nleobject));
229 gst_object_set_name (GST_OBJECT (nleobject), tmp);
230 g_free (tmp);
231
232 GST_DEBUG_OBJECT (object, "Got a valid NleObject, now filling it in");
233
234 object->priv->nleobject = gst_object_ref (nleobject);
235 g_object_set_qdata (G_OBJECT (nleobject), NLE_OBJECT_TRACK_ELEMENT_QUARK,
236 object);
237
238 /* Set some properties on the NleObject */
239 g_object_set (object->priv->nleobject,
240 "start", GES_TIMELINE_ELEMENT_START (object),
241 "inpoint", GES_TIMELINE_ELEMENT_INPOINT (object),
242 "duration", GES_TIMELINE_ELEMENT_DURATION (object),
243 "priority", GES_TIMELINE_ELEMENT_PRIORITY (object),
244 "active", object->active, NULL);
245
246 media_duration_factor =
247 ges_timeline_element_get_media_duration_factor (GES_TIMELINE_ELEMENT
248 (object));
249 g_object_set (object->priv->nleobject,
250 "media-duration-factor", media_duration_factor, NULL);
251
252 G_OBJECT_CLASS (ges_track_element_parent_class)->constructed (gobject);
253 }
254
255 static void
ges_track_element_class_init(GESTrackElementClass * klass)256 ges_track_element_class_init (GESTrackElementClass * klass)
257 {
258 GObjectClass *object_class = G_OBJECT_CLASS (klass);
259 GESTimelineElementClass *element_class = GES_TIMELINE_ELEMENT_CLASS (klass);
260
261 object_class->get_property = ges_track_element_get_property;
262 object_class->set_property = ges_track_element_set_property;
263 object_class->dispose = ges_track_element_dispose;
264 object_class->constructed = ges_track_element_constructed;
265
266
267 /**
268 * GESTrackElement:active:
269 *
270 * Whether the object should be taken into account in the #GESTrack output.
271 * If #FALSE, then its contents will not be used in the resulting track.
272 */
273 properties[PROP_ACTIVE] =
274 g_param_spec_boolean ("active", "Active", "Use object in output", TRUE,
275 G_PARAM_READWRITE);
276 g_object_class_install_property (object_class, PROP_ACTIVE,
277 properties[PROP_ACTIVE]);
278
279 properties[PROP_TRACK_TYPE] = g_param_spec_flags ("track-type", "Track Type",
280 "The track type of the object", GES_TYPE_TRACK_TYPE,
281 GES_TRACK_TYPE_UNKNOWN, G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
282 g_object_class_install_property (object_class, PROP_TRACK_TYPE,
283 properties[PROP_TRACK_TYPE]);
284
285 properties[PROP_TRACK] = g_param_spec_object ("track", "Track",
286 "The track the object is in", GES_TYPE_TRACK, G_PARAM_READABLE);
287 g_object_class_install_property (object_class, PROP_TRACK,
288 properties[PROP_TRACK]);
289
290 /**
291 * GESTrackElement::control-binding-added:
292 * @track_element: a #GESTrackElement
293 * @control_binding: the #GstControlBinding that has been added
294 *
295 * The control-binding-added signal is emitted each time a control binding
296 * is added for a child property of @track_element
297 */
298 ges_track_element_signals[CONTROL_BINDING_ADDED] =
299 g_signal_new ("control-binding-added", G_TYPE_FROM_CLASS (klass),
300 G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_generic,
301 G_TYPE_NONE, 1, GST_TYPE_CONTROL_BINDING);
302
303 /**
304 * GESTrackElement::control-binding-removed:
305 * @track_element: a #GESTrackElement
306 * @control_binding: the #GstControlBinding that has been removed
307 *
308 * The control-binding-removed signal is emitted each time a control binding
309 * is removed for a child property of @track_element
310 */
311 ges_track_element_signals[CONTROL_BINDING_REMOVED] =
312 g_signal_new ("control-binding-removed", G_TYPE_FROM_CLASS (klass),
313 G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_generic,
314 G_TYPE_NONE, 1, GST_TYPE_CONTROL_BINDING);
315
316 element_class->set_start = _set_start;
317 element_class->set_duration = _set_duration;
318 element_class->set_inpoint = _set_inpoint;
319 element_class->set_priority = _set_priority;
320 element_class->get_track_types = _get_track_types;
321 element_class->deep_copy = ges_track_element_copy_properties;
322 element_class->get_layer_priority = _get_layer_priority;
323
324 klass->create_gnl_object = ges_track_element_create_gnl_object_func;
325 klass->list_children_properties = default_list_children_properties;
326 klass->lookup_child = _lookup_child;
327 }
328
329 static void
ges_track_element_init(GESTrackElement * self)330 ges_track_element_init (GESTrackElement * self)
331 {
332 GESTrackElementPrivate *priv = self->priv =
333 ges_track_element_get_instance_private (self);
334
335 /* Sane default values */
336 GES_TIMELINE_ELEMENT_START (self) = 0;
337 GES_TIMELINE_ELEMENT_INPOINT (self) = 0;
338 GES_TIMELINE_ELEMENT_DURATION (self) = GST_SECOND;
339 GES_TIMELINE_ELEMENT_PRIORITY (self) = 0;
340 self->active = TRUE;
341
342 priv->bindings_hashtable = g_hash_table_new_full (g_str_hash, g_str_equal,
343 g_free, NULL);
344 }
345
346 static gfloat
interpolate_values_for_position(GstTimedValue * first_value,GstTimedValue * second_value,guint64 position,gboolean absolute)347 interpolate_values_for_position (GstTimedValue * first_value,
348 GstTimedValue * second_value, guint64 position, gboolean absolute)
349 {
350 gfloat diff;
351 GstClockTime interval;
352 gfloat value_at_pos;
353
354 g_assert (second_value || first_value);
355
356 if (first_value == NULL)
357 return second_value->value;
358
359 if (second_value == NULL)
360 return first_value->value;
361
362 diff = second_value->value - first_value->value;
363 interval = second_value->timestamp - first_value->timestamp;
364
365 if (position > first_value->timestamp)
366 value_at_pos =
367 first_value->value + ((float) (position -
368 first_value->timestamp) / (float) interval) * diff;
369 else
370 value_at_pos =
371 first_value->value - ((float) (first_value->timestamp -
372 position) / (float) interval) * diff;
373
374 if (!absolute)
375 value_at_pos = CLAMP (value_at_pos, 0.0, 1.0);
376
377 return value_at_pos;
378 }
379
380 static void
_update_control_bindings(GESTimelineElement * element,GstClockTime inpoint,GstClockTime duration)381 _update_control_bindings (GESTimelineElement * element, GstClockTime inpoint,
382 GstClockTime duration)
383 {
384 GParamSpec **specs;
385 guint n, n_specs;
386 GstControlBinding *binding;
387 GstTimedValueControlSource *source;
388 GESTrackElement *self = GES_TRACK_ELEMENT (element);
389
390 specs = ges_track_element_list_children_properties (self, &n_specs);
391
392 for (n = 0; n < n_specs; ++n) {
393 GList *values, *tmp;
394 gboolean absolute;
395 GstTimedValue *last, *first, *prev = NULL, *next = NULL;
396 gfloat value_at_pos;
397
398 binding = ges_track_element_get_control_binding (self, specs[n]->name);
399
400 if (!binding)
401 continue;
402
403 g_object_get (binding, "control_source", &source, NULL);
404
405 g_object_get (binding, "absolute", &absolute, NULL);
406 if (duration == 0) {
407 gst_timed_value_control_source_unset_all (GST_TIMED_VALUE_CONTROL_SOURCE
408 (source));
409 continue;
410 }
411
412 values =
413 gst_timed_value_control_source_get_all (GST_TIMED_VALUE_CONTROL_SOURCE
414 (source));
415
416 if (g_list_length (values) == 0)
417 continue;
418
419 first = values->data;
420
421 for (tmp = values->next; tmp; tmp = tmp->next) {
422 next = tmp->data;
423
424 if (next->timestamp > inpoint)
425 break;
426 }
427 g_list_free (values);
428
429 value_at_pos =
430 interpolate_values_for_position (first, next, inpoint, absolute);
431 gst_timed_value_control_source_unset (source, first->timestamp);
432 gst_timed_value_control_source_set (source, inpoint, value_at_pos);
433
434 values =
435 gst_timed_value_control_source_get_all (GST_TIMED_VALUE_CONTROL_SOURCE
436 (source));
437
438 if (duration != GST_CLOCK_TIME_NONE) {
439 last = g_list_last (values)->data;
440
441 for (tmp = g_list_last (values)->prev; tmp; tmp = tmp->prev) {
442 prev = tmp->data;
443
444 if (prev->timestamp < duration + inpoint)
445 break;
446 }
447 g_list_free (values);
448
449 value_at_pos =
450 interpolate_values_for_position (prev, last, duration + inpoint,
451 absolute);
452
453 gst_timed_value_control_source_unset (source, last->timestamp);
454 gst_timed_value_control_source_set (source, duration + inpoint,
455 value_at_pos);
456 values =
457 gst_timed_value_control_source_get_all (GST_TIMED_VALUE_CONTROL_SOURCE
458 (source));
459 }
460
461 for (tmp = values; tmp; tmp = tmp->next) {
462 GstTimedValue *value = tmp->data;
463 if (value->timestamp < inpoint)
464 gst_timed_value_control_source_unset (source, value->timestamp);
465 else if (duration != GST_CLOCK_TIME_NONE
466 && value->timestamp > duration + inpoint)
467 gst_timed_value_control_source_unset (source, value->timestamp);
468 }
469 g_list_free (values);
470 }
471
472 g_free (specs);
473 }
474
475 static gboolean
_set_start(GESTimelineElement * element,GstClockTime start)476 _set_start (GESTimelineElement * element, GstClockTime start)
477 {
478 GESTrackElement *object = GES_TRACK_ELEMENT (element);
479
480 g_return_val_if_fail (object->priv->nleobject, FALSE);
481
482 if (G_UNLIKELY (start == _START (object)))
483 return FALSE;
484
485 g_object_set (object->priv->nleobject, "start", start, NULL);
486
487 return TRUE;
488 }
489
490 static gboolean
_set_inpoint(GESTimelineElement * element,GstClockTime inpoint)491 _set_inpoint (GESTimelineElement * element, GstClockTime inpoint)
492 {
493 GESTrackElement *object = GES_TRACK_ELEMENT (element);
494
495 g_return_val_if_fail (object->priv->nleobject, FALSE);
496
497 if (G_UNLIKELY (inpoint == _INPOINT (object)))
498
499 return FALSE;
500
501 g_object_set (object->priv->nleobject, "inpoint", inpoint, NULL);
502 _update_control_bindings (element, inpoint, GST_CLOCK_TIME_NONE);
503
504 return TRUE;
505 }
506
507 static gboolean
_set_duration(GESTimelineElement * element,GstClockTime duration)508 _set_duration (GESTimelineElement * element, GstClockTime duration)
509 {
510 GESTrackElement *object = GES_TRACK_ELEMENT (element);
511 GESTrackElementPrivate *priv = object->priv;
512
513 g_return_val_if_fail (object->priv->nleobject, FALSE);
514
515 if (GST_CLOCK_TIME_IS_VALID (_MAXDURATION (element)) &&
516 duration > _INPOINT (object) + _MAXDURATION (element))
517 duration = _MAXDURATION (element) - _INPOINT (object);
518
519 if (G_UNLIKELY (duration == _DURATION (object)))
520 return FALSE;
521
522 g_object_set (priv->nleobject, "duration", duration, NULL);
523
524 _update_control_bindings (element, ges_timeline_element_get_inpoint (element),
525 duration);
526
527 return TRUE;
528 }
529
530 static gboolean
_set_priority(GESTimelineElement * element,guint32 priority)531 _set_priority (GESTimelineElement * element, guint32 priority)
532 {
533 GESTrackElement *object = GES_TRACK_ELEMENT (element);
534
535 g_return_val_if_fail (object->priv->nleobject, FALSE);
536
537 if (priority < MIN_NLE_PRIO) {
538 GST_INFO_OBJECT (element, "Priority (%d) < MIN_NLE_PRIO, setting it to %d",
539 priority, MIN_NLE_PRIO);
540 priority = MIN_NLE_PRIO;
541 }
542
543 GST_DEBUG_OBJECT (object, "priority:%" G_GUINT32_FORMAT, priority);
544
545 if (G_UNLIKELY (priority == _PRIORITY (object)))
546 return FALSE;
547
548 g_object_set (object->priv->nleobject, "priority", priority, NULL);
549
550 return TRUE;
551 }
552
553 GESTrackType
_get_track_types(GESTimelineElement * object)554 _get_track_types (GESTimelineElement * object)
555 {
556 return ges_track_element_get_track_type (GES_TRACK_ELEMENT (object));
557 }
558
559 /**
560 * ges_track_element_set_active:
561 * @object: a #GESTrackElement
562 * @active: visibility
563 *
564 * Sets the usage of the @object. If @active is %TRUE, the object will be used for
565 * playback and rendering, else it will be ignored.
566 *
567 * Returns: %TRUE if the property was toggled, else %FALSE
568 */
569 gboolean
ges_track_element_set_active(GESTrackElement * object,gboolean active)570 ges_track_element_set_active (GESTrackElement * object, gboolean active)
571 {
572 g_return_val_if_fail (GES_IS_TRACK_ELEMENT (object), FALSE);
573 g_return_val_if_fail (object->priv->nleobject, FALSE);
574
575 GST_DEBUG_OBJECT (object, "object:%p, active:%d", object, active);
576
577 if (G_UNLIKELY (active == object->active))
578 return FALSE;
579
580 g_object_set (object->priv->nleobject, "active", active, NULL);
581
582 if (active != object->active) {
583 object->active = active;
584 if (GES_TRACK_ELEMENT_GET_CLASS (object)->active_changed)
585 GES_TRACK_ELEMENT_GET_CLASS (object)->active_changed (object, active);
586 }
587
588 return TRUE;
589 }
590
591 void
ges_track_element_set_track_type(GESTrackElement * object,GESTrackType type)592 ges_track_element_set_track_type (GESTrackElement * object, GESTrackType type)
593 {
594 g_return_if_fail (GES_IS_TRACK_ELEMENT (object));
595
596 if (object->priv->track_type != type) {
597 object->priv->track_type = type;
598 g_object_notify_by_pspec (G_OBJECT (object), properties[PROP_TRACK_TYPE]);
599 }
600 }
601
602 GESTrackType
ges_track_element_get_track_type(GESTrackElement * object)603 ges_track_element_get_track_type (GESTrackElement * object)
604 {
605 g_return_val_if_fail (GES_IS_TRACK_ELEMENT (object), GES_TRACK_TYPE_UNKNOWN);
606
607 return object->priv->track_type;
608 }
609
610 /* default 'create_gnl_object' virtual method implementation */
611 static GstElement *
ges_track_element_create_gnl_object_func(GESTrackElement * self)612 ges_track_element_create_gnl_object_func (GESTrackElement * self)
613 {
614 GESTrackElementClass *klass = NULL;
615 GstElement *child = NULL;
616 GstElement *nleobject;
617
618 klass = GES_TRACK_ELEMENT_GET_CLASS (self);
619
620 if (G_UNLIKELY (self->priv->nleobject != NULL))
621 goto already_have_nleobject;
622
623 if (G_UNLIKELY (klass->nleobject_factorytype == NULL))
624 goto no_nlefactory;
625
626 GST_DEBUG ("Creating a supporting nleobject of type '%s'",
627 klass->nleobject_factorytype);
628
629 nleobject = gst_element_factory_make (klass->nleobject_factorytype, NULL);
630
631 if (G_UNLIKELY (nleobject == NULL))
632 goto no_nleobject;
633
634 if (klass->create_element) {
635 GST_DEBUG ("Calling subclass 'create_element' vmethod");
636 child = klass->create_element (self);
637
638 if (G_UNLIKELY (!child))
639 goto child_failure;
640
641 if (!gst_bin_add (GST_BIN (nleobject), child))
642 goto add_failure;
643
644 GST_DEBUG ("Succesfully got the element to put in the nleobject");
645 self->priv->element = child;
646 }
647
648 GST_DEBUG ("done");
649 return nleobject;
650
651
652 /* ERROR CASES */
653
654 already_have_nleobject:
655 {
656 GST_ERROR ("Already controlling a NleObject %s",
657 GST_ELEMENT_NAME (self->priv->nleobject));
658 return NULL;
659 }
660
661 no_nlefactory:
662 {
663 GST_ERROR ("No GESTrackElement::nleobject_factorytype implementation!");
664 return NULL;
665 }
666
667 no_nleobject:
668 {
669 GST_ERROR ("Error creating a nleobject of type '%s'",
670 klass->nleobject_factorytype);
671 return NULL;
672 }
673
674 child_failure:
675 {
676 GST_ERROR ("create_element returned NULL");
677 gst_object_unref (nleobject);
678 return NULL;
679 }
680
681 add_failure:
682 {
683 GST_ERROR ("Error adding the contents to the nleobject");
684 gst_object_unref (child);
685 gst_object_unref (nleobject);
686 return NULL;
687 }
688 }
689
690 static void
ges_track_element_add_child_props(GESTrackElement * self,GstElement * child,const gchar ** wanted_categories,const gchar ** blacklist,const gchar ** whitelist)691 ges_track_element_add_child_props (GESTrackElement * self,
692 GstElement * child, const gchar ** wanted_categories,
693 const gchar ** blacklist, const gchar ** whitelist)
694 {
695 GstElementFactory *factory;
696 const gchar *klass;
697 GParamSpec **parray;
698 GObjectClass *gobject_klass;
699 gchar **categories;
700 guint i;
701
702 factory = gst_element_get_factory (child);
703 klass = gst_element_factory_get_metadata (factory,
704 GST_ELEMENT_METADATA_KLASS);
705
706 if (strv_find_str (blacklist, GST_OBJECT_NAME (factory))) {
707 GST_DEBUG_OBJECT (self, "%s blacklisted", GST_OBJECT_NAME (factory));
708 return;
709 }
710
711 GST_DEBUG_OBJECT (self, "Looking at element '%s' of klass '%s'",
712 GST_ELEMENT_NAME (child), klass);
713
714 categories = g_strsplit (klass, "/", 0);
715
716 for (i = 0; categories[i]; i++) {
717 if ((!wanted_categories ||
718 strv_find_str (wanted_categories, categories[i]))) {
719 guint i, nb_specs;
720
721 gobject_klass = G_OBJECT_GET_CLASS (child);
722 parray = g_object_class_list_properties (gobject_klass, &nb_specs);
723 for (i = 0; i < nb_specs; i++) {
724 if ((!whitelist && (parray[i]->flags & G_PARAM_WRITABLE))
725 || (strv_find_str (whitelist, parray[i]->name))) {
726 ges_timeline_element_add_child_property (GES_TIMELINE_ELEMENT
727 (self), parray[i], G_OBJECT (child));
728 }
729 }
730 g_free (parray);
731
732 GST_DEBUG
733 ("%d configurable properties of '%s' added to property hashtable",
734 nb_specs, GST_ELEMENT_NAME (child));
735 break;
736 }
737 }
738
739 g_strfreev (categories);
740 }
741
742 /**
743 * ges_track_element_add_children_props:
744 * @self: The #GESTrackElement to set chidlren props on
745 * @element: The GstElement to retrieve properties from
746 * @wanted_categories: (array zero-terminated=1) (transfer none) (allow-none):
747 * An array of categories of GstElement to
748 * take into account (as defined in the factory meta "klass" field)
749 * @blacklist: (array zero-terminated=1) (transfer none) (allow-none): A
750 * blacklist of elements factory names to not take into account
751 * @whitelist: (array zero-terminated=1) (transfer none) (allow-none): A list
752 * of propery names to add as children properties
753 *
754 * Looks for the properties defines with the various parametters and add
755 * them to the hashtable of children properties.
756 *
757 * To be used by subclasses only
758 */
759 void
ges_track_element_add_children_props(GESTrackElement * self,GstElement * element,const gchar ** wanted_categories,const gchar ** blacklist,const gchar ** whitelist)760 ges_track_element_add_children_props (GESTrackElement * self,
761 GstElement * element, const gchar ** wanted_categories,
762 const gchar ** blacklist, const gchar ** whitelist)
763 {
764 GValue item = { 0, };
765 GstIterator *it;
766 gboolean done = FALSE;
767
768 if (!GST_IS_BIN (element)) {
769 ges_track_element_add_child_props (self, element, wanted_categories,
770 blacklist, whitelist);
771 return;
772 }
773
774 /* We go over child elements recursivly, and add writable properties to the
775 * hashtable */
776 it = gst_bin_iterate_recurse (GST_BIN (element));
777 while (!done) {
778 switch (gst_iterator_next (it, &item)) {
779 case GST_ITERATOR_OK:
780 {
781 GstElement *child = g_value_get_object (&item);
782 ges_track_element_add_child_props (self, child, wanted_categories,
783 blacklist, whitelist);
784 g_value_reset (&item);
785 break;
786 }
787 case GST_ITERATOR_RESYNC:
788 /* FIXME, properly restart the process */
789 GST_DEBUG ("iterator resync");
790 gst_iterator_resync (it);
791 break;
792
793 case GST_ITERATOR_DONE:
794 GST_DEBUG ("iterator done");
795 done = TRUE;
796 break;
797
798 default:
799 break;
800 }
801 g_value_unset (&item);
802 }
803 gst_iterator_free (it);
804 }
805
806 /* INTERNAL USAGE */
807 gboolean
ges_track_element_set_track(GESTrackElement * object,GESTrack * track)808 ges_track_element_set_track (GESTrackElement * object, GESTrack * track)
809 {
810 gboolean ret = TRUE;
811
812 g_return_val_if_fail (object->priv->nleobject, FALSE);
813
814 GST_DEBUG_OBJECT (object, "new track: %" GST_PTR_FORMAT, track);
815
816 object->priv->track = track;
817
818 if (object->priv->track) {
819 ges_track_element_set_track_type (object, track->type);
820
821 g_object_set (object->priv->nleobject,
822 "caps", ges_track_get_caps (object->priv->track), NULL);
823 }
824
825 g_object_notify_by_pspec (G_OBJECT (object), properties[PROP_TRACK]);
826 return ret;
827 }
828
829 /**
830 * ges_track_element_get_all_control_bindings
831 * @trackelement: The #TrackElement from which to get all set bindings
832 *
833 * Returns: (element-type gchar* GstControlBinding)(transfer none): A
834 * #GHashTable containing all property_name: GstControlBinding
835 */
836 GHashTable *
ges_track_element_get_all_control_bindings(GESTrackElement * trackelement)837 ges_track_element_get_all_control_bindings (GESTrackElement * trackelement)
838 {
839 GESTrackElementPrivate *priv = GES_TRACK_ELEMENT (trackelement)->priv;
840
841 return priv->bindings_hashtable;
842 }
843
844 /**
845 * ges_track_element_get_track:
846 * @object: a #GESTrackElement
847 *
848 * Get the #GESTrack to which this object belongs.
849 *
850 * Returns: (transfer none) (nullable): The #GESTrack to which this object
851 * belongs. Can be %NULL if it is not in any track
852 */
853 GESTrack *
ges_track_element_get_track(GESTrackElement * object)854 ges_track_element_get_track (GESTrackElement * object)
855 {
856 g_return_val_if_fail (GES_IS_TRACK_ELEMENT (object), NULL);
857
858 return object->priv->track;
859 }
860
861 /**
862 * ges_track_element_get_gnlobject:
863 * @object: a #GESTrackElement
864 *
865 * Get the NleObject object this object is controlling.
866 *
867 * Returns: (transfer none): the NleObject object this object is controlling.
868 *
869 * Deprecated: use #ges_track_element_get_nleobject instead.
870 */
871 GstElement *
ges_track_element_get_gnlobject(GESTrackElement * object)872 ges_track_element_get_gnlobject (GESTrackElement * object)
873 {
874 g_return_val_if_fail (GES_IS_TRACK_ELEMENT (object), NULL);
875
876 return object->priv->nleobject;
877 }
878
879 /**
880 * ges_track_element_get_nleobject:
881 * @object: a #GESTrackElement
882 *
883 * Get the GNonLin object this object is controlling.
884 *
885 * Returns: (transfer none): the GNonLin object this object is controlling.
886 *
887 * Since: 1.6
888 */
889 GstElement *
ges_track_element_get_nleobject(GESTrackElement * object)890 ges_track_element_get_nleobject (GESTrackElement * object)
891 {
892 g_return_val_if_fail (GES_IS_TRACK_ELEMENT (object), NULL);
893
894 return object->priv->nleobject;
895 }
896
897 /**
898 * ges_track_element_get_element:
899 * @object: a #GESTrackElement
900 *
901 * Get the #GstElement this track element is controlling within GNonLin.
902 *
903 * Returns: (transfer none): the #GstElement this track element is controlling
904 * within GNonLin.
905 */
906 GstElement *
ges_track_element_get_element(GESTrackElement * object)907 ges_track_element_get_element (GESTrackElement * object)
908 {
909 g_return_val_if_fail (GES_IS_TRACK_ELEMENT (object), NULL);
910
911 return object->priv->element;
912 }
913
914 /**
915 * ges_track_element_is_active:
916 * @object: a #GESTrackElement
917 *
918 * Lets you know if @object will be used for playback and rendering,
919 * or not.
920 *
921 * Returns: %TRUE if @object is active, %FALSE otherwize
922 */
923 gboolean
ges_track_element_is_active(GESTrackElement * object)924 ges_track_element_is_active (GESTrackElement * object)
925 {
926 g_return_val_if_fail (GES_IS_TRACK_ELEMENT (object), FALSE);
927 g_return_val_if_fail (object->priv->nleobject, FALSE);
928
929 return object->active;
930 }
931
932 /**
933 * ges_track_element_lookup_child:
934 * @object: object to lookup the property in
935 * @prop_name: name of the property to look up. You can specify the name of the
936 * class as such: "ClassName::property-name", to guarantee that you get the
937 * proper GParamSpec in case various GstElement-s contain the same property
938 * name. If you don't do so, you will get the first element found, having
939 * this property and the and the corresponding GParamSpec.
940 * @element: (out) (allow-none) (transfer full): pointer to a #GstElement that
941 * takes the real object to set property on
942 * @pspec: (out) (allow-none) (transfer full): pointer to take the #GParamSpec
943 * describing the property
944 *
945 * Looks up which @element and @pspec would be effected by the given @name. If various
946 * contained elements have this property name you will get the first one, unless you
947 * specify the class name in @name.
948 *
949 * Returns: TRUE if @element and @pspec could be found. FALSE otherwise. In that
950 * case the values for @pspec and @element are not modified. Unref @element after
951 * usage.
952 *
953 * Deprecated: Use #ges_timeline_element_lookup_child
954 */
955 gboolean
ges_track_element_lookup_child(GESTrackElement * object,const gchar * prop_name,GstElement ** element,GParamSpec ** pspec)956 ges_track_element_lookup_child (GESTrackElement * object,
957 const gchar * prop_name, GstElement ** element, GParamSpec ** pspec)
958 {
959 return ges_timeline_element_lookup_child (GES_TIMELINE_ELEMENT (object),
960 prop_name, ((GObject **) element), pspec);
961 }
962
963 /**
964 * ges_track_element_set_child_property_by_pspec: (skip):
965 * @object: a #GESTrackElement
966 * @pspec: The #GParamSpec that specifies the property you want to set
967 * @value: the value
968 *
969 * Sets a property of a child of @object.
970 *
971 * Deprecated: Use #ges_timeline_element_set_child_property_by_spec
972 */
973 void
ges_track_element_set_child_property_by_pspec(GESTrackElement * object,GParamSpec * pspec,GValue * value)974 ges_track_element_set_child_property_by_pspec (GESTrackElement * object,
975 GParamSpec * pspec, GValue * value)
976 {
977 g_return_if_fail (GES_IS_TRACK_ELEMENT (object));
978
979 ges_timeline_element_set_child_property_by_pspec (GES_TIMELINE_ELEMENT
980 (object), pspec, value);
981
982 return;
983 }
984
985 /**
986 * ges_track_element_set_child_property_valist: (skip):
987 * @object: The #GESTrackElement parent object
988 * @first_property_name: The name of the first property to set
989 * @var_args: value for the first property, followed optionally by more
990 * name/return location pairs, followed by NULL
991 *
992 * Sets a property of a child of @object. If there are various child elements
993 * that have the same property name, you can distinguish them using the following
994 * syntax: 'ClasseName::property_name' as property name. If you don't, the
995 * corresponding property of the first element found will be set.
996 *
997 * Deprecated: Use #ges_timeline_element_set_child_property_valist
998 */
999 void
ges_track_element_set_child_property_valist(GESTrackElement * object,const gchar * first_property_name,va_list var_args)1000 ges_track_element_set_child_property_valist (GESTrackElement * object,
1001 const gchar * first_property_name, va_list var_args)
1002 {
1003 ges_timeline_element_set_child_property_valist (GES_TIMELINE_ELEMENT (object),
1004 first_property_name, var_args);
1005 }
1006
1007 /**
1008 * ges_track_element_set_child_properties: (skip):
1009 * @object: The #GESTrackElement parent object
1010 * @first_property_name: The name of the first property to set
1011 * @...: value for the first property, followed optionally by more
1012 * name/return location pairs, followed by NULL
1013 *
1014 * Sets a property of a child of @object. If there are various child elements
1015 * that have the same property name, you can distinguish them using the following
1016 * syntax: 'ClasseName::property_name' as property name. If you don't, the
1017 * corresponding property of the first element found will be set.
1018 *
1019 * Deprecated: Use #ges_timeline_element_set_child_properties
1020 */
1021 void
ges_track_element_set_child_properties(GESTrackElement * object,const gchar * first_property_name,...)1022 ges_track_element_set_child_properties (GESTrackElement * object,
1023 const gchar * first_property_name, ...)
1024 {
1025 va_list var_args;
1026
1027 g_return_if_fail (GES_IS_TRACK_ELEMENT (object));
1028
1029 va_start (var_args, first_property_name);
1030 ges_track_element_set_child_property_valist (object, first_property_name,
1031 var_args);
1032 va_end (var_args);
1033 }
1034
1035 /**
1036 * ges_track_element_get_child_property_valist: (skip):
1037 * @object: The #GESTrackElement parent object
1038 * @first_property_name: The name of the first property to get
1039 * @var_args: value for the first property, followed optionally by more
1040 * name/return location pairs, followed by NULL
1041 *
1042 * Gets a property of a child of @object. If there are various child elements
1043 * that have the same property name, you can distinguish them using the following
1044 * syntax: 'ClasseName::property_name' as property name. If you don't, the
1045 * corresponding property of the first element found will be set.
1046 *
1047 * Deprecated: Use #ges_timeline_element_get_child_property_valist
1048 */
1049 void
ges_track_element_get_child_property_valist(GESTrackElement * object,const gchar * first_property_name,va_list var_args)1050 ges_track_element_get_child_property_valist (GESTrackElement * object,
1051 const gchar * first_property_name, va_list var_args)
1052 {
1053 ges_timeline_element_get_child_property_valist (GES_TIMELINE_ELEMENT (object),
1054 first_property_name, var_args);
1055 }
1056
1057 /**
1058 * ges_track_element_list_children_properties:
1059 * @object: The #GESTrackElement to get the list of children properties from
1060 * @n_properties: (out): return location for the length of the returned array
1061 *
1062 * Gets an array of #GParamSpec* for all configurable properties of the
1063 * children of @object.
1064 *
1065 * Returns: (transfer full) (array length=n_properties): an array of #GParamSpec* which should be freed after use or
1066 * %NULL if something went wrong
1067 *
1068 * Deprecated: Use #ges_timeline_element_list_children_properties
1069 */
1070 GParamSpec **
ges_track_element_list_children_properties(GESTrackElement * object,guint * n_properties)1071 ges_track_element_list_children_properties (GESTrackElement * object,
1072 guint * n_properties)
1073 {
1074 return
1075 ges_timeline_element_list_children_properties (GES_TIMELINE_ELEMENT
1076 (object), n_properties);
1077 }
1078
1079 /**
1080 * ges_track_element_get_child_properties: (skip):
1081 * @object: The origin #GESTrackElement
1082 * @first_property_name: The name of the first property to get
1083 * @...: return location for the first property, followed optionally by more
1084 * name/return location pairs, followed by NULL
1085 *
1086 * Gets properties of a child of @object.
1087 *
1088 * Deprecated: Use #ges_timeline_element_get_child_properties
1089 */
1090 void
ges_track_element_get_child_properties(GESTrackElement * object,const gchar * first_property_name,...)1091 ges_track_element_get_child_properties (GESTrackElement * object,
1092 const gchar * first_property_name, ...)
1093 {
1094 va_list var_args;
1095
1096 g_return_if_fail (GES_IS_TRACK_ELEMENT (object));
1097
1098 va_start (var_args, first_property_name);
1099 ges_track_element_get_child_property_valist (object, first_property_name,
1100 var_args);
1101 va_end (var_args);
1102 }
1103
1104 /**
1105 * ges_track_element_get_child_property_by_pspec: (skip):
1106 * @object: a #GESTrackElement
1107 * @pspec: The #GParamSpec that specifies the property you want to get
1108 * @value: (out): return location for the value
1109 *
1110 * Gets a property of a child of @object.
1111 *
1112 * Deprecated: Use #ges_timeline_element_get_child_property_by_pspec
1113 */
1114 void
ges_track_element_get_child_property_by_pspec(GESTrackElement * object,GParamSpec * pspec,GValue * value)1115 ges_track_element_get_child_property_by_pspec (GESTrackElement * object,
1116 GParamSpec * pspec, GValue * value)
1117 {
1118 ges_timeline_element_get_child_property_by_pspec (GES_TIMELINE_ELEMENT
1119 (object), pspec, value);
1120 }
1121
1122 /**
1123 * ges_track_element_set_child_property: (skip):
1124 * @object: The origin #GESTrackElement
1125 * @property_name: The name of the property
1126 * @value: the value
1127 *
1128 * Sets a property of a GstElement contained in @object.
1129 *
1130 * Note that #ges_track_element_set_child_property is really
1131 * intended for language bindings, #ges_track_element_set_child_properties
1132 * is much more convenient for C programming.
1133 *
1134 * Returns: %TRUE if the property was set, %FALSE otherwize
1135 *
1136 * Deprecated: use #ges_timeline_element_set_child_property instead
1137 */
1138 gboolean
ges_track_element_set_child_property(GESTrackElement * object,const gchar * property_name,GValue * value)1139 ges_track_element_set_child_property (GESTrackElement * object,
1140 const gchar * property_name, GValue * value)
1141 {
1142 return ges_timeline_element_set_child_property (GES_TIMELINE_ELEMENT (object),
1143 property_name, value);
1144 }
1145
1146 /**
1147 * ges_track_element_get_child_property: (skip):
1148 * @object: The origin #GESTrackElement
1149 * @property_name: The name of the property
1150 * @value: (out): return location for the property value, it will
1151 * be initialized if it is initialized with 0
1152 *
1153 * In general, a copy is made of the property contents and
1154 * the caller is responsible for freeing the memory by calling
1155 * g_value_unset().
1156 *
1157 * Gets a property of a GstElement contained in @object.
1158 *
1159 * Note that #ges_track_element_get_child_property is really
1160 * intended for language bindings, #ges_track_element_get_child_properties
1161 * is much more convenient for C programming.
1162 *
1163 * Returns: %TRUE if the property was found, %FALSE otherwize
1164 *
1165 * Deprecated: Use #ges_timeline_element_get_child_property
1166 */
1167 gboolean
ges_track_element_get_child_property(GESTrackElement * object,const gchar * property_name,GValue * value)1168 ges_track_element_get_child_property (GESTrackElement * object,
1169 const gchar * property_name, GValue * value)
1170 {
1171 return ges_timeline_element_get_child_property (GES_TIMELINE_ELEMENT (object),
1172 property_name, value);
1173 }
1174
1175 static GParamSpec **
default_list_children_properties(GESTrackElement * object,guint * n_properties)1176 default_list_children_properties (GESTrackElement * object,
1177 guint * n_properties)
1178 {
1179 return
1180 GES_TIMELINE_ELEMENT_GET_CLASS (object)->list_children_properties
1181 (GES_TIMELINE_ELEMENT (object), n_properties);
1182 }
1183
1184 void
ges_track_element_copy_properties(GESTimelineElement * element,GESTimelineElement * elementcopy)1185 ges_track_element_copy_properties (GESTimelineElement * element,
1186 GESTimelineElement * elementcopy)
1187 {
1188 GParamSpec **specs;
1189 guint n, n_specs;
1190 GValue val = { 0 };
1191 GESTrackElement *copy = GES_TRACK_ELEMENT (elementcopy);
1192
1193 specs =
1194 ges_track_element_list_children_properties (GES_TRACK_ELEMENT (element),
1195 &n_specs);
1196 for (n = 0; n < n_specs; ++n) {
1197 if (!(specs[n]->flags & G_PARAM_WRITABLE))
1198 continue;
1199 g_value_init (&val, specs[n]->value_type);
1200 ges_track_element_get_child_property_by_pspec (GES_TRACK_ELEMENT (element),
1201 specs[n], &val);
1202 ges_track_element_set_child_property_by_pspec (copy, specs[n], &val);
1203 g_value_unset (&val);
1204 }
1205
1206 g_free (specs);
1207 }
1208
1209 static void
_split_binding(GESTrackElement * element,GESTrackElement * new_element,guint64 position,GstTimedValueControlSource * source,GstTimedValueControlSource * new_source,gboolean absolute)1210 _split_binding (GESTrackElement * element, GESTrackElement * new_element,
1211 guint64 position, GstTimedValueControlSource * source,
1212 GstTimedValueControlSource * new_source, gboolean absolute)
1213 {
1214 GstTimedValue *last_value = NULL;
1215 gboolean past_position = FALSE;
1216 GList *values, *tmp;
1217
1218 values =
1219 gst_timed_value_control_source_get_all (GST_TIMED_VALUE_CONTROL_SOURCE
1220 (source));
1221
1222 for (tmp = values; tmp; tmp = tmp->next) {
1223 GstTimedValue *value = tmp->data;
1224
1225 if (value->timestamp > position && !past_position) {
1226 gfloat value_at_pos;
1227
1228 /* FIXME We should be able to use gst_control_source_get_value so
1229 * all modes are handled. Right now that method only works if the value
1230 * we are looking for is between two actual keyframes which is not enough
1231 * in our case. bug #706621 */
1232 value_at_pos =
1233 interpolate_values_for_position (last_value, value, position,
1234 absolute);
1235
1236 past_position = TRUE;
1237
1238 gst_timed_value_control_source_set (new_source, position, value_at_pos);
1239 gst_timed_value_control_source_set (new_source, value->timestamp,
1240 value->value);
1241
1242 gst_timed_value_control_source_unset (source, value->timestamp);
1243 gst_timed_value_control_source_set (source, position, value_at_pos);
1244 } else if (past_position) {
1245 gst_timed_value_control_source_set (new_source, value->timestamp,
1246 value->value);
1247 gst_timed_value_control_source_unset (source, value->timestamp);
1248 }
1249 last_value = value;
1250
1251 }
1252 g_list_free (values);
1253 }
1254
1255 static void
_copy_binding(GESTrackElement * element,GESTrackElement * new_element,guint64 position,GstTimedValueControlSource * source,GstTimedValueControlSource * new_source,gboolean absolute)1256 _copy_binding (GESTrackElement * element, GESTrackElement * new_element,
1257 guint64 position, GstTimedValueControlSource * source,
1258 GstTimedValueControlSource * new_source, gboolean absolute)
1259 {
1260 GList *values, *tmp;
1261
1262 values =
1263 gst_timed_value_control_source_get_all (GST_TIMED_VALUE_CONTROL_SOURCE
1264 (source));
1265 for (tmp = values; tmp; tmp = tmp->next) {
1266 GstTimedValue *value = tmp->data;
1267
1268 gst_timed_value_control_source_set (new_source, value->timestamp,
1269 value->value);
1270 }
1271 g_list_free (values);
1272 }
1273
1274 /* position == GST_CLOCK_TIME_NONE means that we do a simple copy
1275 * other position means that the function will do a splitting
1276 * and thus interpollate the values in the element and new_element
1277 */
1278 void
ges_track_element_copy_bindings(GESTrackElement * element,GESTrackElement * new_element,guint64 position)1279 ges_track_element_copy_bindings (GESTrackElement * element,
1280 GESTrackElement * new_element, guint64 position)
1281 {
1282 GParamSpec **specs;
1283 guint n, n_specs;
1284 gboolean absolute;
1285 GstControlBinding *binding;
1286 GstTimedValueControlSource *source, *new_source;
1287
1288 specs =
1289 ges_track_element_list_children_properties (GES_TRACK_ELEMENT (element),
1290 &n_specs);
1291 for (n = 0; n < n_specs; ++n) {
1292 GstInterpolationMode mode;
1293
1294 binding = ges_track_element_get_control_binding (element, specs[n]->name);
1295 if (!binding)
1296 continue;
1297
1298 /* FIXME : this should work as well with other types of control sources */
1299 g_object_get (binding, "control_source", &source, NULL);
1300 if (!GST_IS_TIMED_VALUE_CONTROL_SOURCE (source))
1301 continue;
1302
1303 g_object_get (binding, "absolute", &absolute, NULL);
1304 g_object_get (source, "mode", &mode, NULL);
1305
1306 new_source =
1307 GST_TIMED_VALUE_CONTROL_SOURCE (gst_interpolation_control_source_new
1308 ());
1309 g_object_set (new_source, "mode", mode, NULL);
1310
1311 if (GST_CLOCK_TIME_IS_VALID (position))
1312 _split_binding (element, new_element, position, source, new_source,
1313 absolute);
1314 else
1315 _copy_binding (element, new_element, position, source, new_source,
1316 absolute);
1317
1318 /* We only manage direct (absolute) bindings, see TODO in set_control_source */
1319 if (absolute)
1320 ges_track_element_set_control_source (new_element,
1321 GST_CONTROL_SOURCE (new_source), specs[n]->name, "direct-absolute");
1322 else
1323 ges_track_element_set_control_source (new_element,
1324 GST_CONTROL_SOURCE (new_source), specs[n]->name, "direct");
1325 }
1326
1327 g_free (specs);
1328 }
1329
1330 /**
1331 * ges_track_element_edit:
1332 * @object: the #GESTrackElement to edit
1333 * @layers: (element-type GESLayer): The layers you want the edit to
1334 * happen in, %NULL means that the edition is done in all the
1335 * #GESLayers contained in the current timeline.
1336 * FIXME: This is not implemented yet.
1337 * @mode: The #GESEditMode in which the edition will happen.
1338 * @edge: The #GESEdge the edit should happen on.
1339 * @position: The position at which to edit @object (in nanosecond)
1340 *
1341 * Edit @object in the different exisiting #GESEditMode modes. In the case of
1342 * slide, and roll, you need to specify a #GESEdge
1343 *
1344 * Returns: %TRUE if the object as been edited properly, %FALSE if an error
1345 * occured
1346 */
1347 gboolean
ges_track_element_edit(GESTrackElement * object,GList * layers,GESEditMode mode,GESEdge edge,guint64 position)1348 ges_track_element_edit (GESTrackElement * object,
1349 GList * layers, GESEditMode mode, GESEdge edge, guint64 position)
1350 {
1351 GESTrack *track = ges_track_element_get_track (object);
1352 GESTimeline *timeline;
1353
1354 g_return_val_if_fail (GES_IS_TRACK_ELEMENT (object), FALSE);
1355
1356 if (G_UNLIKELY (!track)) {
1357 GST_WARNING_OBJECT (object, "Trying to edit in %d mode but not in "
1358 "any Track yet.", mode);
1359 return FALSE;
1360 }
1361
1362 timeline = GES_TIMELINE (ges_track_get_timeline (track));
1363
1364 if (G_UNLIKELY (!timeline)) {
1365 GST_WARNING_OBJECT (object, "Trying to edit in %d mode but "
1366 "track %p is not in any timeline yet.", mode, track);
1367 return FALSE;
1368 }
1369
1370 switch (mode) {
1371 case GES_EDIT_MODE_NORMAL:
1372 return timeline_move_object (timeline, GES_TIMELINE_ELEMENT (object), -1,
1373 layers, edge, position);
1374 break;
1375 case GES_EDIT_MODE_TRIM:
1376 return timeline_trim_object (timeline, GES_TIMELINE_ELEMENT (object), -1,
1377 layers, edge, position);
1378 break;
1379 case GES_EDIT_MODE_RIPPLE:
1380 return timeline_ripple_object (timeline, GES_TIMELINE_ELEMENT (object),
1381 GES_TIMELINE_ELEMENT_PRIORITY (object) / LAYER_HEIGHT,
1382 layers, edge, position);
1383 break;
1384 case GES_EDIT_MODE_ROLL:
1385 return timeline_roll_object (timeline, GES_TIMELINE_ELEMENT (object),
1386 layers, edge, position);
1387 break;
1388 case GES_EDIT_MODE_SLIDE:
1389 return timeline_slide_object (timeline, object, layers, edge, position);
1390 break;
1391 default:
1392 GST_ERROR ("Unkown edit mode: %d", mode);
1393 return FALSE;
1394 }
1395
1396 return TRUE;
1397 }
1398
1399 /**
1400 * ges_track_element_remove_control_binding:
1401 * @object: the #GESTrackElement on which to set a control binding
1402 * @property_name: The name of the property to control.
1403 *
1404 * Removes a #GstControlBinding from @object.
1405 *
1406 * Returns: %TRUE if the binding could be removed, %FALSE if an error
1407 * occured
1408 */
1409 gboolean
ges_track_element_remove_control_binding(GESTrackElement * object,const gchar * property_name)1410 ges_track_element_remove_control_binding (GESTrackElement * object,
1411 const gchar * property_name)
1412 {
1413 GESTrackElementPrivate *priv;
1414 GstControlBinding *binding;
1415 GstObject *target;
1416
1417 g_return_val_if_fail (GES_IS_TRACK_ELEMENT (object), FALSE);
1418
1419 priv = GES_TRACK_ELEMENT (object)->priv;
1420 binding =
1421 (GstControlBinding *) g_hash_table_lookup (priv->bindings_hashtable,
1422 property_name);
1423
1424 if (binding) {
1425 g_object_get (binding, "object", &target, NULL);
1426 GST_DEBUG_OBJECT (object, "Removing binding %p for property %s", binding,
1427 property_name);
1428
1429 gst_object_ref (binding);
1430 gst_object_remove_control_binding (target, binding);
1431
1432 g_signal_emit (object, ges_track_element_signals[CONTROL_BINDING_REMOVED],
1433 0, binding);
1434
1435 gst_object_unref (target);
1436 gst_object_unref (binding);
1437 g_hash_table_remove (priv->bindings_hashtable, property_name);
1438
1439 return TRUE;
1440 }
1441
1442 return FALSE;
1443 }
1444
1445 /**
1446 * ges_track_element_set_control_source:
1447 * @object: the #GESTrackElement on which to set a control binding
1448 * @source: the #GstControlSource to set on the binding.
1449 * @property_name: The name of the property to control.
1450 * @binding_type: The type of binding to create. Currently the following values are valid:
1451 * - "direct": See #gst_direct_control_binding_new
1452 * - "direct-absolute": See #gst_direct_control_binding_new_absolute
1453 *
1454 * Creates a #GstControlBinding and adds it to the #GstElement concerned by the
1455 * property. Use the same syntax as #ges_track_element_lookup_child for
1456 * the property name.
1457 *
1458 * Returns: %TRUE if the binding could be created and added, %FALSE if an error
1459 * occured
1460 */
1461 gboolean
ges_track_element_set_control_source(GESTrackElement * object,GstControlSource * source,const gchar * property_name,const gchar * binding_type)1462 ges_track_element_set_control_source (GESTrackElement * object,
1463 GstControlSource * source,
1464 const gchar * property_name, const gchar * binding_type)
1465 {
1466 GESTrackElementPrivate *priv;
1467 GstElement *element;
1468 GParamSpec *pspec;
1469 GstControlBinding *binding;
1470 gboolean direct, direct_absolute;
1471
1472 g_return_val_if_fail (GES_IS_TRACK_ELEMENT (object), FALSE);
1473 priv = GES_TRACK_ELEMENT (object)->priv;
1474
1475 if (G_UNLIKELY (!(GST_IS_CONTROL_SOURCE (source)))) {
1476 GST_WARNING
1477 ("You need to provide a non-null control source to build a new control binding");
1478 return FALSE;
1479 }
1480
1481 if (!ges_track_element_lookup_child (object, property_name, &element, &pspec)) {
1482 GST_WARNING ("You need to provide a valid and controllable property name");
1483 return FALSE;
1484 }
1485
1486 /* TODO : update this according to new types of bindings */
1487 direct = !g_strcmp0 (binding_type, "direct");
1488 direct_absolute = !g_strcmp0 (binding_type, "direct-absolute");
1489
1490 if (direct || direct_absolute) {
1491 /* First remove existing binding */
1492 if (ges_track_element_remove_control_binding (object, property_name)) {
1493 GST_LOG ("Removed old binding for property %s", property_name);
1494 }
1495
1496 if (direct_absolute)
1497 binding =
1498 gst_direct_control_binding_new_absolute (GST_OBJECT (element),
1499 property_name, source);
1500 else
1501 binding =
1502 gst_direct_control_binding_new (GST_OBJECT (element), property_name,
1503 source);
1504
1505 gst_object_add_control_binding (GST_OBJECT (element), binding);
1506 g_hash_table_insert (priv->bindings_hashtable, g_strdup (property_name),
1507 binding);
1508 g_signal_emit (object, ges_track_element_signals[CONTROL_BINDING_ADDED],
1509 0, binding);
1510 return TRUE;
1511 }
1512
1513 GST_WARNING ("Binding type must be in [direct]");
1514
1515 return FALSE;
1516 }
1517
1518 /**
1519 * ges_track_element_get_control_binding:
1520 * @object: the #GESTrackElement in which to lookup the bindings.
1521 * @property_name: The property_name to which the binding is associated.
1522 *
1523 * Looks up the various controlled properties for that #GESTrackElement,
1524 * and returns the #GstControlBinding which controls @property_name.
1525 *
1526 * Returns: (transfer none) (nullable): the #GstControlBinding associated with
1527 * @property_name, or %NULL if that property is not controlled.
1528 */
1529 GstControlBinding *
ges_track_element_get_control_binding(GESTrackElement * object,const gchar * property_name)1530 ges_track_element_get_control_binding (GESTrackElement * object,
1531 const gchar * property_name)
1532 {
1533 GESTrackElementPrivate *priv;
1534 GstControlBinding *binding;
1535
1536 g_return_val_if_fail (GES_IS_TRACK_ELEMENT (object), NULL);
1537
1538 priv = GES_TRACK_ELEMENT (object)->priv;
1539
1540 binding =
1541 (GstControlBinding *) g_hash_table_lookup (priv->bindings_hashtable,
1542 property_name);
1543 return binding;
1544 }
1545