command-line-formatter: Stop uselessly looping over options
[platform/upstream/gstreamer.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
1086   if (self->start == start)
1087     return TRUE;
1088
1089   GST_DEBUG_OBJECT (self, "current start: %" GST_TIME_FORMAT
1090       " new start: %" GST_TIME_FORMAT,
1091       GST_TIME_ARGS (GES_TIMELINE_ELEMENT_START (self)), GST_TIME_ARGS (start));
1092
1093   if (self->timeline && !GES_TIMELINE_ELEMENT_BEING_EDITED (self))
1094     return ges_timeline_element_edit (self, NULL, -1, GES_EDIT_MODE_NORMAL,
1095         GES_EDGE_NONE, start);
1096
1097   toplevel_container = ges_timeline_element_peak_toplevel (self);
1098   parent = self->parent;
1099
1100   /* FIXME This should not belong to GESTimelineElement */
1101   /* only check if no timeline, otherwise the timeline-tree will handle this
1102    * check */
1103   if (!self->timeline && toplevel_container &&
1104       ((gint64) (_START (toplevel_container) + start - _START (self))) < 0 &&
1105       parent
1106       && GES_CONTAINER (parent)->children_control_mode == GES_CHILDREN_UPDATE) {
1107     GST_INFO_OBJECT (self,
1108         "Can not move the object as it would imply its "
1109         "container to have a negative start value");
1110
1111     return FALSE;
1112   }
1113
1114   klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1115   if (klass->set_start) {
1116     gint res = klass->set_start (self, start);
1117     if (res == FALSE)
1118       return FALSE;
1119     if (res == TRUE) {
1120       self->start = start;
1121       g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_START]);
1122     }
1123
1124     GST_DEBUG_OBJECT (self, "New start: %" GST_TIME_FORMAT,
1125         GST_TIME_ARGS (GES_TIMELINE_ELEMENT_START (self)));
1126
1127     return TRUE;
1128   }
1129
1130   GST_WARNING_OBJECT (self, "No set_start virtual method implementation"
1131       " on class %s. Can not set start %" GST_TIME_FORMAT,
1132       G_OBJECT_CLASS_NAME (klass), GST_TIME_ARGS (start));
1133   return FALSE;
1134 }
1135
1136 /**
1137  * ges_timeline_element_set_inpoint:
1138  * @self: A #GESTimelineElement
1139  * @inpoint: The in-point, in internal time coordinates
1140  *
1141  * Sets #GESTimelineElement:in-point for the element. If the new in-point
1142  * is above the current #GESTimelineElement:max-duration of the element,
1143  * this method will fail.
1144  *
1145  * Returns: %TRUE if @inpoint could be set for @self.
1146  */
1147 gboolean
1148 ges_timeline_element_set_inpoint (GESTimelineElement * self,
1149     GstClockTime inpoint)
1150 {
1151   GESTimelineElementClass *klass;
1152
1153   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1154
1155   GST_DEBUG_OBJECT (self, "current inpoint: %" GST_TIME_FORMAT
1156       " new inpoint: %" GST_TIME_FORMAT, GST_TIME_ARGS (self->inpoint),
1157       GST_TIME_ARGS (inpoint));
1158
1159   if (G_UNLIKELY (inpoint == self->inpoint))
1160     return TRUE;
1161
1162   if (GES_CLOCK_TIME_IS_LESS (self->maxduration, inpoint)) {
1163     GST_WARNING_OBJECT (self, "Can not set an in-point of %" GST_TIME_FORMAT
1164         " because it exceeds the element's max-duration: %" GST_TIME_FORMAT,
1165         GST_TIME_ARGS (inpoint), GST_TIME_ARGS (self->maxduration));
1166     return FALSE;
1167   }
1168
1169   klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1170
1171   if (klass->set_inpoint) {
1172     /* FIXME: Could we instead use g_object_freeze_notify() to prevent
1173      * duplicate notify signals? Rather than relying on the return value
1174      * being -1 for setting that succeeds but does not want a notify
1175      * signal because it will call this method on itself a second time. */
1176     if (!klass->set_inpoint (self, inpoint))
1177       return FALSE;
1178
1179     self->inpoint = inpoint;
1180     g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_INPOINT]);
1181
1182     return TRUE;
1183   }
1184
1185   GST_DEBUG_OBJECT (self, "No set_inpoint virtual method implementation"
1186       " on class %s. Can not set inpoint %" GST_TIME_FORMAT,
1187       G_OBJECT_CLASS_NAME (klass), GST_TIME_ARGS (inpoint));
1188
1189   return FALSE;
1190 }
1191
1192 /**
1193  * ges_timeline_element_set_max_duration:
1194  * @self: A #GESTimelineElement
1195  * @maxduration: The maximum duration, in internal time coordinates
1196  *
1197  * Sets #GESTimelineElement:max-duration for the element. If the new
1198  * maximum duration is below the current #GESTimelineElement:in-point of
1199  * the element, this method will fail.
1200  *
1201  * Returns: %TRUE if @maxduration could be set for @self.
1202  */
1203 gboolean
1204 ges_timeline_element_set_max_duration (GESTimelineElement * self,
1205     GstClockTime maxduration)
1206 {
1207   GESTimelineElementClass *klass;
1208
1209   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1210
1211   GST_DEBUG_OBJECT (self, "current max-duration: %" GST_TIME_FORMAT
1212       " new max-duration: %" GST_TIME_FORMAT,
1213       GST_TIME_ARGS (self->maxduration), GST_TIME_ARGS (maxduration));
1214
1215   if (G_UNLIKELY (maxduration == self->maxduration))
1216     return TRUE;
1217
1218   if (GES_CLOCK_TIME_IS_LESS (maxduration, self->inpoint)) {
1219     GST_WARNING_OBJECT (self, "Can not set a max-duration of %"
1220         GST_TIME_FORMAT " because it lies below the element's in-point: %"
1221         GST_TIME_FORMAT, GST_TIME_ARGS (maxduration),
1222         GST_TIME_ARGS (self->inpoint));
1223     return FALSE;
1224   }
1225
1226   klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1227
1228   if (klass->set_max_duration) {
1229     if (!klass->set_max_duration (self, maxduration))
1230       return FALSE;
1231     self->maxduration = maxduration;
1232     g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MAX_DURATION]);
1233
1234     return TRUE;
1235   }
1236
1237   GST_DEBUG_OBJECT (self, "No set_max_duration virtual method implementation"
1238       " on class %s. Can not set max-duration  %" GST_TIME_FORMAT,
1239       G_OBJECT_CLASS_NAME (klass), GST_TIME_ARGS (maxduration));
1240
1241   return FALSE;
1242 }
1243
1244 /**
1245  * ges_timeline_element_set_duration:
1246  * @self: A #GESTimelineElement
1247  * @duration: The desired duration in its timeline
1248  *
1249  * Sets #GESTimelineElement:duration for the element.
1250  *
1251  * Whilst the element is part of a #GESTimeline, this is the same as
1252  * editing the element with ges_timeline_element_edit() under
1253  * #GES_EDIT_MODE_TRIM with #GES_EDGE_END. In particular, the
1254  * #GESTimelineElement:duration of the element may be snapped to a
1255  * different timeline time difference from the one given. In addition,
1256  * setting may fail if it would place the timeline in an unsupported
1257  * configuration, or the element does not have enough internal content to
1258  * last the desired duration.
1259  *
1260  * Returns: %TRUE if @duration could be set for @self.
1261  */
1262 gboolean
1263 ges_timeline_element_set_duration (GESTimelineElement * self,
1264     GstClockTime duration)
1265 {
1266   GESTimelineElementClass *klass;
1267
1268   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1269
1270   if (duration == self->duration)
1271     return TRUE;
1272
1273   if (self->timeline && !GES_TIMELINE_ELEMENT_BEING_EDITED (self))
1274     return ges_timeline_element_edit (self, NULL, -1, GES_EDIT_MODE_TRIM,
1275         GES_EDGE_END, self->start + duration);
1276
1277   GST_DEBUG_OBJECT (self, "current duration: %" GST_TIME_FORMAT
1278       " new duration: %" GST_TIME_FORMAT,
1279       GST_TIME_ARGS (GES_TIMELINE_ELEMENT_DURATION (self)),
1280       GST_TIME_ARGS (duration));
1281
1282   klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1283   if (klass->set_duration) {
1284     gint res = klass->set_duration (self, duration);
1285     if (res == FALSE)
1286       return FALSE;
1287     if (res == TRUE) {
1288       self->duration = duration;
1289       g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DURATION]);
1290     }
1291
1292     return TRUE;
1293   }
1294
1295   GST_WARNING_OBJECT (self, "No set_duration virtual method implementation"
1296       " on class %s. Can not set duration %" GST_TIME_FORMAT,
1297       G_OBJECT_CLASS_NAME (klass), GST_TIME_ARGS (duration));
1298   return FALSE;
1299 }
1300
1301 /**
1302  * ges_timeline_element_get_start:
1303  * @self: A #GESTimelineElement
1304  *
1305  * Gets the #GESTimelineElement:start for the element.
1306  *
1307  * Returns: The start of @self (in nanoseconds).
1308  */
1309 GstClockTime
1310 ges_timeline_element_get_start (GESTimelineElement * self)
1311 {
1312   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), GST_CLOCK_TIME_NONE);
1313
1314   return self->start;
1315 }
1316
1317 /**
1318  * ges_timeline_element_get_inpoint:
1319  * @self: A #GESTimelineElement
1320  *
1321  * Gets the #GESTimelineElement:in-point for the element.
1322  *
1323  * Returns: The in-point of @self (in nanoseconds).
1324  */
1325 GstClockTime
1326 ges_timeline_element_get_inpoint (GESTimelineElement * self)
1327 {
1328   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), GST_CLOCK_TIME_NONE);
1329
1330   return self->inpoint;
1331 }
1332
1333 /**
1334  * ges_timeline_element_get_duration:
1335  * @self: A #GESTimelineElement
1336  *
1337  * Gets the #GESTimelineElement:duration for the element.
1338  *
1339  * Returns: The duration of @self (in nanoseconds).
1340  */
1341 GstClockTime
1342 ges_timeline_element_get_duration (GESTimelineElement * self)
1343 {
1344   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), GST_CLOCK_TIME_NONE);
1345
1346   return self->duration;
1347 }
1348
1349 /**
1350  * ges_timeline_element_get_max_duration:
1351  * @self: A #GESTimelineElement
1352  *
1353  * Gets the #GESTimelineElement:max-duration for the element.
1354  *
1355  * Returns: The max-duration of @self (in nanoseconds).
1356  */
1357 GstClockTime
1358 ges_timeline_element_get_max_duration (GESTimelineElement * self)
1359 {
1360   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), GST_CLOCK_TIME_NONE);
1361
1362   return self->maxduration;
1363 }
1364
1365 /**
1366  * ges_timeline_element_get_priority:
1367  * @self: A #GESTimelineElement
1368  *
1369  * Gets the #GESTimelineElement:priority for the element.
1370  *
1371  * Returns: The priority of @self.
1372  */
1373 guint32
1374 ges_timeline_element_get_priority (GESTimelineElement * self)
1375 {
1376   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), 0);
1377
1378   return self->priority;
1379 }
1380
1381 /**
1382  * ges_timeline_element_set_priority:
1383  * @self: A #GESTimelineElement
1384  * @priority: The priority
1385  *
1386  * Sets the priority of the element within the containing layer.
1387  *
1388  * Deprecated:1.10: All priority management is done by GES itself now.
1389  * To set #GESEffect priorities #ges_clip_set_top_effect_index should
1390  * be used.
1391  *
1392  * Returns: %TRUE if @priority could be set for @self.
1393  */
1394 gboolean
1395 ges_timeline_element_set_priority (GESTimelineElement * self, guint32 priority)
1396 {
1397   GESTimelineElementClass *klass;
1398
1399   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1400
1401   klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1402
1403   GST_DEBUG_OBJECT (self, "current priority: %d new priority: %d",
1404       self->priority, priority);
1405
1406   if (klass->set_priority) {
1407     gboolean res = klass->set_priority (self, priority);
1408     if (res) {
1409       self->priority = priority;
1410       g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PRIORITY]);
1411     }
1412
1413     return res;
1414   }
1415
1416   GST_WARNING_OBJECT (self, "No set_priority virtual method implementation"
1417       " on class %s. Can not set priority %d", G_OBJECT_CLASS_NAME (klass),
1418       priority);
1419   return FALSE;
1420 }
1421
1422 /**
1423  * ges_timeline_element_ripple:
1424  * @self: The #GESTimelineElement to ripple
1425  * @start: The new start time of @self in ripple mode
1426  *
1427  * Edits the start time of an element within its timeline in ripple mode.
1428  * See ges_timeline_element_edit() with #GES_EDIT_MODE_RIPPLE and
1429  * #GES_EDGE_NONE.
1430  *
1431  * Returns: %TRUE if the ripple edit of @self completed, %FALSE on
1432  * failure.
1433  */
1434 gboolean
1435 ges_timeline_element_ripple (GESTimelineElement * self, GstClockTime start)
1436 {
1437   GESTimelineElementClass *klass;
1438
1439   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1440
1441   klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1442
1443   if (klass->ripple)
1444     return klass->ripple (self, start);
1445
1446   return ges_timeline_element_edit (self, NULL, -1, GES_EDIT_MODE_RIPPLE,
1447       GES_EDGE_NONE, start);
1448
1449   return FALSE;
1450 }
1451
1452 /**
1453  * ges_timeline_element_ripple_end:
1454  * @self: The #GESTimelineElement to ripple
1455  * @end: The new end time of @self in ripple mode
1456  *
1457  * Edits the end time of an element within its timeline in ripple mode.
1458  * See ges_timeline_element_edit() with #GES_EDIT_MODE_RIPPLE and
1459  * #GES_EDGE_END.
1460  *
1461  * Returns: %TRUE if the ripple edit of @self completed, %FALSE on
1462  * failure.
1463  */
1464 gboolean
1465 ges_timeline_element_ripple_end (GESTimelineElement * self, GstClockTime end)
1466 {
1467   GESTimelineElementClass *klass;
1468
1469   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1470
1471   klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1472
1473   if (klass->ripple_end)
1474     return klass->ripple_end (self, end);
1475
1476   return ges_timeline_element_edit (self, NULL, -1, GES_EDIT_MODE_RIPPLE,
1477       GES_EDGE_END, end);
1478 }
1479
1480 /**
1481  * ges_timeline_element_roll_start:
1482  * @self: The #GESTimelineElement to roll
1483  * @start: The new start time of @self in roll mode
1484  *
1485  * Edits the start time of an element within its timeline in roll mode.
1486  * See ges_timeline_element_edit() with #GES_EDIT_MODE_ROLL and
1487  * #GES_EDGE_START.
1488  *
1489  * Returns: %TRUE if the roll edit of @self completed, %FALSE on failure.
1490  */
1491 gboolean
1492 ges_timeline_element_roll_start (GESTimelineElement * self, GstClockTime start)
1493 {
1494   GESTimelineElementClass *klass;
1495
1496   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1497
1498   klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1499
1500   if (klass->roll_start)
1501     return klass->roll_start (self, start);
1502
1503   return ges_timeline_element_edit (self, NULL, -1, GES_EDIT_MODE_ROLL,
1504       GES_EDGE_START, start);
1505 }
1506
1507 /**
1508  * ges_timeline_element_roll_end:
1509  * @self: The #GESTimelineElement to roll
1510  * @end: The new end time of @self in roll mode
1511  *
1512  * Edits the end time of an element within its timeline in roll mode.
1513  * See ges_timeline_element_edit() with #GES_EDIT_MODE_ROLL and
1514  * #GES_EDGE_END.
1515  *
1516  * Returns: %TRUE if the roll edit of @self completed, %FALSE on failure.
1517  */
1518 gboolean
1519 ges_timeline_element_roll_end (GESTimelineElement * self, GstClockTime end)
1520 {
1521   GESTimelineElementClass *klass;
1522
1523   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1524
1525   klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1526
1527   if (klass->roll_end)
1528     return klass->roll_end (self, end);
1529
1530   return ges_timeline_element_edit (self, NULL, -1, GES_EDIT_MODE_ROLL,
1531       GES_EDGE_END, end);
1532 }
1533
1534 /**
1535  * ges_timeline_element_trim:
1536  * @self: The #GESTimelineElement to trim
1537  * @start: The new start time of @self in trim mode
1538  *
1539  * Edits the start time of an element within its timeline in trim mode.
1540  * See ges_timeline_element_edit() with #GES_EDIT_MODE_TRIM and
1541  * #GES_EDGE_START.
1542  *
1543  * Returns: %TRUE if the trim edit of @self completed, %FALSE on failure.
1544  */
1545 gboolean
1546 ges_timeline_element_trim (GESTimelineElement * self, GstClockTime start)
1547 {
1548   GESTimelineElementClass *klass;
1549
1550   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1551
1552   klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1553
1554   if (klass->trim)
1555     return klass->trim (self, start);
1556
1557   return ges_timeline_element_edit (self, NULL, -1, GES_EDIT_MODE_TRIM,
1558       GES_EDGE_START, start);
1559 }
1560
1561 /**
1562  * ges_timeline_element_copy:
1563  * @self: The #GESTimelineElement to copy
1564  * @deep: Whether the copy is needed for pasting
1565  *
1566  * Create a copy of @self. All the properties of @self are copied into
1567  * a new element, with the exception of #GESTimelineElement:parent,
1568  * #GESTimelineElement:timeline and #GESTimelineElement:name. Other data,
1569  * such the list of a #GESContainer's children, is **not** copied.
1570  *
1571  * If @deep is %TRUE, then the new element is prepared so that it can be
1572  * used in ges_timeline_element_paste() or ges_timeline_paste_element().
1573  * In the case of copying a #GESContainer, this ensures that the children
1574  * of @self will also be pasted. The new element should not be used for
1575  * anything else and can only be used **once** in a pasting operation. In
1576  * particular, the new element itself is not an actual 'deep' copy of
1577  * @self, but should be thought of as an intermediate object used for a
1578  * single paste operation.
1579  *
1580  * Returns: (transfer floating): The newly create element,
1581  * copied from @self.
1582  */
1583 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;       /* Start ignoring GParameter deprecation */
1584 GESTimelineElement *
1585 ges_timeline_element_copy (GESTimelineElement * self, gboolean deep)
1586 {
1587   GESAsset *asset;
1588   GParamSpec **specs;
1589   GESTimelineElementClass *klass;
1590   guint n, n_specs;
1591
1592   GESTimelineElement *ret = NULL;
1593
1594   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), NULL);
1595
1596   klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1597
1598   specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (self), &n_specs);
1599
1600   asset = ges_extractable_get_asset (GES_EXTRACTABLE (self));
1601   g_assert (asset);
1602   ret = GES_TIMELINE_ELEMENT (ges_asset_extract (asset, NULL));
1603   for (n = 0; n < n_specs; ++n) {
1604     /* We do not want the timeline or the name to be copied */
1605     if (g_strcmp0 (specs[n]->name, "parent") &&
1606         g_strcmp0 (specs[n]->name, "timeline") &&
1607         g_strcmp0 (specs[n]->name, "name") &&
1608         (specs[n]->flags & G_PARAM_READWRITE) == G_PARAM_READWRITE &&
1609         (specs[n]->flags & G_PARAM_CONSTRUCT_ONLY) == 0) {
1610       GValue v = G_VALUE_INIT;
1611       g_value_init (&v, specs[n]->value_type);
1612       g_object_get_property (G_OBJECT (self), specs[n]->name, &v);
1613
1614       g_object_set_property (G_OBJECT (ret), specs[n]->name, &v);
1615       g_value_reset (&v);
1616     }
1617   }
1618
1619   g_free (specs);
1620   if (deep) {
1621     if (klass->deep_copy)
1622       klass->deep_copy (self, ret);
1623     else
1624       GST_WARNING_OBJECT (self, "No deep_copy virtual method implementation"
1625           " on class %s. Can not finish the copy", G_OBJECT_CLASS_NAME (klass));
1626   }
1627
1628   if (deep) {
1629     ret->priv->copied_from = gst_object_ref (self);
1630   }
1631
1632   return ret;
1633 }
1634
1635 G_GNUC_END_IGNORE_DEPRECATIONS; /* End ignoring GParameter deprecation */
1636
1637 /**
1638  * ges_timeline_element_get_toplevel_parent:
1639  * @self: The #GESTimelineElement to get the toplevel parent from
1640  *
1641  * Gets the toplevel #GESTimelineElement:parent of the element.
1642  *
1643  * Returns: (transfer full): The toplevel parent of @self.
1644  */
1645 GESTimelineElement *
1646 ges_timeline_element_get_toplevel_parent (GESTimelineElement * self)
1647 {
1648   GESTimelineElement *toplevel;
1649
1650   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), NULL);
1651
1652   toplevel = ges_timeline_element_peak_toplevel (self);
1653
1654   return gst_object_ref (toplevel);
1655 }
1656
1657 /**
1658  * ges_timeline_element_get_name:
1659  * @self: A #GESTimelineElement
1660  *
1661  * Gets the #GESTimelineElement:name for the element.
1662  *
1663  * Returns: (transfer full): The name of @self.
1664  */
1665 gchar *
1666 ges_timeline_element_get_name (GESTimelineElement * self)
1667 {
1668   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), NULL);
1669
1670   return g_strdup (self->name);
1671 }
1672
1673 /**
1674  * ges_timeline_element_set_name:
1675  * @self: A #GESTimelineElement
1676  * @name: (allow-none): The name @self should take
1677  *
1678  * Sets the #GESTimelineElement:name for the element. If %NULL is given
1679  * for @name, then the library will instead generate a new name based on
1680  * the type name of the element, such as the name "uriclip3" for a
1681  * #GESUriClip, and will set that name instead.
1682  *
1683  * If @self already has a #GESTimelineElement:timeline, you should not
1684  * call this function with @name set to %NULL.
1685  *
1686  * You should ensure that, within each #GESTimeline, every element has a
1687  * unique name. If you call this function with @name as %NULL, then
1688  * the library should ensure that the set generated name is unique from
1689  * previously **generated** names. However, if you choose a @name that
1690  * interferes with the naming conventions of the library, the library will
1691  * attempt to ensure that the generated names will not conflict with the
1692  * chosen name, which may lead to a different name being set instead, but
1693  * the uniqueness between generated and user-chosen names is not
1694  * guaranteed.
1695  *
1696  * Returns: %TRUE if @name or a generated name for @self could be set.
1697  */
1698 gboolean
1699 ges_timeline_element_set_name (GESTimelineElement * self, const gchar * name)
1700 {
1701   gboolean result = TRUE, readd_to_timeline = FALSE;
1702
1703   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1704
1705   if (name != NULL && !g_strcmp0 (name, self->name)) {
1706     GST_DEBUG_OBJECT (self, "Same name!");
1707     return TRUE;
1708   }
1709
1710   /* parented objects cannot be renamed */
1711   if (self->timeline != NULL && name) {
1712     GESTimelineElement *tmp = ges_timeline_get_element (self->timeline, name);
1713
1714     /* FIXME: if tmp == self then this means that we setting the name of
1715      * self to its existing name. There is no need to throw an error */
1716     if (tmp) {
1717       gst_object_unref (tmp);
1718       goto had_timeline;
1719     }
1720
1721     timeline_remove_element (self->timeline, self);
1722     readd_to_timeline = TRUE;
1723   }
1724   /* FIXME: if self already has a timeline and name is NULL, then it also
1725    * needs to be re-added to the timeline (or, at least its entry in
1726    * timeline->priv->all_elements needs its key to be updated) using the
1727    * new generated name */
1728
1729   _set_name (self, name);
1730
1731   /* FIXME: the set name may not always be unique in a given timeline, see
1732    * _set_name(). This can cause timeline_add_element to fail! */
1733   if (readd_to_timeline)
1734     timeline_add_element (self->timeline, self);
1735
1736   return result;
1737
1738   /* error */
1739 had_timeline:
1740   {
1741     /* FIXME: message is misleading. We are here if some other object in
1742      * the timeline was added under @name (see above) */
1743     GST_WARNING ("Object %s already in a timeline can't be renamed to %s",
1744         self->name, name);
1745     return FALSE;
1746   }
1747 }
1748
1749 /**
1750  * ges_timeline_element_add_child_property:
1751  * @self: A #GESTimelineElement
1752  * @pspec: The specification for the property to add
1753  * @child: The #GstObject who the property belongs to
1754  *
1755  * Register a property of a child of the element to allow it to be
1756  * written with ges_timeline_element_set_child_property() and read with
1757  * ges_timeline_element_get_child_property(). A change in the property
1758  * will also appear in the #GESTimelineElement::deep-notify signal.
1759  *
1760  * @pspec should be unique from other children properties that have been
1761  * registered on @self.
1762  *
1763  * Returns: %TRUE if the property was successfully registered.
1764  */
1765 gboolean
1766 ges_timeline_element_add_child_property (GESTimelineElement * self,
1767     GParamSpec * pspec, GObject * child)
1768 {
1769   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1770   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
1771   g_return_val_if_fail (G_IS_OBJECT (child), FALSE);
1772
1773   return ges_timeline_element_add_child_property_full (self, NULL, pspec,
1774       child);
1775 }
1776
1777 /**
1778  * ges_timeline_element_get_child_property_by_pspec:
1779  * @self: A #GESTimelineElement
1780  * @pspec: The specification of a registered child property to get
1781  * @value: (out): The return location for the value
1782  *
1783  * Gets the property of a child of the element. Specifically, the property
1784  * corresponding to the @pspec used in
1785  * ges_timeline_element_add_child_property() is copied into @value.
1786  */
1787 void
1788 ges_timeline_element_get_child_property_by_pspec (GESTimelineElement * self,
1789     GParamSpec * pspec, GValue * value)
1790 {
1791   ChildPropHandler *handler;
1792
1793   g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
1794   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
1795
1796   handler = g_hash_table_lookup (self->priv->children_props, pspec);
1797   if (!handler)
1798     goto not_found;
1799
1800   g_object_get_property (G_OBJECT (handler->child), pspec->name, value);
1801
1802   return;
1803
1804 not_found:
1805   {
1806     GST_ERROR_OBJECT (self, "The %s property doesn't exist", pspec->name);
1807     return;
1808   }
1809 }
1810
1811 /**
1812  * ges_timeline_element_set_child_property_by_pspec:
1813  * @self: A #GESTimelineElement
1814  * @pspec: The specification of a registered child property to set
1815  * @value: The value to set the property to
1816  *
1817  * Sets the property of a child of the element. Specifically, the property
1818  * corresponding to the @pspec used in
1819  * ges_timeline_element_add_child_property() is set to @value.
1820  */
1821 void
1822 ges_timeline_element_set_child_property_by_pspec (GESTimelineElement * self,
1823     GParamSpec * pspec, const GValue * value)
1824 {
1825   g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
1826   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
1827
1828   set_child_property_by_pspec (self, pspec, value, NULL);
1829 }
1830
1831 /**
1832  * ges_timeline_element_set_child_property_full:
1833  * @self: A #GESTimelineElement
1834  * @property_name: The name of the child property to set
1835  * @value: The value to set the property to
1836  * @error: (nullable): Return location for an error
1837  *
1838  * Sets the property of a child of the element.
1839  *
1840  * @property_name can either be in the format "prop-name" or
1841  * "TypeName::prop-name", where "prop-name" is the name of the property
1842  * to set (as used in g_object_set()), and "TypeName" is the type name of
1843  * the child (as returned by G_OBJECT_TYPE_NAME()). The latter format is
1844  * useful when two children of different types share the same property
1845  * name.
1846  *
1847  * The first child found with the given "prop-name" property that was
1848  * registered with ges_timeline_element_add_child_property() (and of the
1849  * type "TypeName", if it was given) will have the corresponding
1850  * property set to @value. Other children that may have also matched the
1851  * property name (and type name) are left unchanged!
1852  *
1853  * Returns: %TRUE if the property was found and set.
1854  * Since: 1.18
1855  */
1856 gboolean
1857 ges_timeline_element_set_child_property_full (GESTimelineElement * self,
1858     const gchar * property_name, const GValue * value, GError ** error)
1859 {
1860   GParamSpec *pspec;
1861   GObject *child;
1862
1863   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1864   g_return_val_if_fail (!error || !*error, FALSE);
1865
1866   if (!ges_timeline_element_lookup_child (self, property_name, &child, &pspec))
1867     goto not_found;
1868
1869   return set_child_property_by_pspec (self, pspec, value, error);
1870
1871 not_found:
1872   {
1873     GST_WARNING_OBJECT (self, "The %s property doesn't exist", property_name);
1874
1875     return FALSE;
1876   }
1877 }
1878
1879 /**
1880  * ges_timeline_element_set_child_property:
1881  * @self: A #GESTimelineElement
1882  * @property_name: The name of the child property to set
1883  * @value: The value to set the property to
1884  *
1885  * See ges_timeline_element_set_child_property_full(), which also gives an
1886  * error.
1887  *
1888  * Note that ges_timeline_element_set_child_properties() may be more
1889  * convenient for C programming.
1890  *
1891  * Returns: %TRUE if the property was found and set.
1892  */
1893 gboolean
1894 ges_timeline_element_set_child_property (GESTimelineElement * self,
1895     const gchar * property_name, const GValue * value)
1896 {
1897   return ges_timeline_element_set_child_property_full (self, property_name,
1898       value, NULL);
1899 }
1900
1901 /**
1902  * ges_timeline_element_get_child_property:
1903  * @self: A #GESTimelineElement
1904  * @property_name: The name of the child property to get
1905  * @value: (out): The return location for the value
1906  *
1907  * Gets the property of a child of the element.
1908  *
1909  * @property_name can either be in the format "prop-name" or
1910  * "TypeName::prop-name", where "prop-name" is the name of the property
1911  * to get (as used in g_object_get()), and "TypeName" is the type name of
1912  * the child (as returned by G_OBJECT_TYPE_NAME()). The latter format is
1913  * useful when two children of different types share the same property
1914  * name.
1915  *
1916  * The first child found with the given "prop-name" property that was
1917  * registered with ges_timeline_element_add_child_property() (and of the
1918  * type "TypeName", if it was given) will have the corresponding
1919  * property copied into @value.
1920  *
1921  * Note that ges_timeline_element_get_child_properties() may be more
1922  * convenient for C programming.
1923  *
1924  * Returns: %TRUE if the property was found and copied to @value.
1925  */
1926 gboolean
1927 ges_timeline_element_get_child_property (GESTimelineElement * self,
1928     const gchar * property_name, GValue * value)
1929 {
1930   GParamSpec *pspec;
1931   GObject *child;
1932
1933   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1934
1935   if (!ges_timeline_element_lookup_child (self, property_name, &child, &pspec))
1936     goto not_found;
1937
1938   /* FIXME: since GLib 2.60, g_object_get_property() will automatically
1939    * initialize the type */
1940   if (G_VALUE_TYPE (value) == G_TYPE_INVALID)
1941     g_value_init (value, pspec->value_type);
1942
1943   g_object_get_property (child, pspec->name, value);
1944
1945   gst_object_unref (child);
1946   g_param_spec_unref (pspec);
1947
1948   return TRUE;
1949
1950 not_found:
1951   {
1952     GST_WARNING_OBJECT (self, "The %s property doesn't exist", property_name);
1953
1954     return FALSE;
1955   }
1956 }
1957
1958 /**
1959  * ges_timeline_element_lookup_child:
1960  * @self: A #GESTimelineElement
1961  * @prop_name: The name of a child property
1962  * @child: (out) (optional) (transfer full): The return location for the
1963  * found child
1964  * @pspec: (out) (optional) (transfer full): The return location for the
1965  * specification of the child property
1966  *
1967  * Looks up a child property of the element.
1968  *
1969  * @prop_name can either be in the format "prop-name" or
1970  * "TypeName::prop-name", where "prop-name" is the name of the property
1971  * to look up (as used in g_object_get()), and "TypeName" is the type name
1972  * of the child (as returned by G_OBJECT_TYPE_NAME()). The latter format is
1973  * useful when two children of different types share the same property
1974  * name.
1975  *
1976  * The first child found with the given "prop-name" property that was
1977  * registered with ges_timeline_element_add_child_property() (and of the
1978  * type "TypeName", if it was given) will be passed to @child, and the
1979  * registered specification of this property will be passed to @pspec.
1980  *
1981  * Returns: %TRUE if a child corresponding to the property was found, in
1982  * which case @child and @pspec are set.
1983  */
1984 gboolean
1985 ges_timeline_element_lookup_child (GESTimelineElement * self,
1986     const gchar * prop_name, GObject ** child, GParamSpec ** pspec)
1987 {
1988   GESTimelineElementClass *class;
1989
1990   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1991   class = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1992   g_return_val_if_fail (class->lookup_child, FALSE);
1993
1994   return class->lookup_child (self, prop_name, child, pspec);
1995 }
1996
1997 /**
1998  * ges_timeline_element_set_child_property_valist:
1999  * @self: A #GESTimelineElement
2000  * @first_property_name: The name of the first child property to set
2001  * @var_args: The value for the first property, followed optionally by more
2002  * name/value pairs, followed by %NULL
2003  *
2004  * Sets several of the children properties of the element. See
2005  * ges_timeline_element_set_child_property().
2006  */
2007 void
2008 ges_timeline_element_set_child_property_valist (GESTimelineElement * self,
2009     const gchar * first_property_name, va_list var_args)
2010 {
2011   const gchar *name;
2012   GParamSpec *pspec;
2013
2014   gchar *error = NULL;
2015   GValue value = { 0, };
2016
2017   g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
2018
2019   name = first_property_name;
2020
2021   /* Note: This part is in big part copied from the gst_child_object_set_valist
2022    * method. */
2023
2024   /* iterate over pairs */
2025   while (name) {
2026     if (!ges_timeline_element_lookup_child (self, name, NULL, &pspec))
2027       goto not_found;
2028
2029     G_VALUE_COLLECT_INIT (&value, pspec->value_type, var_args,
2030         G_VALUE_NOCOPY_CONTENTS, &error);
2031
2032     if (error)
2033       goto cant_copy;
2034
2035     set_child_property_by_pspec (self, pspec, &value, NULL);
2036
2037     g_param_spec_unref (pspec);
2038     g_value_unset (&value);
2039
2040     name = va_arg (var_args, gchar *);
2041   }
2042   return;
2043
2044 not_found:
2045   {
2046     GST_WARNING_OBJECT (self, "No property %s in OBJECT\n", name);
2047     return;
2048   }
2049 cant_copy:
2050   {
2051     GST_WARNING_OBJECT (self, "error copying value %s in %p: %s", pspec->name,
2052         self, error);
2053
2054     g_param_spec_unref (pspec);
2055     g_value_unset (&value);
2056     return;
2057   }
2058 }
2059
2060 /**
2061  * ges_timeline_element_set_child_properties:
2062  * @self: A #GESTimelineElement
2063  * @first_property_name: The name of the first child property to set
2064  * @...: The value for the first property, followed optionally by more
2065  * name/value pairs, followed by %NULL
2066  *
2067  * Sets several of the children properties of the element. See
2068  * ges_timeline_element_set_child_property().
2069  */
2070 void
2071 ges_timeline_element_set_child_properties (GESTimelineElement * self,
2072     const gchar * first_property_name, ...)
2073 {
2074   va_list var_args;
2075
2076   g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
2077
2078   va_start (var_args, first_property_name);
2079   ges_timeline_element_set_child_property_valist (self, first_property_name,
2080       var_args);
2081   va_end (var_args);
2082 }
2083
2084 /**
2085  * ges_timeline_element_get_child_property_valist:
2086  * @self: A #GESTimelineElement
2087  * @first_property_name: The name of the first child property to get
2088  * @var_args: The return location for the first property, followed
2089  * optionally by more name/return location pairs, followed by %NULL
2090  *
2091  * Gets several of the children properties of the element. See
2092  * ges_timeline_element_get_child_property().
2093  */
2094 void
2095 ges_timeline_element_get_child_property_valist (GESTimelineElement * self,
2096     const gchar * first_property_name, va_list var_args)
2097 {
2098   const gchar *name;
2099   gchar *error = NULL;
2100   GValue value = { 0, };
2101   GParamSpec *pspec;
2102   GObject *child;
2103
2104   g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
2105
2106   name = first_property_name;
2107
2108   /* This part is in big part copied from the gst_child_object_get_valist method */
2109   while (name) {
2110     if (!ges_timeline_element_lookup_child (self, name, &child, &pspec))
2111       goto not_found;
2112
2113     g_value_init (&value, pspec->value_type);
2114     g_object_get_property (child, pspec->name, &value);
2115     gst_object_unref (child);
2116     g_param_spec_unref (pspec);
2117
2118     G_VALUE_LCOPY (&value, var_args, 0, &error);
2119     if (error)
2120       goto cant_copy;
2121     g_value_unset (&value);
2122     name = va_arg (var_args, gchar *);
2123   }
2124   return;
2125
2126 not_found:
2127   {
2128     GST_WARNING_OBJECT (self, "no child property %s", name);
2129     return;
2130   }
2131 cant_copy:
2132   {
2133     GST_WARNING_OBJECT (self, "error copying value %s in %s", pspec->name,
2134         error);
2135
2136     g_value_unset (&value);
2137     return;
2138   }
2139 }
2140
2141 static gint
2142 compare_gparamspec (GParamSpec ** a, GParamSpec ** b, gpointer udata)
2143 {
2144   return g_strcmp0 ((*a)->name, (*b)->name);
2145 }
2146
2147
2148 /**
2149  * ges_timeline_element_list_children_properties:
2150  * @self: A #GESTimelineElement
2151  * @n_properties: (out): The return location for the length of the
2152  * returned array
2153  *
2154  * Get a list of children properties of the element, which is a list of
2155  * all the specifications passed to
2156  * ges_timeline_element_add_child_property().
2157  *
2158  * Returns: (transfer full) (array length=n_properties): An array of
2159  * #GParamSpec corresponding to the child properties of @self, or %NULL if
2160  * something went wrong.
2161  */
2162 GParamSpec **
2163 ges_timeline_element_list_children_properties (GESTimelineElement * self,
2164     guint * n_properties)
2165 {
2166   GParamSpec **ret;
2167   GESTimelineElementClass *class;
2168
2169   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), NULL);
2170
2171   class = GES_TIMELINE_ELEMENT_GET_CLASS (self);
2172
2173   if (!class->list_children_properties) {
2174     GST_INFO_OBJECT (self, "No %s->list_children_properties implementation",
2175         G_OBJECT_TYPE_NAME (self));
2176
2177     *n_properties = 0;
2178     return NULL;
2179   }
2180
2181   ret = class->list_children_properties (self, n_properties);
2182   g_qsort_with_data (ret, *n_properties, sizeof (GParamSpec *),
2183       (GCompareDataFunc) compare_gparamspec, NULL);
2184
2185   return ret;
2186 }
2187
2188 /**
2189  * ges_timeline_element_get_child_properties:
2190  * @self: A #GESTimelineElement
2191  * @first_property_name: The name of the first child property to get
2192  * @...: The return location for the first property, followed
2193  * optionally by more name/return location pairs, followed by %NULL
2194  *
2195  * Gets several of the children properties of the element. See
2196  * ges_timeline_element_get_child_property().
2197  */
2198 void
2199 ges_timeline_element_get_child_properties (GESTimelineElement * self,
2200     const gchar * first_property_name, ...)
2201 {
2202   va_list var_args;
2203
2204   g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
2205
2206   va_start (var_args, first_property_name);
2207   ges_timeline_element_get_child_property_valist (self, first_property_name,
2208       var_args);
2209   va_end (var_args);
2210 }
2211
2212 /**
2213  * ges_timeline_element_remove_child_property:
2214  * @self: A #GESTimelineElement
2215  * @pspec: The specification for the property to remove
2216  *
2217  * Remove a child property from the element. @pspec should be a
2218  * specification that was passed to
2219  * ges_timeline_element_add_child_property(). The corresponding property
2220  * will no longer be registered as a child property for the element.
2221  *
2222  * Returns: %TRUE if the property was successfully un-registered for @self.
2223  */
2224 gboolean
2225 ges_timeline_element_remove_child_property (GESTimelineElement * self,
2226     GParamSpec * pspec)
2227 {
2228   gpointer key, value;
2229   GParamSpec *found_pspec;
2230   ChildPropHandler *handler;
2231
2232   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
2233   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
2234
2235   if (!g_hash_table_lookup_extended (self->priv->children_props, pspec,
2236           &key, &value)) {
2237     GST_WARNING_OBJECT (self, "No child property with pspec %p (%s) found",
2238         pspec, pspec->name);
2239     return FALSE;
2240   }
2241   g_hash_table_steal (self->priv->children_props, pspec);
2242   found_pspec = G_PARAM_SPEC (key);
2243   handler = (ChildPropHandler *) value;
2244
2245   g_signal_emit (self, ges_timeline_element_signals[CHILD_PROPERTY_REMOVED], 0,
2246       handler->child, found_pspec);
2247
2248   g_param_spec_unref (found_pspec);
2249   _child_prop_handler_free (handler);
2250
2251   return TRUE;
2252 }
2253
2254 /**
2255  * ges_timeline_element_get_track_types:
2256  * @self: A #GESTimelineElement
2257  *
2258  * Gets the track types that the element can interact with, i.e. the type
2259  * of #GESTrack it can exist in, or will create #GESTrackElement-s for.
2260  *
2261  * Returns: The track types that @self supports.
2262  *
2263  * Since: 1.6.0
2264  */
2265 GESTrackType
2266 ges_timeline_element_get_track_types (GESTimelineElement * self)
2267 {
2268   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), 0);
2269   g_return_val_if_fail (GES_TIMELINE_ELEMENT_GET_CLASS (self)->get_track_types,
2270       0);
2271
2272   return GES_TIMELINE_ELEMENT_GET_CLASS (self)->get_track_types (self);
2273 }
2274
2275 /**
2276  * ges_timeline_element_paste:
2277  * @self: The #GESTimelineElement to paste
2278  * @paste_position: The position in the timeline @element should be pasted
2279  * to, i.e. the #GESTimelineElement:start value for the pasted element.
2280  *
2281  * Paste an element inside the same timeline and layer as @self. @self
2282  * **must** be the return of ges_timeline_element_copy() with `deep=TRUE`,
2283  * and it should not be changed before pasting.
2284  * @self is not placed in the timeline, instead a new element is created,
2285  * alike to the originally copied element. Note that the originally
2286  * copied element must stay within the same timeline and layer, at both
2287  * the point of copying and pasting.
2288  *
2289  * Pasting may fail if it would place the timeline in an unsupported
2290  * configuration.
2291  *
2292  * After calling this function @element should not be used. In particular,
2293  * @element can **not** be pasted again. Instead, you can copy the
2294  * returned element and paste that copy (although, this is only possible
2295  * if the paste was successful).
2296  *
2297  * See also ges_timeline_paste_element().
2298  *
2299  * Returns: (transfer full) (nullable): The newly created element, or
2300  * %NULL if pasting fails.
2301  *
2302  * Since: 1.6.0
2303  */
2304 GESTimelineElement *
2305 ges_timeline_element_paste (GESTimelineElement * self,
2306     GstClockTime paste_position)
2307 {
2308   GESTimelineElement *res;
2309   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
2310
2311   if (!self->priv->copied_from) {
2312     GST_ERROR_OBJECT (self, "Is not being 'deeply' copied!");
2313
2314     return NULL;
2315   }
2316
2317   if (!GES_TIMELINE_ELEMENT_GET_CLASS (self)->paste) {
2318     GST_ERROR_OBJECT (self, "No paste vmethod implemented");
2319
2320     return NULL;
2321   }
2322
2323   res = GES_TIMELINE_ELEMENT_GET_CLASS (self)->paste (self,
2324       self->priv->copied_from, paste_position);
2325
2326   g_clear_object (&self->priv->copied_from);
2327
2328   return res ? g_object_ref_sink (res) : res;
2329 }
2330
2331 /**
2332  * ges_timeline_element_get_layer_priority:
2333  * @self: A #GESTimelineElement
2334  *
2335  * Gets the priority of the layer the element is in. A #GESGroup may span
2336  * several layers, so this would return the highest priority (numerically,
2337  * the smallest) amongst them.
2338  *
2339  * Returns: The priority of the layer @self is in, or
2340  * #GES_TIMELINE_ELEMENT_NO_LAYER_PRIORITY if @self does not exist in a
2341  * layer.
2342  *
2343  * Since: 1.16
2344  */
2345 guint32
2346 ges_timeline_element_get_layer_priority (GESTimelineElement * self)
2347 {
2348   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self),
2349       GES_TIMELINE_ELEMENT_NO_LAYER_PRIORITY);
2350
2351   if (!GES_TIMELINE_ELEMENT_GET_CLASS (self)->get_layer_priority)
2352     return self->priority;
2353
2354   return GES_TIMELINE_ELEMENT_GET_CLASS (self)->get_layer_priority (self);
2355 }
2356
2357 /**
2358  * ges_timeline_element_edit_full:
2359  * @self: The #GESTimelineElement to edit
2360  * @new_layer_priority: The priority/index of the layer @self should be
2361  * moved to. -1 means no move
2362  * @mode: The edit mode
2363  * @edge: The edge of @self where the edit should occur
2364  * @position: The edit position: a new location for the edge of @self
2365  * (in nanoseconds) in the timeline coordinates
2366  * @error: (nullable): Return location for an error
2367  *
2368  * Edits the element within its timeline by adjusting its
2369  * #GESTimelineElement:start, #GESTimelineElement:duration or
2370  * #GESTimelineElement:in-point, and potentially doing the same for
2371  * other elements in the timeline. See #GESEditMode for details about each
2372  * edit mode. An edit may fail if it would place one of these properties
2373  * out of bounds, or if it would place the timeline in an unsupported
2374  * configuration.
2375  *
2376  * Note that if you act on a #GESTrackElement, this will edit its parent
2377  * #GESClip instead. Moreover, for any #GESTimelineElement, if you select
2378  * #GES_EDGE_NONE for #GES_EDIT_MODE_NORMAL or #GES_EDIT_MODE_RIPPLE, this
2379  * will edit the toplevel instead, but still in such a way as to make the
2380  * #GESTimelineElement:start of @self reach the edit @position.
2381  *
2382  * Note that if the element's timeline has a
2383  * #GESTimeline:snapping-distance set, then the edit position may be
2384  * snapped to the edge of some element under the edited element.
2385  *
2386  * @new_layer_priority can be used to switch @self, and other elements
2387  * moved by the edit, to a new layer. New layers may be be created if the
2388  * the corresponding layer priority/index does not yet exist for the
2389  * timeline.
2390  *
2391  * Returns: %TRUE if the edit of @self completed, %FALSE on failure.
2392  * Since: 1.18
2393  */
2394
2395 gboolean
2396 ges_timeline_element_edit_full (GESTimelineElement * self,
2397     gint64 new_layer_priority, GESEditMode mode, GESEdge edge, guint64 position,
2398     GError ** error)
2399 {
2400   GESTimeline *timeline;
2401   guint32 layer_prio;
2402
2403   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
2404   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (position), FALSE);
2405   g_return_val_if_fail (!error || !*error, FALSE);
2406
2407   timeline = GES_TIMELINE_ELEMENT_TIMELINE (self);
2408   g_return_val_if_fail (timeline, FALSE);
2409
2410   layer_prio = GES_TIMELINE_ELEMENT_LAYER_PRIORITY (self);
2411
2412   if (new_layer_priority < 0)
2413     new_layer_priority = layer_prio;
2414
2415   GST_DEBUG_OBJECT (self, "Editing %s at edge %s to position %"
2416       GST_TIME_FORMAT " under %s mode, and to layer %" G_GINT64_FORMAT,
2417       self->name, ges_edge_name (edge), GST_TIME_ARGS (position),
2418       ges_edit_mode_name (mode), new_layer_priority);
2419
2420   return ges_timeline_edit (timeline, self, new_layer_priority, mode,
2421       edge, position, error);
2422 }
2423
2424 /**
2425  * ges_timeline_element_edit:
2426  * @self: The #GESTimelineElement to edit
2427  * @layers: (element-type GESLayer) (nullable): A whitelist of layers
2428  * where the edit can be performed, %NULL allows all layers in the
2429  * timeline.
2430  * @new_layer_priority: The priority/index of the layer @self should be
2431  * moved to. -1 means no move
2432  * @mode: The edit mode
2433  * @edge: The edge of @self where the edit should occur
2434  * @position: The edit position: a new location for the edge of @self
2435  * (in nanoseconds) in the timeline coordinates
2436  *
2437  * See ges_timeline_element_edit_full(), which also gives an error.
2438  *
2439  * Note that the @layers argument is currently ignored, so you should
2440  * just pass %NULL.
2441  *
2442  * Returns: %TRUE if the edit of @self completed, %FALSE on failure.
2443  *
2444  * Since: 1.18
2445  */
2446
2447 /* FIXME: handle the layers argument. Currently we always treat it as if
2448  * it is NULL in the ges-timeline code */
2449 gboolean
2450 ges_timeline_element_edit (GESTimelineElement * self, GList * layers,
2451     gint64 new_layer_priority, GESEditMode mode, GESEdge edge, guint64 position)
2452 {
2453   return ges_timeline_element_edit_full (self, new_layer_priority, mode, edge,
2454       position, NULL);
2455 }
2456
2457 /**
2458  * ges_timeline_element_get_natural_framerate:
2459  * @self: The #GESTimelineElement to get "natural" framerate from
2460  * @framerate_n: (out): The framerate numerator
2461  * @framerate_d: (out): The framerate denominator
2462  *
2463  * Get the "natural" framerate of @self. This is to say, for example
2464  * for a #GESVideoUriSource the framerate of the source.
2465  *
2466  * Note that a #GESAudioSource may also have a natural framerate if it derives
2467  * from the same #GESSourceClip asset as a #GESVideoSource, and its value will
2468  * be that of the video source. For example, if the uri of a #GESUriClip points
2469  * to a file that contains both a video and audio stream, then the corresponding
2470  * #GESAudioUriSource will share the natural framerate of the corresponding
2471  * #GESVideoUriSource.
2472  *
2473  * Returns: Whether @self has a natural framerate or not, @framerate_n
2474  * and @framerate_d will be set to, respectively, 0 and -1 if it is
2475  * not the case.
2476  *
2477  * Since: 1.18
2478  */
2479 gboolean
2480 ges_timeline_element_get_natural_framerate (GESTimelineElement * self,
2481     gint * framerate_n, gint * framerate_d)
2482 {
2483   GESTimelineElementClass *klass;
2484
2485   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
2486   g_return_val_if_fail (framerate_n && framerate_d, FALSE);
2487
2488   klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
2489
2490   *framerate_n = 0;
2491   *framerate_d = -1;
2492   return klass->get_natural_framerate (self, framerate_n, framerate_d);
2493 }