Merge branch 'tizen' into tizen_gst_1.19.2
[platform/upstream/gst-editing-services.git] / ges / ges-timeline.c
1 /* GStreamer Editing Services
2  * Copyright (C) 2009 Edward Hervey <edward.hervey@collabora.co.uk>
3  *               2009 Nokia Corporation
4  *               2012 Thibault Saunier <tsaunier@gnome.org>
5  *               2012 Collabora Ltd.
6  *                 Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
7  *               2019 Igalia S.L
8  *                 Author: Thibault Saunier <tsaunier@igalia.com>
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public
21  * License along with this library; if not, write to the
22  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
23  * Boston, MA 02110-1301, USA.
24  */
25
26 /**
27  * SECTION:gestimeline
28  * @title: GESTimeline
29  * @short_description: Multimedia timeline
30  *
31  * #GESTimeline is the central object for any multimedia timeline.
32  *
33  * A timeline is composed of a set of #GESTrack-s and a set of
34  * #GESLayer-s, which are added to the timeline using
35  * ges_timeline_add_track() and ges_timeline_append_layer(), respectively.
36  *
37  * The contained tracks define the supported types of the timeline
38  * and provide the media output. Essentially, each track provides an
39  * additional source #GstPad.
40  *
41  * Most usage of a timeline will likely only need a single #GESAudioTrack
42  * and/or a single #GESVideoTrack. You can create such a timeline with
43  * ges_timeline_new_audio_video(). After this, you are unlikely to need to
44  * work with the tracks directly.
45  *
46  * A timeline's layers contain #GESClip-s, which in turn control the
47  * creation of #GESTrackElement-s, which are added to the timeline's
48  * tracks. See #GESTimeline::select-tracks-for-object if you wish to have
49  * more control over which track a clip's elements are added to.
50  *
51  * The layers are ordered, with higher priority layers having their
52  * content prioritised in the tracks. This ordering can be changed using
53  * ges_timeline_move_layer().
54  *
55  * ## Editing
56  *
57  * See #GESTimelineElement for the various ways the elements of a timeline
58  * can be edited.
59  *
60  * If you change the timing or ordering of a timeline's
61  * #GESTimelineElement-s, then these changes will not actually be taken
62  * into account in the output of the timeline's tracks until the
63  * ges_timeline_commit() method is called. This allows you to move its
64  * elements around, say, in response to an end user's mouse dragging, with
65  * little expense before finalising their effect on the produced data.
66  *
67  * ## Overlaps and Auto-Transitions
68  *
69  * There are certain restrictions placed on how #GESSource-s may overlap
70  * in a #GESTrack that belongs to a timeline. These will be enforced by
71  * GES, so the user will not need to keep track of them, but they should
72  * be aware that certain edits will be refused as a result if the overlap
73  * rules would be broken.
74  *
75  * Consider two #GESSource-s, `A` and `B`, with start times `startA` and
76  * `startB`, and end times `endA` and `endB`, respectively. The start
77  * time refers to their #GESTimelineElement:start, and the end time is
78  * their #GESTimelineElement:start + #GESTimelineElement:duration. These
79  * two sources *overlap* if:
80  *
81  * + they share the same #GESTrackElement:track (non %NULL), which belongs
82  *   to the timeline;
83  * + they share the same #GES_TIMELINE_ELEMENT_LAYER_PRIORITY; and
84  * + `startA < endB` and `startB < endA `.
85  *
86  * Note that when `startA = endB` or `startB = endA` then the two sources
87  * will *touch* at their edges, but are not considered overlapping.
88  *
89  * If, in addition, `startA < startB < endA`, then we can say that the
90  * end of `A` overlaps the start of `B`.
91  *
92  * If, instead, `startA <= startB` and `endA >= endB`, then we can say
93  * that `A` fully overlaps `B`.
94  *
95  * The overlap rules for a timeline are that:
96  *
97  * 1. One source cannot fully overlap another source.
98  * 2. A source can only overlap the end of up to one other source at its
99  *    start.
100  * 3. A source can only overlap the start of up to one other source at its
101  *    end.
102  *
103  * The last two rules combined essentially mean that at any given timeline
104  * position, only up to two #GESSource-s may overlap at that position. So
105  * triple or more overlaps are not allowed.
106  *
107  * If you switch on #GESTimeline:auto-transition, then at any moment when
108  * the end of one source (the first source) overlaps the start of another
109  * (the second source), a #GESTransitionClip will be automatically created
110  * for the pair in the same layer and it will cover their overlap. If the
111  * two elements are edited in a way such that the end of the first source
112  * no longer overlaps the start of the second, the transition will be
113  * automatically removed from the timeline. However, if the two sources
114  * still overlap at the same edges after the edit, then the same
115  * transition object will be kept, but with its timing and layer adjusted
116  * accordingly.
117  *
118  * ## Saving
119  *
120  * To save/load a timeline, you can use the ges_timeline_load_from_uri()
121  * and ges_timeline_save_to_uri() methods that use the default format.
122  *
123  * ## Playing
124  *
125  * A timeline is a #GstBin with a source #GstPad for each of its
126  * tracks, which you can fetch with ges_timeline_get_pad_for_track(). You
127  * will likely want to link these to some compatible sink #GstElement-s to
128  * be able to play or capture the content of the timeline.
129  *
130  * You can use a #GESPipeline to easily preview/play the timeline's
131  * content, or render it to a file.
132  */
133 #ifdef HAVE_CONFIG_H
134 #include "config.h"
135 #endif
136
137 #include "ges-internal.h"
138 #include "ges-project.h"
139 #include "ges-container.h"
140 #include "ges-timeline.h"
141 #include "ges-timeline-tree.h"
142 #include "ges-track.h"
143 #include "ges-layer.h"
144 #include "ges-auto-transition.h"
145 #include "ges.h"
146
147
148 static GPtrArray *select_tracks_for_object_default (GESTimeline * timeline,
149     GESClip * clip, GESTrackElement * tr_obj, gpointer user_data);
150 static void ges_extractable_interface_init (GESExtractableInterface * iface);
151 static void ges_meta_container_interface_init
152     (GESMetaContainerInterface * iface);
153
154 GST_DEBUG_CATEGORY_STATIC (ges_timeline_debug);
155 #undef GST_CAT_DEFAULT
156 #define GST_CAT_DEFAULT ges_timeline_debug
157
158 /* lock to protect dynamic callbacks, like pad-added */
159 #define DYN_LOCK(timeline) (&GES_TIMELINE (timeline)->priv->dyn_mutex)
160 #define LOCK_DYN(timeline) G_STMT_START {                       \
161     GST_LOG_OBJECT (timeline, "Getting dynamic lock from %p", \
162         g_thread_self());                                       \
163     g_rec_mutex_lock (DYN_LOCK (timeline));                     \
164     GST_LOG_OBJECT (timeline, "Got Dynamic lock from %p",     \
165         g_thread_self());         \
166   } G_STMT_END
167
168 #define UNLOCK_DYN(timeline) G_STMT_START {                         \
169     GST_LOG_OBJECT (timeline, "Unlocking dynamic lock from %p", \
170         g_thread_self());                                         \
171     g_rec_mutex_unlock (DYN_LOCK (timeline));                     \
172     GST_LOG_OBJECT (timeline, "Unlocked Dynamic lock from %p",  \
173         g_thread_self());         \
174   } G_STMT_END
175
176 #define CHECK_THREAD(timeline) g_assert(timeline->priv->valid_thread == g_thread_self())
177
178 struct _GESTimelinePrivate
179 {
180   GNode *tree;
181
182   /* The duration of the timeline */
183   gint64 duration;
184
185   /* The auto-transition of the timeline */
186   gboolean auto_transition;
187
188   /* Timeline edition modes and snapping management */
189   guint64 snapping_distance;
190
191   GRecMutex dyn_mutex;
192   GList *priv_tracks;
193
194   /* Avoid sorting layers when we are actually resyncing them ourself */
195   gboolean resyncing_layers;
196   GList *auto_transitions;
197
198   /* Last snapping  properties */
199   GstClockTime last_snap_ts;
200   GESTrackElement *last_snaped1;
201   GESTrackElement *last_snaped2;
202
203   GESTrack *auto_transition_track;
204   GESTrack *new_track;
205
206   /* While we are creating and adding the TrackElements for a clip, we need to
207    * ignore the child-added signal */
208   gboolean track_elements_moving;
209   /* whether any error occurred during track selection, including
210    * programming or usage errors */
211   gboolean has_any_track_selection_error;
212   /* error set for non-programming/usage errors */
213   GError *track_selection_error;
214   GList *groups;
215
216   guint stream_start_group_id;
217
218   GHashTable *all_elements;
219
220   /* With GST_OBJECT_LOCK */
221   guint expected_async_done;
222   /* With GST_OBJECT_LOCK */
223   guint expected_commited;
224
225   /* For ges_timeline_commit_sync */
226   GMutex commited_lock;
227   GCond commited_cond;
228   gboolean commit_frozen;
229   gboolean commit_delayed;
230
231   GThread *valid_thread;
232   gboolean disposed;
233
234   GstStreamCollection *stream_collection;
235
236   gboolean rendering_smartly;
237 };
238
239 /* private structure to contain our track-related information */
240
241 typedef struct
242 {
243   GESTimeline *timeline;
244   GESTrack *track;
245   GstPad *pad;                  /* Pad from the track */
246   GstPad *ghostpad;
247   gulong track_element_added_sigid;
248
249   gulong probe_id;
250   GstStream *stream;
251 } TrackPrivate;
252
253 enum
254 {
255   PROP_0,
256   PROP_DURATION,
257   PROP_AUTO_TRANSITION,
258   PROP_SNAPPING_DISTANCE,
259   PROP_UPDATE,
260   PROP_LAST
261 };
262
263 static GParamSpec *properties[PROP_LAST];
264
265 enum
266 {
267   TRACK_ADDED,
268   TRACK_REMOVED,
269   LAYER_ADDED,
270   LAYER_REMOVED,
271   GROUP_ADDED,
272   GROUP_REMOVED,
273   SNAPING_STARTED,
274   SNAPING_ENDED,
275   SELECT_TRACKS_FOR_OBJECT,
276   COMMITED,
277   SELECT_ELEMENT_TRACK,
278   LAST_SIGNAL
279 };
280
281 G_DEFINE_TYPE_WITH_CODE (GESTimeline, ges_timeline, GST_TYPE_BIN,
282     G_ADD_PRIVATE (GESTimeline)
283     G_IMPLEMENT_INTERFACE (GES_TYPE_EXTRACTABLE, ges_extractable_interface_init)
284     G_IMPLEMENT_INTERFACE (GES_TYPE_META_CONTAINER,
285         ges_meta_container_interface_init));
286
287 static GstBinClass *parent_class;
288
289 static guint ges_timeline_signals[LAST_SIGNAL] = { 0 };
290
291 static gint custom_find_track (TrackPrivate * tr_priv, GESTrack * track);
292
293 static guint nb_assets = 0;
294
295 /* GESExtractable implementation */
296 static gchar *
297 extractable_check_id (GType type, const gchar * id)
298 {
299   gchar *res;
300
301   if (id == NULL)
302     res = g_strdup_printf ("%s-%i", "project", nb_assets);
303   else
304     res = g_strdup (id);
305
306   nb_assets++;
307
308   return res;
309 }
310
311 static gchar *
312 extractable_get_id (GESExtractable * self)
313 {
314   GESAsset *asset;
315
316   if (!(asset = ges_extractable_get_asset (self)))
317     return NULL;
318
319   return g_strdup (ges_asset_get_id (asset));
320 }
321
322 static void
323 ges_extractable_interface_init (GESExtractableInterface * iface)
324 {
325   iface->asset_type = GES_TYPE_PROJECT;
326   iface->check_id = (GESExtractableCheckId) extractable_check_id;
327   iface->get_id = extractable_get_id;
328 }
329
330 static void
331 ges_meta_container_interface_init (GESMetaContainerInterface * iface)
332 {
333 }
334
335 /* GObject Standard vmethods*/
336 static void
337 ges_timeline_get_property (GObject * object, guint property_id,
338     GValue * value, GParamSpec * pspec)
339 {
340   GESTimeline *timeline = GES_TIMELINE (object);
341
342   switch (property_id) {
343     case PROP_DURATION:
344       g_value_set_uint64 (value, timeline->priv->duration);
345       break;
346     case PROP_AUTO_TRANSITION:
347       g_value_set_boolean (value, timeline->priv->auto_transition);
348       break;
349     case PROP_SNAPPING_DISTANCE:
350       g_value_set_uint64 (value, timeline->priv->snapping_distance);
351       break;
352     default:
353       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
354   }
355 }
356
357 static void
358 ges_timeline_set_property (GObject * object, guint property_id,
359     const GValue * value, GParamSpec * pspec)
360 {
361   GESTimeline *timeline = GES_TIMELINE (object);
362
363   switch (property_id) {
364     case PROP_AUTO_TRANSITION:
365       ges_timeline_set_auto_transition (timeline, g_value_get_boolean (value));
366       break;
367     case PROP_SNAPPING_DISTANCE:
368       timeline->priv->snapping_distance = g_value_get_uint64 (value);
369       break;
370     default:
371       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
372   }
373 }
374
375 gboolean
376 ges_timeline_is_disposed (GESTimeline * timeline)
377 {
378   return timeline->priv->disposed;
379 }
380
381 static void
382 ges_timeline_dispose (GObject * object)
383 {
384   GESTimeline *tl = GES_TIMELINE (object);
385   GESTimelinePrivate *priv = tl->priv;
386   GList *tmp, *groups;
387
388   priv->disposed = TRUE;
389   while (tl->layers) {
390     GESLayer *layer = (GESLayer *) tl->layers->data;
391     ges_timeline_remove_layer (GES_TIMELINE (object), layer);
392   }
393
394   /* FIXME: it should be possible to remove tracks before removing
395    * layers, but at the moment this creates a problem because the track
396    * objects aren't notified that their nleobjects have been destroyed.
397    */
398
399   LOCK_DYN (tl);
400   while (tl->tracks)
401     ges_timeline_remove_track (GES_TIMELINE (object), tl->tracks->data);
402   UNLOCK_DYN (tl);
403
404   /* NOTE: the timeline should not contain empty groups */
405   groups = g_list_copy_deep (priv->groups, (GCopyFunc) gst_object_ref, NULL);
406   for (tmp = groups; tmp; tmp = tmp->next) {
407     GList *elems = ges_container_ungroup (tmp->data, FALSE);
408
409     g_list_free_full (elems, gst_object_unref);
410   }
411   g_list_free_full (groups, gst_object_unref);
412   g_list_free_full (priv->groups, gst_object_unref);
413
414   g_list_free_full (priv->auto_transitions, gst_object_unref);
415
416   g_hash_table_unref (priv->all_elements);
417   gst_object_unref (priv->stream_collection);
418
419   gst_clear_object (&priv->auto_transition_track);
420   gst_clear_object (&priv->new_track);
421   g_clear_error (&priv->track_selection_error);
422   priv->track_selection_error = NULL;
423
424   G_OBJECT_CLASS (ges_timeline_parent_class)->dispose (object);
425 }
426
427 static void
428 ges_timeline_finalize (GObject * object)
429 {
430   GESTimeline *tl = GES_TIMELINE (object);
431
432   g_rec_mutex_clear (&tl->priv->dyn_mutex);
433   g_node_destroy (tl->priv->tree);
434
435   G_OBJECT_CLASS (ges_timeline_parent_class)->finalize (object);
436 }
437
438 static void
439 ges_timeline_handle_message (GstBin * bin, GstMessage * message)
440 {
441   GESTimeline *timeline = GES_TIMELINE (bin);
442
443   if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ASYNC_START) {
444     GST_INFO_OBJECT (timeline, "Dropping %" GST_PTR_FORMAT, message);
445     return;
446   }
447
448   if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ASYNC_DONE) {
449     GST_INFO_OBJECT (timeline, "Dropping %" GST_PTR_FORMAT, message);
450
451     return;
452   }
453
454   if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ELEMENT) {
455     GstMessage *amessage = NULL;
456     const GstStructure *mstructure = gst_message_get_structure (message);
457
458     if (gst_structure_has_name (mstructure, "NleCompositionStartUpdate")) {
459       if (g_strcmp0 (gst_structure_get_string (mstructure, "reason"), "Seek")) {
460         GST_INFO_OBJECT (timeline,
461             "A composition is starting an update because of %s"
462             " not considering async", gst_structure_get_string (mstructure,
463                 "reason"));
464
465         goto forward;
466       }
467
468       GST_OBJECT_LOCK (timeline);
469       if (timeline->priv->expected_async_done == 0) {
470         amessage = gst_message_new_async_start (GST_OBJECT_CAST (bin));
471         LOCK_DYN (timeline);
472         timeline->priv->expected_async_done = g_list_length (timeline->tracks);
473         UNLOCK_DYN (timeline);
474         GST_INFO_OBJECT (timeline, "Posting ASYNC_START %s",
475             gst_structure_get_string (mstructure, "reason"));
476       }
477       GST_OBJECT_UNLOCK (timeline);
478
479     } else if (gst_structure_has_name (mstructure, "NleCompositionUpdateDone")) {
480       if (g_strcmp0 (gst_structure_get_string (mstructure, "reason"), "Seek")) {
481         GST_INFO_OBJECT (timeline,
482             "A composition is done updating because of %s"
483             " not considering async", gst_structure_get_string (mstructure,
484                 "reason"));
485
486         goto forward;
487       }
488
489       GST_OBJECT_LOCK (timeline);
490       timeline->priv->expected_async_done -= 1;
491       if (timeline->priv->expected_async_done == 0) {
492         amessage = gst_message_new_async_done (GST_OBJECT_CAST (bin),
493             GST_CLOCK_TIME_NONE);
494         GST_INFO_OBJECT (timeline, "Posting ASYNC_DONE %s",
495             gst_structure_get_string (mstructure, "reason"));
496       }
497       GST_OBJECT_UNLOCK (timeline);
498     }
499
500     if (amessage) {
501       gst_message_unref (message);
502       gst_element_post_message (GST_ELEMENT_CAST (bin), amessage);
503       return;
504     }
505   }
506
507 forward:
508   gst_element_post_message (GST_ELEMENT_CAST (bin), message);
509 }
510
511 static GstStateChangeReturn
512 ges_timeline_change_state (GstElement * element, GstStateChange transition)
513 {
514   GstStateChangeReturn res;
515   GESTimeline *timeline = GES_TIMELINE (element);
516
517   res = GST_ELEMENT_CLASS (ges_timeline_parent_class)->change_state (element,
518       transition);
519
520   if (transition == GST_STATE_CHANGE_READY_TO_PAUSED)
521     gst_element_post_message ((GstElement *) timeline,
522         gst_message_new_stream_collection ((GstObject *) timeline,
523             timeline->priv->stream_collection));
524   return res;
525 }
526
527 static gboolean
528 ges_timeline_send_event (GstElement * element, GstEvent * event)
529 {
530   GESTimeline *timeline = GES_TIMELINE (element);
531
532   if (GST_EVENT_TYPE (event) == GST_EVENT_SELECT_STREAMS) {
533     GList *stream_ids = NULL, *tmp, *to_remove =
534         ges_timeline_get_tracks (timeline);
535
536     gst_event_parse_select_streams (event, &stream_ids);
537     for (tmp = stream_ids; tmp; tmp = tmp->next) {
538       GList *trackit;
539       gchar *stream_id = tmp->data;
540
541       LOCK_DYN (timeline);
542       for (trackit = timeline->priv->priv_tracks; trackit;
543           trackit = trackit->next) {
544         TrackPrivate *tr_priv = trackit->data;
545
546         if (!g_strcmp0 (gst_stream_get_stream_id (tr_priv->stream), stream_id)) {
547           to_remove = g_list_remove (to_remove, tr_priv->track);
548         }
549       }
550       UNLOCK_DYN (timeline);
551     }
552     for (tmp = to_remove; tmp; tmp = tmp->next) {
553       GST_INFO_OBJECT (timeline, "Removed unselected track: %" GST_PTR_FORMAT,
554           tmp->data);
555       ges_timeline_remove_track (timeline, tmp->data);
556     }
557
558     g_list_free_full (stream_ids, g_free);
559     g_list_free (to_remove);
560
561     return TRUE;
562   }
563
564   return GST_ELEMENT_CLASS (ges_timeline_parent_class)->send_event (element,
565       event);
566 }
567
568 /* we collect the first result */
569 static gboolean
570 _gst_array_accumulator (GSignalInvocationHint * ihint,
571     GValue * return_accu, const GValue * handler_return, gpointer dummy)
572 {
573   gpointer array;
574
575   array = g_value_get_boxed (handler_return);
576   if (!(ihint->run_type & G_SIGNAL_RUN_CLEANUP))
577     g_value_set_boxed (return_accu, array);
578
579   return FALSE;
580 }
581
582 static void
583 ges_timeline_class_init (GESTimelineClass * klass)
584 {
585   GObjectClass *object_class = G_OBJECT_CLASS (klass);
586   GstElementClass *element_class = (GstElementClass *) klass;
587   GstBinClass *bin_class = GST_BIN_CLASS (klass);
588
589   GST_DEBUG_CATEGORY_INIT (ges_timeline_debug, "gestimeline",
590       GST_DEBUG_FG_YELLOW, "ges timeline");
591   timeline_tree_init_debug ();
592
593   parent_class = g_type_class_peek_parent (klass);
594
595   object_class->get_property = ges_timeline_get_property;
596   object_class->set_property = ges_timeline_set_property;
597   object_class->dispose = ges_timeline_dispose;
598   object_class->finalize = ges_timeline_finalize;
599
600   element_class->change_state = GST_DEBUG_FUNCPTR (ges_timeline_change_state);
601   element_class->send_event = GST_DEBUG_FUNCPTR (ges_timeline_send_event);
602
603   bin_class->handle_message = GST_DEBUG_FUNCPTR (ges_timeline_handle_message);
604
605   /**
606    * GESTimeline:duration:
607    *
608    * The current duration (in nanoseconds) of the timeline. A timeline
609    * 'starts' at time 0, so this is the maximum end time of all of its
610    * #GESTimelineElement-s.
611    */
612   properties[PROP_DURATION] =
613       g_param_spec_uint64 ("duration", "Duration",
614       "The duration of the timeline", 0, G_MAXUINT64,
615       GST_CLOCK_TIME_NONE, G_PARAM_READABLE);
616   g_object_class_install_property (object_class, PROP_DURATION,
617       properties[PROP_DURATION]);
618
619   /**
620    * GESTimeline:auto-transition:
621    *
622    * Whether to automatically create a transition whenever two
623    * #GESSource-s overlap in a track of the timeline. See
624    * #GESLayer:auto-transition if you want this to only happen in some
625    * layers.
626    */
627   g_object_class_install_property (object_class, PROP_AUTO_TRANSITION,
628       g_param_spec_boolean ("auto-transition", "Auto-Transition",
629           "whether the transitions are added", FALSE, G_PARAM_READWRITE));
630
631   /**
632    * GESTimeline:snapping-distance:
633    *
634    * The distance (in nanoseconds) at which a #GESTimelineElement being
635    * moved within the timeline should snap one of its #GESSource-s with
636    * another #GESSource-s edge. See #GESEditMode for which edges can
637    * snap during an edit. 0 means no snapping.
638    */
639   properties[PROP_SNAPPING_DISTANCE] =
640       g_param_spec_uint64 ("snapping-distance", "Snapping distance",
641       "Distance from which moving an object will snap with neighbours", 0,
642       G_MAXUINT64, 0, G_PARAM_READWRITE);
643   g_object_class_install_property (object_class, PROP_SNAPPING_DISTANCE,
644       properties[PROP_SNAPPING_DISTANCE]);
645
646   /**
647    * GESTimeline::track-added:
648    * @timeline: The #GESTimeline
649    * @track: The track that was added to @timeline
650    *
651    * Will be emitted after the track is added to the timeline.
652    *
653    * Note that this should not be emitted whilst a timeline is being
654    * loaded from its #GESProject asset. You should connect to the
655    * project's #GESProject::loaded signal if you want to know which
656    * tracks were created for the timeline.
657    */
658   ges_timeline_signals[TRACK_ADDED] =
659       g_signal_new ("track-added", G_TYPE_FROM_CLASS (klass),
660       G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GESTimelineClass, track_added), NULL,
661       NULL, NULL, G_TYPE_NONE, 1, GES_TYPE_TRACK);
662
663   /**
664    * GESTimeline::track-removed:
665    * @timeline: The #GESTimeline
666    * @track: The track that was removed from @timeline
667    *
668    * Will be emitted after the track is removed from the timeline.
669    */
670   ges_timeline_signals[TRACK_REMOVED] =
671       g_signal_new ("track-removed", G_TYPE_FROM_CLASS (klass),
672       G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GESTimelineClass, track_removed),
673       NULL, NULL, NULL, G_TYPE_NONE, 1, GES_TYPE_TRACK);
674
675   /**
676    * GESTimeline::layer-added:
677    * @timeline: The #GESTimeline
678    * @layer: The layer that was added to @timeline
679    *
680    * Will be emitted after the layer is added to the timeline.
681    *
682    * Note that this should not be emitted whilst a timeline is being
683    * loaded from its #GESProject asset. You should connect to the
684    * project's #GESProject::loaded signal if you want to know which
685    * layers were created for the timeline.
686    */
687   ges_timeline_signals[LAYER_ADDED] =
688       g_signal_new ("layer-added", G_TYPE_FROM_CLASS (klass),
689       G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GESTimelineClass, layer_added), NULL,
690       NULL, NULL, G_TYPE_NONE, 1, GES_TYPE_LAYER);
691
692   /**
693    * GESTimeline::layer-removed:
694    * @timeline: The #GESTimeline
695    * @layer: The layer that was removed from @timeline
696    *
697    * Will be emitted after the layer is removed from the timeline.
698    */
699   ges_timeline_signals[LAYER_REMOVED] =
700       g_signal_new ("layer-removed", G_TYPE_FROM_CLASS (klass),
701       G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GESTimelineClass, layer_removed),
702       NULL, NULL, NULL, G_TYPE_NONE, 1, GES_TYPE_LAYER);
703
704   /**
705    * GESTimeline::group-added
706    * @timeline: The #GESTimeline
707    * @group: The group that was added to @timeline
708    *
709    * Will be emitted after the group is added to to the timeline. This can
710    * happen when grouping with `ges_container_group`, or by adding
711    * containers to a newly created group.
712    *
713    * Note that this should not be emitted whilst a timeline is being
714    * loaded from its #GESProject asset. You should connect to the
715    * project's #GESProject::loaded signal if you want to know which groups
716    * were created for the timeline.
717    */
718   ges_timeline_signals[GROUP_ADDED] =
719       g_signal_new ("group-added", G_TYPE_FROM_CLASS (klass),
720       G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GESTimelineClass, group_added), NULL,
721       NULL, NULL, G_TYPE_NONE, 1, GES_TYPE_GROUP);
722
723   /**
724    * GESTimeline::group-removed
725    * @timeline: The #GESTimeline
726    * @group: The group that was removed from @timeline
727    * @children: (element-type GESContainer) (transfer none): A list
728    * of #GESContainer-s that _were_ the children of the removed @group
729    *
730    * Will be emitted after the group is removed from the timeline through
731    * `ges_container_ungroup`. Note that @group will no longer contain its
732    * former children, these are held in @children.
733    *
734    * Note that if a group is emptied, then it will no longer belong to the
735    * timeline, but this signal will **not** be emitted in such a case.
736    */
737   ges_timeline_signals[GROUP_REMOVED] =
738       g_signal_new ("group-removed", G_TYPE_FROM_CLASS (klass),
739       G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GESTimelineClass, group_removed),
740       NULL, NULL, NULL, G_TYPE_NONE, 2, GES_TYPE_GROUP, G_TYPE_PTR_ARRAY);
741
742   /**
743    * GESTimeline::snapping-started:
744    * @timeline: The #GESTimeline
745    * @obj1: The first element that is snapping
746    * @obj2: The second element that is snapping
747    * @position: The position where the two objects will snap to
748    *
749    * Will be emitted whenever an element's movement invokes a snapping
750    * event during an edit (usually of one of its ancestors) because its
751    * start or end point lies within the #GESTimeline:snapping-distance of
752    * another element's start or end point.
753    *
754    * See #GESEditMode to see what can snap during an edit.
755    *
756    * Note that only up to one snapping-started signal will be emitted per
757    * element edit within a timeline.
758    */
759   ges_timeline_signals[SNAPING_STARTED] =
760       g_signal_new ("snapping-started", G_TYPE_FROM_CLASS (klass),
761       G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
762       G_TYPE_NONE, 3, GES_TYPE_TRACK_ELEMENT, GES_TYPE_TRACK_ELEMENT,
763       G_TYPE_UINT64);
764
765   /**
766    * GESTimeline::snapping-ended:
767    * @timeline: The #GESTimeline
768    * @obj1: The first element that was snapping
769    * @obj2: The second element that was snapping
770    * @position: The position where the two objects were to be snapped to
771    *
772    * Will be emitted whenever a snapping event ends. After a snap event
773    * has started (see #GESTimeline::snapping-started), it can later end
774    * because either another timeline edit has occurred (which may or may
775    * not have created a new snapping event), or because the timeline has
776    * been committed.
777    */
778   ges_timeline_signals[SNAPING_ENDED] =
779       g_signal_new ("snapping-ended", G_TYPE_FROM_CLASS (klass),
780       G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
781       G_TYPE_NONE, 3, GES_TYPE_TRACK_ELEMENT, GES_TYPE_TRACK_ELEMENT,
782       G_TYPE_UINT64);
783
784   /**
785    * GESTimeline::select-tracks-for-object:
786    * @timeline: The #GESTimeline
787    * @clip: The clip that @track_element is being added to
788    * @track_element: The element being added
789    *
790    * This will be emitted whenever the timeline needs to determine which
791    * tracks a clip's children should be added to. The track element will
792    * be added to each of the tracks given in the return. If a track
793    * element is selected to go into multiple tracks, it will be copied
794    * into the additional tracks, under the same clip. Note that the copy
795    * will *not* keep its properties or state in sync with the original.
796    *
797    * Connect to this signal once if you wish to control which element
798    * should be added to which track. Doing so will overwrite the default
799    * behaviour, which adds @track_element to all tracks whose
800    * #GESTrack:track-type includes the @track_element's
801    * #GESTrackElement:track-type.
802    *
803    * Note that under the default track selection, if a clip would produce
804    * multiple core children of the same #GESTrackType, it will choose
805    * one of the core children arbitrarily to place in the corresponding
806    * tracks, with a warning for the other core children that are not
807    * placed in the track. For example, this would happen for a #GESUriClip
808    * that points to a file that contains multiple audio streams. If you
809    * wish to choose the stream, you could connect to this signal, and use,
810    * say, ges_uri_source_asset_get_stream_info() to choose which core
811    * source to add.
812    *
813    * When a clip is first added to a timeline, its core elements will
814    * be created for the current tracks in the timeline if they have not
815    * already been created. Then this will be emitted for each of these
816    * core children to select which tracks, if any, they should be added
817    * to. It will then be called for any non-core children in the clip.
818    *
819    * In addition, if a new track element is ever added to a clip in a
820    * timeline (and it is not already part of a track) this will be emitted
821    * to select which tracks the element should be added to.
822    *
823    * Finally, as a special case, if a track is added to the timeline
824    * *after* it already contains clips, then it will request the creation
825    * of the clips' core elements of the corresponding type, if they have
826    * not already been created, and this signal will be emitted for each of
827    * these newly created elements. In addition, this will also be released
828    * for all other track elements in the timeline's clips that have not
829    * yet been assigned a track. However, in this final case, the timeline
830    * will only check whether the newly added track appears in the track
831    * list. If it does appear, the track element will be added to the newly
832    * added track. All other tracks in the returned track list are ignored.
833    *
834    * In this latter case, track elements that are already part of a track
835    * will not be asked if they want to be copied into the new track. If
836    * you wish to do this, you can use ges_clip_add_child_to_track().
837    *
838    * Note that the returned #GPtrArray should own a new reference to each
839    * of its contained #GESTrack. The timeline will set the #GDestroyNotify
840    * free function on the #GPtrArray to dereference the elements.
841    *
842    * Returns: (transfer full) (element-type GESTrack): An array of
843    * #GESTrack-s that @track_element should be added to, or %NULL to
844    * not add the element to any track.
845    */
846   ges_timeline_signals[SELECT_TRACKS_FOR_OBJECT] =
847       g_signal_new ("select-tracks-for-object", G_TYPE_FROM_CLASS (klass),
848       G_SIGNAL_RUN_LAST, 0, _gst_array_accumulator, NULL, NULL,
849       G_TYPE_PTR_ARRAY, 2, GES_TYPE_CLIP, GES_TYPE_TRACK_ELEMENT);
850
851   /**
852    * GESTimeline::select-element-track:
853    * @timeline: The #GESTimeline
854    * @clip: The clip that @track_element is being added to
855    * @track_element: The element being added
856    *
857    * Simplified version of #GESTimeline::select-tracks-for-object which only
858    * allows @track_element to be added to a single #GESTrack.
859    *
860    * Returns: (transfer full): A track to put @track_element into, or %NULL if
861    * it should be discarded.
862    *
863    * Since: 1.18
864    */
865   ges_timeline_signals[SELECT_ELEMENT_TRACK] =
866       g_signal_new ("select-element-track", G_TYPE_FROM_CLASS (klass),
867       G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
868       GES_TYPE_TRACK, 2, GES_TYPE_CLIP, GES_TYPE_TRACK_ELEMENT);
869
870   /**
871    * GESTimeline::commited:
872    * @timeline: The #GESTimeline
873    *
874    * This signal will be emitted once the changes initiated by
875    * ges_timeline_commit() have been executed in the backend. Use
876    * ges_timeline_commit_sync() if you do not want to have to connect
877    * to this signal.
878    */
879   ges_timeline_signals[COMMITED] =
880       g_signal_new ("commited", G_TYPE_FROM_CLASS (klass),
881       G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
882 }
883
884 static void
885 ges_timeline_init (GESTimeline * self)
886 {
887   GESTimelinePrivate *priv = self->priv;
888
889   self->priv = ges_timeline_get_instance_private (self);
890   self->priv->tree = g_node_new (self);
891
892   priv = self->priv;
893   self->layers = NULL;
894   self->tracks = NULL;
895   self->priv->duration = 0;
896   self->priv->auto_transition = FALSE;
897   priv->snapping_distance = 0;
898   priv->expected_async_done = 0;
899   priv->expected_commited = 0;
900
901   self->priv->last_snap_ts = GST_CLOCK_TIME_NONE;
902
903   priv->priv_tracks = NULL;
904
905   priv->all_elements =
906       g_hash_table_new_full (g_str_hash, g_str_equal, g_free, gst_object_unref);
907
908   priv->stream_start_group_id = -1;
909   priv->stream_collection = gst_stream_collection_new (NULL);
910
911   g_signal_connect_after (self, "select-tracks-for-object",
912       G_CALLBACK (select_tracks_for_object_default), NULL);
913
914   g_rec_mutex_init (&priv->dyn_mutex);
915   g_mutex_init (&priv->commited_lock);
916   priv->valid_thread = g_thread_self ();
917 }
918
919 /* Private methods */
920
921 /* Sorting utils*/
922 static gint
923 sort_layers (gpointer a, gpointer b)
924 {
925   GESLayer *layer_a, *layer_b;
926   guint prio_a, prio_b;
927
928   layer_a = GES_LAYER (a);
929   layer_b = GES_LAYER (b);
930
931   prio_a = ges_layer_get_priority (layer_a);
932   prio_b = ges_layer_get_priority (layer_b);
933
934   if (prio_a > prio_b)
935     return 1;
936   if (prio_a < prio_b)
937     return -1;
938
939   return 0;
940 }
941
942 static void
943 _resync_layers (GESTimeline * timeline)
944 {
945   GList *tmp;
946   gint i = 0;
947
948   timeline->priv->resyncing_layers = TRUE;
949   for (tmp = timeline->layers; tmp; tmp = tmp->next) {
950     layer_set_priority (tmp->data, i, TRUE);
951     i++;
952   }
953   timeline->priv->resyncing_layers = FALSE;
954 }
955
956 void
957 timeline_update_duration (GESTimeline * timeline)
958 {
959   GstClockTime duration = timeline_tree_get_duration (timeline->priv->tree);
960
961   if (timeline->priv->duration != duration) {
962     GST_DEBUG ("track duration : %" GST_TIME_FORMAT " current : %"
963         GST_TIME_FORMAT, GST_TIME_ARGS (duration),
964         GST_TIME_ARGS (timeline->priv->duration));
965
966     timeline->priv->duration = duration;
967
968     g_object_notify_by_pspec (G_OBJECT (timeline), properties[PROP_DURATION]);
969   }
970 }
971
972 static gint
973 custom_find_track (TrackPrivate * tr_priv, GESTrack * track)
974 {
975   if (tr_priv->track == track)
976     return 0;
977   return -1;
978 }
979
980 static void
981 _destroy_auto_transition_cb (GESAutoTransition * auto_transition,
982     GESTimeline * timeline)
983 {
984   GESTimelinePrivate *priv = timeline->priv;
985   GESClip *transition = auto_transition->transition_clip;
986   GESLayer *layer = ges_clip_get_layer (transition);
987
988   ges_layer_remove_clip (layer, transition);
989   g_signal_handlers_disconnect_by_func (auto_transition,
990       _destroy_auto_transition_cb, timeline);
991
992   priv->auto_transitions =
993       g_list_remove (priv->auto_transitions, auto_transition);
994   gst_object_unref (auto_transition);
995 }
996
997 GESAutoTransition *
998 ges_timeline_create_transition (GESTimeline * timeline,
999     GESTrackElement * previous, GESTrackElement * next, GESClip * transition,
1000     GESLayer * layer, guint64 start, guint64 duration)
1001 {
1002   GESAutoTransition *auto_transition;
1003   GESTrackElement *child;
1004   /* track should not be NULL */
1005   GESTrack *track = ges_track_element_get_track (next);
1006
1007   if (transition == NULL) {
1008     GESAsset *asset;
1009
1010     LOCK_DYN (timeline);
1011     timeline->priv->auto_transition_track = gst_object_ref (track);
1012     UNLOCK_DYN (timeline);
1013
1014     asset = ges_asset_request (GES_TYPE_TRANSITION_CLIP, "crossfade", NULL);
1015     transition = ges_layer_add_asset (layer, asset, start, 0, duration,
1016         ges_track_element_get_track_type (next));
1017     gst_object_unref (asset);
1018
1019     LOCK_DYN (timeline);
1020     /* should have been set to NULL, but clear just in case */
1021     gst_clear_object (&timeline->priv->auto_transition_track);
1022     UNLOCK_DYN (timeline);
1023   } else {
1024     GST_DEBUG_OBJECT (timeline,
1025         "Reusing already existing transition: %" GST_PTR_FORMAT, transition);
1026   }
1027
1028   g_return_val_if_fail (transition, NULL);
1029   g_return_val_if_fail (g_list_length (GES_CONTAINER_CHILDREN (transition)) ==
1030       1, NULL);
1031   child = GES_CONTAINER_CHILDREN (transition)->data;
1032   if (ges_track_element_get_track (child) != track) {
1033     GST_ERROR_OBJECT (timeline, "The auto transition element %"
1034         GES_FORMAT " for elements %" GES_FORMAT " and %" GES_FORMAT
1035         " is not in the same track %" GST_PTR_FORMAT,
1036         GES_ARGS (child), GES_ARGS (previous), GES_ARGS (next), track);
1037     return NULL;
1038   }
1039
1040   /* We know there is only 1 TrackElement */
1041   auto_transition = ges_auto_transition_new (child, previous, next);
1042
1043   g_signal_connect (auto_transition, "destroy-me",
1044       G_CALLBACK (_destroy_auto_transition_cb), timeline);
1045
1046   timeline->priv->auto_transitions =
1047       g_list_prepend (timeline->priv->auto_transitions, auto_transition);
1048
1049   return auto_transition;
1050 }
1051
1052 GESAutoTransition *
1053 ges_timeline_find_auto_transition (GESTimeline * timeline,
1054     GESTrackElement * prev, GESTrackElement * next,
1055     GstClockTime transition_duration)
1056 {
1057   GList *tmp;
1058
1059   for (tmp = timeline->priv->auto_transitions; tmp; tmp = tmp->next) {
1060     GESAutoTransition *auto_trans = (GESAutoTransition *) tmp->data;
1061
1062     /* We already have a transition linked to one of the elements we want to
1063      * find a transition for */
1064     if (auto_trans->previous_source == prev || auto_trans->next_source == next) {
1065       if (auto_trans->previous_source != prev
1066           || auto_trans->next_source != next) {
1067         GST_ERROR_OBJECT (timeline, "Failed creating auto transition, "
1068             " trying to have 3 clips overlapping, rolling back");
1069       }
1070
1071       return auto_trans;
1072     }
1073   }
1074
1075   return NULL;
1076 }
1077
1078 GESAutoTransition *
1079 ges_timeline_get_auto_transition_at_edge (GESTimeline * timeline,
1080     GESTrackElement * source, GESEdge edge)
1081 {
1082   GList *tmp, *auto_transitions;
1083   GESAutoTransition *ret = NULL;
1084
1085   LOCK_DYN (timeline);
1086   auto_transitions = g_list_copy_deep (timeline->priv->auto_transitions,
1087       (GCopyFunc) gst_object_ref, NULL);
1088   UNLOCK_DYN (timeline);
1089
1090   for (tmp = auto_transitions; tmp; tmp = tmp->next) {
1091     GESAutoTransition *auto_trans = (GESAutoTransition *) tmp->data;
1092
1093     /* We already have a transition linked to one of the elements we want to
1094      * find a transition for */
1095     if (edge == GES_EDGE_END && auto_trans->previous_source == source) {
1096       ret = gst_object_ref (auto_trans);
1097       break;
1098     } else if (edge == GES_EDGE_START && auto_trans->next_source == source) {
1099       ret = gst_object_ref (auto_trans);
1100       break;
1101     }
1102   }
1103
1104   g_list_free_full (auto_transitions, gst_object_unref);
1105
1106   return ret;
1107 }
1108
1109 static GESAutoTransition *
1110 _create_auto_transition_from_transitions (GESTimeline * timeline,
1111     GESTrackElement * prev, GESTrackElement * next,
1112     GstClockTime transition_duration)
1113 {
1114   GList *tmp, *elements;
1115   GESLayer *layer;
1116   guint32 layer_prio = GES_TIMELINE_ELEMENT_LAYER_PRIORITY (prev);
1117   GESTrack *track;
1118   GESAutoTransition *auto_transition =
1119       ges_timeline_find_auto_transition (timeline, prev, next,
1120       transition_duration);
1121
1122   if (auto_transition)
1123     return auto_transition;
1124
1125   layer = ges_timeline_get_layer (timeline, layer_prio);
1126   track = ges_track_element_get_track (prev);
1127   elements = ges_track_get_elements (track);
1128   for (tmp = elements; tmp; tmp = tmp->next) {
1129     GESTrackElement *maybe_transition = tmp->data;
1130
1131     if (ges_timeline_element_get_layer_priority (tmp->data) != layer_prio)
1132       continue;
1133
1134     if (_START (maybe_transition) > _START (next))
1135       break;
1136     else if (_START (maybe_transition) != _START (next) ||
1137         _DURATION (maybe_transition) != transition_duration)
1138       continue;
1139     else if (GES_IS_TRANSITION (maybe_transition)) {
1140       /* Use that transition */
1141       /* TODO We should make sure that the transition contains only
1142        * TrackElement-s in @track and if it is not the case properly unlink the
1143        * object to use it */
1144       auto_transition = ges_timeline_create_transition (timeline, prev, next,
1145           GES_CLIP (GES_TIMELINE_ELEMENT_PARENT (maybe_transition)), layer,
1146           _START (next), transition_duration);
1147
1148       break;
1149     }
1150   }
1151   gst_object_unref (layer);
1152   g_list_free_full (elements, gst_object_unref);
1153
1154   return auto_transition;
1155 }
1156
1157 void
1158 ges_timeline_emit_snapping (GESTimeline * timeline, GESTrackElement * elem1,
1159     GESTrackElement * elem2, GstClockTime snap_time)
1160 {
1161   GESTimelinePrivate *priv = timeline->priv;
1162   GstClockTime last_snap_ts = timeline->priv->last_snap_ts;
1163
1164   if (!GST_CLOCK_TIME_IS_VALID (snap_time)) {
1165     if (priv->last_snaped1 != NULL && priv->last_snaped2 != NULL) {
1166       g_signal_emit (timeline, ges_timeline_signals[SNAPING_ENDED], 0,
1167           priv->last_snaped1, priv->last_snaped2, last_snap_ts);
1168       priv->last_snaped1 = NULL;
1169       priv->last_snaped2 = NULL;
1170       priv->last_snap_ts = GST_CLOCK_TIME_NONE;
1171     }
1172
1173     return;
1174   }
1175
1176   g_assert (elem1 != elem2);
1177
1178   if (GST_CLOCK_TIME_IS_VALID (last_snap_ts))
1179     g_signal_emit (timeline, ges_timeline_signals[SNAPING_ENDED], 0,
1180         priv->last_snaped1, priv->last_snaped2, (last_snap_ts));
1181
1182   priv->last_snaped1 = elem1;
1183   priv->last_snaped2 = elem2;
1184   timeline->priv->last_snap_ts = snap_time;
1185   g_signal_emit (timeline, ges_timeline_signals[SNAPING_STARTED], 0,
1186       elem1, elem2, snap_time);
1187 }
1188
1189 /* Accept @self == NULL, making it use default framerate */
1190 void
1191 timeline_get_framerate (GESTimeline * self, gint * fps_n, gint * fps_d)
1192 {
1193   GList *tmp;
1194
1195   *fps_n = *fps_d = -1;
1196   if (!self)
1197     goto done;
1198
1199   LOCK_DYN (self);
1200   for (tmp = self->tracks; tmp; tmp = tmp->next) {
1201     if (GES_IS_VIDEO_TRACK (tmp->data)) {
1202       GstCaps *restriction = ges_track_get_restriction_caps (tmp->data);
1203       gint i;
1204
1205       if (!restriction)
1206         continue;
1207
1208       for (i = 0; i < gst_caps_get_size (restriction); i++) {
1209         gint n, d;
1210
1211         if (!gst_structure_get_fraction (gst_caps_get_structure (restriction,
1212                     i), "framerate", &n, &d))
1213           continue;
1214
1215         if (*fps_n != -1 && *fps_d != -1 && !(n == *fps_n && d == *fps_d)) {
1216           GST_WARNING_OBJECT (self,
1217               "Various framerates specified, this is not supported"
1218               " First one will be used.");
1219           continue;
1220         }
1221
1222         *fps_n = n;
1223         *fps_d = d;
1224       }
1225       gst_caps_unref (restriction);
1226     }
1227   }
1228   UNLOCK_DYN (self);
1229
1230 done:
1231   if (*fps_n == -1 && *fps_d == -1) {
1232     GST_INFO_OBJECT (self,
1233         "No framerate found, using default " G_STRINGIFY (FRAMERATE_N) "/ "
1234         G_STRINGIFY (FRAMERATE_D));
1235     *fps_n = DEFAULT_FRAMERATE_N;
1236     *fps_d = DEFAULT_FRAMERATE_D;
1237   }
1238 }
1239
1240 void
1241 ges_timeline_freeze_auto_transitions (GESTimeline * timeline, gboolean freeze)
1242 {
1243   GList *tmp, *trans = g_list_copy (timeline->priv->auto_transitions);
1244   for (tmp = trans; tmp; tmp = tmp->next) {
1245     GESAutoTransition *auto_transition = tmp->data;
1246     auto_transition->frozen = freeze;
1247     if (freeze == FALSE) {
1248       GST_LOG_OBJECT (timeline, "Un-Freezing %" GES_FORMAT,
1249           GES_ARGS (auto_transition->transition_clip));
1250       ges_auto_transition_update (auto_transition);
1251     } else {
1252       GST_LOG_OBJECT (timeline, "Freezing %" GES_FORMAT,
1253           GES_ARGS (auto_transition->transition_clip));
1254     }
1255   }
1256   g_list_free (trans);
1257 }
1258
1259 static gint
1260 _edit_auto_transition (GESTimeline * timeline, GESTimelineElement * element,
1261     gint64 new_layer_priority, GESEditMode mode, GESEdge edge,
1262     GstClockTime position, GError ** error)
1263 {
1264   GList *tmp;
1265   guint32 layer_prio = ges_timeline_element_get_layer_priority (element);
1266   GESLayer *layer = ges_timeline_get_layer (timeline, layer_prio);
1267
1268   if (!ges_layer_get_auto_transition (layer)) {
1269     gst_object_unref (layer);
1270     return -1;
1271   }
1272
1273   gst_object_unref (layer);
1274   for (tmp = timeline->priv->auto_transitions; tmp; tmp = tmp->next) {
1275     GESTimelineElement *replace;
1276     GESAutoTransition *auto_transition = tmp->data;
1277
1278     if (GES_TIMELINE_ELEMENT (auto_transition->transition) == element ||
1279         GES_TIMELINE_ELEMENT (auto_transition->transition_clip) == element) {
1280       if (auto_transition->positioning) {
1281         GST_ERROR_OBJECT (element, "Trying to edit an auto-transition "
1282             "whilst it is being positioned");
1283         return FALSE;
1284       }
1285       if (new_layer_priority != layer_prio) {
1286         GST_WARNING_OBJECT (element, "Cannot edit an auto-transition to a "
1287             "new layer");
1288         return FALSE;
1289       }
1290       if (mode != GES_EDIT_MODE_TRIM) {
1291         GST_WARNING_OBJECT (element, "Cannot edit an auto-transition "
1292             "under the edit mode %i", mode);
1293         return FALSE;
1294       }
1295
1296       if (edge == GES_EDGE_END)
1297         replace = GES_TIMELINE_ELEMENT (auto_transition->previous_source);
1298       else
1299         replace = GES_TIMELINE_ELEMENT (auto_transition->next_source);
1300
1301       GST_INFO_OBJECT (element, "Trimming %" GES_FORMAT " in place  of "
1302           "trimming the corresponding auto-transition", GES_ARGS (replace));
1303       return ges_timeline_element_edit_full (replace, -1, mode, edge,
1304           position, error);
1305     }
1306   }
1307
1308   return -1;
1309 }
1310
1311 gboolean
1312 ges_timeline_edit (GESTimeline * timeline, GESTimelineElement * element,
1313     gint64 new_layer_priority, GESEditMode mode, GESEdge edge,
1314     guint64 position, GError ** error)
1315 {
1316   GstClockTimeDiff edge_diff = (edge == GES_EDGE_END ?
1317       GST_CLOCK_DIFF (position, element->start + element->duration) :
1318       GST_CLOCK_DIFF (position, element->start));
1319   gint64 prio_diff = (gint64) ges_timeline_element_get_layer_priority (element)
1320       - new_layer_priority;
1321   gint res = -1;
1322
1323   if ((GES_IS_TRANSITION (element) || GES_IS_TRANSITION_CLIP (element)))
1324     res = _edit_auto_transition (timeline, element, new_layer_priority, mode,
1325         edge, position, error);
1326
1327   if (res != -1)
1328     return res;
1329
1330   switch (mode) {
1331     case GES_EDIT_MODE_RIPPLE:
1332       return timeline_tree_ripple (timeline->priv->tree, element, prio_diff,
1333           edge_diff, edge, timeline->priv->snapping_distance, error);
1334     case GES_EDIT_MODE_TRIM:
1335       return timeline_tree_trim (timeline->priv->tree, element, prio_diff,
1336           edge_diff, edge, timeline->priv->snapping_distance, error);
1337     case GES_EDIT_MODE_NORMAL:
1338       return timeline_tree_move (timeline->priv->tree, element, prio_diff,
1339           edge_diff, edge, timeline->priv->snapping_distance, error);
1340     case GES_EDIT_MODE_ROLL:
1341       if (prio_diff != 0) {
1342         GST_WARNING_OBJECT (element, "Cannot roll an element to a new layer");
1343         return FALSE;
1344       }
1345       return timeline_tree_roll (timeline->priv->tree, element,
1346           edge_diff, edge, timeline->priv->snapping_distance, error);
1347     case GES_EDIT_MODE_SLIDE:
1348       GST_ERROR_OBJECT (element, "Sliding not implemented.");
1349       return FALSE;
1350   }
1351   return FALSE;
1352 }
1353
1354 void
1355 timeline_add_group (GESTimeline * timeline, GESGroup * group)
1356 {
1357   GST_DEBUG_OBJECT (timeline, "Adding group %" GST_PTR_FORMAT, group);
1358
1359   timeline->priv->groups = g_list_prepend (timeline->priv->groups,
1360       gst_object_ref_sink (group));
1361
1362   ges_timeline_element_set_timeline (GES_TIMELINE_ELEMENT (group), timeline);
1363 }
1364
1365 /**
1366  * timeline_emit_group_added:
1367  * @timeline: The #GESTimeline
1368  * @group: group that was added
1369  *
1370  * Emit group-added signal.
1371  */
1372 void
1373 timeline_emit_group_added (GESTimeline * timeline, GESGroup * group)
1374 {
1375   g_signal_emit (timeline, ges_timeline_signals[GROUP_ADDED], 0, group);
1376 }
1377
1378 /**
1379  * timeline_emit_group_removed:
1380  * @timeline: The #GESTimeline
1381  * @group: group that was removed
1382  *
1383  * Emit group-removed signal.
1384  */
1385 void
1386 timeline_emit_group_removed (GESTimeline * timeline, GESGroup * group,
1387     GPtrArray * array)
1388 {
1389   g_signal_emit (timeline, ges_timeline_signals[GROUP_REMOVED], 0, group,
1390       array);
1391 }
1392
1393 void
1394 timeline_remove_group (GESTimeline * timeline, GESGroup * group)
1395 {
1396   GST_DEBUG_OBJECT (timeline, "Removing group %" GST_PTR_FORMAT, group);
1397
1398   timeline->priv->groups = g_list_remove (timeline->priv->groups, group);
1399
1400   ges_timeline_element_set_timeline (GES_TIMELINE_ELEMENT (group), NULL);
1401   gst_object_unref (group);
1402 }
1403
1404 static GESTrackElement *
1405 _core_in_track (GESTrack * track, GESClip * clip)
1406 {
1407   GList *tmp;
1408   for (tmp = GES_CONTAINER_CHILDREN (clip); tmp; tmp = tmp->next) {
1409     GESTrackElement *el = tmp->data;
1410     if (ges_track_element_is_core (el)
1411         && ges_track_element_get_track (el) == track) {
1412       return tmp->data;
1413     }
1414   }
1415   return NULL;
1416 }
1417
1418 static GPtrArray *
1419 select_tracks_for_object_default (GESTimeline * timeline,
1420     GESClip * clip, GESTrackElement * tr_object, gpointer user_data)
1421 {
1422   GPtrArray *result;
1423   GList *tmp;
1424   GESTrackElement *core;
1425
1426   result = g_ptr_array_new ();
1427
1428   LOCK_DYN (timeline);
1429   for (tmp = timeline->tracks; tmp; tmp = tmp->next) {
1430     GESTrack *track = GES_TRACK (tmp->data);
1431
1432     if ((track->type & ges_track_element_get_track_type (tr_object))) {
1433       if (ges_track_element_is_core (tr_object)) {
1434         core = _core_in_track (track, clip);
1435         if (core) {
1436           GST_WARNING_OBJECT (timeline, "The clip '%s' contains multiple "
1437               "core elements of the same %s track type. The core child "
1438               "'%s' has already been chosen arbitrarily for the track %"
1439               GST_PTR_FORMAT ", which means that the other core child "
1440               "'%s' of the same type can not be added to the track. "
1441               "Consider connecting to "
1442               "GESTimeline::select-tracks-for-objects to be able to "
1443               "specify which core element should land in the track",
1444               GES_TIMELINE_ELEMENT_NAME (clip),
1445               ges_track_type_name (track->type),
1446               GES_TIMELINE_ELEMENT_NAME (core), track,
1447               GES_TIMELINE_ELEMENT_NAME (tr_object));
1448           continue;
1449         }
1450       }
1451       gst_object_ref (track);
1452       g_ptr_array_add (result, track);
1453     }
1454   }
1455   UNLOCK_DYN (timeline);
1456
1457   return result;
1458 }
1459
1460 static GPtrArray *
1461 _get_selected_tracks (GESTimeline * timeline, GESClip * clip,
1462     GESTrackElement * track_element)
1463 {
1464   guint i, j;
1465   GPtrArray *tracks = NULL;
1466   GESTrack *track = NULL;
1467
1468   g_signal_emit (G_OBJECT (timeline),
1469       ges_timeline_signals[SELECT_ELEMENT_TRACK], 0, clip, track_element,
1470       &track);
1471
1472   if (track) {
1473     tracks = g_ptr_array_new ();
1474
1475     g_ptr_array_add (tracks, track);
1476   } else {
1477     g_signal_emit (G_OBJECT (timeline),
1478         ges_timeline_signals[SELECT_TRACKS_FOR_OBJECT], 0, clip, track_element,
1479         &tracks);
1480   }
1481
1482   if (tracks == NULL)
1483     tracks = g_ptr_array_new ();
1484
1485   g_ptr_array_set_free_func (tracks, gst_object_unref);
1486
1487   /* make sure unique */
1488   for (i = 0; i < tracks->len;) {
1489     GESTrack *track = GES_TRACK (g_ptr_array_index (tracks, i));
1490
1491     for (j = i + 1; j < tracks->len;) {
1492       if (track == g_ptr_array_index (tracks, j)) {
1493         GST_WARNING_OBJECT (timeline, "Found the track %" GST_PTR_FORMAT
1494             " more than once in the return for select-tracks-for-object "
1495             "signal for track element %" GES_FORMAT " in clip %"
1496             GES_FORMAT ". Ignoring the extra track", track,
1497             GES_ARGS (track_element), GES_ARGS (clip));
1498         g_ptr_array_remove_index (tracks, j);
1499         /* don't increase index since the next track is in its place */
1500         continue;
1501       }
1502       j++;
1503     }
1504
1505     if (ges_track_get_timeline (track) != timeline) {
1506       GST_WARNING_OBJECT (timeline, "The track %" GST_PTR_FORMAT
1507           " found in the return for select-tracks-for-object belongs "
1508           "to a different timeline %" GST_PTR_FORMAT ". Ignoring this "
1509           "track", track, ges_track_get_timeline (track));
1510       g_ptr_array_remove_index (tracks, i);
1511       /* don't increase index since the next track is in its place */
1512       continue;
1513     }
1514     i++;
1515   }
1516
1517   return tracks;
1518 }
1519
1520 /* returns TRUE if track element was successfully added to all the
1521  * selected tracks */
1522 static gboolean
1523 _add_track_element_to_tracks (GESTimeline * timeline, GESClip * clip,
1524     GESTrackElement * track_element, GError ** error)
1525 {
1526   guint i;
1527   gboolean ret = TRUE;
1528   GPtrArray *tracks = _get_selected_tracks (timeline, clip, track_element);
1529
1530   for (i = 0; i < tracks->len; i++) {
1531     GESTrack *track = GES_TRACK (g_ptr_array_index (tracks, i));
1532     if (!ges_clip_add_child_to_track (clip, track_element, track, error)) {
1533       ret = FALSE;
1534       if (error)
1535         break;
1536     }
1537   }
1538
1539   g_ptr_array_unref (tracks);
1540
1541   return ret;
1542 }
1543
1544 static gboolean
1545 _try_add_track_element_to_track (GESTimeline * timeline, GESClip * clip,
1546     GESTrackElement * track_element, GESTrack * track, GError ** error)
1547 {
1548   gboolean no_error = TRUE;
1549   GPtrArray *tracks = _get_selected_tracks (timeline, clip, track_element);
1550
1551   /* if we are trying to add the element to a newly added track, then
1552    * we only check whether the track list contains the newly added track,
1553    * if it does we add the track element to the track, or add a copy if
1554    * the track element is already in a track */
1555   if (g_ptr_array_find (tracks, track, NULL)) {
1556     if (!ges_clip_add_child_to_track (clip, track_element, track, error))
1557       no_error = FALSE;
1558   }
1559
1560   g_ptr_array_unref (tracks);
1561   return no_error;
1562 }
1563
1564 /* accepts NULL */
1565 void
1566 ges_timeline_set_moving_track_elements (GESTimeline * timeline, gboolean moving)
1567 {
1568   if (timeline) {
1569     LOCK_DYN (timeline);
1570     timeline->priv->track_elements_moving = moving;
1571     UNLOCK_DYN (timeline);
1572   }
1573 }
1574
1575 void
1576 ges_timeline_set_track_selection_error (GESTimeline * timeline,
1577     gboolean was_error, GError * error)
1578 {
1579   GESTimelinePrivate *priv;
1580
1581   LOCK_DYN (timeline);
1582
1583   priv = timeline->priv;
1584   g_clear_error (&priv->track_selection_error);
1585   priv->track_selection_error = error;
1586   priv->has_any_track_selection_error = was_error;
1587
1588   UNLOCK_DYN (timeline);
1589 }
1590
1591 gboolean
1592 ges_timeline_take_track_selection_error (GESTimeline * timeline,
1593     GError ** error)
1594 {
1595   gboolean ret;
1596   GESTimelinePrivate *priv;
1597
1598   LOCK_DYN (timeline);
1599
1600   priv = timeline->priv;
1601   if (error) {
1602     if (*error) {
1603       GST_ERROR_OBJECT (timeline, "Error not handled %s", (*error)->message);
1604       g_error_free (*error);
1605     }
1606     *error = priv->track_selection_error;
1607   } else if (priv->track_selection_error) {
1608     GST_WARNING_OBJECT (timeline, "Got track selection error: %s",
1609         priv->track_selection_error->message);
1610     g_error_free (priv->track_selection_error);
1611   }
1612   priv->track_selection_error = NULL;
1613   ret = priv->has_any_track_selection_error;
1614   priv->has_any_track_selection_error = FALSE;
1615
1616   UNLOCK_DYN (timeline);
1617
1618   return ret;
1619 }
1620
1621 static void
1622 clip_track_element_added_cb (GESClip * clip,
1623     GESTrackElement * track_element, GESTimeline * timeline)
1624 {
1625   GESTrack *auto_trans_track, *new_track;
1626   GError *error = NULL;
1627   gboolean success = FALSE;
1628
1629   if (timeline->priv->track_elements_moving) {
1630     GST_DEBUG_OBJECT (timeline, "Ignoring element added: %" GES_FORMAT
1631         " in %" GES_FORMAT, GES_ARGS (track_element), GES_ARGS (clip));
1632     return;
1633   }
1634
1635   if (ges_track_element_get_track (track_element) != NULL) {
1636     GST_DEBUG_OBJECT (timeline, "Not selecting tracks for %" GES_FORMAT
1637         " in %" GES_FORMAT " because it already part of the track %"
1638         GST_PTR_FORMAT, GES_ARGS (track_element), GES_ARGS (clip),
1639         ges_track_element_get_track (track_element));
1640     return;
1641   }
1642
1643   LOCK_DYN (timeline);
1644   /* take ownership of auto_transition_track. For auto-transitions, this
1645    * should be used exactly once! */
1646   auto_trans_track = timeline->priv->auto_transition_track;
1647   timeline->priv->auto_transition_track = NULL;
1648   /* don't take ownership of new_track */
1649   new_track = timeline->priv->new_track;
1650   UNLOCK_DYN (timeline);
1651
1652   if (auto_trans_track) {
1653     /* don't use track-selection */
1654     success = ! !ges_clip_add_child_to_track (clip, track_element,
1655         auto_trans_track, &error);
1656     gst_object_unref (auto_trans_track);
1657   } else {
1658     if (new_track)
1659       success = _try_add_track_element_to_track (timeline, clip, track_element,
1660           new_track, &error);
1661     else
1662       success = _add_track_element_to_tracks (timeline, clip, track_element,
1663           &error);
1664   }
1665
1666   if (error || !success) {
1667     if (!error)
1668       GST_WARNING_OBJECT (timeline, "Track selection failed for %" GES_FORMAT,
1669           GES_ARGS (track_element));
1670     ges_timeline_set_track_selection_error (timeline, TRUE, error);
1671   }
1672 }
1673
1674 static void
1675 clip_track_element_removed_cb (GESClip * clip,
1676     GESTrackElement * track_element, GESTimeline * timeline)
1677 {
1678   GESTrack *track = ges_track_element_get_track (track_element);
1679
1680   if (timeline->priv->track_elements_moving) {
1681     GST_DEBUG_OBJECT (timeline, "Ignoring element removed (%" GST_PTR_FORMAT
1682         " in %" GST_PTR_FORMAT, track_element, clip);
1683
1684     return;
1685   }
1686
1687   if (track) {
1688     /* if we have non-core elements in the same track, they should be
1689      * removed from them to preserve the rule that a non-core can only be
1690      * in the same track as a core element from the same clip */
1691     if (ges_track_element_is_core (track_element))
1692       ges_clip_empty_from_track (clip, track);
1693     ges_track_remove_element (track, track_element);
1694   }
1695 }
1696
1697 static void
1698 track_element_added_cb (GESTrack * track, GESTrackElement * element,
1699     GESTimeline * timeline)
1700 {
1701   if (GES_IS_SOURCE (element))
1702     timeline_tree_create_transitions_for_track_element (timeline->priv->tree,
1703         element, ges_timeline_find_auto_transition);
1704 }
1705
1706 /* returns TRUE if no errors in adding to tracks */
1707 static gboolean
1708 _add_clip_children_to_tracks (GESTimeline * timeline, GESClip * clip,
1709     gboolean add_core, GESTrack * new_track, GList * blacklist, GError ** error)
1710 {
1711   GList *tmp, *children;
1712   gboolean no_errors = TRUE;
1713
1714   /* list of children may change if some are copied into tracks */
1715   children = ges_container_get_children (GES_CONTAINER (clip), FALSE);
1716   for (tmp = children; tmp; tmp = tmp->next) {
1717     GESTrackElement *el = tmp->data;
1718     if (ges_track_element_is_core (el) != add_core)
1719       continue;
1720     if (g_list_find (blacklist, el))
1721       continue;
1722     if (ges_track_element_get_track (el) == NULL) {
1723       gboolean res;
1724       if (new_track)
1725         res = _try_add_track_element_to_track (timeline, clip, el, new_track,
1726             error);
1727       else
1728         res = _add_track_element_to_tracks (timeline, clip, el, error);
1729       if (!res) {
1730         no_errors = FALSE;
1731         if (error)
1732           goto done;
1733       }
1734     }
1735   }
1736
1737 done:
1738   g_list_free_full (children, gst_object_unref);
1739
1740   return no_errors;
1741 }
1742
1743 /* returns TRUE if no errors in adding to tracks */
1744 static gboolean
1745 add_object_to_tracks (GESTimeline * timeline, GESClip * clip,
1746     GESTrack * new_track, GError ** error)
1747 {
1748   GList *tracks, *tmp, *list, *created, *just_added = NULL;
1749   gboolean no_errors = TRUE;
1750
1751   GST_DEBUG_OBJECT (timeline, "Creating %" GST_PTR_FORMAT
1752       " trackelements and adding them to our tracks", clip);
1753
1754   LOCK_DYN (timeline);
1755   tracks =
1756       g_list_copy_deep (timeline->tracks, (GCopyFunc) gst_object_ref, NULL);
1757   timeline->priv->new_track = new_track ? gst_object_ref (new_track) : NULL;
1758   UNLOCK_DYN (timeline);
1759
1760   /* create core elements */
1761   for (tmp = tracks; tmp; tmp = tmp->next) {
1762     GESTrack *track = GES_TRACK (tmp->data);
1763     if (new_track && track != new_track)
1764       continue;
1765
1766     list = ges_clip_create_track_elements (clip, track->type);
1767     /* just_added only used for pointer comparison, so safe to include
1768      * elements that may be destroyed because they fail to be added to
1769      * the clip */
1770     just_added = g_list_concat (just_added, list);
1771
1772     for (created = list; created; created = created->next) {
1773       GESTimelineElement *el = created->data;
1774
1775       gst_object_ref (el);
1776
1777       /* make track selection be handled by clip_track_element_added_cb
1778        * This is needed for backward-compatibility: when adding a clip to
1779        * a layer, the track is set for the core elements of the clip
1780        * during the child-added signal emission, just before the user's
1781        * own connection.
1782        * NOTE: for the children that have not just been created, they
1783        * are already part of the clip and so child-added will not be
1784        * released. And when a child is selected for multiple tracks, their
1785        * copy will be added to the clip before the track is selected, so
1786        * the track will not be set in the child-added signal */
1787       ges_timeline_set_track_selection_error (timeline, FALSE, NULL);
1788       ges_clip_set_add_error (clip, NULL);
1789       if (!ges_container_add (GES_CONTAINER (clip), el)) {
1790         no_errors = FALSE;
1791         if (!error)
1792           GST_ERROR_OBJECT (clip, "Could not add the core element %s "
1793               "to the clip", el->name);
1794       }
1795       gst_object_unref (el);
1796       ges_clip_take_add_error (clip, error);
1797
1798       if (error && !no_errors)
1799         goto done;
1800
1801       if (ges_timeline_take_track_selection_error (timeline, error)) {
1802         no_errors = FALSE;
1803         if (error)
1804           goto done;
1805         /* else, carry on as much as we can */
1806       }
1807     }
1808   }
1809
1810   /* set the tracks for the other children, with core elements first to
1811    * make sure the non-core can be placed above them in the track (a
1812    * non-core can not be in a track by itself) */
1813   /* include just_added as a blacklist to ensure we do not try the track
1814    * selection a second time when track selection returns no tracks */
1815   if (!_add_clip_children_to_tracks (timeline, clip, TRUE, new_track,
1816           just_added, error)) {
1817     no_errors = FALSE;
1818     if (error)
1819       goto done;
1820   }
1821
1822   if (!_add_clip_children_to_tracks (timeline, clip, FALSE, new_track,
1823           just_added, error)) {
1824     no_errors = FALSE;
1825     if (error)
1826       goto done;
1827   }
1828
1829 done:
1830   g_list_free_full (tracks, gst_object_unref);
1831
1832   LOCK_DYN (timeline);
1833   gst_clear_object (&timeline->priv->new_track);
1834   UNLOCK_DYN (timeline);
1835
1836   g_list_free (just_added);
1837
1838   return no_errors;
1839 }
1840
1841 static void
1842 layer_active_changed_cb (GESLayer * layer, gboolean active G_GNUC_UNUSED,
1843     GPtrArray * tracks G_GNUC_UNUSED, GESTimeline * timeline)
1844 {
1845   timeline_tree_reset_layer_active (timeline->priv->tree, layer);
1846 }
1847
1848 static void
1849 layer_auto_transition_changed_cb (GESLayer * layer,
1850     GParamSpec * arg G_GNUC_UNUSED, GESTimeline * timeline)
1851 {
1852   GList *tmp, *clips;
1853
1854   timeline_tree_create_transitions (timeline->priv->tree,
1855       _create_auto_transition_from_transitions);
1856   clips = ges_layer_get_clips (layer);
1857   for (tmp = clips; tmp; tmp = tmp->next) {
1858     if (GES_IS_TRANSITION_CLIP (tmp->data)) {
1859       GList *tmpautotrans;
1860       gboolean found = FALSE;
1861
1862       for (tmpautotrans = timeline->priv->auto_transitions; tmpautotrans;
1863           tmpautotrans = tmpautotrans->next) {
1864         if (GES_AUTO_TRANSITION (tmpautotrans->data)->transition_clip ==
1865             tmp->data) {
1866           found = TRUE;
1867           break;
1868         }
1869       }
1870
1871       if (!found) {
1872         GST_ERROR_OBJECT (timeline,
1873             "Transition %s could not be wrapped into an auto transition"
1874             " REMOVING it", GES_TIMELINE_ELEMENT_NAME (tmp->data));
1875
1876         ges_layer_remove_clip (layer, tmp->data);
1877       }
1878     }
1879   }
1880   g_list_free_full (clips, gst_object_unref);
1881 }
1882
1883 /* returns TRUE if selecting of tracks did not error */
1884 gboolean
1885 ges_timeline_add_clip (GESTimeline * timeline, GESClip * clip, GError ** error)
1886 {
1887   GESProject *project;
1888   gboolean ret;
1889
1890   ges_timeline_element_set_timeline (GES_TIMELINE_ELEMENT (clip), timeline);
1891
1892   /* We make sure not to be connected twice */
1893   g_signal_handlers_disconnect_by_func (clip, clip_track_element_added_cb,
1894       timeline);
1895   g_signal_handlers_disconnect_by_func (clip, clip_track_element_removed_cb,
1896       timeline);
1897
1898   /* And we connect to the object */
1899   g_signal_connect (clip, "child-added",
1900       G_CALLBACK (clip_track_element_added_cb), timeline);
1901   g_signal_connect (clip, "child-removed",
1902       G_CALLBACK (clip_track_element_removed_cb), timeline);
1903
1904   GST_DEBUG ("Making sure that the asset is in our project");
1905   project =
1906       GES_PROJECT (ges_extractable_get_asset (GES_EXTRACTABLE (timeline)));
1907   ges_project_add_asset (project,
1908       ges_extractable_get_asset (GES_EXTRACTABLE (clip)));
1909
1910   if (ges_clip_is_moving_from_layer (clip)) {
1911     GST_DEBUG ("Clip %p moving from one layer to another, not creating "
1912         "TrackElement", clip);
1913     /* timeline-tree handles creation of auto-transitions */
1914     ret = TRUE;
1915   } else {
1916     ret = add_object_to_tracks (timeline, clip, NULL, error);
1917   }
1918
1919   GST_DEBUG ("Done");
1920
1921   return ret;
1922 }
1923
1924 static void
1925 layer_priority_changed_cb (GESLayer * layer,
1926     GParamSpec * arg G_GNUC_UNUSED, GESTimeline * timeline)
1927 {
1928   if (timeline->priv->resyncing_layers)
1929     return;
1930
1931   timeline->layers = g_list_sort (timeline->layers, (GCompareFunc)
1932       sort_layers);
1933 }
1934
1935 void
1936 ges_timeline_remove_clip (GESTimeline * timeline, GESClip * clip)
1937 {
1938   GList *tmp;
1939
1940   if (ges_clip_is_moving_from_layer (clip)) {
1941     GST_DEBUG ("Clip %p is moving from a layer to another, not doing"
1942         " anything on it", clip);
1943     return;
1944   }
1945
1946   GST_DEBUG_OBJECT (timeline, "Clip %" GES_FORMAT " removed from layer",
1947       GES_ARGS (clip));
1948
1949   LOCK_DYN (timeline);
1950   for (tmp = timeline->tracks; tmp; tmp = tmp->next)
1951     ges_clip_empty_from_track (clip, tmp->data);
1952   UNLOCK_DYN (timeline);
1953
1954   g_signal_handlers_disconnect_by_func (clip, clip_track_element_added_cb,
1955       timeline);
1956   g_signal_handlers_disconnect_by_func (clip, clip_track_element_removed_cb,
1957       timeline);
1958
1959   ges_timeline_element_set_timeline (GES_TIMELINE_ELEMENT (clip), NULL);
1960
1961   GST_DEBUG ("Done");
1962 }
1963
1964 static gboolean
1965 update_stream_object (TrackPrivate * tr_priv)
1966 {
1967   gboolean res = FALSE;
1968   GstStreamType type = GST_STREAM_TYPE_UNKNOWN;
1969   gchar *stream_id;
1970
1971   g_object_get (tr_priv->track, "id", &stream_id, NULL);
1972   if (tr_priv->track->type == GES_TRACK_TYPE_VIDEO)
1973     type = GST_STREAM_TYPE_VIDEO;
1974   if (tr_priv->track->type == GES_TRACK_TYPE_AUDIO)
1975     type = GST_STREAM_TYPE_AUDIO;
1976
1977   if (!tr_priv->stream ||
1978       g_strcmp0 (stream_id, gst_stream_get_stream_id (tr_priv->stream))) {
1979     res = TRUE;
1980     gst_object_replace ((GstObject **) & tr_priv->stream,
1981         (GstObject *) gst_stream_new (stream_id,
1982             (GstCaps *) ges_track_get_caps (tr_priv->track),
1983             type, GST_STREAM_FLAG_NONE)
1984         );
1985   }
1986
1987   g_free (stream_id);
1988
1989   return res;
1990 }
1991
1992 static GstPadProbeReturn
1993 _pad_probe_cb (GstPad * mixer_pad, GstPadProbeInfo * info,
1994     TrackPrivate * tr_priv)
1995 {
1996   GstEvent *event = GST_PAD_PROBE_INFO_EVENT (info);
1997   GESTimeline *timeline = tr_priv->timeline;
1998
1999   if (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_START) {
2000     LOCK_DYN (timeline);
2001     if (timeline->priv->stream_start_group_id == -1) {
2002       if (!gst_event_parse_group_id (event,
2003               &timeline->priv->stream_start_group_id))
2004         timeline->priv->stream_start_group_id = gst_util_group_id_next ();
2005     }
2006
2007     gst_event_unref (event);
2008     event = info->data =
2009         gst_event_new_stream_start (gst_stream_get_stream_id (tr_priv->stream));
2010     gst_event_set_stream (event, tr_priv->stream);
2011     gst_event_set_group_id (event, timeline->priv->stream_start_group_id);
2012     UNLOCK_DYN (timeline);
2013
2014     return GST_PAD_PROBE_REMOVE;
2015   }
2016
2017   return GST_PAD_PROBE_OK;
2018 }
2019
2020 static void
2021 _ghost_track_srcpad (TrackPrivate * tr_priv)
2022 {
2023   GstPad *pad;
2024   gchar *padname;
2025   gboolean no_more;
2026   GList *tmp;
2027   GESTrack *track = tr_priv->track;
2028
2029   pad = gst_element_get_static_pad (GST_ELEMENT (track), "src");
2030
2031   GST_DEBUG ("track:%p, pad:%s:%s", track, GST_DEBUG_PAD_NAME (pad));
2032
2033   /* Remember the pad */
2034   LOCK_DYN (tr_priv->timeline);
2035   GST_OBJECT_LOCK (track);
2036   tr_priv->pad = pad;
2037
2038   no_more = TRUE;
2039   for (tmp = tr_priv->timeline->priv->priv_tracks; tmp; tmp = g_list_next (tmp)) {
2040     TrackPrivate *tr_priv = (TrackPrivate *) tmp->data;
2041
2042     if (!tr_priv->pad) {
2043       GST_LOG ("Found track without pad %p", tr_priv->track);
2044       no_more = FALSE;
2045     }
2046   }
2047   GST_OBJECT_UNLOCK (track);
2048
2049   /* ghost it ! */
2050   GST_DEBUG ("Ghosting pad and adding it to ourself");
2051   padname = g_strdup_printf ("track_%p_src", track);
2052   tr_priv->ghostpad = gst_ghost_pad_new (padname, pad);
2053   g_free (padname);
2054   gst_pad_set_active (tr_priv->ghostpad, TRUE);
2055   gst_element_add_pad (GST_ELEMENT (tr_priv->timeline), tr_priv->ghostpad);
2056
2057   if (no_more) {
2058     GST_DEBUG ("Signaling no-more-pads");
2059     gst_element_no_more_pads (GST_ELEMENT (tr_priv->timeline));
2060   }
2061
2062   tr_priv->probe_id = gst_pad_add_probe (pad,
2063       GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
2064       (GstPadProbeCallback) _pad_probe_cb, tr_priv, NULL);
2065
2066   UNLOCK_DYN (tr_priv->timeline);
2067 }
2068
2069 gboolean
2070 timeline_add_element (GESTimeline * timeline, GESTimelineElement * element)
2071 {
2072   /* FIXME: handle NULL element->name */
2073   GESTimelineElement *same_name =
2074       g_hash_table_lookup (timeline->priv->all_elements,
2075       element->name);
2076
2077   GST_DEBUG_OBJECT (timeline, "Adding element: %s", element->name);
2078   if (same_name) {
2079     GST_ERROR_OBJECT (timeline, "%s Already in the timeline %" GST_PTR_FORMAT,
2080         element->name, same_name);
2081     return FALSE;
2082   }
2083
2084   /* FIXME: why is the hash table using the name of the element, rather than
2085    * the pointer to the element itself as the key? This makes it awkward
2086    * to change the name of an element after it has been added. See
2087    * ges_timeline_element_set_name. It means we have to remove and then
2088    * re-add the element. */
2089   g_hash_table_insert (timeline->priv->all_elements,
2090       ges_timeline_element_get_name (element), gst_object_ref (element));
2091
2092   timeline_tree_track_element (timeline->priv->tree, element);
2093   if (GES_IS_SOURCE (element)) {
2094     ges_source_set_rendering_smartly (GES_SOURCE (element),
2095         timeline->priv->rendering_smartly);
2096   }
2097
2098   return TRUE;
2099 }
2100
2101 gboolean
2102 timeline_remove_element (GESTimeline * timeline, GESTimelineElement * element)
2103 {
2104   if (g_hash_table_remove (timeline->priv->all_elements, element->name)) {
2105     timeline_tree_stop_tracking_element (timeline->priv->tree, element);
2106
2107     return TRUE;
2108   }
2109
2110   return FALSE;
2111 }
2112
2113 void
2114 timeline_fill_gaps (GESTimeline * timeline)
2115 {
2116   GList *tmp;
2117
2118   LOCK_DYN (timeline);
2119   for (tmp = timeline->tracks; tmp; tmp = tmp->next) {
2120     track_resort_and_fill_gaps (tmp->data);
2121   }
2122   UNLOCK_DYN (timeline);
2123 }
2124
2125 GNode *
2126 timeline_get_tree (GESTimeline * timeline)
2127 {
2128   return timeline->priv->tree;
2129 }
2130
2131 void
2132 ges_timeline_set_smart_rendering (GESTimeline * timeline,
2133     gboolean rendering_smartly)
2134 {
2135   if (rendering_smartly) {
2136     GList *tmp;
2137
2138     for (tmp = timeline->tracks; tmp; tmp = tmp->next) {
2139       if (ges_track_get_mixing (tmp->data)) {
2140         GST_INFO_OBJECT (timeline, "Smart rendering will not"
2141             " work as track %" GST_PTR_FORMAT " is doing mixing", tmp->data);
2142       } else {
2143         ges_track_set_smart_rendering (tmp->data, rendering_smartly);
2144       }
2145     }
2146   }
2147   timeline_tree_set_smart_rendering (timeline->priv->tree, rendering_smartly);
2148   timeline->priv->rendering_smartly = rendering_smartly;
2149 }
2150
2151 gboolean
2152 ges_timeline_get_smart_rendering (GESTimeline * timeline)
2153 {
2154   return timeline->priv->rendering_smartly;
2155 }
2156
2157 /**** API *****/
2158 /**
2159  * ges_timeline_new:
2160  *
2161  * Creates a new empty timeline.
2162  *
2163  * Returns: (transfer floating): The new timeline.
2164  */
2165
2166 GESTimeline *
2167 ges_timeline_new (void)
2168 {
2169   GESProject *project = ges_project_new (NULL);
2170   GESExtractable *timeline = g_object_new (GES_TYPE_TIMELINE, NULL);
2171
2172   ges_extractable_set_asset (timeline, GES_ASSET (project));
2173   gst_object_unref (project);
2174
2175   return GES_TIMELINE (timeline);
2176 }
2177
2178 /**
2179  * ges_timeline_new_from_uri:
2180  * @uri: The URI to load from
2181  * @error: (out) (allow-none): An error to be set if loading fails, or
2182  * %NULL to ignore
2183  *
2184  * Creates a timeline from the given URI.
2185  *
2186  * Returns: (transfer floating) (nullable): A new timeline if the uri was loaded
2187  * successfully, or %NULL if the uri could not be loaded.
2188  */
2189 GESTimeline *
2190 ges_timeline_new_from_uri (const gchar * uri, GError ** error)
2191 {
2192   GESTimeline *ret;
2193   GESProject *project = ges_project_new (uri);
2194
2195   ret = GES_TIMELINE (ges_asset_extract (GES_ASSET (project), error));
2196   gst_object_unref (project);
2197
2198   return ret;
2199 }
2200
2201 /**
2202  * ges_timeline_load_from_uri:
2203  * @timeline: An empty #GESTimeline into which to load the formatter
2204  * @uri: The URI to load from
2205  * @error: (out) (allow-none): An error to be set if loading fails, or
2206  * %NULL to ignore
2207  *
2208  * Loads the contents of URI into the timeline.
2209  *
2210  * Returns: %TRUE if the timeline was loaded successfully from @uri.
2211  */
2212 gboolean
2213 ges_timeline_load_from_uri (GESTimeline * timeline, const gchar * uri,
2214     GError ** error)
2215 {
2216   GESProject *project;
2217   gboolean ret = FALSE;
2218
2219   g_return_val_if_fail (GES_IS_TIMELINE (timeline), FALSE);
2220   g_return_val_if_fail ((ges_extractable_get_asset (GES_EXTRACTABLE
2221               (timeline)) == NULL), FALSE);
2222
2223   project = ges_project_new (uri);
2224   ret = ges_project_load (project, timeline, error);
2225   gst_object_unref (project);
2226
2227   return ret;
2228 }
2229
2230 /**
2231  * ges_timeline_save_to_uri:
2232  * @timeline: The #GESTimeline
2233  * @uri: The location to save to
2234  * @formatter_asset: (allow-none): The formatter asset to use, or %NULL
2235  * @overwrite: %TRUE to overwrite file if it exists
2236  * @error: (out) (allow-none): An error to be set if saving fails, or
2237  * %NULL to ignore
2238  *
2239  * Saves the timeline to the given location. If @formatter_asset is %NULL,
2240  * the method will attempt to save in the same format the timeline was
2241  * loaded from, before defaulting to the formatter with highest rank.
2242  *
2243  * Returns: %TRUE if @timeline was successfully saved to @uri.
2244  */
2245 gboolean
2246 ges_timeline_save_to_uri (GESTimeline * timeline, const gchar * uri,
2247     GESAsset * formatter_asset, gboolean overwrite, GError ** error)
2248 {
2249   GESProject *project;
2250
2251   gboolean ret, created_proj = FALSE;
2252
2253   g_return_val_if_fail (GES_IS_TIMELINE (timeline), FALSE);
2254   project =
2255       GES_PROJECT (ges_extractable_get_asset (GES_EXTRACTABLE (timeline)));
2256
2257   if (project == NULL) {
2258     project = ges_project_new (NULL);
2259     created_proj = TRUE;
2260   }
2261
2262   ret = ges_project_save (project, timeline, uri, formatter_asset, overwrite,
2263       error);
2264
2265   if (created_proj)
2266     gst_object_unref (project);
2267
2268   return ret;
2269 }
2270
2271 /**
2272  * ges_timeline_get_groups:
2273  * @timeline: The #GESTimeline
2274  *
2275  * Get the list of #GESGroup-s present in the timeline.
2276  *
2277  * Returns: (transfer none) (element-type GESGroup): The list of
2278  * groups that contain clips present in @timeline's layers.
2279  * Must not be changed.
2280  */
2281 GList *
2282 ges_timeline_get_groups (GESTimeline * timeline)
2283 {
2284   g_return_val_if_fail (GES_IS_TIMELINE (timeline), NULL);
2285   CHECK_THREAD (timeline);
2286
2287   return timeline->priv->groups;
2288 }
2289
2290 /**
2291  * ges_timeline_append_layer:
2292  * @timeline: The #GESTimeline
2293  *
2294  * Append a newly created layer to the timeline. The layer will
2295  * be added at the lowest #GESLayer:priority (numerically, the highest).
2296  *
2297  * Returns: (transfer none): The newly created layer.
2298  */
2299 GESLayer *
2300 ges_timeline_append_layer (GESTimeline * timeline)
2301 {
2302   GList *tmp;
2303   guint32 priority;
2304   GESLayer *layer;
2305
2306   g_return_val_if_fail (GES_IS_TIMELINE (timeline), NULL);
2307   CHECK_THREAD (timeline);
2308
2309   layer = ges_layer_new ();
2310
2311   priority = 0;
2312   for (tmp = timeline->layers; tmp; tmp = tmp->next)
2313     priority = MAX (priority, ges_layer_get_priority (tmp->data) + 1);
2314
2315   ges_layer_set_priority (layer, priority);
2316
2317   ges_timeline_add_layer (timeline, layer);
2318
2319   return layer;
2320 }
2321
2322 /**
2323  * ges_timeline_add_layer:
2324  * @timeline: The #GESTimeline
2325  * @layer: (transfer floating): The layer to add
2326  *
2327  * Add a layer to the timeline.
2328  *
2329  * If the layer contains #GESClip-s, then this may trigger the creation of
2330  * their core track element children for the timeline's tracks, and the
2331  * placement of the clip's children in the tracks of the timeline using
2332  * #GESTimeline::select-tracks-for-object. Some errors may occur if this
2333  * would break one of the configuration rules of the timeline in one of
2334  * its tracks. In such cases, some track elements would fail to be added
2335  * to their tracks, but this method would still return %TRUE. As such, it
2336  * is advised that you only add clips to layers that already part of a
2337  * timeline. In such situations, ges_layer_add_clip() is able to fail if
2338  * adding the clip would cause such an error.
2339  *
2340  * Deprecated: 1.18: This method requires you to ensure the layer's
2341  * #GESLayer:priority will be unique to the timeline. Use
2342  * ges_timeline_append_layer() and ges_timeline_move_layer() instead.
2343  *
2344  * Returns: %TRUE if @layer was properly added.
2345  */
2346 gboolean
2347 ges_timeline_add_layer (GESTimeline * timeline, GESLayer * layer)
2348 {
2349   gboolean auto_transition;
2350   GList *objects, *tmp;
2351
2352   g_return_val_if_fail (GES_IS_TIMELINE (timeline), FALSE);
2353   g_return_val_if_fail (GES_IS_LAYER (layer), FALSE);
2354   CHECK_THREAD (timeline);
2355
2356   GST_DEBUG ("timeline:%p, layer:%p", timeline, layer);
2357
2358   /* We can only add a layer that doesn't already belong to another timeline */
2359   if (G_UNLIKELY (layer->timeline)) {
2360     GST_WARNING ("Layer belongs to another timeline, can't add it");
2361     gst_object_ref_sink (layer);
2362     gst_object_unref (layer);
2363     return FALSE;
2364   }
2365
2366   /* Add to the list of layers, make sure we don't already control it */
2367   if (G_UNLIKELY (g_list_find (timeline->layers, (gconstpointer) layer))) {
2368     GST_WARNING ("Layer is already controlled by this timeline");
2369     gst_object_ref_sink (layer);
2370     gst_object_unref (layer);
2371     return FALSE;
2372   }
2373
2374   /* FIXME: ensure the layer->priority does not conflict with an existing
2375    * layer in the timeline. Currently can add several layers with equal
2376    * layer priorities */
2377
2378   auto_transition = ges_layer_get_auto_transition (layer);
2379
2380   /* If the user doesn't explicitely set layer auto_transition, then set our */
2381   if (!auto_transition) {
2382     auto_transition = ges_timeline_get_auto_transition (timeline);
2383     ges_layer_set_auto_transition (layer, auto_transition);
2384   }
2385
2386   gst_object_ref_sink (layer);
2387   timeline->layers = g_list_insert_sorted (timeline->layers, layer,
2388       (GCompareFunc) sort_layers);
2389
2390   /* Inform the layer that it belongs to a new timeline */
2391   ges_layer_set_timeline (layer, timeline);
2392
2393   /* Connect to 'clip-added'/'clip-removed' signal from the new layer */
2394   g_signal_connect (layer, "notify::priority",
2395       G_CALLBACK (layer_priority_changed_cb), timeline);
2396   g_signal_connect (layer, "notify::auto-transition",
2397       G_CALLBACK (layer_auto_transition_changed_cb), timeline);
2398   g_signal_connect_after (layer, "active-changed",
2399       G_CALLBACK (layer_active_changed_cb), timeline);
2400
2401   GST_DEBUG ("Done adding layer, emitting 'layer-added' signal");
2402   g_signal_emit (timeline, ges_timeline_signals[LAYER_ADDED], 0, layer);
2403
2404   /* add any existing clips to the timeline */
2405   objects = ges_layer_get_clips (layer);
2406   for (tmp = objects; tmp; tmp = tmp->next)
2407     ges_timeline_add_clip (timeline, tmp->data, NULL);
2408   g_list_free_full (objects, gst_object_unref);
2409
2410   return TRUE;
2411 }
2412
2413 /**
2414  * ges_timeline_remove_layer:
2415  * @timeline: The #GESTimeline
2416  * @layer: The layer to remove
2417  *
2418  * Removes a layer from the timeline.
2419  *
2420  * Returns: %TRUE if @layer was properly removed.
2421  */
2422
2423 gboolean
2424 ges_timeline_remove_layer (GESTimeline * timeline, GESLayer * layer)
2425 {
2426   GList *layer_objects, *tmp;
2427
2428   g_return_val_if_fail (GES_IS_TIMELINE (timeline), FALSE);
2429   g_return_val_if_fail (GES_IS_LAYER (layer), FALSE);
2430
2431   if (!timeline->priv->disposed)
2432     CHECK_THREAD (timeline);
2433
2434   GST_DEBUG ("timeline:%p, layer:%p", timeline, layer);
2435
2436   if (G_UNLIKELY (!g_list_find (timeline->layers, layer))) {
2437     GST_WARNING ("Layer doesn't belong to this timeline");
2438     return FALSE;
2439   }
2440
2441   /* remove objects from any private data structures */
2442
2443   layer_objects = ges_layer_get_clips (layer);
2444   for (tmp = layer_objects; tmp; tmp = tmp->next)
2445     ges_timeline_remove_clip (timeline, tmp->data);
2446   g_list_free_full (layer_objects, gst_object_unref);
2447
2448   /* Disconnect signals */
2449   GST_DEBUG ("Disconnecting signal callbacks");
2450   g_signal_handlers_disconnect_by_func (layer, layer_priority_changed_cb,
2451       timeline);
2452   g_signal_handlers_disconnect_by_func (layer,
2453       layer_auto_transition_changed_cb, timeline);
2454   g_signal_handlers_disconnect_by_func (layer, layer_active_changed_cb,
2455       timeline);
2456
2457   timeline->layers = g_list_remove (timeline->layers, layer);
2458   ges_layer_set_timeline (layer, NULL);
2459   /* FIXME: we should resync the layer priorities */
2460
2461   g_signal_emit (timeline, ges_timeline_signals[LAYER_REMOVED], 0, layer);
2462
2463   gst_object_unref (layer);
2464
2465   return TRUE;
2466 }
2467
2468 /**
2469  * ges_timeline_add_track:
2470  * @timeline: The #GESTimeline
2471  * @track: (transfer full): The track to add
2472  *
2473  * Add a track to the timeline.
2474  *
2475  * If the timeline already contains clips, then this may trigger the
2476  * creation of their core track element children for the track, and the
2477  * placement of the clip's children in the track of the timeline using
2478  * #GESTimeline::select-tracks-for-object. Some errors may occur if this
2479  * would break one of the configuration rules for the timeline in the
2480  * track. In such cases, some track elements would fail to be added to the
2481  * track, but this method would still return %TRUE. As such, it is advised
2482  * that you avoid adding tracks to timelines that already contain clips.
2483  *
2484  * Returns: %TRUE if @track was properly added.
2485  */
2486
2487 /* FIXME: create track elements for clips which have already been
2488  * added to existing layers.
2489  */
2490
2491 gboolean
2492 ges_timeline_add_track (GESTimeline * timeline, GESTrack * track)
2493 {
2494   TrackPrivate *tr_priv;
2495   GList *tmp;
2496
2497   g_return_val_if_fail (GES_IS_TIMELINE (timeline), FALSE);
2498   g_return_val_if_fail (GES_IS_TRACK (track), FALSE);
2499   CHECK_THREAD (timeline);
2500
2501   GST_DEBUG ("timeline:%p, track:%p", timeline, track);
2502
2503   /* make sure we don't already control it */
2504   LOCK_DYN (timeline);
2505   if (G_UNLIKELY (g_list_find (timeline->tracks, (gconstpointer) track))) {
2506     UNLOCK_DYN (timeline);
2507     GST_WARNING ("Track is already controlled by this timeline");
2508     return FALSE;
2509   }
2510
2511   /* Add the track to ourself (as a GstBin)
2512    * Reference is stolen ! */
2513   if (G_UNLIKELY (!gst_bin_add (GST_BIN (timeline), GST_ELEMENT (track)))) {
2514     UNLOCK_DYN (timeline);
2515     GST_WARNING ("Couldn't add track to ourself (GST)");
2516     return FALSE;
2517   }
2518
2519   tr_priv = g_new0 (TrackPrivate, 1);
2520   tr_priv->timeline = timeline;
2521   tr_priv->track = track;
2522   tr_priv->track_element_added_sigid = g_signal_connect (track,
2523       "track-element-added", G_CALLBACK (track_element_added_cb), timeline);
2524
2525   update_stream_object (tr_priv);
2526   gst_stream_collection_add_stream (timeline->priv->stream_collection,
2527       gst_object_ref (tr_priv->stream));
2528
2529   /* Add the track to the list of tracks we track */
2530   timeline->priv->priv_tracks = g_list_append (timeline->priv->priv_tracks,
2531       tr_priv);
2532   timeline->tracks = g_list_append (timeline->tracks, track);
2533
2534   /* Inform the track that it's currently being used by ourself */
2535   ges_track_set_timeline (track, timeline);
2536
2537   GST_DEBUG ("Done adding track, emitting 'track-added' signal");
2538
2539   _ghost_track_srcpad (tr_priv);
2540   UNLOCK_DYN (timeline);
2541
2542   /* emit 'track-added' */
2543   g_signal_emit (timeline, ges_timeline_signals[TRACK_ADDED], 0, track);
2544
2545   /* ensure that each existing clip has the opportunity to create a
2546    * track element for this track*/
2547
2548   for (tmp = timeline->layers; tmp; tmp = tmp->next) {
2549     GList *objects, *obj;
2550     objects = ges_layer_get_clips (tmp->data);
2551
2552     for (obj = objects; obj; obj = obj->next)
2553       add_object_to_tracks (timeline, obj->data, track, NULL);
2554
2555     g_list_free_full (objects, gst_object_unref);
2556   }
2557
2558   /* FIXME Check if we should rollback if we can't sync state */
2559   gst_element_sync_state_with_parent (GST_ELEMENT (track));
2560   g_object_set (track, "message-forward", TRUE, NULL);
2561
2562   return TRUE;
2563 }
2564
2565 /**
2566  * ges_timeline_remove_track:
2567  * @timeline: The #GESTimeline
2568  * @track: The track to remove
2569  *
2570  * Remove a track from the timeline.
2571  *
2572  * Returns: %TRUE if @track was properly removed.
2573  */
2574
2575 /* FIXME: release any track elements associated with this layer. currenly this
2576  * will not happen if you remove the track before removing *all*
2577  * clips which have a track element in this track.
2578  */
2579
2580 gboolean
2581 ges_timeline_remove_track (GESTimeline * timeline, GESTrack * track)
2582 {
2583   GList *tmp;
2584   TrackPrivate *tr_priv;
2585   GESTimelinePrivate *priv;
2586
2587   g_return_val_if_fail (GES_IS_TRACK (track), FALSE);
2588   g_return_val_if_fail (GES_IS_TIMELINE (timeline), FALSE);
2589
2590   GST_DEBUG ("timeline:%p, track:%p", timeline, track);
2591
2592   priv = timeline->priv;
2593   LOCK_DYN (timeline);
2594   if (G_UNLIKELY (!(tmp = g_list_find_custom (priv->priv_tracks,
2595                   track, (GCompareFunc) custom_find_track)))) {
2596     GST_WARNING ("Track doesn't belong to this timeline");
2597     UNLOCK_DYN (timeline);
2598     return FALSE;
2599   }
2600
2601   tr_priv = tmp->data;
2602   gst_object_unref (tr_priv->pad);
2603   priv->priv_tracks = g_list_remove (priv->priv_tracks, tr_priv);
2604   UNLOCK_DYN (timeline);
2605
2606   /* empty track of all elements that belong to the timeline's clips */
2607   /* elements with no parent can stay in the track, but their timeline
2608    * will be set to NULL when the track's timeline is set to NULL */
2609
2610   for (tmp = timeline->layers; tmp; tmp = tmp->next) {
2611     GList *clips, *clip;
2612     clips = ges_layer_get_clips (tmp->data);
2613
2614     for (clip = clips; clip; clip = clip->next)
2615       ges_clip_empty_from_track (clip->data, track);
2616
2617     g_list_free_full (clips, gst_object_unref);
2618   }
2619
2620   timeline->tracks = g_list_remove (timeline->tracks, track);
2621   ges_track_set_timeline (track, NULL);
2622
2623   /* Remove ghost pad */
2624   if (tr_priv->ghostpad) {
2625     GST_DEBUG ("Removing ghostpad");
2626     gst_pad_set_active (tr_priv->ghostpad, FALSE);
2627     gst_ghost_pad_set_target ((GstGhostPad *) tr_priv->ghostpad, NULL);
2628     gst_element_remove_pad (GST_ELEMENT (timeline), tr_priv->ghostpad);
2629   }
2630
2631   /* Signal track removal to all layers/objects */
2632   g_signal_emit (timeline, ges_timeline_signals[TRACK_REMOVED], 0, track);
2633
2634   /* remove track from our bin */
2635   gst_object_ref (track);
2636   if (G_UNLIKELY (!gst_bin_remove (GST_BIN (timeline), GST_ELEMENT (track)))) {
2637     GST_WARNING ("Couldn't remove track to ourself (GST)");
2638     gst_object_unref (track);
2639     return FALSE;
2640   }
2641
2642   g_signal_handler_disconnect (track, tr_priv->track_element_added_sigid);
2643
2644   /* set track state to NULL */
2645   gst_element_set_state (GST_ELEMENT (track), GST_STATE_NULL);
2646
2647   gst_object_unref (track);
2648
2649   g_free (tr_priv);
2650
2651   return TRUE;
2652 }
2653
2654 /**
2655  * ges_timeline_get_track_for_pad:
2656  * @timeline: The #GESTimeline
2657  * @pad: A pad
2658  *
2659  * Search for the #GESTrack corresponding to the given timeline's pad.
2660  *
2661  * Returns: (transfer none) (nullable): The track corresponding to @pad,
2662  * or %NULL if there is an error.
2663  */
2664
2665 GESTrack *
2666 ges_timeline_get_track_for_pad (GESTimeline * timeline, GstPad * pad)
2667 {
2668   GList *tmp;
2669
2670   g_return_val_if_fail (GES_IS_TIMELINE (timeline), NULL);
2671
2672   LOCK_DYN (timeline);
2673   for (tmp = timeline->priv->priv_tracks; tmp; tmp = g_list_next (tmp)) {
2674     TrackPrivate *tr_priv = (TrackPrivate *) tmp->data;
2675     if (pad == tr_priv->ghostpad) {
2676       UNLOCK_DYN (timeline);
2677       return tr_priv->track;
2678     }
2679   }
2680   UNLOCK_DYN (timeline);
2681
2682   return NULL;
2683 }
2684
2685 /**
2686  * ges_timeline_get_pad_for_track:
2687  * @timeline: The #GESTimeline
2688  * @track: A track
2689  *
2690  * Search for the #GstPad corresponding to the given timeline's track.
2691  * You can link to this pad to receive the output data of the given track.
2692  *
2693  * Returns: (transfer none) (nullable): The pad corresponding to @track,
2694  * or %NULL if there is an error.
2695  */
2696
2697 GstPad *
2698 ges_timeline_get_pad_for_track (GESTimeline * timeline, GESTrack * track)
2699 {
2700   GList *tmp;
2701
2702   LOCK_DYN (timeline);
2703   for (tmp = timeline->priv->priv_tracks; tmp; tmp = g_list_next (tmp)) {
2704     TrackPrivate *tr_priv = (TrackPrivate *) tmp->data;
2705
2706     if (track == tr_priv->track) {
2707       if (tr_priv->ghostpad)
2708         gst_object_ref (tr_priv->ghostpad);
2709
2710       UNLOCK_DYN (timeline);
2711       return tr_priv->ghostpad;
2712     }
2713   }
2714   UNLOCK_DYN (timeline);
2715
2716   return NULL;
2717 }
2718
2719 /**
2720  * ges_timeline_get_tracks:
2721  * @timeline: The #GESTimeline
2722  *
2723  * Get the list of #GESTrack-s used by the timeline.
2724  *
2725  * Returns: (transfer full) (element-type GESTrack): The list of tracks
2726  * used by @timeline.
2727  */
2728 GList *
2729 ges_timeline_get_tracks (GESTimeline * timeline)
2730 {
2731   GList *res = NULL;
2732   g_return_val_if_fail (GES_IS_TIMELINE (timeline), NULL);
2733
2734   LOCK_DYN (timeline);
2735   res = g_list_copy_deep (timeline->tracks, (GCopyFunc) gst_object_ref, NULL);
2736   UNLOCK_DYN (timeline);
2737
2738   return res;
2739 }
2740
2741 /**
2742  * ges_timeline_get_layers:
2743  * @timeline: The #GESTimeline
2744  *
2745  * Get the list of #GESLayer-s present in the timeline.
2746  *
2747  * Returns: (transfer full) (element-type GESLayer): The list of
2748  * layers present in @timeline sorted by priority.
2749  */
2750 GList *
2751 ges_timeline_get_layers (GESTimeline * timeline)
2752 {
2753   GList *tmp, *res = NULL;
2754
2755   g_return_val_if_fail (GES_IS_TIMELINE (timeline), NULL);
2756   CHECK_THREAD (timeline);
2757
2758   for (tmp = timeline->layers; tmp; tmp = g_list_next (tmp)) {
2759     res = g_list_insert_sorted (res, gst_object_ref (tmp->data),
2760         (GCompareFunc) sort_layers);
2761   }
2762
2763   return res;
2764 }
2765
2766 static void
2767 track_commited_cb (GESTrack * track, GESTimeline * timeline)
2768 {
2769   gboolean emit_commited = FALSE;
2770   GST_OBJECT_LOCK (timeline);
2771   timeline->priv->expected_commited -= 1;
2772   if (timeline->priv->expected_commited == 0)
2773     emit_commited = TRUE;
2774   g_signal_handlers_disconnect_by_func (track, track_commited_cb, timeline);
2775   GST_OBJECT_UNLOCK (timeline);
2776
2777   if (emit_commited) {
2778     g_signal_emit (timeline, ges_timeline_signals[COMMITED], 0);
2779   }
2780 }
2781
2782 /* Must be called with the timeline's DYN_LOCK */
2783 static gboolean
2784 ges_timeline_commit_unlocked (GESTimeline * timeline)
2785 {
2786   GList *tmp;
2787   gboolean res = TRUE;
2788
2789   if (timeline->priv->commit_frozen) {
2790     GST_DEBUG_OBJECT (timeline, "commit locked");
2791     timeline->priv->commit_delayed = TRUE;
2792     return res;
2793   }
2794
2795   GST_DEBUG_OBJECT (timeline, "commiting changes");
2796
2797   timeline_tree_create_transitions (timeline->priv->tree,
2798       ges_timeline_find_auto_transition);
2799   for (tmp = timeline->layers; tmp; tmp = tmp->next) {
2800     GESLayer *layer = tmp->data;
2801
2802     /* Ensure clip priorities are correct after an edit */
2803     ges_layer_resync_priorities (layer);
2804   }
2805
2806   timeline->priv->expected_commited =
2807       g_list_length (timeline->priv->priv_tracks);
2808
2809   if (timeline->priv->expected_commited == 0) {
2810     g_signal_emit (timeline, ges_timeline_signals[COMMITED], 0);
2811   } else {
2812     GstStreamCollection *collection = gst_stream_collection_new (NULL);
2813
2814     LOCK_DYN (timeline);
2815     for (tmp = timeline->tracks; tmp; tmp = tmp->next) {
2816       TrackPrivate *tr_priv =
2817           g_list_find_custom (timeline->priv->priv_tracks, tmp->data,
2818           (GCompareFunc) custom_find_track)->data;
2819
2820       update_stream_object (tr_priv);
2821       gst_stream_collection_add_stream (collection,
2822           gst_object_ref (tr_priv->stream));
2823       g_signal_connect (tmp->data, "commited", G_CALLBACK (track_commited_cb),
2824           timeline);
2825       if (!ges_track_commit (GES_TRACK (tmp->data)))
2826         res = FALSE;
2827     }
2828
2829     gst_object_unref (timeline->priv->stream_collection);
2830     timeline->priv->stream_collection = collection;
2831     UNLOCK_DYN (timeline);
2832   }
2833
2834   return res;
2835 }
2836
2837 /**
2838  * ges_timeline_commit:
2839  * @timeline: A #GESTimeline
2840  *
2841  * Commit all the pending changes of the clips contained in the
2842  * timeline.
2843  *
2844  * When changes happen in a timeline, they are not immediately executed
2845  * internally, in a way that effects the output data of the timeline. You
2846  * should call this method when you are done with a set of changes and you
2847  * want them to be executed.
2848  *
2849  * Any pending changes will be executed in the backend. The
2850  * #GESTimeline::commited signal will be emitted once this has completed.
2851  * You should not try to change the state of the timeline, seek it or add
2852  * tracks to it before receiving this signal. You can use
2853  * ges_timeline_commit_sync() if you do not want to perform other tasks in
2854  * the mean time.
2855  *
2856  * Note that all the pending changes will automatically be executed when
2857  * the timeline goes from #GST_STATE_READY to #GST_STATE_PAUSED, which is
2858  * usually triggered by a corresponding state changes in a containing
2859  * #GESPipeline.
2860  *
2861  * Returns: %TRUE if pending changes were committed, or %FALSE if nothing
2862  * needed to be committed.
2863  */
2864 gboolean
2865 ges_timeline_commit (GESTimeline * timeline)
2866 {
2867   gboolean ret;
2868   GstStreamCollection *pcollection = timeline->priv->stream_collection;
2869
2870   g_return_val_if_fail (GES_IS_TIMELINE (timeline), FALSE);
2871
2872   LOCK_DYN (timeline);
2873   ret = ges_timeline_commit_unlocked (timeline);
2874   UNLOCK_DYN (timeline);
2875
2876   if (pcollection != timeline->priv->stream_collection) {
2877     gst_element_post_message ((GstElement *) timeline,
2878         gst_message_new_stream_collection ((GstObject *) timeline,
2879             timeline->priv->stream_collection));
2880   }
2881
2882   ges_timeline_emit_snapping (timeline, NULL, NULL, GST_CLOCK_TIME_NONE);
2883   return ret;
2884 }
2885
2886 static void
2887 commited_cb (GESTimeline * timeline)
2888 {
2889   g_mutex_lock (&timeline->priv->commited_lock);
2890   g_cond_signal (&timeline->priv->commited_cond);
2891   g_mutex_unlock (&timeline->priv->commited_lock);
2892 }
2893
2894 /**
2895  * ges_timeline_commit_sync:
2896  * @timeline: A #GESTimeline
2897  *
2898  * Commit all the pending changes of the clips contained in the
2899  * timeline and wait for the changes to complete.
2900  *
2901  * See ges_timeline_commit().
2902  *
2903  * Returns: %TRUE if pending changes were committed, or %FALSE if nothing
2904  * needed to be committed.
2905  */
2906 gboolean
2907 ges_timeline_commit_sync (GESTimeline * timeline)
2908 {
2909   gboolean ret;
2910   gboolean wait_for_signal;
2911
2912   g_return_val_if_fail (GES_IS_TIMELINE (timeline), FALSE);
2913
2914   /* Let's make sure our state is stable */
2915   gst_element_get_state (GST_ELEMENT (timeline), NULL, NULL,
2916       GST_CLOCK_TIME_NONE);
2917
2918   /* Let's make sure no track gets added between now and the actual commiting */
2919   LOCK_DYN (timeline);
2920   wait_for_signal = g_list_length (timeline->priv->priv_tracks) > 0
2921       && GST_STATE (timeline) >= GST_STATE_PAUSED;
2922
2923   if (!wait_for_signal) {
2924     ret = ges_timeline_commit_unlocked (timeline);
2925   } else {
2926     gulong handler_id =
2927         g_signal_connect (timeline, "commited", (GCallback) commited_cb, NULL);
2928
2929     g_mutex_lock (&timeline->priv->commited_lock);
2930
2931     ret = ges_timeline_commit_unlocked (timeline);
2932     g_cond_wait (&timeline->priv->commited_cond,
2933         &timeline->priv->commited_lock);
2934     g_mutex_unlock (&timeline->priv->commited_lock);
2935     g_signal_handler_disconnect (timeline, handler_id);
2936   }
2937
2938   UNLOCK_DYN (timeline);
2939
2940   return ret;
2941 }
2942
2943 /**
2944  * ges_timeline_freeze_commit:
2945  * @timeline: The #GESTimeline
2946  *
2947  * Freezes the timeline from being committed. This is usually needed while the
2948  * timeline is being rendered to ensure that not change to the timeline are
2949  * taken into account during that moment. Once the rendering is done, you
2950  * should call #ges_timeline_thaw_commit so that comiting becomes possible
2951  * again and any call to `commit()` that happened during the rendering is
2952  * actually taken into account.
2953  *
2954  * Since: 1.20
2955  *
2956  */
2957 void
2958 ges_timeline_freeze_commit (GESTimeline * timeline)
2959 {
2960   LOCK_DYN (timeline);
2961   timeline->priv->commit_frozen = TRUE;
2962   UNLOCK_DYN (timeline);
2963 }
2964
2965 /**
2966  * ges_timeline_thaw_commit:
2967  * @timeline: The #GESTimeline
2968  *
2969  * Thaw the timeline so that comiting becomes possible
2970  * again and any call to `commit()` that happened during the rendering is
2971  * actually taken into account.
2972  *
2973  * Since: 1.20
2974  *
2975  */
2976 void
2977 ges_timeline_thaw_commit (GESTimeline * timeline)
2978 {
2979   LOCK_DYN (timeline);
2980   timeline->priv->commit_frozen = FALSE;
2981   UNLOCK_DYN (timeline);
2982   if (timeline->priv->commit_delayed) {
2983     ges_timeline_commit (timeline);
2984     timeline->priv->commit_delayed = FALSE;
2985   }
2986 }
2987
2988 /**
2989  * ges_timeline_get_duration:
2990  * @timeline: The #GESTimeline
2991  *
2992  * Get the current #GESTimeline:duration of the timeline
2993  *
2994  * Returns: The current duration of @timeline.
2995  */
2996 GstClockTime
2997 ges_timeline_get_duration (GESTimeline * timeline)
2998 {
2999   g_return_val_if_fail (GES_IS_TIMELINE (timeline), GST_CLOCK_TIME_NONE);
3000   CHECK_THREAD (timeline);
3001
3002   return timeline->priv->duration;
3003 }
3004
3005 /**
3006  * ges_timeline_get_auto_transition:
3007  * @timeline: The #GESTimeline
3008  *
3009  * Gets #GESTimeline:auto-transition for the timeline.
3010  *
3011  * Returns: The auto-transition of @self.
3012  */
3013 gboolean
3014 ges_timeline_get_auto_transition (GESTimeline * timeline)
3015 {
3016   g_return_val_if_fail (GES_IS_TIMELINE (timeline), FALSE);
3017   CHECK_THREAD (timeline);
3018
3019   return timeline->priv->auto_transition;
3020 }
3021
3022 /**
3023  * ges_timeline_set_auto_transition:
3024  * @timeline: The #GESTimeline
3025  * @auto_transition: Whether transitions should be automatically added
3026  * to @timeline's layers
3027  *
3028  * Sets #GESTimeline:auto-transition for the timeline. This will also set
3029  * the corresponding #GESLayer:auto-transition for all of the timeline's
3030  * layers to the same value. See ges_layer_set_auto_transition() if you
3031  * wish to set the layer's #GESLayer:auto-transition individually.
3032  */
3033 void
3034 ges_timeline_set_auto_transition (GESTimeline * timeline,
3035     gboolean auto_transition)
3036 {
3037   GList *layers;
3038   GESLayer *layer;
3039
3040   g_return_if_fail (GES_IS_TIMELINE (timeline));
3041   CHECK_THREAD (timeline);
3042
3043   timeline->priv->auto_transition = auto_transition;
3044   g_object_notify (G_OBJECT (timeline), "auto-transition");
3045
3046   layers = timeline->layers;
3047   for (; layers; layers = layers->next) {
3048     layer = layers->data;
3049     ges_layer_set_auto_transition (layer, auto_transition);
3050   }
3051 }
3052
3053 /**
3054  * ges_timeline_get_snapping_distance:
3055  * @timeline: The #GESTimeline
3056  *
3057  * Gets the #GESTimeline:snapping-distance for the timeline.
3058  *
3059  * Returns: The snapping distance (in nanoseconds) of @timeline.
3060  */
3061 GstClockTime
3062 ges_timeline_get_snapping_distance (GESTimeline * timeline)
3063 {
3064   g_return_val_if_fail (GES_IS_TIMELINE (timeline), GST_CLOCK_TIME_NONE);
3065   CHECK_THREAD (timeline);
3066
3067   return timeline->priv->snapping_distance;
3068
3069 }
3070
3071 /**
3072  * ges_timeline_set_snapping_distance:
3073  * @timeline: The #GESTimeline
3074  * @snapping_distance: The snapping distance to use (in nanoseconds)
3075  *
3076  * Sets #GESTimeline:snapping-distance for the timeline. This new value
3077  * will only effect future snappings and will not be used to snap the
3078  * current element positions within the timeline.
3079  */
3080 void
3081 ges_timeline_set_snapping_distance (GESTimeline * timeline,
3082     GstClockTime snapping_distance)
3083 {
3084   g_return_if_fail (GES_IS_TIMELINE (timeline));
3085   g_return_if_fail (GST_CLOCK_TIME_IS_VALID (snapping_distance));
3086   CHECK_THREAD (timeline);
3087
3088   timeline->priv->snapping_distance = snapping_distance;
3089 }
3090
3091 /**
3092  * ges_timeline_get_element:
3093  * @timeline: The #GESTimeline
3094  * @name: The name of the element to find
3095  *
3096  * Gets the element contained in the timeline with the given name.
3097  *
3098  * Returns: (transfer full) (nullable): The timeline element in @timeline
3099  * with the given @name, or %NULL if it was not found.
3100  */
3101 GESTimelineElement *
3102 ges_timeline_get_element (GESTimeline * timeline, const gchar * name)
3103 {
3104   GESTimelineElement *ret;
3105
3106   g_return_val_if_fail (GES_IS_TIMELINE (timeline), NULL);
3107   CHECK_THREAD (timeline);
3108
3109   /* FIXME: handle NULL name */
3110   ret = g_hash_table_lookup (timeline->priv->all_elements, name);
3111
3112   if (ret)
3113     return gst_object_ref (ret);
3114
3115 #ifndef GST_DISABLE_GST_DEBUG
3116   {
3117     GList *element_names, *tmp;
3118     element_names = g_hash_table_get_keys (timeline->priv->all_elements);
3119
3120     GST_INFO_OBJECT (timeline, "Does not contain element %s", name);
3121
3122     for (tmp = element_names; tmp; tmp = tmp->next) {
3123       GST_DEBUG_OBJECT (timeline, "Containes: %s", (gchar *) tmp->data);
3124     }
3125     g_list_free (element_names);
3126   }
3127 #endif
3128
3129   return NULL;
3130 }
3131
3132 /**
3133  * ges_timeline_is_empty:
3134  * @timeline: The #GESTimeline
3135  *
3136  * Check whether the timeline is empty or not.
3137  *
3138  * Returns: %TRUE if @timeline is empty.
3139  */
3140 gboolean
3141 ges_timeline_is_empty (GESTimeline * timeline)
3142 {
3143   GHashTableIter iter;
3144   gpointer key, value;
3145
3146   g_return_val_if_fail (GES_IS_TIMELINE (timeline), FALSE);
3147   CHECK_THREAD (timeline);
3148
3149   if (g_hash_table_size (timeline->priv->all_elements) == 0)
3150     return TRUE;
3151
3152   g_hash_table_iter_init (&iter, timeline->priv->all_elements);
3153   while (g_hash_table_iter_next (&iter, &key, &value)) {
3154     if (GES_IS_SOURCE (value) &&
3155         ges_track_element_is_active (GES_TRACK_ELEMENT (value)))
3156       return FALSE;
3157   }
3158
3159   return TRUE;
3160 }
3161
3162 /**
3163  * ges_timeline_get_layer:
3164  * @timeline: The #GESTimeline to retrieve a layer from
3165  * @priority: The priority/index of the layer to find
3166  *
3167  * Retrieve the layer whose index in the timeline matches the given
3168  * priority.
3169  *
3170  * Returns: (transfer full) (nullable): The layer with the given
3171  * @priority, or %NULL if none was found.
3172  *
3173  * Since 1.6
3174  */
3175 GESLayer *
3176 ges_timeline_get_layer (GESTimeline * timeline, guint priority)
3177 {
3178   GList *tmp;
3179   GESLayer *layer = NULL;
3180
3181   g_return_val_if_fail (GES_IS_TIMELINE (timeline), NULL);
3182   CHECK_THREAD (timeline);
3183
3184   for (tmp = timeline->layers; tmp; tmp = tmp->next) {
3185     GESLayer *tmp_layer = GES_LAYER (tmp->data);
3186     guint tmp_priority;
3187
3188     g_object_get (tmp_layer, "priority", &tmp_priority, NULL);
3189     if (tmp_priority == priority) {
3190       layer = gst_object_ref (tmp_layer);
3191       break;
3192     }
3193   }
3194
3195   return layer;
3196 }
3197
3198 gboolean
3199 ges_timeline_layer_priority_in_gap (GESTimeline * timeline, guint priority)
3200 {
3201   GList *tmp;
3202
3203   CHECK_THREAD (timeline);
3204
3205   for (tmp = timeline->layers; tmp; tmp = tmp->next) {
3206     GESLayer *layer = GES_LAYER (tmp->data);
3207     guint tmp_priority = ges_layer_get_priority (layer);
3208
3209     if (tmp_priority == priority)
3210       return FALSE;
3211     else if (tmp_priority > priority)
3212       return TRUE;
3213   }
3214
3215   return FALSE;
3216 }
3217
3218 /**
3219  * ges_timeline_paste_element:
3220  * @timeline: The #GESTimeline onto which @element should be pasted
3221  * @element: The element to paste
3222  * @position: The position in the timeline @element should be pasted to,
3223  * i.e. the #GESTimelineElement:start value for the pasted element.
3224  * @layer_priority: The layer into which the element should be pasted.
3225  * -1 means paste to the same layer from which @element has been copied from
3226  *
3227  * Paste an element inside the timeline. @element **must** be the return of
3228  * ges_timeline_element_copy() with `deep=TRUE`,
3229  * and it should not be changed before pasting. @element itself is not
3230  * placed in the timeline, instead a new element is created, alike to the
3231  * originally copied element. Note that the originally copied element must
3232  * also lie within @timeline, at both the point of copying and pasting.
3233  *
3234  * Pasting may fail if it would place the timeline in an unsupported
3235  * configuration.
3236  *
3237  * After calling this function @element should not be used. In particular,
3238  * @element can **not** be pasted again. Instead, you can copy the
3239  * returned element and paste that copy (although, this is only possible
3240  * if the paste was successful).
3241  *
3242  * See also ges_timeline_element_paste().
3243  *
3244  * Returns: (transfer full) (nullable): The newly created element, or
3245  * %NULL if pasting fails.
3246  */
3247 GESTimelineElement *
3248 ges_timeline_paste_element (GESTimeline * timeline,
3249     GESTimelineElement * element, GstClockTime position, gint layer_priority)
3250 {
3251   GESTimelineElement *res, *copied_from;
3252   GESTimelineElementClass *element_class;
3253
3254   g_return_val_if_fail (GES_IS_TIMELINE (timeline), FALSE);
3255   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (element), FALSE);
3256   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (position), FALSE);
3257   CHECK_THREAD (timeline);
3258
3259   element_class = GES_TIMELINE_ELEMENT_GET_CLASS (element);
3260   /* steal ownership of the copied element */
3261   copied_from = ges_timeline_element_get_copied_from (element);
3262
3263   if (!copied_from) {
3264     GST_ERROR_OBJECT (element, "Is not being 'deeply' copied!");
3265
3266     return NULL;
3267   }
3268
3269   if (!element_class->paste) {
3270     GST_ERROR_OBJECT (element, "No paste vmethod implemented");
3271     gst_object_unref (copied_from);
3272     return NULL;
3273   }
3274
3275   /*
3276    * Currently the API only supports pasting onto the same layer from which
3277    * the @element has been copied from, i.e., @layer_priority needs to be -1.
3278    */
3279   if (layer_priority != -1) {
3280     GST_WARNING_OBJECT (timeline,
3281         "Only -1 value for layer priority is supported");
3282     gst_object_unref (copied_from);
3283     return NULL;
3284   }
3285
3286   res = element_class->paste (element, copied_from, position);
3287
3288   gst_object_unref (copied_from);
3289
3290   return res ? g_object_ref_sink (res) : res;
3291 }
3292
3293 /**
3294  * ges_timeline_move_layer:
3295  * @timeline: A #GESTimeline
3296  * @layer: A layer within @timeline, whose priority should be changed
3297  * @new_layer_priority: The new index for @layer
3298  *
3299  * Moves a layer within the timeline to the index given by
3300  * @new_layer_priority.
3301  * An index of 0 corresponds to the layer with the highest priority in a
3302  * timeline. If @new_layer_priority is greater than the number of layers
3303  * present in the timeline, it will become the lowest priority layer.
3304  *
3305  * Since: 1.16
3306  */
3307 gboolean
3308 ges_timeline_move_layer (GESTimeline * timeline, GESLayer * layer,
3309     guint new_layer_priority)
3310 {
3311   gint current_priority;
3312
3313   g_return_val_if_fail (GES_IS_TIMELINE (timeline), FALSE);
3314   g_return_val_if_fail (GES_IS_LAYER (layer), FALSE);
3315   g_return_val_if_fail (ges_layer_get_timeline (layer) == timeline, FALSE);
3316   CHECK_THREAD (timeline);
3317
3318   current_priority = ges_layer_get_priority (layer);
3319
3320   if (new_layer_priority == current_priority) {
3321     GST_DEBUG_OBJECT (timeline,
3322         "Nothing to do for %" GST_PTR_FORMAT ", same priorities", layer);
3323
3324     return TRUE;
3325   }
3326
3327   timeline->layers = g_list_remove (timeline->layers, layer);
3328   timeline->layers = g_list_insert (timeline->layers, layer,
3329       (gint) new_layer_priority);
3330
3331   _resync_layers (timeline);
3332
3333   return TRUE;
3334 }
3335
3336 /**
3337  * ges_timeline_get_frame_time:
3338  * @self: The self on which to retrieve the timestamp for @frame_number
3339  * @frame_number: The frame number to get the corresponding timestamp of in the
3340  *                timeline coordinates
3341  *
3342  * This method allows you to convert a timeline output frame number into a
3343  * timeline #GstClockTime. For example, this time could be used to seek to a
3344  * particular frame in the timeline's output, or as the edit position for
3345  * an element within the timeline.
3346  *
3347  * Returns: The timestamp corresponding to @frame_number in the output of @self.
3348  *
3349  * Since: 1.18
3350  */
3351 GstClockTime
3352 ges_timeline_get_frame_time (GESTimeline * self, GESFrameNumber frame_number)
3353 {
3354   gint fps_n, fps_d;
3355
3356   g_return_val_if_fail (GES_IS_TIMELINE (self), GST_CLOCK_TIME_NONE);
3357   g_return_val_if_fail (GES_FRAME_NUMBER_IS_VALID (frame_number),
3358       GST_CLOCK_TIME_NONE);
3359
3360   timeline_get_framerate (self, &fps_n, &fps_d);
3361
3362   return gst_util_uint64_scale_ceil (frame_number, fps_d * GST_SECOND, fps_n);
3363 }
3364
3365 /**
3366  * ges_timeline_get_frame_at:
3367  * @self: A #GESTimeline
3368  * @timestamp: The timestamp to get the corresponding frame number of
3369  *
3370  * This method allows you to convert a timeline #GstClockTime into its
3371  * corresponding #GESFrameNumber in the timeline's output.
3372  *
3373  * Returns: The frame number @timestamp corresponds to.
3374  *
3375  * Since: 1.18
3376  */
3377 GESFrameNumber
3378 ges_timeline_get_frame_at (GESTimeline * self, GstClockTime timestamp)
3379 {
3380   gint fps_n, fps_d;
3381
3382   g_return_val_if_fail (GES_IS_TIMELINE (self), GES_FRAME_NUMBER_NONE);
3383   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp),
3384       GES_FRAME_NUMBER_NONE);
3385
3386   timeline_get_framerate (self, &fps_n, &fps_d);
3387
3388   return gst_util_uint64_scale (timestamp, fps_n, fps_d * GST_SECOND);
3389 }