Merge branch 'tizen' into tizen_gst_1.19.2
[platform/upstream/gst-editing-services.git] / ges / ges-timeline-element.c
1 /* gst-editing-services
2  * Copyright (C) <2013> Thibault Saunier <thibault.saunier@collabora.com>
3  *               <2013> Collabora Ltd.
4  *
5  * gst-editing-services is free software: you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * gst-editing-services is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13  * See the GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 /**
20  * SECTION:gestimelineelement
21  * @title: GESTimelineElement
22  * @short_description: Base Class for all elements with some temporal extent
23  * within a #GESTimeline.
24  *
25  * A #GESTimelineElement will have some temporal extent in its
26  * corresponding #GESTimelineElement:timeline, controlled by its
27  * #GESTimelineElement:start and #GESTimelineElement:duration. This
28  * determines when its content will be displayed, or its effect applied,
29  * in the timeline. Several objects may overlap within a given
30  * #GESTimeline, in which case their #GESTimelineElement:priority is used
31  * to determine their ordering in the timeline. Priority is mostly handled
32  * internally by #GESLayer-s and #GESClip-s.
33  *
34  * A timeline element can have a #GESTimelineElement:parent,
35  * such as a #GESClip, which is responsible for controlling its timing.
36  *
37  * ## Editing
38  *
39  * Elements can be moved around in their #GESTimelineElement:timeline by
40  * setting their #GESTimelineElement:start and
41  * #GESTimelineElement:duration using ges_timeline_element_set_start()
42  * and ges_timeline_element_set_duration(). Additionally, which parts of
43  * the underlying content are played in the timeline can be adjusted by
44  * setting the #GESTimelineElement:in-point using
45  * ges_timeline_element_set_inpoint(). The library also provides
46  * ges_timeline_element_edit(), with various #GESEditMode-s, which can
47  * adjust these properties in a convenient way, as well as introduce
48  * similar changes in neighbouring or later elements in the timeline.
49  *
50  * However, a timeline may refuse a change in these properties if they
51  * would place the timeline in an unsupported configuration. See
52  * #GESTimeline for its overlap rules.
53  *
54  * Additionally, an edit may be refused if it would place one of the
55  * timing properties out of bounds (such as a negative time value for
56  * #GESTimelineElement:start, or having insufficient internal
57  * content to last for the desired #GESTimelineElement:duration).
58  *
59  * ## Time Coordinates
60  *
61  * There are three main sets of time coordinates to consider when using
62  * timeline elements:
63  *
64  * + Timeline coordinates: these are the time coordinates used in the
65  *   output of the timeline in its #GESTrack-s. Each track share the same
66  *   coordinates, so there is only one set of coordinates for the
67  *   timeline. These extend indefinitely from 0. The times used for
68  *   editing (including setting #GESTimelineElement:start and
69  *   #GESTimelineElement:duration) use these coordinates, since these
70  *   define when an element is present and for how long the element lasts
71  *   for in the timeline.
72  * + Internal source coordinates: these are the time coordinates used
73  *   internally at the element's output. This is only really defined for
74  *   #GESTrackElement-s, where it refers to time coordinates used at the
75  *   final source pad of the wrapped #GstElement-s. However, these
76  *   coordinates may also be used in a #GESClip in reference to its
77  *   children. In particular, these are the coordinates used for
78  *   #GESTimelineElement:in-point and #GESTimelineElement:max-duration.
79  * + Internal sink coordinates: these are the time coordinates used
80  *   internally at the element's input. A #GESSource has no input, so
81  *   these would be undefined. Otherwise, for most #GESTrackElement-s
82  *   these will be the same set of coordinates as the internal source
83  *   coordinates because the element does not change the timing
84  *   internally. Only #GESBaseEffect can support elements where these
85  *   are different. See #GESBaseEffect for more information.
86  *
87  * You can determine the timeline time for a given internal source time
88  * in a #GESTrack in a #GESClip using
89  * ges_clip_get_timeline_time_from_internal_time(), and vice versa using
90  * ges_clip_get_internal_time_from_timeline_time(), for the purposes of
91  * editing and setting timings properties.
92  *
93  * ## Children Properties
94  *
95  * If a timeline element owns another #GstObject and wishes to expose
96  * some of its properties, it can do so by registering the property as one
97  * of the timeline element's children properties using
98  * ges_timeline_element_add_child_property(). The registered property of
99  * the child can then be read and set using the
100  * ges_timeline_element_get_child_property() and
101  * ges_timeline_element_set_child_property() methods, respectively. Some
102  * sub-classed objects will be created with pre-registered children
103  * properties; for example, to expose part of an underlying #GstElement
104  * that is used internally. The registered properties can be listed with
105  * ges_timeline_element_list_children_properties().
106  */
107 #ifdef HAVE_CONFIG_H
108 #include "config.h"
109 #endif
110
111 #include "ges-utils.h"
112 #include "ges-timeline-element.h"
113 #include "ges-extractable.h"
114 #include "ges-meta-container.h"
115 #include "ges-internal.h"
116 #include "ges-effect.h"
117
118 #include <string.h>
119 #include <gobject/gvaluecollector.h>
120
121 /* maps type name quark => count */
122 static GData *object_name_counts = NULL;
123
124 static void
125 extractable_set_asset (GESExtractable * extractable, GESAsset * asset)
126 {
127   GES_TIMELINE_ELEMENT (extractable)->asset = asset;
128 }
129
130 static void
131 ges_extractable_interface_init (GESExtractableInterface * iface)
132 {
133   iface->set_asset = extractable_set_asset;
134 }
135
136 enum
137 {
138   PROP_0,
139   PROP_PARENT,
140   PROP_TIMELINE,
141   PROP_START,
142   PROP_INPOINT,
143   PROP_DURATION,
144   PROP_MAX_DURATION,
145   PROP_PRIORITY,
146   PROP_NAME,
147   PROP_SERIALIZE,
148   PROP_LAST
149 };
150
151 enum
152 {
153   DEEP_NOTIFY,
154   CHILD_PROPERTY_ADDED,
155   CHILD_PROPERTY_REMOVED,
156   LAST_SIGNAL
157 };
158
159 static guint ges_timeline_element_signals[LAST_SIGNAL] = { 0 };
160
161 static GParamSpec *properties[PROP_LAST] = { NULL, };
162
163 typedef struct
164 {
165   GObject *child;
166   GESTimelineElement *owner;
167   gulong handler_id;
168   GESTimelineElement *self;
169 } ChildPropHandler;
170
171 struct _GESTimelineElementPrivate
172 {
173   gboolean serialize;
174
175   /* We keep a link between properties name and elements internally
176    * The hashtable should look like
177    * {GParamaSpec ---> child}*/
178   GHashTable *children_props;
179
180   GESTimelineElement *copied_from;
181
182   GESTimelineElementFlags flags;
183 };
184
185 typedef struct
186 {
187   GObject *child;
188   GParamSpec *arg;
189   GESTimelineElement *self;
190 } EmitDeepNotifyInIdleData;
191
192 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GESTimelineElement, ges_timeline_element,
193     G_TYPE_INITIALLY_UNOWNED, G_ADD_PRIVATE (GESTimelineElement)
194     G_IMPLEMENT_INTERFACE (GES_TYPE_EXTRACTABLE, ges_extractable_interface_init)
195     G_IMPLEMENT_INTERFACE (GES_TYPE_META_CONTAINER, NULL));
196
197 /*********************************************
198  *      Virtual methods implementation       *
199  *********************************************/
200 static void
201 _set_child_property (GESTimelineElement * self G_GNUC_UNUSED, GObject * child,
202     GParamSpec * pspec, GValue * value)
203 {
204   if (G_VALUE_TYPE (value) != pspec->value_type
205       && G_VALUE_TYPE (value) == G_TYPE_STRING)
206     gst_util_set_object_arg (child, pspec->name, g_value_get_string (value));
207   else
208     g_object_set_property (child, pspec->name, value);
209 }
210
211 static gboolean
212 _set_child_property_full (GESTimelineElement * self, GObject * child,
213     GParamSpec * pspec, const GValue * value, GError ** error)
214 {
215   GES_TIMELINE_ELEMENT_GET_CLASS (self)->set_child_property (self, child,
216       pspec, (GValue *) value);
217   return TRUE;
218 }
219
220 static gboolean
221 _lookup_child (GESTimelineElement * self, const gchar * prop_name,
222     GObject ** child, GParamSpec ** pspec)
223 {
224   GHashTableIter iter;
225   gpointer key, value;
226   gchar **names, *name, *classename;
227   gboolean res;
228
229   classename = NULL;
230   res = FALSE;
231
232   names = g_strsplit (prop_name, "::", 2);
233   if (names[1] != NULL) {
234     classename = names[0];
235     name = names[1];
236   } else
237     name = names[0];
238
239   g_hash_table_iter_init (&iter, self->priv->children_props);
240   while (g_hash_table_iter_next (&iter, &key, &value)) {
241     if (g_strcmp0 (G_PARAM_SPEC (key)->name, name) == 0) {
242       ChildPropHandler *handler = (ChildPropHandler *) value;
243       if (classename == NULL ||
244           g_strcmp0 (G_OBJECT_TYPE_NAME (G_OBJECT (handler->child)),
245               classename) == 0 ||
246           g_strcmp0 (g_type_name (G_PARAM_SPEC (key)->owner_type),
247               classename) == 0) {
248         GST_DEBUG_OBJECT (self, "The %s property from %s has been found", name,
249             classename);
250         if (child)
251           *child = gst_object_ref (handler->child);
252
253         if (pspec)
254           *pspec = g_param_spec_ref (key);
255         res = TRUE;
256         break;
257       }
258     }
259   }
260   g_strfreev (names);
261
262   return res;
263 }
264
265 GParamSpec **
266 ges_timeline_element_get_children_properties (GESTimelineElement * self,
267     guint * n_properties)
268 {
269   GParamSpec **pspec, *spec;
270   GHashTableIter iter;
271   gpointer key, value;
272
273   guint i = 0;
274
275   *n_properties = g_hash_table_size (self->priv->children_props);
276   pspec = g_new (GParamSpec *, *n_properties);
277
278   g_hash_table_iter_init (&iter, self->priv->children_props);
279   while (g_hash_table_iter_next (&iter, &key, &value)) {
280     spec = G_PARAM_SPEC (key);
281     pspec[i] = g_param_spec_ref (spec);
282     i++;
283   }
284
285   return pspec;
286 }
287
288 static void
289 _get_property (GObject * object, guint property_id,
290     GValue * value, GParamSpec * pspec)
291 {
292   GESTimelineElement *self = GES_TIMELINE_ELEMENT (object);
293
294   switch (property_id) {
295     case PROP_PARENT:
296       g_value_take_object (value, self->parent);
297       break;
298     case PROP_TIMELINE:
299       g_value_take_object (value, self->timeline);
300       break;
301     case PROP_START:
302       g_value_set_uint64 (value, self->start);
303       break;
304     case PROP_INPOINT:
305       g_value_set_uint64 (value, self->inpoint);
306       break;
307     case PROP_DURATION:
308       g_value_set_uint64 (value, self->duration);
309       break;
310     case PROP_MAX_DURATION:
311       g_value_set_uint64 (value, self->maxduration);
312       break;
313     case PROP_PRIORITY:
314       g_value_set_uint (value, self->priority);
315       break;
316     case PROP_NAME:
317       g_value_take_string (value, ges_timeline_element_get_name (self));
318       break;
319     case PROP_SERIALIZE:
320       g_value_set_boolean (value, self->priv->serialize);
321       break;
322     default:
323       G_OBJECT_WARN_INVALID_PROPERTY_ID (self, property_id, pspec);
324   }
325 }
326
327 static void
328 _set_property (GObject * object, guint property_id,
329     const GValue * value, GParamSpec * pspec)
330 {
331   GESTimelineElement *self = GES_TIMELINE_ELEMENT (object);
332
333   switch (property_id) {
334     case PROP_PARENT:
335       ges_timeline_element_set_parent (self, g_value_get_object (value));
336       break;
337     case PROP_TIMELINE:
338       ges_timeline_element_set_timeline (self, g_value_get_object (value));
339       break;
340     case PROP_START:
341       ges_timeline_element_set_start (self, g_value_get_uint64 (value));
342       break;
343     case PROP_INPOINT:
344       ges_timeline_element_set_inpoint (self, g_value_get_uint64 (value));
345       break;
346     case PROP_DURATION:
347       ges_timeline_element_set_duration (self, g_value_get_uint64 (value));
348       break;
349     case PROP_PRIORITY:
350       ges_timeline_element_set_priority (self, g_value_get_uint (value));
351       break;
352     case PROP_MAX_DURATION:
353       ges_timeline_element_set_max_duration (self, g_value_get_uint64 (value));
354       break;
355     case PROP_NAME:
356       ges_timeline_element_set_name (self, g_value_get_string (value));
357       break;
358     case PROP_SERIALIZE:
359       self->priv->serialize = g_value_get_boolean (value);
360       break;
361     default:
362       G_OBJECT_WARN_INVALID_PROPERTY_ID (self, property_id, pspec);
363   }
364 }
365
366 static void
367 ges_timeline_element_dispose (GObject * object)
368 {
369   GESTimelineElement *self = GES_TIMELINE_ELEMENT (object);
370
371   if (self->priv->children_props) {
372     g_hash_table_unref (self->priv->children_props);
373     self->priv->children_props = NULL;
374   }
375
376   g_clear_object (&self->priv->copied_from);
377
378   G_OBJECT_CLASS (ges_timeline_element_parent_class)->dispose (object);
379 }
380
381 static void
382 ges_timeline_element_finalize (GObject * self)
383 {
384   GESTimelineElement *tle = GES_TIMELINE_ELEMENT (self);
385
386   g_free (tle->name);
387
388   G_OBJECT_CLASS (ges_timeline_element_parent_class)->finalize (self);
389 }
390
391 static void
392 _child_prop_handler_free (ChildPropHandler * handler)
393 {
394   g_object_freeze_notify (handler->child);
395   if (handler->handler_id)
396     g_signal_handler_disconnect (handler->child, handler->handler_id);
397   g_object_thaw_notify (handler->child);
398
399   if (handler->child != (GObject *) handler->self &&
400       handler->child != (GObject *) handler->owner)
401     gst_object_unref (handler->child);
402   g_slice_free (ChildPropHandler, handler);
403 }
404
405 static gboolean
406 _get_natural_framerate (GESTimelineElement * self, gint * framerate_n,
407     gint * framerate_d)
408 {
409   GST_INFO_OBJECT (self, "No natural framerate");
410
411   return FALSE;
412 }
413
414 static void
415 ges_timeline_element_init (GESTimelineElement * self)
416 {
417   self->priv = ges_timeline_element_get_instance_private (self);
418
419   self->priv->serialize = TRUE;
420
421   self->priv->children_props =
422       g_hash_table_new_full ((GHashFunc) ges_pspec_hash, ges_pspec_equal,
423       (GDestroyNotify) g_param_spec_unref,
424       (GDestroyNotify) _child_prop_handler_free);
425 }
426
427 static void
428 ges_timeline_element_class_init (GESTimelineElementClass * klass)
429 {
430   GObjectClass *object_class = G_OBJECT_CLASS (klass);
431
432   object_class->get_property = _get_property;
433   object_class->set_property = _set_property;
434
435   /**
436    * GESTimelineElement:parent:
437    *
438    * The parent container of the element.
439    */
440   properties[PROP_PARENT] =
441       g_param_spec_object ("parent", "Parent",
442       "The parent container of the object", GES_TYPE_TIMELINE_ELEMENT,
443       G_PARAM_READWRITE);
444
445   /**
446    * GESTimelineElement:timeline:
447    *
448    * The timeline that the element lies within.
449    */
450   properties[PROP_TIMELINE] =
451       g_param_spec_object ("timeline", "Timeline",
452       "The timeline the object is in", GES_TYPE_TIMELINE,
453       G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
454
455   /**
456    * GESTimelineElement:start:
457    *
458    * The starting position of the element in the timeline (in nanoseconds
459    * and in the time coordinates of the timeline). For example, for a
460    * source element, this would determine the time at which it should
461    * start outputting its internal content. For an operation element, this
462    * would determine the time at which it should start applying its effect
463    * to any source content.
464    */
465   properties[PROP_START] = g_param_spec_uint64 ("start", "Start",
466       "The position in the timeline", 0, G_MAXUINT64, 0,
467       G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
468
469   /**
470    * GESTimelineElement:in-point:
471    *
472    * The initial offset to use internally when outputting content (in
473    * nanoseconds, but in the time coordinates of the internal content).
474    *
475    * For example, for a #GESVideoUriSource that references some media
476    * file, the "internal content" is the media file data, and the
477    * in-point would correspond to some timestamp in the media file.
478    * When playing the timeline, and when the element is first reached at
479    * timeline-time #GESTimelineElement:start, it will begin outputting the
480    * data from the timestamp in-point **onwards**, until it reaches the
481    * end of its #GESTimelineElement:duration in the timeline.
482    *
483    * For elements that have no internal content, this should be kept
484    * as 0.
485    */
486   properties[PROP_INPOINT] =
487       g_param_spec_uint64 ("in-point", "In-point", "The in-point", 0,
488       G_MAXUINT64, 0, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
489
490   /**
491    * GESTimelineElement:duration:
492    *
493    * The duration that the element is in effect for in the timeline (a
494    * time difference in nanoseconds using the time coordinates of the
495    * timeline). For example, for a source element, this would determine
496    * for how long it should output its internal content for. For an
497    * operation element, this would determine for how long its effect
498    * should be applied to any source content.
499    */
500   properties[PROP_DURATION] =
501       g_param_spec_uint64 ("duration", "Duration", "The play duration", 0,
502       G_MAXUINT64, GST_CLOCK_TIME_NONE,
503       G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
504
505   /**
506    * GESTimelineElement:max-duration:
507    *
508    * The full duration of internal content that is available (a time
509    * difference in nanoseconds using the time coordinates of the internal
510    * content).
511    *
512    * This will act as a cap on the #GESTimelineElement:in-point of the
513    * element (which is in the same time coordinates), and will sometimes
514    * be used to limit the #GESTimelineElement:duration of the element in
515    * the timeline.
516    *
517    * For example, for a #GESVideoUriSource that references some media
518    * file, this would be the length of the media file.
519    *
520    * For elements that have no internal content, or whose content is
521    * indefinite, this should be kept as #GST_CLOCK_TIME_NONE.
522    */
523   properties[PROP_MAX_DURATION] =
524       g_param_spec_uint64 ("max-duration", "Maximum duration",
525       "The maximum duration of the object", 0, G_MAXUINT64, GST_CLOCK_TIME_NONE,
526       G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY);
527
528   /**
529    * GESTimelineElement:priority:
530    *
531    * The priority of the element.
532    *
533    * Deprecated: 1.10: Priority management is now done by GES itself.
534    */
535   properties[PROP_PRIORITY] = g_param_spec_uint ("priority", "Priority",
536       "The priority of the object", 0, G_MAXUINT, 0, G_PARAM_READWRITE);
537
538   /**
539    * GESTimelineElement:name:
540    *
541    * The name of the element. This should be unique within its timeline.
542    */
543   properties[PROP_NAME] =
544       g_param_spec_string ("name", "Name", "The name of the timeline object",
545       NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
546
547   /**
548    * GESTimelineElement:serialize:
549    *
550    * Whether the element should be serialized.
551    */
552   properties[PROP_SERIALIZE] = g_param_spec_boolean ("serialize", "Serialize",
553       "Whether the element should be serialized", TRUE,
554       G_PARAM_READWRITE | GES_PARAM_NO_SERIALIZATION);
555
556   g_object_class_install_properties (object_class, PROP_LAST, properties);
557
558   /**
559    * GESTimelineElement::deep-notify:
560    * @timeline_element: A #GESTtimelineElement
561    * @prop_object: The child whose property has been set
562    * @prop: The specification for the property that been set
563    *
564    * Emitted when a child of the element has one of its registered
565    * properties set. See ges_timeline_element_add_child_property().
566    * Note that unlike #GObject::notify, a child property name can not be
567    * used as a signal detail.
568    */
569   ges_timeline_element_signals[DEEP_NOTIFY] =
570       g_signal_new ("deep-notify", G_TYPE_FROM_CLASS (klass),
571       G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED |
572       G_SIGNAL_NO_HOOKS, 0, NULL, NULL, NULL,
573       G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_PARAM);
574
575   /**
576    * GESTimelineElement::child-property-added:
577    * @timeline_element: A #GESTtimelineElement
578    * @prop_object: The child whose property has been registered
579    * @prop: The specification for the property that has been registered
580    *
581    * Emitted when the element has a new child property registered. See
582    * ges_timeline_element_add_child_property().
583    *
584    * Note that some GES elements will be automatically created with
585    * pre-registered children properties. You can use
586    * ges_timeline_element_list_children_properties() to list these.
587    *
588    * Since: 1.18
589    */
590   ges_timeline_element_signals[CHILD_PROPERTY_ADDED] =
591       g_signal_new ("child-property-added", G_TYPE_FROM_CLASS (klass),
592       G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 2,
593       G_TYPE_OBJECT, G_TYPE_PARAM);
594
595   /**
596    * GESTimelineElement::child-property-removed:
597    * @timeline_element: A #GESTimelineElement
598    * @prop_object: The child whose property has been unregistered
599    * @prop: The specification for the property that has been unregistered
600    *
601    * Emitted when the element has a child property unregistered. See
602    * ges_timeline_element_remove_child_property().
603    *
604    * Since: 1.18
605    */
606   ges_timeline_element_signals[CHILD_PROPERTY_REMOVED] =
607       g_signal_new ("child-property-removed", G_TYPE_FROM_CLASS (klass),
608       G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 2,
609       G_TYPE_OBJECT, G_TYPE_PARAM);
610
611
612   object_class->dispose = ges_timeline_element_dispose;
613   object_class->finalize = ges_timeline_element_finalize;
614
615   klass->set_parent = NULL;
616   klass->set_start = NULL;
617   klass->set_inpoint = NULL;
618   klass->set_duration = NULL;
619   klass->set_max_duration = NULL;
620   klass->set_priority = NULL;
621
622   klass->ripple = NULL;
623   klass->ripple_end = NULL;
624   klass->roll_start = NULL;
625   klass->roll_end = NULL;
626   klass->trim = NULL;
627
628   klass->list_children_properties =
629       ges_timeline_element_get_children_properties;
630   klass->lookup_child = _lookup_child;
631   klass->set_child_property = _set_child_property;
632   klass->set_child_property_full = _set_child_property_full;
633   klass->get_natural_framerate = _get_natural_framerate;
634 }
635
636 static void
637 _set_name (GESTimelineElement * self, const gchar * wanted_name)
638 {
639   const gchar *type_name;
640   gchar *lowcase_type;
641   gint count;
642   GQuark q;
643   guint i, l;
644   gchar *name = NULL;
645
646   if (!object_name_counts) {
647     g_datalist_init (&object_name_counts);
648   }
649
650   q = g_type_qname (G_OBJECT_TYPE (self));
651   count = GPOINTER_TO_INT (g_datalist_id_get_data (&object_name_counts, q));
652
653   /* GstFooSink -> foosink<N> */
654   type_name = g_quark_to_string (q);
655   if (strncmp (type_name, "GES", 3) == 0)
656     type_name += 3;
657
658   lowcase_type = g_strdup (type_name);
659   l = strlen (lowcase_type);
660   for (i = 0; i < l; i++)
661     lowcase_type[i] = g_ascii_tolower (lowcase_type[i]);
662
663   if (wanted_name == NULL) {
664     /* give the 20th "uriclip" element and the first "uriclip2" (if needed in the future)
665      * different names */
666     l = strlen (type_name);
667     if (l > 0 && g_ascii_isdigit (type_name[l - 1])) {
668       name = g_strdup_printf ("%s-%d", lowcase_type, count++);
669     } else {
670       name = g_strdup_printf ("%s%d", lowcase_type, count++);
671     }
672   } else {
673     /* If the wanted name uses the same 'namespace' as default, make
674      * sure it does not badly interfere with our counting system */
675
676     /* FIXME: should we really be allowing a user to set the name
677      * "uriclip1" for, say, a GESTransition? The below code *does not*
678      * capture this case (because the prefix does not match "transition").
679      * If the user subsequently calls _set_name with name == NULL, on a
680      * GESClip *for the first time*, then the GES library will
681      * automatically choose the *same* name "uriclip1", but this is not
682      * unique! */
683     if (g_str_has_prefix (wanted_name, lowcase_type)) {
684       guint64 tmpcount =
685           g_ascii_strtoull (&wanted_name[strlen (lowcase_type)], NULL, 10);
686
687       if (tmpcount > count) {
688         count = tmpcount + 1;
689         GST_DEBUG_OBJECT (self, "Using same naming %s but updated count to %i",
690             wanted_name, count);
691       } else if (tmpcount < count) {
692         /* FIXME: this can unexpectedly change names given by the user
693          * E.g. if "transition2" already exists, and a user then wants to
694          * set a GESTransition to have the name "transition-custom" or
695          * "transition 1 too many" then tmpcount would in fact be 0 or 1,
696          * and the name would then be changed to "transition3"! */
697         name = g_strdup_printf ("%s%d", lowcase_type, count);
698         count++;
699         GST_DEBUG_OBJECT (self, "Name %s already allocated, giving: %s instead"
700             " New count is %i", wanted_name, name, count);
701       } else {
702         count++;
703         GST_DEBUG_OBJECT (self, "Perfect name, just bumping object count");
704       }
705     }
706
707     if (name == NULL)
708       name = g_strdup (wanted_name);
709   }
710
711   g_free (lowcase_type);
712   g_datalist_id_set_data (&object_name_counts, q, GINT_TO_POINTER (count));
713
714   g_free (self->name);
715   self->name = name;
716 }
717
718 /*********************************************
719  *       Internal and private helpers        *
720  *********************************************/
721
722 GESTimelineElement *
723 ges_timeline_element_peak_toplevel (GESTimelineElement * self)
724 {
725   GESTimelineElement *toplevel = self;
726
727   while (toplevel->parent)
728     toplevel = toplevel->parent;
729
730   return toplevel;
731 }
732
733 GESTimelineElement *
734 ges_timeline_element_get_copied_from (GESTimelineElement * self)
735 {
736   GESTimelineElement *copied_from = self->priv->copied_from;
737   self->priv->copied_from = NULL;
738   return copied_from;
739 }
740
741 GESTimelineElementFlags
742 ges_timeline_element_flags (GESTimelineElement * self)
743 {
744   return self->priv->flags;
745 }
746
747 void
748 ges_timeline_element_set_flags (GESTimelineElement * self,
749     GESTimelineElementFlags flags)
750 {
751   self->priv->flags = flags;
752
753 }
754
755 static gboolean
756 emit_deep_notify_in_idle (EmitDeepNotifyInIdleData * data)
757 {
758   g_signal_emit (data->self, ges_timeline_element_signals[DEEP_NOTIFY], 0,
759       data->child, data->arg);
760
761   gst_object_unref (data->child);
762   g_param_spec_unref (data->arg);
763   gst_object_unref (data->self);
764   g_slice_free (EmitDeepNotifyInIdleData, data);
765
766   return FALSE;
767 }
768
769 static void
770 child_prop_changed_cb (GObject * child, GParamSpec * arg,
771     GESTimelineElement * self)
772 {
773   EmitDeepNotifyInIdleData *data;
774
775   /* Emit "deep-notify" right away if in main thread */
776   if (g_main_context_acquire (g_main_context_default ())) {
777     g_main_context_release (g_main_context_default ());
778     g_signal_emit (self, ges_timeline_element_signals[DEEP_NOTIFY], 0,
779         child, arg);
780     return;
781   }
782
783   data = g_slice_new (EmitDeepNotifyInIdleData);
784
785   data->child = gst_object_ref (child);
786   data->arg = g_param_spec_ref (arg);
787   data->self = gst_object_ref (self);
788
789   ges_idle_add ((GSourceFunc) emit_deep_notify_in_idle, data, NULL);
790 }
791
792 static gboolean
793 set_child_property_by_pspec (GESTimelineElement * self,
794     GParamSpec * pspec, const GValue * value, GError ** error)
795 {
796   GESTimelineElementClass *klass;
797   GESTimelineElement *setter = self;
798   ChildPropHandler *handler =
799       g_hash_table_lookup (self->priv->children_props, pspec);
800
801   if (!handler) {
802     GST_ERROR_OBJECT (self, "The %s property doesn't exist", pspec->name);
803     return FALSE;
804   }
805
806   if (handler->owner) {
807     klass = GES_TIMELINE_ELEMENT_GET_CLASS (handler->owner);
808     setter = handler->owner;
809   } else {
810     klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
811   }
812
813   if (klass->set_child_property_full)
814     return klass->set_child_property_full (setter, handler->child, pspec,
815         value, error);
816
817   g_assert (klass->set_child_property);
818   klass->set_child_property (setter, handler->child, pspec, (GValue *) value);
819
820   return TRUE;
821 }
822
823 gboolean
824 ges_timeline_element_add_child_property_full (GESTimelineElement * self,
825     GESTimelineElement * owner, GParamSpec * pspec, GObject * child)
826 {
827   gchar *signame;
828   ChildPropHandler *handler;
829
830   /* FIXME: allow the same pspec, provided the child is different. This
831    * is important for containers that may have duplicate children
832    * If this is changed, _remove_childs_child_property in ges-container.c
833    * should be changed to reflect this.
834    * We could hack around this by copying the pspec into a new instance
835    * of GParamSpec, but there is no such GLib method, and it would break
836    * the usage of get_..._from_pspec and set_..._from_pspec */
837   if (g_hash_table_contains (self->priv->children_props, pspec)) {
838     GST_INFO_OBJECT (self, "Child property already exists: %s", pspec->name);
839     return FALSE;
840   }
841
842   GST_DEBUG_OBJECT (self, "Adding child property: %" GST_PTR_FORMAT "::%s",
843       child, pspec->name);
844
845   signame = g_strconcat ("notify::", pspec->name, NULL);
846   handler = (ChildPropHandler *) g_slice_new0 (ChildPropHandler);
847   handler->self = self;
848   if (child == G_OBJECT (self) || child == G_OBJECT (owner))
849     handler->child = child;
850   else
851     handler->child = gst_object_ref (child);
852   handler->owner = owner;
853   handler->handler_id =
854       g_signal_connect (child, signame, G_CALLBACK (child_prop_changed_cb),
855       self);
856   g_hash_table_insert (self->priv->children_props, g_param_spec_ref (pspec),
857       handler);
858
859   g_signal_emit (self, ges_timeline_element_signals[CHILD_PROPERTY_ADDED], 0,
860       child, pspec);
861
862   g_free (signame);
863   return TRUE;
864 }
865
866 GObject *
867 ges_timeline_element_get_child_from_child_property (GESTimelineElement * self,
868     GParamSpec * pspec)
869 {
870   ChildPropHandler *handler =
871       g_hash_table_lookup (self->priv->children_props, pspec);
872   if (handler)
873     return handler->child;
874   return NULL;
875 }
876
877
878 /*********************************************
879  *            API implementation             *
880  *********************************************/
881
882 /**
883  * ges_timeline_element_set_parent:
884  * @self: A #GESTimelineElement
885  * @parent (nullable): New parent of @self
886  *
887  * Sets the #GESTimelineElement:parent for the element.
888  *
889  * This is used internally and you should normally not call this. A
890  * #GESContainer will set the #GESTimelineElement:parent of its children
891  * in ges_container_add() and ges_container_remove().
892  *
893  * Note, if @parent is not %NULL, @self must not already have a parent
894  * set. Therefore, if you wish to switch parents, you will need to call
895  * this function twice: first to set the parent to %NULL, and then to the
896  * new parent.
897  *
898  * If @parent is not %NULL, you must ensure it already has a
899  * (non-floating) reference to @self before calling this.
900  *
901  * Returns: %TRUE if @parent could be set for @self.
902  */
903 gboolean
904 ges_timeline_element_set_parent (GESTimelineElement * self,
905     GESTimelineElement * parent)
906 {
907   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
908   g_return_val_if_fail (parent == NULL
909       || GES_IS_TIMELINE_ELEMENT (parent), FALSE);
910
911   if (self == parent) {
912     GST_INFO_OBJECT (self, "Trying to add %p in itself, not a good idea!",
913         self);
914     /* FIXME: why are we sinking and then unreffing self when we do not
915      * own it? */
916     gst_object_ref_sink (self);
917     gst_object_unref (self);
918     return FALSE;
919   }
920
921   GST_DEBUG_OBJECT (self, "set parent to %" GST_PTR_FORMAT, parent);
922
923   if (self->parent != NULL && parent != NULL)
924     goto had_parent;
925
926   if (GES_TIMELINE_ELEMENT_GET_CLASS (self)->set_parent) {
927     if (!GES_TIMELINE_ELEMENT_GET_CLASS (self)->set_parent (self, parent))
928       return FALSE;
929   }
930
931   self->parent = parent;
932
933   g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PARENT]);
934   return TRUE;
935
936   /* ERROR handling */
937 had_parent:
938   {
939     GST_WARNING_OBJECT (self, "set parent failed, object already had a parent");
940     /* FIXME: why are we sinking and then unreffing self when we do not
941      * own it? */
942     gst_object_ref_sink (self);
943     gst_object_unref (self);
944     return FALSE;
945   }
946 }
947
948 /**
949  * ges_timeline_element_get_parent:
950  * @self: A #GESTimelineElement
951  *
952  * Gets the #GESTimelineElement:parent for the element.
953  *
954  * Returns: (transfer full) (nullable): The parent of @self, or %NULL if
955  * @self has no parent.
956  */
957 GESTimelineElement *
958 ges_timeline_element_get_parent (GESTimelineElement * self)
959 {
960   GESTimelineElement *result = NULL;
961
962   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), NULL);
963
964   result = self->parent;
965   if (G_LIKELY (result))
966     gst_object_ref (result);
967
968   return result;
969 }
970
971 /**
972  * ges_timeline_element_set_timeline:
973  * @self: A #GESTimelineElement
974  * @timeline (nullable): The #GESTimeline @self should be in
975  *
976  * Sets the #GESTimelineElement:timeline of the element.
977  *
978  * This is used internally and you should normally not call this. A
979  * #GESClip will have its #GESTimelineElement:timeline set through its
980  * #GESLayer. A #GESTrack will similarly take care of setting the
981  * #GESTimelineElement:timeline of its #GESTrackElement-s. A #GESGroup
982  * will adopt the same #GESTimelineElement:timeline as its children.
983  *
984  * If @timeline is %NULL, this will stop its current
985  * #GESTimelineElement:timeline from tracking it, otherwise @timeline will
986  * start tracking @self. Note, in the latter case, @self must not already
987  * have a timeline set. Therefore, if you wish to switch timelines, you
988  * will need to call this function twice: first to set the timeline to
989  * %NULL, and then to the new timeline.
990  *
991  * Returns: %TRUE if @timeline could be set for @self.
992  */
993 gboolean
994 ges_timeline_element_set_timeline (GESTimelineElement * self,
995     GESTimeline * timeline)
996 {
997   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
998   g_return_val_if_fail (timeline == NULL || GES_IS_TIMELINE (timeline), FALSE);
999
1000   GST_DEBUG_OBJECT (self, "set timeline to %" GST_PTR_FORMAT, timeline);
1001
1002   if (self->timeline == timeline)
1003     return TRUE;
1004
1005   if (timeline != NULL && G_UNLIKELY (self->timeline != NULL))
1006     goto had_timeline;
1007
1008   if (timeline == NULL) {
1009     if (self->timeline) {
1010       if (!timeline_remove_element (self->timeline, self)) {
1011         GST_INFO_OBJECT (self, "Could not remove from"
1012             " currently set timeline %" GST_PTR_FORMAT, self->timeline);
1013         return FALSE;
1014       }
1015     }
1016   } else {
1017     if (!timeline_add_element (timeline, self)) {
1018       GST_INFO_OBJECT (self, "Could not add to timeline %" GST_PTR_FORMAT,
1019           self);
1020       return FALSE;
1021     }
1022   }
1023
1024   self->timeline = timeline;
1025
1026   g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TIMELINE]);
1027   return TRUE;
1028
1029   /* ERROR handling */
1030 had_timeline:
1031   {
1032     GST_DEBUG_OBJECT (self, "set timeline failed, object already had a "
1033         "timeline");
1034     return FALSE;
1035   }
1036 }
1037
1038 /**
1039  * ges_timeline_element_get_timeline:
1040  * @self: A #GESTimelineElement
1041  *
1042  * Gets the #GESTimelineElement:timeline for the element.
1043  *
1044  * Returns: (transfer full) (nullable): The timeline of @self, or %NULL
1045  * if @self has no timeline.
1046  */
1047 GESTimeline *
1048 ges_timeline_element_get_timeline (GESTimelineElement * self)
1049 {
1050   GESTimeline *result = NULL;
1051
1052   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), NULL);
1053
1054   result = self->timeline;
1055   if (G_LIKELY (result))
1056     gst_object_ref (result);
1057
1058   return result;
1059 }
1060
1061 /**
1062  * ges_timeline_element_set_start:
1063  * @self: A #GESTimelineElement
1064  * @start: The desired start position of the element in its timeline
1065  *
1066  * Sets #GESTimelineElement:start for the element. If the element has a
1067  * parent, this will also move its siblings with the same shift.
1068  *
1069  * Whilst the element is part of a #GESTimeline, this is the same as
1070  * editing the element with ges_timeline_element_edit() under
1071  * #GES_EDIT_MODE_NORMAL with #GES_EDGE_NONE. In particular, the
1072  * #GESTimelineElement:start of the element may be snapped to a different
1073  * timeline time from the one given. In addition, setting may fail if it
1074  * would place the timeline in an unsupported configuration.
1075  *
1076  * Returns: %TRUE if @start could be set for @self.
1077  */
1078 gboolean
1079 ges_timeline_element_set_start (GESTimelineElement * self, GstClockTime start)
1080 {
1081   GESTimelineElementClass *klass;
1082   GESTimelineElement *toplevel_container, *parent;
1083
1084   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1085   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (start), FALSE);
1086
1087   if (self->start == start)
1088     return TRUE;
1089
1090   GST_DEBUG_OBJECT (self, "current start: %" GST_TIME_FORMAT
1091       " new start: %" GST_TIME_FORMAT,
1092       GST_TIME_ARGS (GES_TIMELINE_ELEMENT_START (self)), GST_TIME_ARGS (start));
1093
1094   if (self->timeline && !GES_TIMELINE_ELEMENT_BEING_EDITED (self))
1095     return ges_timeline_element_edit (self, NULL, -1, GES_EDIT_MODE_NORMAL,
1096         GES_EDGE_NONE, start);
1097
1098   toplevel_container = ges_timeline_element_peak_toplevel (self);
1099   parent = self->parent;
1100
1101   /* FIXME This should not belong to GESTimelineElement */
1102   /* only check if no timeline, otherwise the timeline-tree will handle this
1103    * check */
1104   if (!self->timeline && toplevel_container &&
1105       ((gint64) (_START (toplevel_container) + start - _START (self))) < 0 &&
1106       parent
1107       && GES_CONTAINER (parent)->children_control_mode == GES_CHILDREN_UPDATE) {
1108     GST_INFO_OBJECT (self,
1109         "Can not move the object as it would imply its "
1110         "container to have a negative start value");
1111
1112     return FALSE;
1113   }
1114
1115   klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1116   if (klass->set_start) {
1117     gint res = klass->set_start (self, start);
1118     if (res == FALSE)
1119       return FALSE;
1120     if (res == TRUE) {
1121       self->start = start;
1122       g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_START]);
1123     }
1124
1125     GST_DEBUG_OBJECT (self, "New start: %" GST_TIME_FORMAT,
1126         GST_TIME_ARGS (GES_TIMELINE_ELEMENT_START (self)));
1127
1128     return TRUE;
1129   }
1130
1131   GST_WARNING_OBJECT (self, "No set_start virtual method implementation"
1132       " on class %s. Can not set start %" GST_TIME_FORMAT,
1133       G_OBJECT_CLASS_NAME (klass), GST_TIME_ARGS (start));
1134   return FALSE;
1135 }
1136
1137 /**
1138  * ges_timeline_element_set_inpoint:
1139  * @self: A #GESTimelineElement
1140  * @inpoint: The in-point, in internal time coordinates
1141  *
1142  * Sets #GESTimelineElement:in-point for the element. If the new in-point
1143  * is above the current #GESTimelineElement:max-duration of the element,
1144  * this method will fail.
1145  *
1146  * Returns: %TRUE if @inpoint could be set for @self.
1147  */
1148 gboolean
1149 ges_timeline_element_set_inpoint (GESTimelineElement * self,
1150     GstClockTime inpoint)
1151 {
1152   GESTimelineElementClass *klass;
1153
1154   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1155
1156   GST_DEBUG_OBJECT (self, "current inpoint: %" GST_TIME_FORMAT
1157       " new inpoint: %" GST_TIME_FORMAT, GST_TIME_ARGS (self->inpoint),
1158       GST_TIME_ARGS (inpoint));
1159
1160   if (G_UNLIKELY (inpoint == self->inpoint))
1161     return TRUE;
1162
1163   if (GES_CLOCK_TIME_IS_LESS (self->maxduration, inpoint)) {
1164     GST_WARNING_OBJECT (self, "Can not set an in-point of %" GST_TIME_FORMAT
1165         " because it exceeds the element's max-duration: %" GST_TIME_FORMAT,
1166         GST_TIME_ARGS (inpoint), GST_TIME_ARGS (self->maxduration));
1167     return FALSE;
1168   }
1169
1170   klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1171
1172   if (klass->set_inpoint) {
1173     /* FIXME: Could we instead use g_object_freeze_notify() to prevent
1174      * duplicate notify signals? Rather than relying on the return value
1175      * being -1 for setting that succeeds but does not want a notify
1176      * signal because it will call this method on itself a second time. */
1177     if (!klass->set_inpoint (self, inpoint))
1178       return FALSE;
1179
1180     self->inpoint = inpoint;
1181     g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_INPOINT]);
1182
1183     return TRUE;
1184   }
1185
1186   GST_DEBUG_OBJECT (self, "No set_inpoint virtual method implementation"
1187       " on class %s. Can not set inpoint %" GST_TIME_FORMAT,
1188       G_OBJECT_CLASS_NAME (klass), GST_TIME_ARGS (inpoint));
1189
1190   return FALSE;
1191 }
1192
1193 /**
1194  * ges_timeline_element_set_max_duration:
1195  * @self: A #GESTimelineElement
1196  * @maxduration: The maximum duration, in internal time coordinates
1197  *
1198  * Sets #GESTimelineElement:max-duration for the element. If the new
1199  * maximum duration is below the current #GESTimelineElement:in-point of
1200  * the element, this method will fail.
1201  *
1202  * Returns: %TRUE if @maxduration could be set for @self.
1203  */
1204 gboolean
1205 ges_timeline_element_set_max_duration (GESTimelineElement * self,
1206     GstClockTime maxduration)
1207 {
1208   GESTimelineElementClass *klass;
1209
1210   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1211
1212   GST_DEBUG_OBJECT (self, "current max-duration: %" GST_TIME_FORMAT
1213       " new max-duration: %" GST_TIME_FORMAT,
1214       GST_TIME_ARGS (self->maxduration), GST_TIME_ARGS (maxduration));
1215
1216   if (G_UNLIKELY (maxduration == self->maxduration))
1217     return TRUE;
1218
1219   if (GES_CLOCK_TIME_IS_LESS (maxduration, self->inpoint)) {
1220     GST_WARNING_OBJECT (self, "Can not set a max-duration of %"
1221         GST_TIME_FORMAT " because it lies below the element's in-point: %"
1222         GST_TIME_FORMAT, GST_TIME_ARGS (maxduration),
1223         GST_TIME_ARGS (self->inpoint));
1224     return FALSE;
1225   }
1226
1227   klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1228
1229   if (klass->set_max_duration) {
1230     if (!klass->set_max_duration (self, maxduration))
1231       return FALSE;
1232     self->maxduration = maxduration;
1233     g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MAX_DURATION]);
1234
1235     return TRUE;
1236   }
1237
1238   GST_DEBUG_OBJECT (self, "No set_max_duration virtual method implementation"
1239       " on class %s. Can not set max-duration  %" GST_TIME_FORMAT,
1240       G_OBJECT_CLASS_NAME (klass), GST_TIME_ARGS (maxduration));
1241
1242   return FALSE;
1243 }
1244
1245 /**
1246  * ges_timeline_element_set_duration:
1247  * @self: A #GESTimelineElement
1248  * @duration: The desired duration in its timeline
1249  *
1250  * Sets #GESTimelineElement:duration for the element.
1251  *
1252  * Whilst the element is part of a #GESTimeline, this is the same as
1253  * editing the element with ges_timeline_element_edit() under
1254  * #GES_EDIT_MODE_TRIM with #GES_EDGE_END. In particular, the
1255  * #GESTimelineElement:duration of the element may be snapped to a
1256  * different timeline time difference from the one given. In addition,
1257  * setting may fail if it would place the timeline in an unsupported
1258  * configuration, or the element does not have enough internal content to
1259  * last the desired duration.
1260  *
1261  * Returns: %TRUE if @duration could be set for @self.
1262  */
1263 gboolean
1264 ges_timeline_element_set_duration (GESTimelineElement * self,
1265     GstClockTime duration)
1266 {
1267   GESTimelineElementClass *klass;
1268
1269   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1270
1271   if (duration == self->duration)
1272     return TRUE;
1273
1274   if (self->timeline && !GES_TIMELINE_ELEMENT_BEING_EDITED (self))
1275     return ges_timeline_element_edit (self, NULL, -1, GES_EDIT_MODE_TRIM,
1276         GES_EDGE_END, self->start + duration);
1277
1278   GST_DEBUG_OBJECT (self, "current duration: %" GST_TIME_FORMAT
1279       " new duration: %" GST_TIME_FORMAT,
1280       GST_TIME_ARGS (GES_TIMELINE_ELEMENT_DURATION (self)),
1281       GST_TIME_ARGS (duration));
1282
1283   klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1284   if (klass->set_duration) {
1285     gint res = klass->set_duration (self, duration);
1286     if (res == FALSE)
1287       return FALSE;
1288     if (res == TRUE) {
1289       self->duration = duration;
1290       g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DURATION]);
1291     }
1292
1293     return TRUE;
1294   }
1295
1296   GST_WARNING_OBJECT (self, "No set_duration virtual method implementation"
1297       " on class %s. Can not set duration %" GST_TIME_FORMAT,
1298       G_OBJECT_CLASS_NAME (klass), GST_TIME_ARGS (duration));
1299   return FALSE;
1300 }
1301
1302 /**
1303  * ges_timeline_element_get_start:
1304  * @self: A #GESTimelineElement
1305  *
1306  * Gets the #GESTimelineElement:start for the element.
1307  *
1308  * Returns: The start of @self (in nanoseconds).
1309  */
1310 GstClockTime
1311 ges_timeline_element_get_start (GESTimelineElement * self)
1312 {
1313   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), GST_CLOCK_TIME_NONE);
1314
1315   return self->start;
1316 }
1317
1318 /**
1319  * ges_timeline_element_get_inpoint:
1320  * @self: A #GESTimelineElement
1321  *
1322  * Gets the #GESTimelineElement:in-point for the element.
1323  *
1324  * Returns: The in-point of @self (in nanoseconds).
1325  */
1326 GstClockTime
1327 ges_timeline_element_get_inpoint (GESTimelineElement * self)
1328 {
1329   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), GST_CLOCK_TIME_NONE);
1330
1331   return self->inpoint;
1332 }
1333
1334 /**
1335  * ges_timeline_element_get_duration:
1336  * @self: A #GESTimelineElement
1337  *
1338  * Gets the #GESTimelineElement:duration for the element.
1339  *
1340  * Returns: The duration of @self (in nanoseconds).
1341  */
1342 GstClockTime
1343 ges_timeline_element_get_duration (GESTimelineElement * self)
1344 {
1345   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), GST_CLOCK_TIME_NONE);
1346
1347   return self->duration;
1348 }
1349
1350 /**
1351  * ges_timeline_element_get_max_duration:
1352  * @self: A #GESTimelineElement
1353  *
1354  * Gets the #GESTimelineElement:max-duration for the element.
1355  *
1356  * Returns: The max-duration of @self (in nanoseconds).
1357  */
1358 GstClockTime
1359 ges_timeline_element_get_max_duration (GESTimelineElement * self)
1360 {
1361   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), GST_CLOCK_TIME_NONE);
1362
1363   return self->maxduration;
1364 }
1365
1366 /**
1367  * ges_timeline_element_get_priority:
1368  * @self: A #GESTimelineElement
1369  *
1370  * Gets the #GESTimelineElement:priority for the element.
1371  *
1372  * Returns: The priority of @self.
1373  */
1374 guint32
1375 ges_timeline_element_get_priority (GESTimelineElement * self)
1376 {
1377   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), 0);
1378
1379   return self->priority;
1380 }
1381
1382 /**
1383  * ges_timeline_element_set_priority:
1384  * @self: A #GESTimelineElement
1385  * @priority: The priority
1386  *
1387  * Sets the priority of the element within the containing layer.
1388  *
1389  * Deprecated:1.10: All priority management is done by GES itself now.
1390  * To set #GESEffect priorities #ges_clip_set_top_effect_index should
1391  * be used.
1392  *
1393  * Returns: %TRUE if @priority could be set for @self.
1394  */
1395 gboolean
1396 ges_timeline_element_set_priority (GESTimelineElement * self, guint32 priority)
1397 {
1398   GESTimelineElementClass *klass;
1399
1400   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1401
1402   klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1403
1404   GST_DEBUG_OBJECT (self, "current priority: %d new priority: %d",
1405       self->priority, priority);
1406
1407   if (klass->set_priority) {
1408     gboolean res = klass->set_priority (self, priority);
1409     if (res) {
1410       self->priority = priority;
1411       g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PRIORITY]);
1412     }
1413
1414     return res;
1415   }
1416
1417   GST_WARNING_OBJECT (self, "No set_priority virtual method implementation"
1418       " on class %s. Can not set priority %d", G_OBJECT_CLASS_NAME (klass),
1419       priority);
1420   return FALSE;
1421 }
1422
1423 /**
1424  * ges_timeline_element_ripple:
1425  * @self: The #GESTimelineElement to ripple
1426  * @start: The new start time of @self in ripple mode
1427  *
1428  * Edits the start time of an element within its timeline in ripple mode.
1429  * See ges_timeline_element_edit() with #GES_EDIT_MODE_RIPPLE and
1430  * #GES_EDGE_NONE.
1431  *
1432  * Returns: %TRUE if the ripple edit of @self completed, %FALSE on
1433  * failure.
1434  */
1435 gboolean
1436 ges_timeline_element_ripple (GESTimelineElement * self, GstClockTime start)
1437 {
1438   GESTimelineElementClass *klass;
1439
1440   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1441   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (start), FALSE);
1442
1443   klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1444
1445   if (klass->ripple)
1446     return klass->ripple (self, start);
1447
1448   return ges_timeline_element_edit (self, NULL, -1, GES_EDIT_MODE_RIPPLE,
1449       GES_EDGE_NONE, start);
1450
1451   return FALSE;
1452 }
1453
1454 /**
1455  * ges_timeline_element_ripple_end:
1456  * @self: The #GESTimelineElement to ripple
1457  * @end: The new end time of @self in ripple mode
1458  *
1459  * Edits the end time of an element within its timeline in ripple mode.
1460  * See ges_timeline_element_edit() with #GES_EDIT_MODE_RIPPLE and
1461  * #GES_EDGE_END.
1462  *
1463  * Returns: %TRUE if the ripple edit of @self completed, %FALSE on
1464  * failure.
1465  */
1466 gboolean
1467 ges_timeline_element_ripple_end (GESTimelineElement * self, GstClockTime end)
1468 {
1469   GESTimelineElementClass *klass;
1470
1471   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1472   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (end), FALSE);
1473
1474   klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1475
1476   if (klass->ripple_end)
1477     return klass->ripple_end (self, end);
1478
1479   return ges_timeline_element_edit (self, NULL, -1, GES_EDIT_MODE_RIPPLE,
1480       GES_EDGE_END, end);
1481 }
1482
1483 /**
1484  * ges_timeline_element_roll_start:
1485  * @self: The #GESTimelineElement to roll
1486  * @start: The new start time of @self in roll mode
1487  *
1488  * Edits the start time of an element within its timeline in roll mode.
1489  * See ges_timeline_element_edit() with #GES_EDIT_MODE_ROLL and
1490  * #GES_EDGE_START.
1491  *
1492  * Returns: %TRUE if the roll edit of @self completed, %FALSE on failure.
1493  */
1494 gboolean
1495 ges_timeline_element_roll_start (GESTimelineElement * self, GstClockTime start)
1496 {
1497   GESTimelineElementClass *klass;
1498
1499   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1500   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (start), FALSE);
1501
1502   klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1503
1504   if (klass->roll_start)
1505     return klass->roll_start (self, start);
1506
1507   return ges_timeline_element_edit (self, NULL, -1, GES_EDIT_MODE_ROLL,
1508       GES_EDGE_START, start);
1509 }
1510
1511 /**
1512  * ges_timeline_element_roll_end:
1513  * @self: The #GESTimelineElement to roll
1514  * @end: The new end time of @self in roll mode
1515  *
1516  * Edits the end time of an element within its timeline in roll mode.
1517  * See ges_timeline_element_edit() with #GES_EDIT_MODE_ROLL and
1518  * #GES_EDGE_END.
1519  *
1520  * Returns: %TRUE if the roll edit of @self completed, %FALSE on failure.
1521  */
1522 gboolean
1523 ges_timeline_element_roll_end (GESTimelineElement * self, GstClockTime end)
1524 {
1525   GESTimelineElementClass *klass;
1526
1527   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1528   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (end), FALSE);
1529
1530   klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1531
1532   if (klass->roll_end)
1533     return klass->roll_end (self, end);
1534
1535   return ges_timeline_element_edit (self, NULL, -1, GES_EDIT_MODE_ROLL,
1536       GES_EDGE_END, end);
1537 }
1538
1539 /**
1540  * ges_timeline_element_trim:
1541  * @self: The #GESTimelineElement to trim
1542  * @start: The new start time of @self in trim mode
1543  *
1544  * Edits the start time of an element within its timeline in trim mode.
1545  * See ges_timeline_element_edit() with #GES_EDIT_MODE_TRIM and
1546  * #GES_EDGE_START.
1547  *
1548  * Returns: %TRUE if the trim edit of @self completed, %FALSE on failure.
1549  */
1550 gboolean
1551 ges_timeline_element_trim (GESTimelineElement * self, GstClockTime start)
1552 {
1553   GESTimelineElementClass *klass;
1554
1555   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1556   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (start), FALSE);
1557
1558   klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1559
1560   if (klass->trim)
1561     return klass->trim (self, start);
1562
1563   return ges_timeline_element_edit (self, NULL, -1, GES_EDIT_MODE_TRIM,
1564       GES_EDGE_START, start);
1565 }
1566
1567 /**
1568  * ges_timeline_element_copy:
1569  * @self: The #GESTimelineElement to copy
1570  * @deep: Whether the copy is needed for pasting
1571  *
1572  * Create a copy of @self. All the properties of @self are copied into
1573  * a new element, with the exception of #GESTimelineElement:parent,
1574  * #GESTimelineElement:timeline and #GESTimelineElement:name. Other data,
1575  * such the list of a #GESContainer's children, is **not** copied.
1576  *
1577  * If @deep is %TRUE, then the new element is prepared so that it can be
1578  * used in ges_timeline_element_paste() or ges_timeline_paste_element().
1579  * In the case of copying a #GESContainer, this ensures that the children
1580  * of @self will also be pasted. The new element should not be used for
1581  * anything else and can only be used **once** in a pasting operation. In
1582  * particular, the new element itself is not an actual 'deep' copy of
1583  * @self, but should be thought of as an intermediate object used for a
1584  * single paste operation.
1585  *
1586  * Returns: (transfer floating): The newly create element,
1587  * copied from @self.
1588  */
1589 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;       /* Start ignoring GParameter deprecation */
1590 GESTimelineElement *
1591 ges_timeline_element_copy (GESTimelineElement * self, gboolean deep)
1592 {
1593   GESAsset *asset;
1594   GParamSpec **specs;
1595   GESTimelineElementClass *klass;
1596   guint n, n_specs;
1597
1598   GESTimelineElement *ret = NULL;
1599
1600   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), NULL);
1601
1602   klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1603
1604   specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (self), &n_specs);
1605
1606   asset = ges_extractable_get_asset (GES_EXTRACTABLE (self));
1607   g_assert (asset);
1608   ret = GES_TIMELINE_ELEMENT (ges_asset_extract (asset, NULL));
1609   for (n = 0; n < n_specs; ++n) {
1610     /* We do not want the timeline or the name to be copied */
1611     if (g_strcmp0 (specs[n]->name, "parent") &&
1612         g_strcmp0 (specs[n]->name, "timeline") &&
1613         g_strcmp0 (specs[n]->name, "name") &&
1614         (specs[n]->flags & G_PARAM_READWRITE) == G_PARAM_READWRITE &&
1615         (specs[n]->flags & G_PARAM_CONSTRUCT_ONLY) == 0) {
1616       GValue v = G_VALUE_INIT;
1617       g_value_init (&v, specs[n]->value_type);
1618       g_object_get_property (G_OBJECT (self), specs[n]->name, &v);
1619
1620       g_object_set_property (G_OBJECT (ret), specs[n]->name, &v);
1621       g_value_reset (&v);
1622     }
1623   }
1624
1625   g_free (specs);
1626   if (deep) {
1627     if (klass->deep_copy)
1628       klass->deep_copy (self, ret);
1629     else
1630       GST_WARNING_OBJECT (self, "No deep_copy virtual method implementation"
1631           " on class %s. Can not finish the copy", G_OBJECT_CLASS_NAME (klass));
1632   }
1633
1634   if (deep) {
1635     ret->priv->copied_from = gst_object_ref (self);
1636   }
1637
1638   return ret;
1639 }
1640
1641 G_GNUC_END_IGNORE_DEPRECATIONS; /* End ignoring GParameter deprecation */
1642
1643 /**
1644  * ges_timeline_element_get_toplevel_parent:
1645  * @self: The #GESTimelineElement to get the toplevel parent from
1646  *
1647  * Gets the toplevel #GESTimelineElement:parent of the element.
1648  *
1649  * Returns: (transfer full): The toplevel parent of @self.
1650  */
1651 GESTimelineElement *
1652 ges_timeline_element_get_toplevel_parent (GESTimelineElement * self)
1653 {
1654   GESTimelineElement *toplevel;
1655
1656   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), NULL);
1657
1658   toplevel = ges_timeline_element_peak_toplevel (self);
1659
1660   return gst_object_ref (toplevel);
1661 }
1662
1663 /**
1664  * ges_timeline_element_get_name:
1665  * @self: A #GESTimelineElement
1666  *
1667  * Gets the #GESTimelineElement:name for the element.
1668  *
1669  * Returns: (transfer full): The name of @self.
1670  */
1671 gchar *
1672 ges_timeline_element_get_name (GESTimelineElement * self)
1673 {
1674   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), NULL);
1675
1676   return g_strdup (self->name);
1677 }
1678
1679 /**
1680  * ges_timeline_element_set_name:
1681  * @self: A #GESTimelineElement
1682  * @name: (allow-none): The name @self should take
1683  *
1684  * Sets the #GESTimelineElement:name for the element. If %NULL is given
1685  * for @name, then the library will instead generate a new name based on
1686  * the type name of the element, such as the name "uriclip3" for a
1687  * #GESUriClip, and will set that name instead.
1688  *
1689  * If @self already has a #GESTimelineElement:timeline, you should not
1690  * call this function with @name set to %NULL.
1691  *
1692  * You should ensure that, within each #GESTimeline, every element has a
1693  * unique name. If you call this function with @name as %NULL, then
1694  * the library should ensure that the set generated name is unique from
1695  * previously **generated** names. However, if you choose a @name that
1696  * interferes with the naming conventions of the library, the library will
1697  * attempt to ensure that the generated names will not conflict with the
1698  * chosen name, which may lead to a different name being set instead, but
1699  * the uniqueness between generated and user-chosen names is not
1700  * guaranteed.
1701  *
1702  * Returns: %TRUE if @name or a generated name for @self could be set.
1703  */
1704 gboolean
1705 ges_timeline_element_set_name (GESTimelineElement * self, const gchar * name)
1706 {
1707   gboolean result = TRUE, readd_to_timeline = FALSE;
1708
1709   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1710
1711   if (name != NULL && !g_strcmp0 (name, self->name)) {
1712     GST_DEBUG_OBJECT (self, "Same name!");
1713     return TRUE;
1714   }
1715
1716   /* parented objects cannot be renamed */
1717   if (self->timeline != NULL && name) {
1718     GESTimelineElement *tmp = ges_timeline_get_element (self->timeline, name);
1719
1720     /* FIXME: if tmp == self then this means that we setting the name of
1721      * self to its existing name. There is no need to throw an error */
1722     if (tmp) {
1723       gst_object_unref (tmp);
1724       goto had_timeline;
1725     }
1726
1727     timeline_remove_element (self->timeline, self);
1728     readd_to_timeline = TRUE;
1729   }
1730   /* FIXME: if self already has a timeline and name is NULL, then it also
1731    * needs to be re-added to the timeline (or, at least its entry in
1732    * timeline->priv->all_elements needs its key to be updated) using the
1733    * new generated name */
1734
1735   _set_name (self, name);
1736
1737   /* FIXME: the set name may not always be unique in a given timeline, see
1738    * _set_name(). This can cause timeline_add_element to fail! */
1739   if (readd_to_timeline)
1740     timeline_add_element (self->timeline, self);
1741
1742   return result;
1743
1744   /* error */
1745 had_timeline:
1746   {
1747     /* FIXME: message is misleading. We are here if some other object in
1748      * the timeline was added under @name (see above) */
1749     GST_WARNING ("Object %s already in a timeline can't be renamed to %s",
1750         self->name, name);
1751     return FALSE;
1752   }
1753 }
1754
1755 /**
1756  * ges_timeline_element_add_child_property:
1757  * @self: A #GESTimelineElement
1758  * @pspec: The specification for the property to add
1759  * @child: The #GstObject who the property belongs to
1760  *
1761  * Register a property of a child of the element to allow it to be
1762  * written with ges_timeline_element_set_child_property() and read with
1763  * ges_timeline_element_get_child_property(). A change in the property
1764  * will also appear in the #GESTimelineElement::deep-notify signal.
1765  *
1766  * @pspec should be unique from other children properties that have been
1767  * registered on @self.
1768  *
1769  * Returns: %TRUE if the property was successfully registered.
1770  */
1771 gboolean
1772 ges_timeline_element_add_child_property (GESTimelineElement * self,
1773     GParamSpec * pspec, GObject * child)
1774 {
1775   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1776   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
1777   g_return_val_if_fail (G_IS_OBJECT (child), FALSE);
1778
1779   return ges_timeline_element_add_child_property_full (self, NULL, pspec,
1780       child);
1781 }
1782
1783 /**
1784  * ges_timeline_element_get_child_property_by_pspec:
1785  * @self: A #GESTimelineElement
1786  * @pspec: The specification of a registered child property to get
1787  * @value: (out): The return location for the value
1788  *
1789  * Gets the property of a child of the element. Specifically, the property
1790  * corresponding to the @pspec used in
1791  * ges_timeline_element_add_child_property() is copied into @value.
1792  */
1793 void
1794 ges_timeline_element_get_child_property_by_pspec (GESTimelineElement * self,
1795     GParamSpec * pspec, GValue * value)
1796 {
1797   ChildPropHandler *handler;
1798
1799   g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
1800   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
1801
1802   handler = g_hash_table_lookup (self->priv->children_props, pspec);
1803   if (!handler)
1804     goto not_found;
1805
1806   g_object_get_property (G_OBJECT (handler->child), pspec->name, value);
1807
1808   return;
1809
1810 not_found:
1811   {
1812     GST_ERROR_OBJECT (self, "The %s property doesn't exist", pspec->name);
1813     return;
1814   }
1815 }
1816
1817 /**
1818  * ges_timeline_element_set_child_property_by_pspec:
1819  * @self: A #GESTimelineElement
1820  * @pspec: The specification of a registered child property to set
1821  * @value: The value to set the property to
1822  *
1823  * Sets the property of a child of the element. Specifically, the property
1824  * corresponding to the @pspec used in
1825  * ges_timeline_element_add_child_property() is set to @value.
1826  */
1827 void
1828 ges_timeline_element_set_child_property_by_pspec (GESTimelineElement * self,
1829     GParamSpec * pspec, const GValue * value)
1830 {
1831   g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
1832   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
1833
1834   set_child_property_by_pspec (self, pspec, value, NULL);
1835 }
1836
1837 /**
1838  * ges_timeline_element_set_child_property_full:
1839  * @self: A #GESTimelineElement
1840  * @property_name: The name of the child property to set
1841  * @value: The value to set the property to
1842  * @error: (nullable): Return location for an error
1843  *
1844  * Sets the property of a child of the element.
1845  *
1846  * @property_name can either be in the format "prop-name" or
1847  * "TypeName::prop-name", where "prop-name" is the name of the property
1848  * to set (as used in g_object_set()), and "TypeName" is the type name of
1849  * the child (as returned by G_OBJECT_TYPE_NAME()). The latter format is
1850  * useful when two children of different types share the same property
1851  * name.
1852  *
1853  * The first child found with the given "prop-name" property that was
1854  * registered with ges_timeline_element_add_child_property() (and of the
1855  * type "TypeName", if it was given) will have the corresponding
1856  * property set to @value. Other children that may have also matched the
1857  * property name (and type name) are left unchanged!
1858  *
1859  * Returns: %TRUE if the property was found and set.
1860  * Since: 1.18
1861  */
1862 gboolean
1863 ges_timeline_element_set_child_property_full (GESTimelineElement * self,
1864     const gchar * property_name, const GValue * value, GError ** error)
1865 {
1866   GParamSpec *pspec;
1867   GObject *child;
1868
1869   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1870   g_return_val_if_fail (!error || !*error, FALSE);
1871
1872   if (!ges_timeline_element_lookup_child (self, property_name, &child, &pspec))
1873     goto not_found;
1874
1875   return set_child_property_by_pspec (self, pspec, value, error);
1876
1877 not_found:
1878   {
1879     GST_WARNING_OBJECT (self, "The %s property doesn't exist", property_name);
1880
1881     return FALSE;
1882   }
1883 }
1884
1885 /**
1886  * ges_timeline_element_set_child_property:
1887  * @self: A #GESTimelineElement
1888  * @property_name: The name of the child property to set
1889  * @value: The value to set the property to
1890  *
1891  * See ges_timeline_element_set_child_property_full(), which also gives an
1892  * error.
1893  *
1894  * Note that ges_timeline_element_set_child_properties() may be more
1895  * convenient for C programming.
1896  *
1897  * Returns: %TRUE if the property was found and set.
1898  */
1899 gboolean
1900 ges_timeline_element_set_child_property (GESTimelineElement * self,
1901     const gchar * property_name, const GValue * value)
1902 {
1903   return ges_timeline_element_set_child_property_full (self, property_name,
1904       value, NULL);
1905 }
1906
1907 /**
1908  * ges_timeline_element_get_child_property:
1909  * @self: A #GESTimelineElement
1910  * @property_name: The name of the child property to get
1911  * @value: (out): The return location for the value
1912  *
1913  * Gets the property of a child of the element.
1914  *
1915  * @property_name can either be in the format "prop-name" or
1916  * "TypeName::prop-name", where "prop-name" is the name of the property
1917  * to get (as used in g_object_get()), and "TypeName" is the type name of
1918  * the child (as returned by G_OBJECT_TYPE_NAME()). The latter format is
1919  * useful when two children of different types share the same property
1920  * name.
1921  *
1922  * The first child found with the given "prop-name" property that was
1923  * registered with ges_timeline_element_add_child_property() (and of the
1924  * type "TypeName", if it was given) will have the corresponding
1925  * property copied into @value.
1926  *
1927  * Note that ges_timeline_element_get_child_properties() may be more
1928  * convenient for C programming.
1929  *
1930  * Returns: %TRUE if the property was found and copied to @value.
1931  */
1932 gboolean
1933 ges_timeline_element_get_child_property (GESTimelineElement * self,
1934     const gchar * property_name, GValue * value)
1935 {
1936   GParamSpec *pspec;
1937   GObject *child;
1938
1939   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1940
1941   if (!ges_timeline_element_lookup_child (self, property_name, &child, &pspec))
1942     goto not_found;
1943
1944   /* FIXME: since GLib 2.60, g_object_get_property() will automatically
1945    * initialize the type */
1946   if (G_VALUE_TYPE (value) == G_TYPE_INVALID)
1947     g_value_init (value, pspec->value_type);
1948
1949   g_object_get_property (child, pspec->name, value);
1950
1951   gst_object_unref (child);
1952   g_param_spec_unref (pspec);
1953
1954   return TRUE;
1955
1956 not_found:
1957   {
1958     GST_WARNING_OBJECT (self, "The %s property doesn't exist", property_name);
1959
1960     return FALSE;
1961   }
1962 }
1963
1964 /**
1965  * ges_timeline_element_lookup_child:
1966  * @self: A #GESTimelineElement
1967  * @prop_name: The name of a child property
1968  * @child: (out) (optional) (transfer full): The return location for the
1969  * found child
1970  * @pspec: (out) (optional) (transfer full): The return location for the
1971  * specification of the child property
1972  *
1973  * Looks up a child property of the element.
1974  *
1975  * @prop_name can either be in the format "prop-name" or
1976  * "TypeName::prop-name", where "prop-name" is the name of the property
1977  * to look up (as used in g_object_get()), and "TypeName" is the type name
1978  * of the child (as returned by G_OBJECT_TYPE_NAME()). The latter format is
1979  * useful when two children of different types share the same property
1980  * name.
1981  *
1982  * The first child found with the given "prop-name" property that was
1983  * registered with ges_timeline_element_add_child_property() (and of the
1984  * type "TypeName", if it was given) will be passed to @child, and the
1985  * registered specification of this property will be passed to @pspec.
1986  *
1987  * Returns: %TRUE if a child corresponding to the property was found, in
1988  * which case @child and @pspec are set.
1989  */
1990 gboolean
1991 ges_timeline_element_lookup_child (GESTimelineElement * self,
1992     const gchar * prop_name, GObject ** child, GParamSpec ** pspec)
1993 {
1994   GESTimelineElementClass *class;
1995
1996   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1997   class = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1998   g_return_val_if_fail (class->lookup_child, FALSE);
1999
2000   return class->lookup_child (self, prop_name, child, pspec);
2001 }
2002
2003 /**
2004  * ges_timeline_element_set_child_property_valist:
2005  * @self: A #GESTimelineElement
2006  * @first_property_name: The name of the first child property to set
2007  * @var_args: The value for the first property, followed optionally by more
2008  * name/value pairs, followed by %NULL
2009  *
2010  * Sets several of the children properties of the element. See
2011  * ges_timeline_element_set_child_property().
2012  */
2013 void
2014 ges_timeline_element_set_child_property_valist (GESTimelineElement * self,
2015     const gchar * first_property_name, va_list var_args)
2016 {
2017   const gchar *name;
2018   GParamSpec *pspec;
2019
2020   gchar *error = NULL;
2021   GValue value = { 0, };
2022
2023   g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
2024
2025   name = first_property_name;
2026
2027   /* Note: This part is in big part copied from the gst_child_object_set_valist
2028    * method. */
2029
2030   /* iterate over pairs */
2031   while (name) {
2032     if (!ges_timeline_element_lookup_child (self, name, NULL, &pspec))
2033       goto not_found;
2034
2035     G_VALUE_COLLECT_INIT (&value, pspec->value_type, var_args,
2036         G_VALUE_NOCOPY_CONTENTS, &error);
2037
2038     if (error)
2039       goto cant_copy;
2040
2041     set_child_property_by_pspec (self, pspec, &value, NULL);
2042
2043     g_param_spec_unref (pspec);
2044     g_value_unset (&value);
2045
2046     name = va_arg (var_args, gchar *);
2047   }
2048   return;
2049
2050 not_found:
2051   {
2052     GST_WARNING_OBJECT (self, "No property %s in OBJECT\n", name);
2053     return;
2054   }
2055 cant_copy:
2056   {
2057     GST_WARNING_OBJECT (self, "error copying value %s in %p: %s", pspec->name,
2058         self, error);
2059
2060     g_param_spec_unref (pspec);
2061     g_value_unset (&value);
2062     return;
2063   }
2064 }
2065
2066 /**
2067  * ges_timeline_element_set_child_properties:
2068  * @self: A #GESTimelineElement
2069  * @first_property_name: The name of the first child property to set
2070  * @...: The value for the first property, followed optionally by more
2071  * name/value pairs, followed by %NULL
2072  *
2073  * Sets several of the children properties of the element. See
2074  * ges_timeline_element_set_child_property().
2075  */
2076 void
2077 ges_timeline_element_set_child_properties (GESTimelineElement * self,
2078     const gchar * first_property_name, ...)
2079 {
2080   va_list var_args;
2081
2082   g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
2083
2084   va_start (var_args, first_property_name);
2085   ges_timeline_element_set_child_property_valist (self, first_property_name,
2086       var_args);
2087   va_end (var_args);
2088 }
2089
2090 /**
2091  * ges_timeline_element_get_child_property_valist:
2092  * @self: A #GESTimelineElement
2093  * @first_property_name: The name of the first child property to get
2094  * @var_args: The return location for the first property, followed
2095  * optionally by more name/return location pairs, followed by %NULL
2096  *
2097  * Gets several of the children properties of the element. See
2098  * ges_timeline_element_get_child_property().
2099  */
2100 void
2101 ges_timeline_element_get_child_property_valist (GESTimelineElement * self,
2102     const gchar * first_property_name, va_list var_args)
2103 {
2104   const gchar *name;
2105   gchar *error = NULL;
2106   GValue value = { 0, };
2107   GParamSpec *pspec;
2108   GObject *child;
2109
2110   g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
2111
2112   name = first_property_name;
2113
2114   /* This part is in big part copied from the gst_child_object_get_valist method */
2115   while (name) {
2116     if (!ges_timeline_element_lookup_child (self, name, &child, &pspec))
2117       goto not_found;
2118
2119     g_value_init (&value, pspec->value_type);
2120     g_object_get_property (child, pspec->name, &value);
2121     gst_object_unref (child);
2122     g_param_spec_unref (pspec);
2123
2124     G_VALUE_LCOPY (&value, var_args, 0, &error);
2125     if (error)
2126       goto cant_copy;
2127     g_value_unset (&value);
2128     name = va_arg (var_args, gchar *);
2129   }
2130   return;
2131
2132 not_found:
2133   {
2134     GST_WARNING_OBJECT (self, "no child property %s", name);
2135     return;
2136   }
2137 cant_copy:
2138   {
2139     GST_WARNING_OBJECT (self, "error copying value %s in %s", pspec->name,
2140         error);
2141
2142     g_value_unset (&value);
2143     return;
2144   }
2145 }
2146
2147 static gint
2148 compare_gparamspec (GParamSpec ** a, GParamSpec ** b, gpointer udata)
2149 {
2150   return g_strcmp0 ((*a)->name, (*b)->name);
2151 }
2152
2153
2154 /**
2155  * ges_timeline_element_list_children_properties:
2156  * @self: A #GESTimelineElement
2157  * @n_properties: (out): The return location for the length of the
2158  * returned array
2159  *
2160  * Get a list of children properties of the element, which is a list of
2161  * all the specifications passed to
2162  * ges_timeline_element_add_child_property().
2163  *
2164  * Returns: (transfer full) (array length=n_properties): An array of
2165  * #GParamSpec corresponding to the child properties of @self, or %NULL if
2166  * something went wrong.
2167  */
2168 GParamSpec **
2169 ges_timeline_element_list_children_properties (GESTimelineElement * self,
2170     guint * n_properties)
2171 {
2172   GParamSpec **ret;
2173   GESTimelineElementClass *class;
2174
2175   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), NULL);
2176
2177   class = GES_TIMELINE_ELEMENT_GET_CLASS (self);
2178
2179   if (!class->list_children_properties) {
2180     GST_INFO_OBJECT (self, "No %s->list_children_properties implementation",
2181         G_OBJECT_TYPE_NAME (self));
2182
2183     *n_properties = 0;
2184     return NULL;
2185   }
2186
2187   ret = class->list_children_properties (self, n_properties);
2188   g_qsort_with_data (ret, *n_properties, sizeof (GParamSpec *),
2189       (GCompareDataFunc) compare_gparamspec, NULL);
2190
2191   return ret;
2192 }
2193
2194 /**
2195  * ges_timeline_element_get_child_properties:
2196  * @self: A #GESTimelineElement
2197  * @first_property_name: The name of the first child property to get
2198  * @...: The return location for the first property, followed
2199  * optionally by more name/return location pairs, followed by %NULL
2200  *
2201  * Gets several of the children properties of the element. See
2202  * ges_timeline_element_get_child_property().
2203  */
2204 void
2205 ges_timeline_element_get_child_properties (GESTimelineElement * self,
2206     const gchar * first_property_name, ...)
2207 {
2208   va_list var_args;
2209
2210   g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
2211
2212   va_start (var_args, first_property_name);
2213   ges_timeline_element_get_child_property_valist (self, first_property_name,
2214       var_args);
2215   va_end (var_args);
2216 }
2217
2218 /**
2219  * ges_timeline_element_remove_child_property:
2220  * @self: A #GESTimelineElement
2221  * @pspec: The specification for the property to remove
2222  *
2223  * Remove a child property from the element. @pspec should be a
2224  * specification that was passed to
2225  * ges_timeline_element_add_child_property(). The corresponding property
2226  * will no longer be registered as a child property for the element.
2227  *
2228  * Returns: %TRUE if the property was successfully un-registered for @self.
2229  */
2230 gboolean
2231 ges_timeline_element_remove_child_property (GESTimelineElement * self,
2232     GParamSpec * pspec)
2233 {
2234   gpointer key, value;
2235   GParamSpec *found_pspec;
2236   ChildPropHandler *handler;
2237
2238   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
2239   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
2240
2241   if (!g_hash_table_lookup_extended (self->priv->children_props, pspec,
2242           &key, &value)) {
2243     GST_WARNING_OBJECT (self, "No child property with pspec %p (%s) found",
2244         pspec, pspec->name);
2245     return FALSE;
2246   }
2247   g_hash_table_steal (self->priv->children_props, pspec);
2248   found_pspec = G_PARAM_SPEC (key);
2249   handler = (ChildPropHandler *) value;
2250
2251   g_signal_emit (self, ges_timeline_element_signals[CHILD_PROPERTY_REMOVED], 0,
2252       handler->child, found_pspec);
2253
2254   g_param_spec_unref (found_pspec);
2255   _child_prop_handler_free (handler);
2256
2257   return TRUE;
2258 }
2259
2260 /**
2261  * ges_timeline_element_get_track_types:
2262  * @self: A #GESTimelineElement
2263  *
2264  * Gets the track types that the element can interact with, i.e. the type
2265  * of #GESTrack it can exist in, or will create #GESTrackElement-s for.
2266  *
2267  * Returns: The track types that @self supports.
2268  *
2269  * Since: 1.6.0
2270  */
2271 GESTrackType
2272 ges_timeline_element_get_track_types (GESTimelineElement * self)
2273 {
2274   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), 0);
2275   g_return_val_if_fail (GES_TIMELINE_ELEMENT_GET_CLASS (self)->get_track_types,
2276       0);
2277
2278   return GES_TIMELINE_ELEMENT_GET_CLASS (self)->get_track_types (self);
2279 }
2280
2281 /**
2282  * ges_timeline_element_paste:
2283  * @self: The #GESTimelineElement to paste
2284  * @paste_position: The position in the timeline @element should be pasted
2285  * to, i.e. the #GESTimelineElement:start value for the pasted element.
2286  *
2287  * Paste an element inside the same timeline and layer as @self. @self
2288  * **must** be the return of ges_timeline_element_copy() with `deep=TRUE`,
2289  * and it should not be changed before pasting.
2290  * @self is not placed in the timeline, instead a new element is created,
2291  * alike to the originally copied element. Note that the originally
2292  * copied element must stay within the same timeline and layer, at both
2293  * the point of copying and pasting.
2294  *
2295  * Pasting may fail if it would place the timeline in an unsupported
2296  * configuration.
2297  *
2298  * After calling this function @element should not be used. In particular,
2299  * @element can **not** be pasted again. Instead, you can copy the
2300  * returned element and paste that copy (although, this is only possible
2301  * if the paste was successful).
2302  *
2303  * See also ges_timeline_paste_element().
2304  *
2305  * Returns: (transfer full) (nullable): The newly created element, or
2306  * %NULL if pasting fails.
2307  *
2308  * Since: 1.6.0
2309  */
2310 GESTimelineElement *
2311 ges_timeline_element_paste (GESTimelineElement * self,
2312     GstClockTime paste_position)
2313 {
2314   GESTimelineElement *res;
2315   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
2316   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (paste_position), FALSE);
2317
2318   if (!self->priv->copied_from) {
2319     GST_ERROR_OBJECT (self, "Is not being 'deeply' copied!");
2320
2321     return NULL;
2322   }
2323
2324   if (!GES_TIMELINE_ELEMENT_GET_CLASS (self)->paste) {
2325     GST_ERROR_OBJECT (self, "No paste vmethod implemented");
2326
2327     return NULL;
2328   }
2329
2330   res = GES_TIMELINE_ELEMENT_GET_CLASS (self)->paste (self,
2331       self->priv->copied_from, paste_position);
2332
2333   g_clear_object (&self->priv->copied_from);
2334
2335   return res ? g_object_ref_sink (res) : res;
2336 }
2337
2338 /**
2339  * ges_timeline_element_get_layer_priority:
2340  * @self: A #GESTimelineElement
2341  *
2342  * Gets the priority of the layer the element is in. A #GESGroup may span
2343  * several layers, so this would return the highest priority (numerically,
2344  * the smallest) amongst them.
2345  *
2346  * Returns: The priority of the layer @self is in, or
2347  * #GES_TIMELINE_ELEMENT_NO_LAYER_PRIORITY if @self does not exist in a
2348  * layer.
2349  *
2350  * Since: 1.16
2351  */
2352 guint32
2353 ges_timeline_element_get_layer_priority (GESTimelineElement * self)
2354 {
2355   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self),
2356       GES_TIMELINE_ELEMENT_NO_LAYER_PRIORITY);
2357
2358   if (!GES_TIMELINE_ELEMENT_GET_CLASS (self)->get_layer_priority)
2359     return self->priority;
2360
2361   return GES_TIMELINE_ELEMENT_GET_CLASS (self)->get_layer_priority (self);
2362 }
2363
2364 /**
2365  * ges_timeline_element_edit_full:
2366  * @self: The #GESTimelineElement to edit
2367  * @new_layer_priority: The priority/index of the layer @self should be
2368  * moved to. -1 means no move
2369  * @mode: The edit mode
2370  * @edge: The edge of @self where the edit should occur
2371  * @position: The edit position: a new location for the edge of @self
2372  * (in nanoseconds) in the timeline coordinates
2373  * @error: (nullable): Return location for an error
2374  *
2375  * Edits the element within its timeline by adjusting its
2376  * #GESTimelineElement:start, #GESTimelineElement:duration or
2377  * #GESTimelineElement:in-point, and potentially doing the same for
2378  * other elements in the timeline. See #GESEditMode for details about each
2379  * edit mode. An edit may fail if it would place one of these properties
2380  * out of bounds, or if it would place the timeline in an unsupported
2381  * configuration.
2382  *
2383  * Note that if you act on a #GESTrackElement, this will edit its parent
2384  * #GESClip instead. Moreover, for any #GESTimelineElement, if you select
2385  * #GES_EDGE_NONE for #GES_EDIT_MODE_NORMAL or #GES_EDIT_MODE_RIPPLE, this
2386  * will edit the toplevel instead, but still in such a way as to make the
2387  * #GESTimelineElement:start of @self reach the edit @position.
2388  *
2389  * Note that if the element's timeline has a
2390  * #GESTimeline:snapping-distance set, then the edit position may be
2391  * snapped to the edge of some element under the edited element.
2392  *
2393  * @new_layer_priority can be used to switch @self, and other elements
2394  * moved by the edit, to a new layer. New layers may be be created if the
2395  * the corresponding layer priority/index does not yet exist for the
2396  * timeline.
2397  *
2398  * Returns: %TRUE if the edit of @self completed, %FALSE on failure.
2399  * Since: 1.18
2400  */
2401
2402 gboolean
2403 ges_timeline_element_edit_full (GESTimelineElement * self,
2404     gint64 new_layer_priority, GESEditMode mode, GESEdge edge, guint64 position,
2405     GError ** error)
2406 {
2407   GESTimeline *timeline;
2408   guint32 layer_prio;
2409
2410   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
2411   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (position), FALSE);
2412   g_return_val_if_fail (!error || !*error, FALSE);
2413
2414   timeline = GES_TIMELINE_ELEMENT_TIMELINE (self);
2415   g_return_val_if_fail (timeline, FALSE);
2416
2417   layer_prio = GES_TIMELINE_ELEMENT_LAYER_PRIORITY (self);
2418
2419   if (new_layer_priority < 0)
2420     new_layer_priority = layer_prio;
2421
2422   GST_DEBUG_OBJECT (self, "Editing %s at edge %s to position %"
2423       GST_TIME_FORMAT " under %s mode, and to layer %" G_GINT64_FORMAT,
2424       self->name, ges_edge_name (edge), GST_TIME_ARGS (position),
2425       ges_edit_mode_name (mode), new_layer_priority);
2426
2427   return ges_timeline_edit (timeline, self, new_layer_priority, mode,
2428       edge, position, error);
2429 }
2430
2431 /**
2432  * ges_timeline_element_edit:
2433  * @self: The #GESTimelineElement to edit
2434  * @layers: (element-type GESLayer) (nullable): A whitelist of layers
2435  * where the edit can be performed, %NULL allows all layers in the
2436  * timeline.
2437  * @new_layer_priority: The priority/index of the layer @self should be
2438  * moved to. -1 means no move
2439  * @mode: The edit mode
2440  * @edge: The edge of @self where the edit should occur
2441  * @position: The edit position: a new location for the edge of @self
2442  * (in nanoseconds) in the timeline coordinates
2443  *
2444  * See ges_timeline_element_edit_full(), which also gives an error.
2445  *
2446  * Note that the @layers argument is currently ignored, so you should
2447  * just pass %NULL.
2448  *
2449  * Returns: %TRUE if the edit of @self completed, %FALSE on failure.
2450  *
2451  * Since: 1.18
2452  */
2453
2454 /* FIXME: handle the layers argument. Currently we always treat it as if
2455  * it is NULL in the ges-timeline code */
2456 gboolean
2457 ges_timeline_element_edit (GESTimelineElement * self, GList * layers,
2458     gint64 new_layer_priority, GESEditMode mode, GESEdge edge, guint64 position)
2459 {
2460   return ges_timeline_element_edit_full (self, new_layer_priority, mode, edge,
2461       position, NULL);
2462 }
2463
2464 /**
2465  * ges_timeline_element_get_natural_framerate:
2466  * @self: The #GESTimelineElement to get "natural" framerate from
2467  * @framerate_n: (out): The framerate numerator
2468  * @framerate_d: (out): The framerate denominator
2469  *
2470  * Get the "natural" framerate of @self. This is to say, for example
2471  * for a #GESVideoUriSource the framerate of the source.
2472  *
2473  * Note that a #GESAudioSource may also have a natural framerate if it derives
2474  * from the same #GESSourceClip asset as a #GESVideoSource, and its value will
2475  * be that of the video source. For example, if the uri of a #GESUriClip points
2476  * to a file that contains both a video and audio stream, then the corresponding
2477  * #GESAudioUriSource will share the natural framerate of the corresponding
2478  * #GESVideoUriSource.
2479  *
2480  * Returns: Whether @self has a natural framerate or not, @framerate_n
2481  * and @framerate_d will be set to, respectively, 0 and -1 if it is
2482  * not the case.
2483  *
2484  * Since: 1.18
2485  */
2486 gboolean
2487 ges_timeline_element_get_natural_framerate (GESTimelineElement * self,
2488     gint * framerate_n, gint * framerate_d)
2489 {
2490   GESTimelineElementClass *klass;
2491
2492   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
2493   g_return_val_if_fail (framerate_n && framerate_d, FALSE);
2494
2495   klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
2496
2497   *framerate_n = 0;
2498   *framerate_d = -1;
2499   return klass->get_natural_framerate (self, framerate_n, framerate_d);
2500 }