#include "ges.h"
#include "ges-timeline-source.h"
-static void
-timeline_object_height_changed_cb (GESTimelineObject * obj,
- GESTrackEffect * tr_eff, GESTimelineObject * second_obj);
-
static void ges_meta_container_interface_init
(GESMetaContainerInterface * iface);
self->max_gnl_priority = LAYER_HEIGHT;
}
-static GList *
-track_get_by_layer (GESTimelineLayer * layer, GESTrack * track)
-{
- GESTrackObject *tckobj;
- guint32 layer_prio = layer->priv->priority;
-
- GList *tck_objects_list = NULL, *tmp = NULL, *return_list = NULL;
-
- tck_objects_list = ges_track_get_objects (track);
- for (tmp = tck_objects_list; tmp; tmp = tmp->next) {
- tckobj = GES_TRACK_OBJECT (tmp->data);
-
- if (tckobj->priority / LAYER_HEIGHT == layer_prio) {
- /* We steal the reference from tck_objects_list */
- return_list = g_list_append (return_list, tmp->data);
- } else
- g_object_unref (tmp->data);
- }
-
- return return_list;
-}
-
-/* Compare:
- * @compared: The #GList of #GESTrackObjects that we compare with @track_object
- * @track_object: The #GESTrackObject that serves as a reference
- * @ahead: %TRUE if we are comparing frontward %FALSE if we are comparing
- * backward*/
-static void
-compare (GList * compared, GESTrackObject * track_object, gboolean ahead)
-{
- GList *tmp;
- gint64 start, duration, compared_start, compared_duration, end, compared_end,
- tr_start, tr_duration;
- GESTimelineStandardTransition *trans = NULL;
- GESTrack *track;
- GESTimelineLayer *layer;
- GESTimelineObject *object, *compared_object, *first_object, *second_object;
- gint priority;
-
- g_return_if_fail (compared);
-
- GST_DEBUG ("Recalculating transitions");
-
- object = ges_track_object_get_timeline_object (track_object);
-
- if (!object) {
- GST_WARNING ("Trackobject not in a timeline object: "
- "Can not calulate transitions");
-
- return;
- }
-
- compared_object = ges_track_object_get_timeline_object (compared->data);
- layer = ges_timeline_object_get_layer (object);
-
- start = ges_track_object_get_start (track_object);
- duration = ges_track_object_get_duration (track_object);
- compared_start = ges_track_object_get_start (compared->data);
- compared_duration = ges_track_object_get_duration (compared->data);
- end = start + duration;
- compared_end = compared_start + compared_duration;
-
- if (ahead) {
- /* Make sure we remove the last transition we created it is not needed
- * FIXME make it a smarter way */
- if (compared->prev && GES_IS_TRACK_TRANSITION (compared->prev->data)) {
- trans = GES_TIMELINE_STANDARD_TRANSITION
- (ges_track_object_get_timeline_object (compared->prev->data));
- g_object_get (compared->prev->data, "start", &tr_start, "duration",
- &tr_duration, NULL);
- if (tr_start >= compared_start && tr_start + tr_duration <= compared_end)
- ges_timeline_layer_remove_object (layer, GES_TIMELINE_OBJECT (trans));
- trans = NULL;
- }
-
- for (tmp = compared->next; tmp; tmp = tmp->next) {
- /* If we have a transitionmnmnm we recaluculuculate its values */
- if (GES_IS_TRACK_TRANSITION (tmp->data)) {
- g_object_get (tmp->data, "start", &tr_start, "duration", &tr_duration,
- NULL);
-
- if (tr_start + tr_duration == compared_start + compared_duration) {
- GESTimelineObject *tlobj;
- tlobj = ges_track_object_get_timeline_object (tmp->data);
-
- trans = GES_TIMELINE_STANDARD_TRANSITION (tlobj);
- break;
- }
- }
- }
-
- if (compared_end <= start) {
- if (trans) {
- ges_timeline_layer_remove_object (layer, GES_TIMELINE_OBJECT (trans));
- g_object_get (compared_object, "priority", &priority, NULL);
- g_object_set (object, "priority", priority, NULL);
- }
-
- goto clean;
- } else if (start > compared_start && end < compared_end) {
- if (trans) {
- /* Transition not needed anymore */
- ges_timeline_layer_remove_object (layer, GES_TIMELINE_OBJECT (trans));
- }
- goto clean;
- } else if (start <= compared_start) {
- if (trans) {
- ges_timeline_layer_remove_object (layer, GES_TIMELINE_OBJECT (trans));
- }
-
- goto clean;
- }
-
- } else {
- if (compared->next && GES_IS_TRACK_TRANSITION (compared->next->data)) {
- trans = GES_TIMELINE_STANDARD_TRANSITION
- (ges_track_object_get_timeline_object (compared->next->data));
- g_object_get (compared->prev->data, "start", &tr_start, "duration",
- &tr_duration, NULL);
- if (tr_start >= compared_start && tr_start + tr_duration <= compared_end)
- ges_timeline_layer_remove_object (layer, GES_TIMELINE_OBJECT (trans));
- trans = NULL;
- }
- for (tmp = compared->prev; tmp; tmp = tmp->prev) {
- if GES_IS_TRACK_TRANSITION
- (tmp->data) {
- g_object_get (tmp->data, "start", &tr_start, "duration", &tr_duration,
- NULL);
- if (tr_start == compared_start) {
- trans = GES_TIMELINE_STANDARD_TRANSITION
- (ges_track_object_get_timeline_object (tmp->data));
- break;
- }
- }
- }
-
- if (start + duration <= compared_start) {
- if (trans) {
- ges_timeline_layer_remove_object (layer, GES_TIMELINE_OBJECT (trans));
- g_object_get (object, "priority", &priority, NULL);
- g_object_set (compared_object, "priority", priority, NULL);
- }
- goto clean;
-
- } else if (start > compared_start) {
- if (trans)
- ges_timeline_layer_remove_object (layer, GES_TIMELINE_OBJECT (trans));
-
- goto clean;
- } else if (start < compared_start && end > compared_end) {
- if (trans) {
- ges_timeline_layer_remove_object (layer, GES_TIMELINE_OBJECT (trans));
- }
-
- goto clean;
- }
- }
-
- if (!trans) {
- gint height;
-
- trans =
- ges_timeline_standard_transition_new_for_nick ((gchar *) "crossfade");
- track = ges_track_object_get_track (track_object);
-
- ges_timeline_object_set_supported_formats (GES_TIMELINE_OBJECT (trans),
- track->type);
-
- ges_timeline_layer_add_object (layer, GES_TIMELINE_OBJECT (trans));
-
- if (ahead) {
- first_object = ges_track_object_get_timeline_object (compared->data);
- second_object = object;
- } else {
- second_object = ges_track_object_get_timeline_object (compared->data);
- first_object = object;
- }
-
- g_object_get (first_object, "priority", &priority, "height", &height, NULL);
- g_object_set (second_object, "priority", priority + height, NULL);
- g_signal_connect (first_object, "notify::height",
- (GCallback) timeline_object_height_changed_cb, second_object);
- }
-
- if (ahead) {
- g_object_set (trans, "start", start, "duration",
- compared_duration + compared_start - start, NULL);
- } else {
- g_object_set (trans, "start", compared_start, "duration",
- start + duration - compared_start, NULL);
- }
-
-clean:
- g_object_unref (layer);
-}
-
-static void
-calculate_next_transition_with_list (GESTrackObject * track_object,
- GList * tckobjs_in_layer, GESTimelineLayer * layer)
-{
- GList *compared;
-
- if (!(compared = g_list_find (tckobjs_in_layer, track_object)))
- return;
-
- if (compared == NULL)
- /* This is the last TrackObject of the Track */
- return;
-
- do {
- compared = compared->next;
- if (compared == NULL)
- return;
- } while (!GES_IS_TRACK_SOURCE (compared->data));
-
- compare (compared, track_object, FALSE);
-}
-
-
-static void
-calculate_next_transition (GESTrackObject * track_object,
- GESTimelineLayer * layer)
-{
- GESTrack *track;
- GList *tckobjs_in_layer;
-
- if ((track = ges_track_object_get_track (track_object))) {
- tckobjs_in_layer = track_get_by_layer (layer, track);
- calculate_next_transition_with_list (track_object, tckobjs_in_layer, layer);
-
- g_list_foreach (tckobjs_in_layer, (GFunc) g_object_unref, NULL);
- g_list_free (tckobjs_in_layer);
- }
-}
-
-static void
-calculate_transitions (GESTrackObject * track_object)
-{
- GList *tckobjs_in_layer, *compared;
- GESTimelineLayer *layer;
- GESTimelineObject *tlobj;
-
- GESTrack *track = ges_track_object_get_track (track_object);
-
- if (track == NULL)
- return;
-
- tlobj = ges_track_object_get_timeline_object (track_object);
- layer = ges_timeline_object_get_layer (tlobj);
- tckobjs_in_layer = track_get_by_layer (layer, track);
- if (!(compared = g_list_find (tckobjs_in_layer, track_object)))
- return;
- do {
- compared = compared->prev;
-
- if (compared == NULL) {
- /* Nothing before, let's check after */
- calculate_next_transition_with_list (track_object, tckobjs_in_layer,
- layer);
- goto done;
-
- }
- } while (!GES_IS_TRACK_SOURCE (compared->data));
-
- compare (compared, track_object, TRUE);
-
- calculate_next_transition_with_list (track_object, tckobjs_in_layer, layer);
-
-done:
- g_list_foreach (tckobjs_in_layer, (GFunc) g_object_unref, NULL);
- g_list_free (tckobjs_in_layer);
-}
-
-
-static void
-look_for_transition (GESTrackObject * track_object, GESTimelineLayer * layer)
-{
- GESTrack *track;
- GList *track_objects, *tmp, *cur;
-
- track = ges_track_object_get_track (track_object);
- track_objects = ges_track_get_objects (track);
-
- cur = g_list_find (track_objects, track_object);
-
- for (tmp = cur->next; tmp; tmp = tmp->next) {
- if (GES_IS_TRACK_SOURCE (tmp->data)) {
- break;
- }
- if (GES_IS_TRACK_AUDIO_TRANSITION (tmp->data)
- || GES_IS_TRACK_VIDEO_TRANSITION (tmp->data)) {
- ges_timeline_layer_remove_object (layer,
- ges_track_object_get_timeline_object (tmp->data));
- }
- }
-
- for (tmp = cur->prev; tmp; tmp = tmp->prev) {
- if (GES_IS_TRACK_SOURCE (tmp->data)) {
- break;
- }
- if (GES_IS_TRACK_AUDIO_TRANSITION (tmp->data)
- || GES_IS_TRACK_VIDEO_TRANSITION (tmp->data)) {
- ges_timeline_layer_remove_object (layer,
- ges_track_object_get_timeline_object (tmp->data));
- }
- }
- g_list_foreach (track_objects, (GFunc) g_object_unref, NULL);
- g_list_free (track_objects);
-}
-
/**
* ges_timeline_layer_resync_priorities:
* @layer: a #GESTimelineLayer
return TRUE;
}
-/* Callbacks */
-
-static void
-track_object_duration_cb (GESTrackObject * track_object,
- GParamSpec * arg G_GNUC_UNUSED)
-{
- GESTimelineLayer *layer;
- GESTimelineObject *tlobj;
-
- tlobj = ges_track_object_get_timeline_object (track_object);
- layer = ges_timeline_object_get_layer (tlobj);
- if (G_LIKELY (GES_IS_TRACK_SOURCE (track_object)))
- calculate_next_transition (track_object, layer);
-}
-
-static void
-track_object_removed_cb (GESTrack * track, GESTrackObject * track_object)
-{
- GList *track_objects, *tmp, *cur;
- GESTimelineLayer *layer;
-
- track_objects = ges_track_get_objects (track);
- cur = g_list_find (track_objects, track_object);
- for (tmp = cur->next; tmp; tmp = tmp->next) {
- if (GES_IS_TRACK_SOURCE (tmp->data)) {
- break;
- }
- if (GES_IS_TRACK_AUDIO_TRANSITION (tmp->data)
- || GES_IS_TRACK_VIDEO_TRANSITION (tmp->data)) {
- layer =
- ges_timeline_object_get_layer (ges_track_object_get_timeline_object
- (tmp->data));
- if (ges_timeline_layer_get_auto_transition (layer)) {
- ges_track_enable_update (track, FALSE);
- ges_timeline_layer_remove_object (layer,
- ges_track_object_get_timeline_object (tmp->data));
- ges_track_enable_update (track, TRUE);
- }
- g_object_unref (layer);
- }
- }
-
- for (tmp = cur->prev; tmp; tmp = tmp->prev) {
- if (GES_IS_TRACK_SOURCE (tmp->data)) {
- break;
- }
- if (GES_IS_TRACK_AUDIO_TRANSITION (tmp->data)
- || GES_IS_TRACK_VIDEO_TRANSITION (tmp->data)) {
- layer =
- ges_timeline_object_get_layer (ges_track_object_get_timeline_object
- (tmp->data));
- if (ges_timeline_layer_get_auto_transition (layer)) {
- ges_track_enable_update (track, FALSE);
- ges_timeline_layer_remove_object (layer,
- ges_track_object_get_timeline_object (tmp->data));
- ges_track_enable_update (track, TRUE);
- }
- g_object_unref (layer);
- }
- }
- g_object_unref (track_object);
-}
-
-static void
-track_object_changed_cb (GESTrackObject * track_object,
- GParamSpec * arg G_GNUC_UNUSED)
-{
- if (G_LIKELY (GES_IS_TRACK_SOURCE (track_object)))
- calculate_transitions (track_object);
-}
-
-static void
-track_object_added_cb (GESTrack * track, GESTrackObject * track_object,
- GESTimelineLayer * layer)
-{
- if (GES_IS_TRACK_SOURCE (track_object)) {
- g_signal_connect (G_OBJECT (track_object), "notify::start",
- G_CALLBACK (track_object_changed_cb), NULL);
- g_signal_connect (G_OBJECT (track_object), "notify::duration",
- G_CALLBACK (track_object_duration_cb), NULL);
- calculate_transitions (track_object);
- }
-
-}
-
-static void
-track_removed_cb (GESTrack * track, GESTrackObject * track_object,
- GESTimelineLayer * layer)
-{
- g_signal_handlers_disconnect_by_func (track, track_object_added_cb, layer);
- g_signal_handlers_disconnect_by_func (track, track_object_removed_cb, NULL);
-}
-
-static void
-track_added_cb (GESTimeline * timeline, GESTrack * track,
- GESTimelineLayer * layer)
-{
- g_signal_connect (track, "track-object-removed",
- (GCallback) track_object_removed_cb, NULL);
- g_signal_connect (track, "track-object-added",
- (GCallback) track_object_added_cb, NULL);
-}
-
-static void
-timeline_object_height_changed_cb (GESTimelineObject * obj,
- GESTrackEffect * tr_eff, GESTimelineObject * second_obj)
-{
- gint priority, height;
- g_object_get (obj, "height", &height, "priority", &priority, NULL);
- g_object_set (second_obj, "priority", priority + height, NULL);
-}
-
-static void
-start_calculating_transitions (GESTimelineLayer * layer)
-{
- GList *tmp, *tracks = ges_timeline_get_tracks (layer->timeline);
-
- g_signal_connect (layer->timeline, "track-added", G_CALLBACK (track_added_cb),
- layer);
- g_signal_connect (layer->timeline, "track-removed",
- G_CALLBACK (track_removed_cb), layer);
-
- for (tmp = tracks; tmp; tmp = tmp->next) {
- g_signal_connect (G_OBJECT (tmp->data), "track-object-added",
- G_CALLBACK (track_object_added_cb), layer);
- g_signal_connect (G_OBJECT (tmp->data), "track-object-removed",
- G_CALLBACK (track_object_removed_cb), NULL);
- }
-
- g_list_free_full (tracks, g_object_unref);
-
- /* FIXME calculate all the transitions at that time */
-}
-
static void
new_asset_cb (GESAsset * source, GAsyncResult * res, NewAssetUData * udata)
{
GESTimelineObject * object)
{
GESTimelineLayer *current_layer;
- GList *trackobjects, *tmp;
g_return_val_if_fail (GES_IS_TIMELINE_LAYER (layer), FALSE);
g_return_val_if_fail (GES_IS_TIMELINE_OBJECT (object), FALSE);
}
g_object_unref (current_layer);
- if (layer->priv->auto_transition && GES_IS_TIMELINE_SOURCE (object)) {
- trackobjects = ges_timeline_object_get_track_objects (object);
-
- for (tmp = trackobjects; tmp; tmp = tmp->next) {
- look_for_transition (tmp->data, layer);
- }
-
- g_list_foreach (trackobjects, (GFunc) g_object_unref, NULL);
- g_list_free (trackobjects);
- }
-
/* emit 'object-removed' */
g_signal_emit (layer, ges_timeline_layer_signals[OBJECT_REMOVED], 0, object);
g_return_if_fail (GES_IS_TIMELINE_LAYER (layer));
- if (auto_transition && layer->timeline)
- start_calculating_transitions (layer);
-
layer->priv->auto_transition = auto_transition;
g_object_notify (G_OBJECT (layer), "auto-transition");
}
priv = layer->priv;
current_layer = ges_timeline_object_get_layer (object);
-
if (G_UNLIKELY (current_layer)) {
GST_WARNING ("TimelineObject %p already belongs to another layer", object);
g_object_unref (current_layer);
{
GST_DEBUG ("layer:%p, timeline:%p", layer, timeline);
- if (layer->priv->auto_transition == TRUE) {
- if (layer->timeline != NULL) {
- g_signal_handlers_disconnect_by_func (layer->timeline, track_added_cb,
- layer);
- g_signal_handlers_disconnect_by_func (layer->timeline, track_removed_cb,
- layer);
- }
-
- layer->timeline = timeline;
- if (timeline != NULL)
- start_calculating_transitions (layer);
-
- } else
- layer->timeline = timeline;
+ layer->timeline = timeline;
}
#include "ges-timeline.h"
#include "ges-track.h"
#include "ges-timeline-layer.h"
+#include "ges-auto-transition.h"
#include "ges.h"
typedef struct _MoveContext MoveContext;
* probably through a ges_timeline_layer_get_track_objects () method */
GHashTable *by_layer; /* {layer: GSequence of TrackObject by start/priorities} */
+ /* The set of auto_transitions we control, currently the key is
+ * pointerToPreviousiTrackObjAdresspointerToNextTrackObjAdress as a string,
+ * ... not really optimal but it works */
+ GHashTable *auto_transitions;
+
MoveContext movecontext;
+ /* This variable is set to %TRUE when it makes sense to update the transitions,
+ * and %FALSE otherwize */
+ gboolean needs_transitions_update;
+
gboolean updates_enabled;
};
g_hash_table_unref (priv->by_start);
g_hash_table_unref (priv->by_end);
g_hash_table_unref (priv->by_object);
+ g_hash_table_unref (priv->by_layer);
g_hash_table_unref (priv->obj_iters);
g_sequence_free (priv->starts_ends);
g_sequence_free (priv->tracksources);
g_list_free (priv->movecontext.moving_tckobjs);
g_hash_table_unref (priv->movecontext.moving_tlobjs);
+ g_hash_table_unref (priv->auto_transitions);
+
G_OBJECT_CLASS (ges_timeline_parent_class)->dispose (object);
}
priv->starts_ends = g_sequence_new (g_free);
priv->tracksources = g_sequence_new (g_object_unref);
+ priv->auto_transitions =
+ g_hash_table_new_full (g_str_hash, g_str_equal, NULL, gst_object_unref);
+ priv->needs_transitions_update = TRUE;
+
+ priv->updates_enabled = TRUE;
+
g_signal_connect_after (self, "select-tracks-for-object",
G_CALLBACK (select_tracks_for_object_default), NULL);
}
timeline_update_duration (timeline);
}
+static void
+_destroy_auto_transition_cb (GESAutoTransition * auto_transition,
+ GESTimeline * timeline)
+{
+ GESTimelinePrivate *priv = timeline->priv;
+ GESTimelineObject *transition = auto_transition->timeline_transition;
+ GESTimelineLayer *layer = ges_timeline_object_get_layer (transition);
+
+ ges_timeline_layer_remove_object (layer, transition);
+ g_signal_handlers_disconnect_by_func (auto_transition,
+ _destroy_auto_transition_cb, timeline);
+
+ if (!g_hash_table_remove (priv->auto_transitions, auto_transition->key))
+ GST_WARNING_OBJECT (timeline, "Could not remove auto_transition %"
+ GST_PTR_FORMAT, auto_transition->key);
+}
+
+static GESAutoTransition *
+create_transition (GESTimeline * timeline, GESTrackObject * previous,
+ GESTrackObject * next, GESTimelineObject * transition,
+ GESTimelineLayer * layer, guint64 start, guint64 duration)
+{
+ GList *tckobjs;
+ GESAsset *asset;
+ GESAutoTransition *auto_transition;
+
+ if (transition == NULL) {
+ /* TODO make it possible to specify a Transition asset in the API */
+ asset = ges_asset_request (GES_TYPE_TIMELINE_STANDARD_TRANSITION,
+ "crossfade", NULL);
+ transition =
+ ges_timeline_layer_add_asset (layer, asset, start, 0, duration, 1,
+ ges_track_object_get_track_type (next));
+ } else {
+ GST_DEBUG_OBJECT (timeline,
+ "Reusing already existing transition: %" GST_PTR_FORMAT, transition);
+ }
+
+ /* We know there is only 1 TrackObject */
+ tckobjs = ges_timeline_object_get_track_objects (transition);
+ auto_transition = ges_auto_transition_new (tckobjs->data, previous, next);
+ g_list_free_full (tckobjs, gst_object_unref);
+
+ g_signal_connect (auto_transition, "destroy-me",
+ G_CALLBACK (_destroy_auto_transition_cb), timeline);
+
+ g_hash_table_insert (timeline->priv->auto_transitions,
+ auto_transition->key, auto_transition);
+
+ return auto_transition;
+}
+
+typedef GESAutoTransition *(*GetAutoTransitionFunc) (GESTimeline * timeline,
+ GESTimelineLayer * layer, GESTrack * track, GESTrackObject * previous,
+ GESTrackObject * next, GstClockTime transition_duration);
+
+static GESAutoTransition *
+_find_transition_from_auto_transitions (GESTimeline * timeline,
+ GESTimelineLayer * layer, GESTrack * track, GESTrackObject * prev,
+ GESTrackObject * next, GstClockTime transition_duration)
+{
+ GESAutoTransition *auto_transition;
+
+ gchar *key = g_strdup_printf ("%p%p", prev, next);
+
+ auto_transition = g_hash_table_lookup (timeline->priv->auto_transitions, key);
+ g_free (key);
+
+ return auto_transition;
+}
+
+static GESAutoTransition *
+_create_auto_transition_from_transitions (GESTimeline * timeline,
+ GESTimelineLayer * layer, GESTrack * track, GESTrackObject * prev,
+ GESTrackObject * next, GstClockTime transition_duration)
+{
+ GSequenceIter *tmp_iter;
+ GSequence *by_layer_sequence;
+
+ GESTimelinePrivate *priv = timeline->priv;
+ GESAutoTransition *auto_transition =
+ _find_transition_from_auto_transitions (timeline, layer, track, prev,
+ next, transition_duration);
+
+ if (auto_transition)
+ return auto_transition;
+
+
+ /* Try to find a transition that perfectly fits with the one that
+ * should be added at that place
+ * optimize: Use g_sequence_search instead of going over all the
+ * sequence */
+ by_layer_sequence = g_hash_table_lookup (priv->by_layer, layer);
+ for (tmp_iter = g_sequence_get_begin_iter (by_layer_sequence);
+ tmp_iter && !g_sequence_iter_is_end (tmp_iter);
+ tmp_iter = g_sequence_iter_next (tmp_iter)) {
+ GESTrackObject *maybe_transition = g_sequence_get (tmp_iter);
+
+ if (ges_track_object_get_track (maybe_transition) != track)
+ continue;
+
+ if (maybe_transition->start > next->start)
+ break;
+ else if (maybe_transition->start != next->start ||
+ maybe_transition->duration != transition_duration)
+ continue;
+ else if (GES_IS_TRACK_TRANSITION (maybe_transition))
+ /* Use that transition */
+ /* TODO We should make sure that the transition contains only
+ * TrackObject-s in @track and if it is not the case properly unlink the
+ * object to use it */
+ return create_transition (timeline, prev, next,
+ ges_track_object_get_timeline_object (maybe_transition), layer,
+ next->start, transition_duration);
+ }
+
+ return NULL;
+}
+
+/* Create all transition that do not exist on @layer.
+ * @get_auto_transition is called to check if a particular transition exists
+ * if @ track is specified, we will create the transitions only for that particular
+ * track */
+static void
+_create_transitions_on_layer (GESTimeline * timeline, GESTimelineLayer * layer,
+ GESTrack * track, GESTrackObject * initiating_obj,
+ GetAutoTransitionFunc get_auto_transition)
+{
+ guint32 layer_prio;
+ GSequenceIter *iter;
+ GESAutoTransition *transition;
+
+ GESTrack *ctrack = track;
+ GList *entered = NULL; /* List of TrackObject for wich we walk through the
+ * "start" but not the "end" in the starts_ends list */
+ GESTimelinePrivate *priv = timeline->priv;
+
+ if (!layer || !ges_timeline_layer_get_auto_transition (layer))
+ return;
+
+ layer_prio = ges_timeline_layer_get_priority (layer);
+ for (iter = g_sequence_get_begin_iter (priv->starts_ends);
+ iter && !g_sequence_iter_is_end (iter);
+ iter = g_sequence_iter_next (iter)) {
+ GList *tmp;
+ guint *start_or_end = g_sequence_get (iter);
+ GESTrackObject *next = g_hash_table_lookup (timeline->priv->by_object,
+ start_or_end);
+
+ /* Only object that are in that layer and track */
+ if ((next->priority / LAYER_HEIGHT) != layer_prio ||
+ (track && track != ges_track_object_get_track (next)))
+ continue;
+
+ if (track == NULL)
+ ctrack = ges_track_object_get_track (next);
+
+ if (start_or_end == g_hash_table_lookup (priv->by_end, next)) {
+ if (initiating_obj == next) {
+ /* We passed the objects that initiated the research
+ * we are now done */
+ g_list_free (entered);
+ return;
+ }
+ entered = g_list_remove (entered, next);
+
+ continue;
+ }
+
+ for (tmp = entered; tmp; tmp = tmp->next) {
+ gint64 transition_duration;
+
+ GESTrackObject *prev = tmp->data;
+
+ if (ctrack != ges_track_object_get_track (prev))
+ continue;
+
+ transition_duration = (prev->start + prev->duration) - next->start;
+ if (transition_duration > 0 && transition_duration < prev->duration &&
+ transition_duration < next->duration) {
+ transition =
+ get_auto_transition (timeline, layer, ctrack, prev, next,
+ transition_duration);
+ if (!transition)
+ transition = create_transition (timeline, prev, next, NULL, layer,
+ next->start, transition_duration);
+ }
+ }
+
+ /* And add that object to the entered list so that it we can possibly set
+ * a transition on its end edge */
+ entered = g_list_append (entered, next);
+ }
+}
+
+/* @tck_obj must be a GESTrackSource */
+static void
+create_transitions (GESTimeline * timeline, GESTrackObject * tck_obj)
+{
+ GESTrack *track;
+ GList *layer_node;
+
+ GESTimelinePrivate *priv = timeline->priv;
+
+ if (!priv->needs_transitions_update || !priv->updates_enabled)
+ return;
+
+ GST_DEBUG_OBJECT (timeline, "Creating transitions around %p", tck_obj);
+
+ track = ges_track_object_get_track (tck_obj);
+ layer_node = g_list_find_custom (timeline->layers,
+ GINT_TO_POINTER (tck_obj->priority / LAYER_HEIGHT),
+ (GCompareFunc) find_layer_by_prio);
+
+ _create_transitions_on_layer (timeline,
+ layer_node ? layer_node->data : NULL, track, tck_obj,
+ _find_transition_from_auto_transitions);
+
+ GST_DEBUG_OBJECT (timeline, "Done updating transitions");
+}
+
/* Timeline edition functions */
static inline void
init_movecontext (MoveContext * mv_ctx, gboolean first_init)
timeline->priv->movecontext.needs_move_ctx = TRUE;
timeline_update_duration (timeline);
+ create_transitions (timeline, tckobj);
}
}
duration = MAX (0, real_dur);
duration = MIN (duration, max_duration - obj->inpoint);
+ timeline->priv->needs_transitions_update = FALSE;
ges_track_object_set_start (obj, nstart);
- ges_track_object_set_duration (obj, duration);
ges_track_object_set_inpoint (obj, inpoint);
+ timeline->priv->needs_transitions_update = TRUE;
+
+ ges_track_object_set_duration (obj, duration);
break;
case GES_EDGE_END:
{
case GES_EDGE_NONE:
GST_DEBUG ("Simply rippling");
+ /* We should be smart here to avoid recalculate transitions when possible */
cur = g_hash_table_lookup (timeline->priv->by_end, obj);
snapped = ges_timeline_snap_position (timeline, obj, cur, position, TRUE);
if (snapped)
break;
case GES_EDGE_END:
+ timeline->priv->needs_transitions_update = FALSE;
GST_DEBUG ("Rippling end");
cur = g_hash_table_lookup (timeline->priv->by_end, obj);
}
g_list_free (moved_tlobjs);
+ timeline->priv->needs_transitions_update = TRUE;
GST_DEBUG ("Done Rippling end");
break;
case GES_EDGE_START:
duration = ges_track_object_get_duration (obj);
end = start + duration;
+ timeline->priv->needs_transitions_update = FALSE;
switch (edge) {
case GES_EDGE_START:
}
}
+static void
+layer_auto_transition_changed_cb (GESTimelineLayer * layer,
+ GParamSpec * arg G_GNUC_UNUSED, GESTimeline * timeline)
+{
+ _create_transitions_on_layer (timeline, layer, NULL, NULL,
+ _create_auto_transition_from_transitions);
+
+}
+
static void
layer_object_added_cb (GESTimelineLayer * layer, GESTimelineObject * object,
GESTimeline * timeline)
GST_DEBUG ("TimelineObject %p is moving from a layer to another, not doing"
" anything on it", object);
timeline->priv->movecontext.needs_move_ctx = TRUE;
+
+ _create_transitions_on_layer (timeline, layer, NULL, NULL,
+ _find_transition_from_auto_transitions);
+
return;
}
ges_track_object_get_track (trobj),
(GCompareFunc) custom_find_track))) {
GST_DEBUG ("Belongs to one of the tracks we control");
- ges_track_remove_object (ges_track_object_get_track (trobj), trobj);
+ ges_track_remove_object (ges_track_object_get_track (trobj), trobj);
ges_timeline_object_release_track_object (object, trobj);
}
/* removing the reference added by _get_track_objects() */
timeline->priv->snapping_distance == 0)
timeline->priv->movecontext.needs_move_ctx = TRUE;
+ create_transitions (timeline, child);
}
}
timeline->priv->snapping_distance == 0) {
timeline->priv->movecontext.needs_move_ctx = TRUE;
}
+
+ create_transitions (timeline, child);
}
}
{
if (GES_IS_TRACK_SOURCE (object)) {
-
/* Make sure to reinitialise the moving context next time */
timeline->priv->movecontext.needs_move_ctx = TRUE;
}
/* Disconnect all signal handlers */
+ g_signal_handlers_disconnect_by_func (object, trackobj_start_changed_cb,
+ NULL);
g_signal_handlers_disconnect_by_func (object, trackobj_duration_changed_cb,
NULL);
g_signal_handlers_disconnect_by_func (object, trackobj_priority_changed_cb,
NULL);
+
stop_tracking_track_object (timeline, object);
}
G_CALLBACK (layer_object_removed_cb), timeline);
g_signal_connect (layer, "notify::priority",
G_CALLBACK (layer_priority_changed_cb), timeline);
+ g_signal_connect (layer, "notify::auto-transition",
+ G_CALLBACK (layer_auto_transition_changed_cb), timeline);
GST_DEBUG ("Done adding layer, emitting 'layer-added' signal");
g_signal_emit (timeline, ges_timeline_signals[LAYER_ADDED], 0, layer);
g_signal_handlers_disconnect_by_func (layer, layer_object_added_cb, timeline);
g_signal_handlers_disconnect_by_func (layer, layer_object_removed_cb,
timeline);
+ g_signal_handlers_disconnect_by_func (layer, layer_priority_changed_cb,
+ timeline);
+ g_signal_handlers_disconnect_by_func (layer,
+ layer_auto_transition_changed_cb, timeline);
g_hash_table_remove (timeline->priv->by_layer, layer);
timeline->layers = g_list_remove (timeline->layers, layer);
-
ges_timeline_layer_set_timeline (layer, NULL);
g_signal_emit (timeline, ges_timeline_signals[LAYER_REMOVED], 0, layer);
/* Make sure we reset the context */
timeline->priv->movecontext.needs_move_ctx = TRUE;
timeline->priv->updates_enabled = enabled;
+
+ for (tmp = timeline->layers; tmp; tmp = tmp->next) {
+ _create_transitions_on_layer (timeline, GES_TIMELINE_LAYER (tmp->data),
+ NULL, NULL, _find_transition_from_auto_transitions);
+ }
+
if (res)
g_object_notify_by_pspec (G_OBJECT (timeline), properties[PROP_UPDATE]);
GST_END_TEST;
-GST_START_TEST (test_layer_automatic_transition)
+GST_START_TEST (test_single_layer_automatic_transition)
{
+ GESAsset *asset;
GESTimeline *timeline;
+ GList *objects, *current;
+ GESTimelineObject *transition;
GESTimelineLayer *layer;
- GESTimelineTestSource *src, *srcbis;
- GList *objects = NULL, *tmp = NULL;
- gboolean res = FALSE;
+ GESTimelineObject *src, *src1, *src2;
ges_init ();
+ asset = ges_asset_request (GES_TYPE_TIMELINE_TEST_SOURCE, NULL, NULL);
+ fail_unless (GES_IS_ASSET (asset));
+
+ GST_DEBUG ("Create timeline");
timeline = ges_timeline_new_audio_video ();
+ assert_is_type (timeline, GES_TYPE_TIMELINE);
+
+ GST_DEBUG ("Create first layer");
layer = ges_timeline_layer_new ();
- ges_timeline_add_layer (timeline, layer);
+ assert_is_type (layer, GES_TYPE_TIMELINE_LAYER);
- g_object_set (layer, "auto-transition", TRUE, NULL);
- src = ges_timeline_test_source_new ();
- srcbis = ges_timeline_test_source_new ();
+ GST_DEBUG ("Add first layer to timeline");
+ fail_unless (ges_timeline_add_layer (timeline, layer));
- g_object_set (srcbis, "start", (gint64) 5000, "duration", (gint64) 10000LL,
- NULL);
- g_object_set (src, "start", (gint64) 0, "duration", (gint64) 10000LL, NULL);
+ GST_DEBUG ("Set auto transition to first layer");
+ ges_timeline_layer_set_auto_transition (layer, TRUE);
+
+ GST_DEBUG ("Check that auto-transition was properly set");
+ fail_unless (ges_timeline_layer_get_auto_transition (layer));
+
+ GST_DEBUG ("Adding assets to first layer");
+ GST_DEBUG ("Adding object from 0 -- 1000 to first layer");
+ src = GES_TIMELINE_OBJECT (ges_timeline_layer_add_asset (layer, asset, 0, 0,
+ 1000, 1, GES_TRACK_TYPE_UNKNOWN));
+ fail_unless (GES_IS_TIMELINE_OBJECT (src));
+
+ GST_DEBUG ("Adding object from 500 -- 1000 to first layer");
+ src1 = GES_TIMELINE_OBJECT (ges_timeline_layer_add_asset (layer, asset, 500,
+ 0, 1000, 1, GES_TRACK_TYPE_UNKNOWN));
+ fail_unless (GES_IS_TIMELINE_OBJECT (src1));
+
+ /*
+ * 500__transition__1000
+ * 0___________src_________1000
+ * 500___________src1_________1500
+ */
+ GST_DEBUG ("Checking src timing values");
+ assert_equals_uint64 (src->start, 0);
+ assert_equals_uint64 (src->duration, 1000);
+ assert_equals_uint64 (src1->start, 500);
+ assert_equals_uint64 (src1->duration, 1500 - 500);
+
+ GST_DEBUG ("Checking that a transition has been added");
+ objects = ges_timeline_layer_get_objects (layer);
+ assert_equals_int (g_list_length (objects), 4);
+ assert_is_type (objects->data, GES_TYPE_TIMELINE_TEST_SOURCE);
+
+ transition = objects->next->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 500);
+ assert_equals_uint64 (transition->duration, 500);
+
+ transition = objects->next->next->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 500);
+ assert_equals_uint64 (transition->duration, 500);
+ g_list_free_full (objects, gst_object_unref);
+ ASSERT_OBJECT_REFCOUNT (transition, "Only the layer owns a ref", 1);
+
+ GST_DEBUG ("Moving first source to 250");
+ ges_timeline_object_set_start (src, 250);
+
+ /*
+ * 500_____transition____1250
+ * 250___________src_________1250
+ * 500___________src1_________1500
+ */
+ GST_DEBUG ("Checking src timing values");
+ assert_equals_uint64 (src->start, 250);
+ assert_equals_uint64 (src->duration, 1250 - 250);
+ assert_equals_uint64 (src1->start, 500);
+ assert_equals_uint64 (src1->duration, 1500 - 500);
- ges_timeline_layer_add_object (layer, GES_TIMELINE_OBJECT (src));
- ges_timeline_layer_add_object (layer, GES_TIMELINE_OBJECT (srcbis));
+ objects = ges_timeline_layer_get_objects (layer);
+ assert_equals_int (g_list_length (objects), 4);
+ assert_is_type (objects->data, GES_TYPE_TIMELINE_TEST_SOURCE);
+
+ transition = objects->next->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 500);
+ assert_equals_uint64 (transition->duration, 750);
+
+ transition = objects->next->next->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_int (transition->start, 500);
+ assert_equals_uint64 (transition->duration, 750);
+ g_list_free_full (objects, gst_object_unref);
+
+ GST_DEBUG ("Moving second source to 250, the transitions should be removed");
+ ges_timeline_object_set_start (src1, 250);
+
+ /* The transition should be removed
+ * 250___________src_________1250
+ * 250___________src1________1250
+ */
+ GST_DEBUG ("Checking src timing values");
+ assert_equals_uint64 (src->start, 250);
+ assert_equals_uint64 (src->duration, 1250 - 250);
+ assert_equals_uint64 (src1->start, 250);
+ assert_equals_uint64 (src1->duration, 1250 - 250);
objects = ges_timeline_layer_get_objects (layer);
+ assert_equals_int (g_list_length (objects), 2);
+ g_list_free_full (objects, gst_object_unref);
+
+ GST_DEBUG ("Trimming second source to 500 no transition should be created "
+ "as they have the same end");
+ ges_timeline_object_edit (src1, NULL, -1, GES_EDIT_MODE_TRIM, GES_EDGE_START,
+ 500);
+
+ /* 250___________src_________1250
+ * 500______src1_______1250
+ */
+ GST_DEBUG ("Checking src timing values");
+ assert_equals_uint64 (src->start, 250);
+ assert_equals_uint64 (src->duration, 1250 - 250);
+ assert_equals_uint64 (src1->start, 500);
+ assert_equals_uint64 (src1->duration, 1250 - 500);
- for (tmp = objects; tmp; tmp = tmp->next) {
- if (GES_IS_TIMELINE_STANDARD_TRANSITION (tmp->data)) {
- res = TRUE;
- }
- }
+ objects = ges_timeline_layer_get_objects (layer);
+ assert_equals_int (g_list_length (objects), 2);
+ g_list_free_full (objects, gst_object_unref);
+
+ GST_DEBUG ("Trimming second source to 500, no transition should be created");
+ ges_timeline_object_trim_start (src, 500);
+
+ /* 500___________src_________1250
+ * 500___________src1________1250
+ */
+ GST_DEBUG ("Checking src timing values");
+ assert_equals_uint64 (src->start, 500);
+ assert_equals_uint64 (src->duration, 1250 - 500);
+ assert_equals_uint64 (src1->start, 500);
+ assert_equals_uint64 (src1->duration, 1250 - 500);
+
+ GST_DEBUG ("Trimming first source to 750, no transition should be created");
+ ges_timeline_object_trim_start (src, 750);
+
+ /* 750_______src_______1250
+ * 500___________src1________1250
+ */
+ GST_DEBUG ("Checking src timing values");
+ assert_equals_uint64 (src->start, 750);
+ assert_equals_uint64 (src->duration, 1250 - 750);
+ assert_equals_uint64 (src1->start, 500);
+ assert_equals_uint64 (src1->duration, 1250 - 500);
+
+ objects = ges_timeline_layer_get_objects (layer);
+ assert_equals_int (g_list_length (objects), 2);
+ g_list_free_full (objects, gst_object_unref);
+
+ objects = ges_timeline_layer_get_objects (layer);
+ assert_equals_int (g_list_length (objects), 2);
+ g_list_free_full (objects, gst_object_unref);
+
+ GST_DEBUG ("Moving first source to 500, no transition should be created");
+ ges_timeline_object_set_start (src, 500);
+
+ /* 500________src______1000
+ * 500___________src1________1250
+ */
+ GST_DEBUG ("Checking src timing values");
+ assert_equals_uint64 (src->start, 500);
+ assert_equals_uint64 (src->duration, 1000 - 500);
+ assert_equals_uint64 (src1->start, 500);
+ assert_equals_uint64 (src1->duration, 1250 - 500);
+
+ objects = ges_timeline_layer_get_objects (layer);
+ assert_equals_int (g_list_length (objects), 2);
+ g_list_free_full (objects, gst_object_unref);
+
+ objects = ges_timeline_layer_get_objects (layer);
+ assert_equals_int (g_list_length (objects), 2);
+ g_list_free_full (objects, gst_object_unref);
+
+ GST_DEBUG ("Moving first source to 600, no transition should be created");
+ ges_timeline_object_set_start (src, 600);
+ /* 600____src___1100
+ * 500___________src1________1250
+ */
+ GST_DEBUG ("Checking src timing values");
+ assert_equals_uint64 (src->start, 600);
+ assert_equals_uint64 (src->duration, 1100 - 600);
+ assert_equals_uint64 (src1->start, 500);
+ assert_equals_uint64 (src1->duration, 1250 - 500);
+
+ objects = ges_timeline_layer_get_objects (layer);
+ assert_equals_int (g_list_length (objects), 2);
+ g_list_free_full (objects, gst_object_unref);
+
+ objects = ges_timeline_layer_get_objects (layer);
+ assert_equals_int (g_list_length (objects), 2);
+ g_list_free_full (objects, gst_object_unref);
+
+ GST_DEBUG ("Adding asset to first layer");
+ GST_DEBUG ("Adding object from 1250 -- 1000 to first layer");
+ src2 =
+ GES_TIMELINE_OBJECT (ges_timeline_layer_add_asset (layer, asset, 1250, 0,
+ 1000, 1, GES_TRACK_TYPE_UNKNOWN));
+ assert_is_type (src2, GES_TYPE_TIMELINE_TEST_SOURCE);
+
+ /* 600____src___1100
+ * 500___________src1________1250
+ * 1250___________src2________2250
+ */
+ assert_equals_uint64 (src->start, 600);
+ assert_equals_uint64 (src->duration, 1100 - 600);
+ assert_equals_uint64 (src1->start, 500);
+ assert_equals_uint64 (src1->duration, 1250 - 500);
+ assert_equals_uint64 (src2->start, 1250);
+ assert_equals_uint64 (src2->duration, 1000);
+
+ objects = ges_timeline_layer_get_objects (layer);
+ assert_equals_int (g_list_length (objects), 3);
+ g_list_free_full (objects, gst_object_unref);
+
+ GST_DEBUG
+ ("Changig first source duration to 800 2 transitions should be created");
+ ges_timeline_object_set_duration (src, 800);
+ /* 600__________________src_____________1400
+ * 500___________src1________1250
+ * 1250___________src2________2250
+ * 600_____trans1_______1250
+ * 1250___trans2___1400
+ */
+ GST_DEBUG ("Checking src timing values");
+ assert_equals_uint64 (src->start, 600);
+ assert_equals_uint64 (src->duration, 1400 - 600);
+ assert_equals_uint64 (src1->start, 500);
+ assert_equals_uint64 (src1->duration, 1250 - 500);
+
+ current = objects = ges_timeline_layer_get_objects (layer);
+ assert_equals_int (g_list_length (objects), 7);
+ assert_is_type (objects->data, GES_TYPE_TIMELINE_TEST_SOURCE);
+ fail_unless (objects->data == src1);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 600);
+ assert_equals_uint64 (transition->duration, 1250 - 600);
+ ASSERT_OBJECT_REFCOUNT (transition, "The layer and ourself own a ref", 2);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 600);
+ assert_equals_uint64 (transition->duration, 1250 - 600);
+ ASSERT_OBJECT_REFCOUNT (transition, "The layer and ourself own a ref", 2);
+
+ current = current->next;
+ fail_unless (current->data == src);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 1250);
+ assert_equals_uint64 (transition->duration, 1400 - 1250);
+ ASSERT_OBJECT_REFCOUNT (transition, "The layer and ourself own a ref", 2);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 1250);
+ assert_equals_uint64 (transition->duration, 1400 - 1250);
+ ASSERT_OBJECT_REFCOUNT (transition, "The layer and ourself own a ref", 2);
+
+ current = current->next;
+ fail_unless (current->data == src2);
+ g_list_free_full (objects, gst_object_unref);
+
+ GST_DEBUG ("Back to previous state");
+ ges_timeline_object_set_duration (src, 1100 - 600);
+ /* 600____src___1100
+ * 500___________src1________1250
+ * 1250___________src2________2250
+ */
+ assert_equals_uint64 (src->start, 600);
+ assert_equals_uint64 (src->duration, 1100 - 600);
+ assert_equals_uint64 (src1->start, 500);
+ assert_equals_uint64 (src1->duration, 1250 - 500);
+ assert_equals_uint64 (src2->start, 1250);
+ assert_equals_uint64 (src2->duration, 1000);
+
+ /* We check that the transition as actually been freed */
+ fail_if (GES_IS_TIMELINE_STANDARD_TRANSITION (transition));
+
+ objects = ges_timeline_layer_get_objects (layer);
+ assert_equals_int (g_list_length (objects), 3);
+ g_list_free_full (objects, gst_object_unref);
+
+ GST_DEBUG
+ ("Set third object start to 1100, 1 new transition should be created");
+ ges_timeline_object_set_start (src2, 1100);
+ /* 600____src___1100
+ * 500___________src1________1250
+ * 1100___________src2________2100
+ * ^__trans___^
+ */
+ assert_equals_uint64 (src->start, 600);
+ assert_equals_uint64 (src->duration, 1100 - 600);
+ assert_equals_uint64 (src1->start, 500);
+ assert_equals_uint64 (src1->duration, 1250 - 500);
+ assert_equals_uint64 (src2->start, 1100);
+ assert_equals_uint64 (src2->duration, 1000);
+
+ current = objects = ges_timeline_layer_get_objects (layer);
+ assert_equals_int (g_list_length (objects), 5);
+ assert_is_type (objects->data, GES_TYPE_TIMELINE_TEST_SOURCE);
+ fail_unless (current->data == src1);
+
+ current = current->next;
+ fail_unless (current->data == src);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 1100);
+ assert_equals_uint64 (transition->duration, 1250 - 1100);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 1100);
+ assert_equals_uint64 (transition->duration, 1250 - 1100);
+
+ current = current->next;
+ fail_unless (current->data == src2);
+ g_list_free_full (objects, gst_object_unref);
+
+ GST_DEBUG ("Set third object start to 1000, Transition should be updated");
+ ges_timeline_object_edit (src2, NULL, -1, GES_EDIT_MODE_NORMAL,
+ GES_EDGE_START, 1000);
+ /* 600____src___1100
+ * !_tr__^
+ * 500___________src1________1250
+ * 1000___________src2________2000
+ * ^____trans____^
+ */
+ assert_equals_uint64 (src->start, 600);
+ assert_equals_uint64 (src->duration, 500);
+ assert_equals_uint64 (src1->start, 500);
+ assert_equals_uint64 (src1->duration, 1250 - 500);
+ assert_equals_uint64 (src2->start, 1000);
+ assert_equals_uint64 (src2->duration, 1000);
+
+ current = objects = ges_timeline_layer_get_objects (layer);
+ current = objects;
+ assert_equals_int (g_list_length (objects), 7);
+ assert_is_type (objects->data, GES_TYPE_TIMELINE_TEST_SOURCE);
+ fail_unless (current->data == src1);
+
+ current = current->next;
+ fail_unless (current->data == src);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 1000);
+ assert_equals_uint64 (transition->duration, 1100 - 1000);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 1000);
+ assert_equals_uint64 (transition->duration, 1100 - 1000);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 1000);
+ assert_equals_uint64 (transition->duration, 1250 - 1000);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 1000);
+ assert_equals_uint64 (transition->duration, 1250 - 1000);
+
+ current = current->next;
+ fail_unless (current->data == src2);
+ g_list_free_full (objects, gst_object_unref);
+
+ g_object_unref (timeline);
+}
- fail_unless (res == TRUE);
+GST_END_TEST;
+
+GST_START_TEST (test_multi_layer_automatic_transition)
+{
+ GESAsset *asset;
+ GESTimeline *timeline;
+ GList *objects, *current;
+ GESTimelineObject *transition;
+ GESTimelineLayer *layer, *layer1;
+ GESTimelineObject *src, *src1, *src2, *src3;
+
+ ges_init ();
+
+ asset = ges_asset_request (GES_TYPE_TIMELINE_TEST_SOURCE, NULL, NULL);
+ fail_unless (GES_IS_ASSET (asset));
+
+ GST_DEBUG ("Create timeline");
+ timeline = ges_timeline_new_audio_video ();
+ assert_is_type (timeline, GES_TYPE_TIMELINE);
+
+ GST_DEBUG ("Create first layer");
+ layer = ges_timeline_layer_new ();
+ assert_is_type (layer, GES_TYPE_TIMELINE_LAYER);
+
+ GST_DEBUG ("Add first layer to timeline");
+ fail_unless (ges_timeline_add_layer (timeline, layer));
+
+ GST_DEBUG ("Append a new layer to the timeline");
+ layer1 = ges_timeline_append_layer (timeline);
+ assert_is_type (layer1, GES_TYPE_TIMELINE_LAYER);
+
+ GST_DEBUG ("Set auto transition to first layer");
+ ges_timeline_layer_set_auto_transition (layer, TRUE);
+
+ GST_DEBUG ("Check that auto-transition was properly set");
+ fail_unless (ges_timeline_layer_get_auto_transition (layer));
+ fail_if (ges_timeline_layer_get_auto_transition (layer1));
+
+ GST_DEBUG ("Adding assets to first layer");
+ GST_DEBUG ("Adding object from 0 -- 1000 to first layer");
+ src = GES_TIMELINE_OBJECT (ges_timeline_layer_add_asset (layer, asset, 0, 0,
+ 1000, 1, GES_TRACK_TYPE_UNKNOWN));
+ fail_unless (GES_IS_TIMELINE_OBJECT (src));
+
+ GST_DEBUG ("Adding object from 500 -- 1000 to first layer");
+ src1 = GES_TIMELINE_OBJECT (ges_timeline_layer_add_asset (layer, asset, 500,
+ 0, 1000, 1, GES_TRACK_TYPE_UNKNOWN));
+ fail_unless (GES_IS_TIMELINE_OBJECT (src1));
+
+ /*
+ * 500__transition__1000
+ * 0___________src_________1000
+ * 500___________src1_________1500
+ */
+ GST_DEBUG ("Checking src timing values");
+ assert_equals_uint64 (src->start, 0);
+ assert_equals_uint64 (src->duration, 1000);
+ assert_equals_uint64 (src1->start, 500);
+ assert_equals_uint64 (src1->duration, 1500 - 500);
+
+ GST_DEBUG ("Checking that a transition has been added");
+ current = objects = ges_timeline_layer_get_objects (layer);
+ assert_equals_int (g_list_length (objects), 4);
+ assert_is_type (current->data, GES_TYPE_TIMELINE_TEST_SOURCE);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 500);
+ assert_equals_uint64 (transition->duration, 500);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 500);
+ assert_equals_uint64 (transition->duration, 500);
+ g_list_free_full (objects, gst_object_unref);
+ ASSERT_OBJECT_REFCOUNT (transition, "Only the layer owns a ref", 1);
+
+ GST_DEBUG ("Adding object 2 from 500 -- 1000 to second layer");
+ src2 = GES_TIMELINE_OBJECT (ges_timeline_layer_add_asset (layer1, asset, 0,
+ 0, 1000, 1, GES_TRACK_TYPE_UNKNOWN));
+ GST_DEBUG ("Adding object 3 from 500 -- 1000 to second layer");
+ src3 = GES_TIMELINE_OBJECT (ges_timeline_layer_add_asset (layer1, asset, 500,
+ 0, 1000, 1, GES_TRACK_TYPE_UNKNOWN));
+ assert_is_type (src3, GES_TYPE_TIMELINE_TEST_SOURCE);
+
+ /* 500__transition__1000
+ * 0___________src_________1000
+ * 500___________src1_________1500
+ *----------------------------------------------------
+ * 0___________src2_________1000
+ * 500___________src3_________1500 Layer1
+ */
+ GST_DEBUG ("Checking src timing values");
+ assert_equals_uint64 (src->start, 0);
+ assert_equals_uint64 (src->duration, 1000);
+ assert_equals_uint64 (src1->start, 500);
+ assert_equals_uint64 (src1->duration, 1500 - 500);
+ assert_equals_uint64 (src2->start, 0);
+ assert_equals_uint64 (src2->duration, 1000);
+ assert_equals_uint64 (src3->start, 500);
+ assert_equals_uint64 (src3->duration, 1500 - 500);
+
+ GST_DEBUG ("Checking transitions on first layer");
+ current = objects = ges_timeline_layer_get_objects (layer);
+ assert_equals_int (g_list_length (objects), 4);
+ assert_is_type (current->data, GES_TYPE_TIMELINE_TEST_SOURCE);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 500);
+ assert_equals_uint64 (transition->duration, 500);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 500);
+ assert_equals_uint64 (transition->duration, 500);
+ g_list_free_full (objects, gst_object_unref);
+ ASSERT_OBJECT_REFCOUNT (transition, "Only the layer owns a ref", 1);
+
+ GST_DEBUG ("Checking transitions on second layer");
+ current = objects = ges_timeline_layer_get_objects (layer1);
+ assert_equals_int (g_list_length (objects), 2);
+ fail_unless (current->data == src2);
+ fail_unless (current->next->data == src3);
+ g_list_free_full (objects, gst_object_unref);
+
+ GST_DEBUG
+ ("Set auto transition to second layer, a new transition should be added");
+ ges_timeline_layer_set_auto_transition (layer1, TRUE);
+
+ /* 500__transition__1000
+ * 0___________src_________1000
+ * 500___________src1_________1500
+ *----------------------------------------------------
+ * 500__transition__1000
+ * 0__________src2_________1000
+ * 500___________src3_________1500 Layer1
+ */
+ GST_DEBUG ("Checking src timing values");
+ assert_equals_uint64 (src->start, 0);
+ assert_equals_uint64 (src->duration, 1000);
+ assert_equals_uint64 (src1->start, 500);
+ assert_equals_uint64 (src1->duration, 1500 - 500);
+ assert_equals_uint64 (src2->start, 0);
+ assert_equals_uint64 (src2->duration, 1000);
+ assert_equals_uint64 (src3->start, 500);
+ assert_equals_uint64 (src3->duration, 1500 - 500);
+
+ GST_DEBUG ("Checking transitions on first layer");
+ current = objects = ges_timeline_layer_get_objects (layer);
+ assert_equals_int (g_list_length (objects), 4);
+ assert_is_type (current->data, GES_TYPE_TIMELINE_TEST_SOURCE);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 500);
+ assert_equals_uint64 (transition->duration, 500);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 500);
+ assert_equals_uint64 (transition->duration, 500);
+ g_list_free_full (objects, gst_object_unref);
+ ASSERT_OBJECT_REFCOUNT (transition, "Only the layer owns a ref", 1);
+
+ GST_DEBUG ("Checking transitions has been added on second layer");
+ current = objects = ges_timeline_layer_get_objects (layer1);
+ assert_equals_int (g_list_length (objects), 4);
+ assert_is_type (current->data, GES_TYPE_TIMELINE_TEST_SOURCE);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 500);
+ assert_equals_uint64 (transition->duration, 500);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 500);
+ assert_equals_uint64 (transition->duration, 500);
+ g_list_free_full (objects, gst_object_unref);
+ ASSERT_OBJECT_REFCOUNT (transition, "Only the layer owns a ref", 1);
+
+ GST_DEBUG ("Moving src3 to 1000. should remove transition");
+ ges_timeline_object_set_start (src3, 1000);
+
+ /* 500__transition__1000
+ * 0___________src_________1000
+ * 500___________src1_________1500 Layer
+ *----------------------------------------------------
+ * 0__________src2_________1000
+ * 1000___________src3_________2000 Layer1
+ */
+ GST_DEBUG ("Checking src timing values");
+ assert_equals_uint64 (src->start, 0);
+ assert_equals_uint64 (src->duration, 1000);
+ assert_equals_uint64 (src1->start, 500);
+ assert_equals_uint64 (src1->duration, 1500 - 500);
+ assert_equals_uint64 (src2->start, 0);
+ assert_equals_uint64 (src2->duration, 1000);
+ assert_equals_uint64 (src3->start, 1000);
+ assert_equals_uint64 (src3->duration, 2000 - 1000);
+
+ GST_DEBUG ("Checking transitions on first layer");
+ current = objects = ges_timeline_layer_get_objects (layer);
+ assert_equals_int (g_list_length (objects), 4);
+ assert_is_type (current->data, GES_TYPE_TIMELINE_TEST_SOURCE);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 500);
+ assert_equals_uint64 (transition->duration, 500);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 500);
+ assert_equals_uint64 (transition->duration, 500);
+ g_list_free_full (objects, gst_object_unref);
+ ASSERT_OBJECT_REFCOUNT (transition, "Only the layer owns a ref", 1);
+
+ GST_DEBUG ("Checking transitions has been removed on second layer");
+ current = objects = ges_timeline_layer_get_objects (layer1);
+ assert_equals_int (g_list_length (objects), 2);
+ fail_unless (current->data == src2);
+ fail_unless (current->next->data == src3);
+ g_list_free_full (objects, gst_object_unref);
+ ASSERT_OBJECT_REFCOUNT (transition, "Only the layer owns a ref", 1);
+
+ GST_DEBUG ("Moving src3 to first layer, should add a transition");
+ ges_timeline_object_move_to_layer (src3, layer);
+
+ /* 500__transition__1000
+ * 0___________src_________1000
+ * 500___________src1_________1500
+ * 1000___________src3_________2000 Layer
+ * 1000__tr__1500
+ *----------------------------------------------------
+ * 0__________src2_________1000 Layer1
+ */
+ GST_DEBUG ("Checking src timing values");
+ assert_equals_uint64 (src->start, 0);
+ assert_equals_uint64 (src->duration, 1000);
+ assert_equals_uint64 (src1->start, 500);
+ assert_equals_uint64 (src1->duration, 1500 - 500);
+ assert_equals_uint64 (src2->start, 0);
+ assert_equals_uint64 (src2->duration, 1000);
+ assert_equals_uint64 (src3->start, 1000);
+ assert_equals_uint64 (src3->duration, 2000 - 1000);
+
+ GST_DEBUG ("Checking transitions on first layer");
+ current = objects = ges_timeline_layer_get_objects (layer);
+ assert_equals_int (g_list_length (objects), 7);
+ fail_unless (current->data == src);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 500);
+ assert_equals_uint64 (transition->duration, 500);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 500);
+ assert_equals_uint64 (transition->duration, 500);
+
+ current = current->next;
+ fail_unless (current->data == src1);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 1000);
+ assert_equals_uint64 (transition->duration, 1500 - 1000);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 1000);
+ assert_equals_uint64 (transition->duration, 1500 - 1000);
+
+ current = current->next;
+ fail_unless (current->data == src3);
+
+ g_list_free_full (objects, gst_object_unref);
+ ASSERT_OBJECT_REFCOUNT (transition, "Only the layer owns a ref", 1);
+
+ GST_DEBUG ("Checking second layer");
+ current = objects = ges_timeline_layer_get_objects (layer1);
+ assert_equals_int (g_list_length (objects), 1);
+ fail_unless (current->data == src2);
+ g_list_free_full (objects, gst_object_unref);
+ ASSERT_OBJECT_REFCOUNT (transition, "Only the layer owns a ref", 1);
+
+ GST_DEBUG
+ ("Moving src to second layer, should remove first transition on first layer");
+ ges_timeline_object_move_to_layer (src, layer1);
+
+ /* 500___________src1_________1500
+ * 1000___________src3_________2000 Layer
+ * 1000__tr__1500
+ *----------------------------------------------------
+ * 0___________src_________1000
+ * 0__________src2_________1000 Layer1
+ */
+ GST_DEBUG ("Checking src timing values");
+ assert_equals_uint64 (src->start, 0);
+ assert_equals_uint64 (src->duration, 1000);
+ assert_equals_uint64 (src1->start, 500);
+ assert_equals_uint64 (src1->duration, 1500 - 500);
+ assert_equals_uint64 (src2->start, 0);
+ assert_equals_uint64 (src2->duration, 1000);
+ assert_equals_uint64 (src3->start, 1000);
+ assert_equals_uint64 (src3->duration, 2000 - 1000);
+
+ GST_DEBUG ("Checking transitions on first layer");
+ current = objects = ges_timeline_layer_get_objects (layer);
+ assert_equals_int (g_list_length (objects), 4);
+ fail_unless (current->data == src1);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 1000);
+ assert_equals_uint64 (transition->duration, 500);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 1000);
+ assert_equals_uint64 (transition->duration, 500);
+
+ current = current->next;
+ fail_unless (current->data == src3);
+ g_list_free_full (objects, gst_object_unref);
+ ASSERT_OBJECT_REFCOUNT (transition, "Only the layer owns a ref", 1);
+
+ GST_DEBUG ("Checking second layer");
+ current = objects = ges_timeline_layer_get_objects (layer1);
+ assert_equals_int (g_list_length (objects), 2);
+ assert_is_type (current->data, GES_TYPE_TIMELINE_TEST_SOURCE);
+ assert_is_type (current->next->data, GES_TYPE_TIMELINE_TEST_SOURCE);
+ g_list_free_full (objects, gst_object_unref);
+ ASSERT_OBJECT_REFCOUNT (transition, "Only the layer owns a ref", 1);
+
+ GST_DEBUG ("Edit src to first layer start=1500");
+ ges_timeline_object_edit (src, NULL, 0, GES_EDIT_MODE_NORMAL, GES_EDGE_NONE,
+ 1500);
+ /* 1500___________src_________2500
+ * 1500______tr______2000
+ * 500___________src1_________1500 ^
+ * 1000_________^_src3_________2000 Layer
+ * 1000__tr__1500
+ *---------------------------------------------------------------------------
+ * 0__________src2_________1000 Layer1
+ */
+ GST_DEBUG ("Checking src timing values");
+ assert_equals_uint64 (src->start, 1500);
+ assert_equals_uint64 (src->duration, 1000);
+ assert_equals_uint64 (src1->start, 500);
+ assert_equals_uint64 (src1->duration, 1500 - 500);
+ assert_equals_uint64 (src2->start, 0);
+ assert_equals_uint64 (src2->duration, 1000);
+ assert_equals_uint64 (src3->start, 1000);
+ assert_equals_uint64 (src3->duration, 2000 - 1000);
+
+ GST_DEBUG ("Checking transitions on first layer");
+ current = objects = ges_timeline_layer_get_objects (layer);
+ assert_equals_int (g_list_length (objects), 7);
+ fail_unless (current->data == src1);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 1000);
+ assert_equals_uint64 (transition->duration, 500);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 1000);
+ assert_equals_uint64 (transition->duration, 500);
+
+ current = current->next;
+ fail_unless (current->data == src3);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 1500);
+ assert_equals_uint64 (transition->duration, 500);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 1500);
+ assert_equals_uint64 (transition->duration, 500);
+
+ current = current->next;
+ fail_unless (current->data == src);
+ g_list_free_full (objects, gst_object_unref);
+ ASSERT_OBJECT_REFCOUNT (transition, "Only the layer owns a ref", 1);
+
+ GST_DEBUG ("Checking second layer");
+ current = objects = ges_timeline_layer_get_objects (layer1);
+ assert_equals_int (g_list_length (objects), 1);
+ assert_is_type (current->data, GES_TYPE_TIMELINE_TEST_SOURCE);
+ g_list_free_full (objects, gst_object_unref);
+ ASSERT_OBJECT_REFCOUNT (transition, "Only the layer owns a ref", 1);
+
+ GST_DEBUG ("Ripple src1 to 700");
+ ges_timeline_object_edit (src1, NULL, 0, GES_EDIT_MODE_RIPPLE, GES_EDGE_NONE,
+ 700);
+ /* 1700___________src_________2700
+ * 1700__tr__2000
+ * 700___________src1_________1700
+ * 1000___________src3_________2000 Layer
+ * 1000______tr______1700
+ *---------------------------------------------------------------------------
+ * 0__________src2_________1000 Layer1
+ */
+ GST_DEBUG ("Checking src timing values");
+ assert_equals_uint64 (src->start, 1700);
+ assert_equals_uint64 (src->duration, 1000);
+ assert_equals_uint64 (src1->start, 700);
+ assert_equals_uint64 (src1->duration, 1700 - 700);
+ assert_equals_uint64 (src2->start, 0);
+ assert_equals_uint64 (src2->duration, 1000);
+ assert_equals_uint64 (src3->start, 1000);
+ assert_equals_uint64 (src3->duration, 2000 - 1000);
+
+ GST_DEBUG ("Checking transitions on first layer");
+ current = objects = ges_timeline_layer_get_objects (layer);
+ assert_equals_int (g_list_length (objects), 7);
+ fail_unless (current->data == src1);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 1000);
+ assert_equals_uint64 (transition->duration, 1700 - 1000);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 1000);
+ assert_equals_uint64 (transition->duration, 1700 - 1000);
+
+ current = current->next;
+ fail_unless (current->data == src3);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 1700);
+ assert_equals_uint64 (transition->duration, 2000 - 1700);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 1700);
+ assert_equals_uint64 (transition->duration, 2000 - 1700);
+
+ current = current->next;
+ fail_unless (current->data == src);
+ g_list_free_full (objects, gst_object_unref);
+ ASSERT_OBJECT_REFCOUNT (transition, "Only the layer owns a ref", 1);
+
+ GST_DEBUG ("Checking second layer");
+ current = objects = ges_timeline_layer_get_objects (layer1);
+ assert_equals_int (g_list_length (objects), 1);
+ assert_is_type (current->data, GES_TYPE_TIMELINE_TEST_SOURCE);
+ g_list_free_full (objects, gst_object_unref);
+ ASSERT_OBJECT_REFCOUNT (transition, "Only the layer owns a ref", 1);
+
+ g_object_unref (timeline);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_layer_activate_automatic_transition)
+{
+ GESAsset *asset, *transition_asset;
+ GESTimeline *timeline;
+ GESTimelineLayer *layer;
+ GList *objects, *current;
+ GESTimelineObject *transition;
+ GESTimelineObject *src, *src1, *src2, *src3;
+
+ ges_init ();
+
+ asset = ges_asset_request (GES_TYPE_TIMELINE_TEST_SOURCE, NULL, NULL);
+ transition_asset =
+ ges_asset_request (GES_TYPE_TIMELINE_STANDARD_TRANSITION, "crossfade",
+ NULL);
+ fail_unless (GES_IS_ASSET (asset));
+
+ GST_DEBUG ("Create timeline");
+ timeline = ges_timeline_new_audio_video ();
+ assert_is_type (timeline, GES_TYPE_TIMELINE);
+
+ GST_DEBUG ("Append a layer to the timeline");
+ layer = ges_timeline_append_layer (timeline);
+ assert_is_type (layer, GES_TYPE_TIMELINE_LAYER);
+
+ GST_DEBUG ("Adding object from 0 -- 1000 to layer");
+ src = GES_TIMELINE_OBJECT (ges_timeline_layer_add_asset (layer, asset, 0, 0,
+ 1000, 1, GES_TRACK_TYPE_UNKNOWN));
+ fail_unless (GES_IS_TIMELINE_OBJECT (src));
+
+ GST_DEBUG ("Adding object from 500 -- 1000 to first layer");
+ src1 = GES_TIMELINE_OBJECT (ges_timeline_layer_add_asset (layer, asset, 500,
+ 0, 1000, 1, GES_TRACK_TYPE_UNKNOWN));
+ fail_unless (GES_IS_TIMELINE_OBJECT (src1));
+
+ GST_DEBUG ("Adding object from 1000 -- 2000 to layer");
+ src2 = GES_TIMELINE_OBJECT (ges_timeline_layer_add_asset (layer, asset, 1000,
+ 0, 1000, 1, GES_TRACK_TYPE_UNKNOWN));
+ fail_unless (GES_IS_TIMELINE_OBJECT (src2));
+
+ GST_DEBUG ("Adding object from 2000 -- 2500 to layer");
+ src3 = GES_TIMELINE_OBJECT (ges_timeline_layer_add_asset (layer, asset, 2000,
+ 0, 500, 1, GES_TRACK_TYPE_UNKNOWN));
+ fail_unless (GES_IS_TIMELINE_OBJECT (src3));
+
+ /*
+ * 0___________src_________1000
+ * 500___________src1_________1500
+ * 1000____src2_______2000
+ * 2000_______src2_____2500
+ */
+ GST_DEBUG ("Checking src timing values");
+ assert_equals_uint64 (src->start, 0);
+ assert_equals_uint64 (src->duration, 1000);
+ assert_equals_uint64 (src1->start, 500);
+ assert_equals_uint64 (src1->duration, 1500 - 500);
+ assert_equals_uint64 (src2->start, 1000);
+ assert_equals_uint64 (src2->duration, 1000);
+ assert_equals_uint64 (src3->start, 2000);
+ assert_equals_uint64 (src3->duration, 500);
+
+ GST_DEBUG ("Checking that no transition has been added");
+ current = objects = ges_timeline_layer_get_objects (layer);
+ assert_equals_int (g_list_length (objects), 4);
+ assert_is_type (current->data, GES_TYPE_TIMELINE_TEST_SOURCE);
+ g_list_free_full (objects, gst_object_unref);
+
+ GST_DEBUG ("Adding transition from 1000 -- 1500 to layer");
+ transition =
+ GES_TIMELINE_OBJECT (ges_timeline_layer_add_asset (layer,
+ transition_asset, 1000, 0, 500, 1, GES_TRACK_TYPE_VIDEO));
+ fail_unless (GES_IS_TIMELINE_STANDARD_TRANSITION (transition));
+ objects = ges_timeline_object_get_track_objects (transition);
+ assert_equals_int (g_list_length (objects), 1);
+ g_list_free_full (objects, gst_object_unref);
+
+ GST_DEBUG ("Checking the transitions");
+ /*
+ * 0___________src_________1000
+ * 500___________src1_________1500
+ * 1000__tr__1500 (1 of the 2 tracks only)
+ * 1000____src2_______2000
+ * 2000_______src3_____2500
+ */
+ current = objects = ges_timeline_layer_get_objects (layer);
+ assert_equals_int (g_list_length (objects), 5);
+ current = current->next;
+ assert_is_type (current->data, GES_TYPE_TIMELINE_TEST_SOURCE);
+ current = current->next;
+ assert_is_type (current->data, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ current = current->next;
+ assert_is_type (current->data, GES_TYPE_TIMELINE_TEST_SOURCE);
+ current = current->next;
+ assert_is_type (current->data, GES_TYPE_TIMELINE_TEST_SOURCE);
+ g_list_free_full (objects, gst_object_unref);
+
+ ges_timeline_layer_set_auto_transition (layer, TRUE);
+ /*
+ * 0___________src_________1000
+ * 500______tr______1000
+ * 500___________src1_________1500
+ * 1000__tr__1500
+ * 1000____src2_______2000
+ * 2000_______src3_____2500
+ */
+ current = objects = ges_timeline_layer_get_objects (layer);
+ assert_equals_int (g_list_length (objects), 8);
+ assert_equals_uint64 (src->start, 0);
+ assert_equals_uint64 (src->duration, 1000);
+ assert_equals_uint64 (src1->start, 500);
+ assert_equals_uint64 (src1->duration, 1500 - 500);
+ assert_equals_uint64 (src2->start, 1000);
+ assert_equals_uint64 (src2->duration, 1000);
+ assert_equals_uint64 (src3->start, 2000);
+ assert_equals_uint64 (src3->duration, 500);
+
+ GST_DEBUG ("Checking transitions");
+ fail_unless (current->data == src);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 500);
+ assert_equals_uint64 (transition->duration, 500);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 500);
+ assert_equals_uint64 (transition->duration, 500);
+
+ current = current->next;
+ fail_unless (current->data == src1);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 1000);
+ assert_equals_uint64 (transition->duration, 500);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 1000);
+ assert_equals_uint64 (transition->duration, 500);
+
+ current = current->next;
+ fail_unless (current->data == src2);
+
+ current = current->next;
+ fail_unless (current->data == src3);
+ g_list_free_full (objects, gst_object_unref);
+ ASSERT_OBJECT_REFCOUNT (transition, "Only the layer owns a ref", 1);
+
+ GST_DEBUG ("Moving src2 to 1200, check everything updates properly");
+ ges_timeline_object_set_start (src2, 1200);
+ /*
+ * 0___________src_________1000
+ * 500______tr______1000
+ * 500___________src1_________1500
+ * 1200_tr_1500
+ * 1200____src2_______2200
+ * !__tr__^
+ * 2000_______src3_____2500
+ */
+ current = objects = ges_timeline_layer_get_objects (layer);
+ assert_equals_int (g_list_length (objects), 10);
+ assert_equals_uint64 (src->start, 0);
+ assert_equals_uint64 (src->duration, 1000);
+ assert_equals_uint64 (src1->start, 500);
+ assert_equals_uint64 (src1->duration, 1500 - 500);
+ assert_equals_uint64 (src2->start, 1200);
+ assert_equals_uint64 (src2->duration, 1000);
+ assert_equals_uint64 (src3->start, 2000);
+ assert_equals_uint64 (src3->duration, 500);
+
+ GST_DEBUG ("Checking transitions");
+ fail_unless (current->data == src);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 500);
+ assert_equals_uint64 (transition->duration, 500);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 500);
+ assert_equals_uint64 (transition->duration, 500);
+
+ current = current->next;
+ fail_unless (current->data == src1);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 1200);
+ assert_equals_uint64 (transition->duration, 300);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 1200);
+ assert_equals_uint64 (transition->duration, 300);
+
+ current = current->next;
+ fail_unless (current->data == src2);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 2000);
+ assert_equals_uint64 (transition->duration, 200);
+
+ current = current->next;
+ transition = current->data;
+ assert_is_type (transition, GES_TYPE_TIMELINE_STANDARD_TRANSITION);
+ assert_equals_uint64 (transition->start, 2000);
+ assert_equals_uint64 (transition->duration, 200);
+
+ current = current->next;
+ fail_unless (current->data == src3);
+ g_list_free_full (objects, gst_object_unref);
+ ASSERT_OBJECT_REFCOUNT (transition, "Only the layer owns a ref", 1);
+
+
+ gst_object_unref (timeline);
}
GST_END_TEST;
tcase_add_test (tc_chain, test_layer_properties);
tcase_add_test (tc_chain, test_layer_priorities);
- tcase_add_test (tc_chain, test_layer_automatic_transition);
+ tcase_add_test (tc_chain, test_single_layer_automatic_transition);
+ tcase_add_test (tc_chain, test_multi_layer_automatic_transition);
+ tcase_add_test (tc_chain, test_layer_activate_automatic_transition);
tcase_add_test (tc_chain, test_layer_meta_string);
tcase_add_test (tc_chain, test_layer_meta_boolean);
tcase_add_test (tc_chain, test_layer_meta_int);