80e669e1a2e1e552e3c38a815e4a6bcf92db2d58
[platform/upstream/gst-editing-services.git] / ges / ges-layer.c
1 /* GStreamer Editing Services
2  * Copyright (C) 2009 Edward Hervey <edward.hervey@collabora.co.uk>
3  *               2009 Nokia Corporation
4  *               2011 Mathieu Duponchelle <mathieu.duponchelle@epitech.eu>
5  *               2013 Thibault Saunier <thibault.saunier@collabora.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 /**
24  * SECTION:geslayer
25  * @title: GESLayer
26  * @short_description: Non-overlapping sequence of GESClip
27  *
28  * Responsible for the ordering of the various contained Clip(s). A
29  * timeline layer has a "priority" property, which is used to manage the
30  * priorities of individual Clips. Two layers should not have the
31  * same priority within a given timeline.
32  */
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36
37 #include "ges-internal.h"
38 #include "ges-layer.h"
39 #include "ges.h"
40 #include "ges-source-clip.h"
41
42 static void ges_meta_container_interface_init
43     (GESMetaContainerInterface * iface);
44
45 struct _GESLayerPrivate
46 {
47   /*< private > */
48   GList *clips_start;           /* The Clips sorted by start and
49                                  * priority */
50
51   guint32 priority;             /* The priority of the layer within the
52                                  * containing timeline */
53   gboolean auto_transition;
54 };
55
56 typedef struct
57 {
58   GESClip *clip;
59   GESLayer *layer;
60 } NewAssetUData;
61
62 enum
63 {
64   PROP_0,
65   PROP_PRIORITY,
66   PROP_AUTO_TRANSITION,
67   PROP_LAST
68 };
69
70 enum
71 {
72   OBJECT_ADDED,
73   OBJECT_REMOVED,
74   LAST_SIGNAL
75 };
76
77 static guint ges_layer_signals[LAST_SIGNAL] = { 0 };
78
79 G_DEFINE_TYPE_WITH_CODE (GESLayer, ges_layer,
80     G_TYPE_INITIALLY_UNOWNED, G_IMPLEMENT_INTERFACE (GES_TYPE_EXTRACTABLE, NULL)
81     G_ADD_PRIVATE (GESLayer)
82     G_IMPLEMENT_INTERFACE (GES_TYPE_META_CONTAINER,
83         ges_meta_container_interface_init));
84
85 /* GObject standard vmethods */
86 static void
87 ges_layer_get_property (GObject * object, guint property_id,
88     GValue * value, GParamSpec * pspec)
89 {
90   GESLayer *layer = GES_LAYER (object);
91
92   switch (property_id) {
93     case PROP_PRIORITY:
94       g_value_set_uint (value, layer->priv->priority);
95       break;
96     case PROP_AUTO_TRANSITION:
97       g_value_set_boolean (value, layer->priv->auto_transition);
98       break;
99     default:
100       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
101   }
102 }
103
104 static void
105 ges_layer_set_property (GObject * object, guint property_id,
106     const GValue * value, GParamSpec * pspec)
107 {
108   GESLayer *layer = GES_LAYER (object);
109
110   switch (property_id) {
111     case PROP_PRIORITY:
112       GST_FIXME ("Deprecated, use ges_timeline_move_layer instead");
113       layer_set_priority (layer, g_value_get_uint (value), FALSE);
114       break;
115     case PROP_AUTO_TRANSITION:
116       ges_layer_set_auto_transition (layer, g_value_get_boolean (value));
117       break;
118     default:
119       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
120   }
121 }
122
123 static void
124 ges_layer_dispose (GObject * object)
125 {
126   GESLayer *layer = GES_LAYER (object);
127   GESLayerPrivate *priv = layer->priv;
128
129   GST_DEBUG ("Disposing layer");
130
131   while (priv->clips_start)
132     ges_layer_remove_clip (layer, (GESClip *) priv->clips_start->data);
133
134   G_OBJECT_CLASS (ges_layer_parent_class)->dispose (object);
135 }
136
137 static gboolean
138 _register_metas (GESLayer * layer)
139 {
140   ges_meta_container_register_meta_float (GES_META_CONTAINER (layer),
141       GES_META_READ_WRITE, GES_META_VOLUME, 1.0);
142
143   return TRUE;
144 }
145
146 static void
147 ges_meta_container_interface_init (GESMetaContainerInterface * iface)
148 {
149
150 }
151
152 static void
153 ges_layer_class_init (GESLayerClass * klass)
154 {
155   GObjectClass *object_class = G_OBJECT_CLASS (klass);
156
157   object_class->get_property = ges_layer_get_property;
158   object_class->set_property = ges_layer_set_property;
159   object_class->dispose = ges_layer_dispose;
160
161   /**
162    * GESLayer:priority:
163    *
164    * The priority of the layer in the #GESTimeline. 0 is the highest
165    * priority. Conceptually, a #GESTimeline is a stack of GESLayers,
166    * and the priority of the layer represents its position in the stack. Two
167    * layers should not have the same priority within a given GESTimeline.
168    *
169    * Note that the timeline needs to be commited (with #ges_timeline_commit)
170    * for the change to be taken into account.
171    *
172    * Deprecated:1.16.0: use #ges_timeline_move_layer instead. This deprecation means
173    * that you will not need to handle layer priorities at all yourself, GES
174    * will make sure there is never 'gaps' between layer priorities.
175    */
176   g_object_class_install_property (object_class, PROP_PRIORITY,
177       g_param_spec_uint ("priority", "Priority",
178           "The priority of the layer", 0, G_MAXUINT, 0, G_PARAM_READWRITE));
179
180   /**
181    * GESLayer:auto-transition:
182    *
183    * Sets whether transitions are added automagically when clips overlap.
184    */
185   g_object_class_install_property (object_class, PROP_AUTO_TRANSITION,
186       g_param_spec_boolean ("auto-transition", "Auto-Transition",
187           "whether the transitions are added", FALSE, G_PARAM_READWRITE));
188
189   /**
190    * GESLayer::clip-added:
191    * @layer: the #GESLayer
192    * @clip: the #GESClip that was added.
193    *
194    * Will be emitted after the clip was added to the layer.
195    */
196   ges_layer_signals[OBJECT_ADDED] =
197       g_signal_new ("clip-added", G_TYPE_FROM_CLASS (klass),
198       G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GESLayerClass, object_added),
199       NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GES_TYPE_CLIP);
200
201   /**
202    * GESLayer::clip-removed:
203    * @layer: the #GESLayer
204    * @clip: the #GESClip that was removed
205    *
206    * Will be emitted after the clip was removed from the layer.
207    */
208   ges_layer_signals[OBJECT_REMOVED] =
209       g_signal_new ("clip-removed", G_TYPE_FROM_CLASS (klass),
210       G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GESLayerClass,
211           object_removed), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE,
212       1, GES_TYPE_CLIP);
213 }
214
215 static void
216 ges_layer_init (GESLayer * self)
217 {
218   self->priv = ges_layer_get_instance_private (self);
219
220   self->priv->priority = 0;
221   self->priv->auto_transition = FALSE;
222   self->min_nle_priority = MIN_NLE_PRIO;
223   self->max_nle_priority = LAYER_HEIGHT + MIN_NLE_PRIO;
224
225   _register_metas (self);
226 }
227
228 static gint
229 ges_layer_resync_priorities_by_type (GESLayer * layer,
230     gint starting_priority, GType type)
231 {
232   GstClockTime next_reset = 0;
233   gint priority = starting_priority, max_priority = priority;
234   GList *tmp;
235   GESTimelineElement *element;
236
237   layer->priv->clips_start =
238       g_list_sort (layer->priv->clips_start,
239       (GCompareFunc) element_start_compare);
240   for (tmp = layer->priv->clips_start; tmp; tmp = tmp->next) {
241
242     element = GES_TIMELINE_ELEMENT (tmp->data);
243
244     if (GES_IS_TRANSITION_CLIP (element)) {
245       /* Blindly set transitions priorities to 0 */
246       _set_priority0 (element, 0);
247       continue;
248     } else if (!g_type_is_a (G_OBJECT_TYPE (element), type))
249       continue;
250
251     if (element->start > next_reset) {
252       priority = starting_priority;
253       next_reset = 0;
254     }
255
256     if (element->start + element->duration > next_reset)
257       next_reset = element->start + element->duration;
258
259     _set_priority0 (element, priority);
260     priority = priority + GES_CONTAINER_HEIGHT (element);
261
262     if (priority > max_priority)
263       max_priority = priority;
264   }
265
266   return max_priority;
267 }
268
269 /**
270  * ges_layer_resync_priorities:
271  * @layer: a #GESLayer
272  *
273  * Resyncs the priorities of the clips controlled by @layer.
274  */
275 gboolean
276 ges_layer_resync_priorities (GESLayer * layer)
277 {
278   gint min_source_prios;
279
280   g_return_val_if_fail (GES_IS_LAYER (layer), FALSE);
281
282   GST_INFO_OBJECT (layer, "Resync priorities (prio: %d)",
283       layer->priv->priority);
284
285   min_source_prios = ges_layer_resync_priorities_by_type (layer, 1,
286       GES_TYPE_OPERATION_CLIP);
287
288   ges_layer_resync_priorities_by_type (layer, min_source_prios,
289       GES_TYPE_SOURCE_CLIP);
290
291   return TRUE;
292 }
293
294 void
295 layer_set_priority (GESLayer * layer, guint priority, gboolean emit)
296 {
297   GST_DEBUG ("layer:%p, priority:%d", layer, priority);
298
299   if (priority != layer->priv->priority) {
300     layer->priv->priority = priority;
301     layer->min_nle_priority = (priority * LAYER_HEIGHT) + MIN_NLE_PRIO;
302     layer->max_nle_priority = ((priority + 1) * LAYER_HEIGHT) + MIN_NLE_PRIO;
303
304     ges_layer_resync_priorities (layer);
305   }
306
307   if (emit)
308     g_object_notify (G_OBJECT (layer), "priority");
309 }
310
311 static void
312 new_asset_cb (GESAsset * source, GAsyncResult * res, NewAssetUData * udata)
313 {
314   GError *error = NULL;
315
316   GESAsset *asset = ges_asset_request_finish (res, &error);
317
318   GST_DEBUG_OBJECT (udata->layer, "%" GST_PTR_FORMAT " Asset loaded, "
319       "setting its asset", udata->clip);
320
321   if (error) {
322     GESProject *project = udata->layer->timeline ?
323         GES_PROJECT (ges_extractable_get_asset (GES_EXTRACTABLE
324             (udata->layer->timeline))) : NULL;
325     if (project) {
326       gchar *possible_id;
327
328       possible_id = ges_project_try_updating_id (project, source, error);
329       if (possible_id) {
330         ges_asset_request_async (ges_asset_get_extractable_type (source),
331             possible_id, NULL, (GAsyncReadyCallback) new_asset_cb, udata);
332         g_free (possible_id);
333         return;
334       }
335     }
336
337     GST_ERROR ("Asset could not be created for uri %s, error: %s",
338         ges_asset_get_id (asset), error->message);
339   } else {
340     GESProject *project = udata->layer->timeline ?
341         GES_PROJECT (ges_extractable_get_asset (GES_EXTRACTABLE
342             (udata->layer->timeline))) : NULL;
343     ges_extractable_set_asset (GES_EXTRACTABLE (udata->clip), asset);
344
345     ges_project_add_asset (project, asset);
346
347     /* clip was already ref-sinked when creating udata,
348      * gst_layer_add_clip() creates a new ref as such and
349      * below we unref the ref from udata */
350     ges_layer_add_clip (udata->layer, udata->clip);
351   }
352
353   gst_object_unref (asset);
354   gst_object_unref (udata->clip);
355   g_slice_free (NewAssetUData, udata);
356 }
357
358 /**
359  * ges_layer_get_duration:
360  * @layer: The #GESLayer to get the duration from
361  *
362  * Lets you retrieve the duration of the layer, which means
363  * the end time of the last clip inside it
364  *
365  * Returns: The duration of a layer
366  */
367 GstClockTime
368 ges_layer_get_duration (GESLayer * layer)
369 {
370   GList *tmp;
371   GstClockTime duration = 0;
372
373   g_return_val_if_fail (GES_IS_LAYER (layer), 0);
374
375   for (tmp = layer->priv->clips_start; tmp; tmp = tmp->next) {
376     duration = MAX (duration, _END (tmp->data));
377   }
378
379   return duration;
380 }
381
382 /* Public methods */
383 /**
384  * ges_layer_remove_clip:
385  * @layer: a #GESLayer
386  * @clip: the #GESClip to remove
387  *
388  * Removes the given @clip from the @layer and unparents it.
389  * Unparenting it means the reference owned by @layer on the @clip will be
390  * removed. If you wish to use the @clip after this function, make sure you
391  * call gst_object_ref() before removing it from the @layer.
392  *
393  * Returns: %TRUE if the clip could be removed, %FALSE if the layer does
394  * not want to remove the clip.
395  */
396 gboolean
397 ges_layer_remove_clip (GESLayer * layer, GESClip * clip)
398 {
399   GESLayer *current_layer;
400
401   g_return_val_if_fail (GES_IS_LAYER (layer), FALSE);
402   g_return_val_if_fail (GES_IS_CLIP (clip), FALSE);
403
404   GST_DEBUG ("layer:%p, clip:%p", layer, clip);
405
406   current_layer = ges_clip_get_layer (clip);
407   if (G_UNLIKELY (current_layer != layer)) {
408     GST_WARNING ("Clip doesn't belong to this layer");
409
410     if (current_layer != NULL)
411       gst_object_unref (current_layer);
412
413     return FALSE;
414   }
415   gst_object_unref (current_layer);
416
417   /* Remove it from our list of controlled objects */
418   layer->priv->clips_start = g_list_remove (layer->priv->clips_start, clip);
419
420   /* emit 'clip-removed' */
421   g_signal_emit (layer, ges_layer_signals[OBJECT_REMOVED], 0, clip);
422
423   /* inform the clip it's no longer in a layer */
424   ges_clip_set_layer (clip, NULL);
425   /* so neither in a timeline */
426   if (layer->timeline)
427     ges_timeline_element_set_timeline (GES_TIMELINE_ELEMENT (clip), NULL);
428
429   /* Remove our reference to the clip */
430   gst_object_unref (clip);
431
432   return TRUE;
433 }
434
435 /**
436  * ges_layer_set_priority:
437  * @layer: a #GESLayer
438  * @priority: the priority to set
439  *
440  * Sets the layer to the given @priority. See the documentation of the
441  * priority property for more information.
442  *
443  * Deprecated:1.16.0: use #ges_timeline_move_layer instead. This deprecation means
444  * that you will not need to handle layer priorities at all yourself, GES
445  * will make sure there is never 'gaps' between layer priorities.
446  */
447 void
448 ges_layer_set_priority (GESLayer * layer, guint priority)
449 {
450   g_return_if_fail (GES_IS_LAYER (layer));
451
452   GST_FIXME ("Deprecated, use ges_timeline_move_layer instead");
453
454   layer_set_priority (layer, priority, TRUE);
455 }
456
457 /**
458  * ges_layer_get_auto_transition:
459  * @layer: a #GESLayer
460  *
461  * Gets whether transitions are automatically added when objects
462  * overlap or not.
463  *
464  * Returns: %TRUE if transitions are automatically added, else %FALSE.
465  */
466 gboolean
467 ges_layer_get_auto_transition (GESLayer * layer)
468 {
469   g_return_val_if_fail (GES_IS_LAYER (layer), 0);
470
471   return layer->priv->auto_transition;
472 }
473
474 /**
475  * ges_layer_set_auto_transition:
476  * @layer: a #GESLayer
477  * @auto_transition: whether the auto_transition is active
478  *
479  * Sets the layer to the given @auto_transition. See the documentation of the
480  * property auto_transition for more information.
481  */
482 void
483 ges_layer_set_auto_transition (GESLayer * layer, gboolean auto_transition)
484 {
485
486   g_return_if_fail (GES_IS_LAYER (layer));
487
488   layer->priv->auto_transition = auto_transition;
489   g_object_notify (G_OBJECT (layer), "auto-transition");
490 }
491
492 /**
493  * ges_layer_get_priority:
494  * @layer: a #GESLayer
495  *
496  * Get the priority of @layer within the timeline.
497  *
498  * Returns: The priority of the @layer within the timeline.
499  */
500 guint
501 ges_layer_get_priority (GESLayer * layer)
502 {
503   g_return_val_if_fail (GES_IS_LAYER (layer), 0);
504
505   return layer->priv->priority;
506 }
507
508 /**
509  * ges_layer_get_clips:
510  * @layer: a #GESLayer
511  *
512  * Get the clips this layer contains.
513  *
514  * Returns: (transfer full) (element-type GESClip): a #GList of
515  * clips. The user is responsible for
516  * unreffing the contained objects and freeing the list.
517  */
518
519 GList *
520 ges_layer_get_clips (GESLayer * layer)
521 {
522   GESLayerClass *klass;
523
524   g_return_val_if_fail (GES_IS_LAYER (layer), NULL);
525
526   klass = GES_LAYER_GET_CLASS (layer);
527
528   if (klass->get_objects) {
529     return klass->get_objects (layer);
530   }
531
532   return g_list_sort (g_list_copy_deep (layer->priv->clips_start,
533           (GCopyFunc) gst_object_ref, NULL),
534       (GCompareFunc) element_start_compare);
535 }
536
537 /**
538  * ges_layer_is_empty:
539  * @layer: The #GESLayer to check
540  *
541  * Convenience method to check if @layer is empty (doesn't contain any clip),
542  * or not.
543  *
544  * Returns: %TRUE if @layer is empty, %FALSE if it already contains at least
545  * one #GESClip
546  */
547 gboolean
548 ges_layer_is_empty (GESLayer * layer)
549 {
550   g_return_val_if_fail (GES_IS_LAYER (layer), FALSE);
551
552   return (layer->priv->clips_start == NULL);
553 }
554
555 /**
556  * ges_layer_add_clip:
557  * @layer: a #GESLayer
558  * @clip: (transfer floating): the #GESClip to add.
559  *
560  * Adds the given clip to the layer. Sets the clip's parent, and thus
561  * takes ownership of the clip.
562  *
563  * An clip can only be added to one layer.
564  *
565  * Calling this method will construct and properly set all the media related
566  * elements on @clip. If you need to know when those objects (actually #GESTrackElement)
567  * are constructed, you should connect to the container::child-added signal which
568  * is emited right after those elements are ready to be used.
569  *
570  * Returns: %TRUE if the clip was properly added to the layer, or %FALSE
571  * if the @layer refuses to add the clip.
572  */
573 gboolean
574 ges_layer_add_clip (GESLayer * layer, GESClip * clip)
575 {
576   GESAsset *asset;
577   GESLayerPrivate *priv;
578   GESLayer *current_layer;
579
580   g_return_val_if_fail (GES_IS_LAYER (layer), FALSE);
581   g_return_val_if_fail (GES_IS_CLIP (clip), FALSE);
582
583   GST_DEBUG_OBJECT (layer, "adding clip:%p", clip);
584
585   priv = layer->priv;
586   current_layer = ges_clip_get_layer (clip);
587   if (G_UNLIKELY (current_layer)) {
588     GST_WARNING ("Clip %p already belongs to another layer", clip);
589     gst_object_ref_sink (clip);
590     gst_object_unref (current_layer);
591
592     return FALSE;
593   }
594
595   asset = ges_extractable_get_asset (GES_EXTRACTABLE (clip));
596   if (asset == NULL) {
597     gchar *id;
598     NewAssetUData *mudata = g_slice_new (NewAssetUData);
599
600     mudata->clip = gst_object_ref_sink (clip);
601     mudata->layer = layer;
602
603     GST_DEBUG_OBJECT (layer, "%" GST_PTR_FORMAT " as no reference to any "
604         "assets creating a asset... trying sync", clip);
605
606     id = ges_extractable_get_id (GES_EXTRACTABLE (clip));
607     asset = ges_asset_request (G_OBJECT_TYPE (clip), id, NULL);
608     if (asset == NULL) {
609       GESProject *project = layer->timeline ?
610           GES_PROJECT (ges_extractable_get_asset (GES_EXTRACTABLE
611               (layer->timeline))) : NULL;
612
613       ges_asset_request_async (G_OBJECT_TYPE (clip),
614           id, NULL, (GAsyncReadyCallback) new_asset_cb, mudata);
615
616       if (project)
617         ges_project_add_loading_asset (project, G_OBJECT_TYPE (clip), id);
618       g_free (id);
619
620       GST_LOG_OBJECT (layer, "Object added async");
621       return TRUE;
622     }
623     g_free (id);
624
625     ges_extractable_set_asset (GES_EXTRACTABLE (clip), asset);
626
627     g_slice_free (NewAssetUData, mudata);
628   } else {
629     gst_object_ref_sink (clip);
630   }
631
632   /* Take a reference to the clip and store it stored by start/priority */
633   priv->clips_start = g_list_insert_sorted (priv->clips_start, clip,
634       (GCompareFunc) element_start_compare);
635
636   /* Inform the clip it's now in this layer */
637   ges_clip_set_layer (clip, layer);
638
639   GST_DEBUG ("current clip priority : %d, Height: %d", _PRIORITY (clip),
640       LAYER_HEIGHT);
641
642   /* Set the priority. */
643   if (_PRIORITY (clip) > LAYER_HEIGHT) {
644     GST_WARNING_OBJECT (layer,
645         "%p is out of the layer space, setting its priority to "
646         "%d, setting it to the maximum priority of the layer: %d", clip,
647         _PRIORITY (clip), LAYER_HEIGHT - 1);
648     _set_priority0 (GES_TIMELINE_ELEMENT (clip), LAYER_HEIGHT - 1);
649   }
650
651   ges_layer_resync_priorities (layer);
652
653   ges_timeline_element_set_timeline (GES_TIMELINE_ELEMENT (clip),
654       layer->timeline);
655
656   /* emit 'clip-added' */
657   g_signal_emit (layer, ges_layer_signals[OBJECT_ADDED], 0, clip);
658
659   return TRUE;
660 }
661
662 /**
663  * ges_layer_add_asset:
664  * @layer: a #GESLayer
665  * @asset: The asset to add to
666  * @start: The start value to set on the new #GESClip,
667  * if @start == GST_CLOCK_TIME_NONE, it will be set to
668  * the current duration of @layer
669  * @inpoint: The inpoint value to set on the new #GESClip
670  * @duration: The duration value to set on the new #GESClip
671  * @track_types: The #GESTrackType to set on the the new #GESClip
672  *
673  * Creates Clip from asset, adds it to layer and
674  * returns a reference to it.
675  *
676  * Returns: (transfer none): Created #GESClip
677  */
678 GESClip *
679 ges_layer_add_asset (GESLayer * layer,
680     GESAsset * asset, GstClockTime start, GstClockTime inpoint,
681     GstClockTime duration, GESTrackType track_types)
682 {
683   GESClip *clip;
684
685   g_return_val_if_fail (GES_IS_LAYER (layer), NULL);
686   g_return_val_if_fail (GES_IS_ASSET (asset), NULL);
687   g_return_val_if_fail (g_type_is_a (ges_asset_get_extractable_type
688           (asset), GES_TYPE_CLIP), NULL);
689
690   GST_DEBUG_OBJECT (layer, "Adding asset %s with: start: %" GST_TIME_FORMAT
691       " inpoint: %" GST_TIME_FORMAT " duration: %" GST_TIME_FORMAT
692       " track types: %d (%s)", ges_asset_get_id (asset), GST_TIME_ARGS (start),
693       GST_TIME_ARGS (inpoint), GST_TIME_ARGS (duration), track_types,
694       ges_track_type_name (track_types));
695
696   clip = GES_CLIP (ges_asset_extract (asset, NULL));
697
698   if (!GST_CLOCK_TIME_IS_VALID (start)) {
699     start = ges_layer_get_duration (layer);
700
701     GST_DEBUG_OBJECT (layer,
702         "No start specified, setting it to %" GST_TIME_FORMAT,
703         GST_TIME_ARGS (start));
704   }
705
706   _set_start0 (GES_TIMELINE_ELEMENT (clip), start);
707   _set_inpoint0 (GES_TIMELINE_ELEMENT (clip), inpoint);
708   if (track_types != GES_TRACK_TYPE_UNKNOWN)
709     ges_clip_set_supported_formats (clip, track_types);
710
711   if (GST_CLOCK_TIME_IS_VALID (duration)) {
712     _set_duration0 (GES_TIMELINE_ELEMENT (clip), duration);
713   }
714
715   if (!ges_layer_add_clip (layer, clip)) {
716     return NULL;
717   }
718
719   return clip;
720 }
721
722 /**
723  * ges_layer_new:
724  *
725  * Creates a new #GESLayer.
726  *
727  * Returns: (transfer floating): A new #GESLayer
728  */
729 GESLayer *
730 ges_layer_new (void)
731 {
732   return g_object_new (GES_TYPE_LAYER, NULL);
733 }
734
735 /**
736  * ges_layer_get_timeline:
737  * @layer: The #GESLayer to get the parent #GESTimeline from
738  *
739  * Get the #GESTimeline in which #GESLayer currently is.
740  *
741  * Returns: (transfer none) (nullable): the #GESTimeline in which #GESLayer
742  * currently is or %NULL if not in any timeline yet.
743  */
744 GESTimeline *
745 ges_layer_get_timeline (GESLayer * layer)
746 {
747   g_return_val_if_fail (GES_IS_LAYER (layer), NULL);
748
749   return layer->timeline;
750 }
751
752 void
753 ges_layer_set_timeline (GESLayer * layer, GESTimeline * timeline)
754 {
755   GList *tmp;
756
757   g_return_if_fail (GES_IS_LAYER (layer));
758
759   GST_DEBUG ("layer:%p, timeline:%p", layer, timeline);
760
761   for (tmp = layer->priv->clips_start; tmp; tmp = tmp->next) {
762     ges_timeline_element_set_timeline (tmp->data, timeline);
763   }
764
765   layer->timeline = timeline;
766 }
767
768 /**
769  * ges_layer_get_clips_in_interval:
770  * @layer: a #GESLayer
771  * @start: start of the interval
772  * @end: end of the interval
773  *
774  * Gets the clips which appear between @start and @end on @layer.
775  *
776  * Returns: (transfer full) (element-type GESClip): a #GList of clips intersecting [@start, @end) interval on @layer.
777  */
778 GList *
779 ges_layer_get_clips_in_interval (GESLayer * layer, GstClockTime start,
780     GstClockTime end)
781 {
782   GList *tmp;
783   GList *intersecting_clips = NULL;
784   GstClockTime clip_start, clip_end;
785   gboolean clip_intersects;
786
787   g_return_val_if_fail (GES_IS_LAYER (layer), NULL);
788
789   layer->priv->clips_start =
790       g_list_sort (layer->priv->clips_start,
791       (GCompareFunc) element_start_compare);
792   for (tmp = layer->priv->clips_start; tmp; tmp = tmp->next) {
793     clip_intersects = FALSE;
794     clip_start = ges_timeline_element_get_start (tmp->data);
795     clip_end = clip_start + ges_timeline_element_get_duration (tmp->data);
796     if (start <= clip_start && clip_start < end)
797       clip_intersects = TRUE;
798     else if (start < clip_end && clip_end <= end)
799       clip_intersects = TRUE;
800     else if (clip_start < start && clip_end > end)
801       clip_intersects = TRUE;
802
803     if (clip_intersects)
804       intersecting_clips =
805           g_list_insert_sorted (intersecting_clips,
806           gst_object_ref (tmp->data), (GCompareFunc) element_start_compare);
807   }
808   return intersecting_clips;
809 }