/* GStreamer Editing Services * * Copyright (C) <2012> Thibault Saunier * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include static gboolean my_fill_track_func (GESTimelineObject * object, GESTrackObject * trobject, GstElement * gnlobj, gpointer user_data) { GstElement *src; GST_DEBUG ("timelineobj:%p, trackobjec:%p, gnlobj:%p", object, trobject, gnlobj); /* Let's just put a fakesource in for the time being */ src = gst_element_factory_make ("fakesrc", NULL); /* If this fails... that means that there already was something * in it */ fail_unless (gst_bin_add (GST_BIN (gnlobj), src)); return TRUE; } static inline GESTimelineObject * create_custom_tlobj (void) { return GES_TIMELINE_OBJECT (ges_custom_timeline_source_new (my_fill_track_func, NULL)); } #define CHECK_OBJECT_PROPS(obj, start, inpoint, duration) {\ assert_equals_uint64 (ges_track_object_get_start (obj), start);\ assert_equals_uint64 (ges_track_object_get_inpoint (obj), inpoint);\ assert_equals_uint64 (ges_track_object_get_duration (obj), duration);\ } GST_START_TEST (test_basic_timeline_edition) { GESTrack *track; GESTimeline *timeline; GESTrackObject *tckobj, *tckobj1, *tckobj2; GESTimelineObject *obj, *obj1, *obj2; ges_init (); track = ges_track_new (GES_TRACK_TYPE_CUSTOM, GST_CAPS_ANY); fail_unless (track != NULL); timeline = ges_timeline_new (); fail_unless (timeline != NULL); fail_unless (ges_timeline_add_track (timeline, track)); obj = create_custom_tlobj (); obj1 = create_custom_tlobj (); obj2 = create_custom_tlobj (); fail_unless (obj && obj1 && obj2); /** * Our timeline * * inpoints 0------- 0-------- 0----------- * | obj | | obj1 | | obj2 | * time 0------- 10 --------20 50---------60 */ g_object_set (obj, "start", (guint64) 0, "duration", (guint64) 10, "in-point", (guint64) 0, NULL); g_object_set (obj1, "start", (guint64) 10, "duration", (guint64) 10, "in-point", (guint64) 0, NULL); g_object_set (obj2, "start", (guint64) 50, "duration", (guint64) 60, "in-point", (guint64) 0, NULL); tckobj = ges_timeline_object_create_track_object (obj, track); fail_unless (tckobj != NULL); fail_unless (ges_timeline_object_add_track_object (obj, tckobj)); fail_unless (ges_track_add_object (track, tckobj)); assert_equals_uint64 (ges_track_object_get_duration (tckobj), 10); tckobj1 = ges_timeline_object_create_track_object (obj1, track); fail_unless (tckobj1 != NULL); fail_unless (ges_timeline_object_add_track_object (obj1, tckobj1)); fail_unless (ges_track_add_object (track, tckobj1)); assert_equals_uint64 (ges_track_object_get_duration (tckobj1), 10); tckobj2 = ges_timeline_object_create_track_object (obj2, track); fail_unless (ges_timeline_object_add_track_object (obj2, tckobj2)); fail_unless (tckobj2 != NULL); fail_unless (ges_track_add_object (track, tckobj2)); assert_equals_uint64 (ges_track_object_get_duration (tckobj2), 60); /** * Simple rippling obj to: 10 * * New timeline: * ------------ * * inpoints 0------- 0-------- 0----------- * | obj | | obj1 | | obj2 | * time 10------- 20 --------30 60---------120 */ fail_unless (ges_timeline_object_edit (obj, NULL, -1, GES_EDIT_MODE_RIPPLE, GES_EDGE_NONE, 10) == TRUE); CHECK_OBJECT_PROPS (tckobj, 10, 0, 10); CHECK_OBJECT_PROPS (tckobj1, 20, 0, 10); CHECK_OBJECT_PROPS (tckobj2, 60, 0, 60); /* FIXME find a way to check that we are using the same MovingContext * inside the GESTrack */ fail_unless (ges_timeline_object_edit (obj1, NULL, -1, GES_EDIT_MODE_RIPPLE, GES_EDGE_NONE, 40) == TRUE); CHECK_OBJECT_PROPS (tckobj, 10, 0, 10); CHECK_OBJECT_PROPS (tckobj1, 40, 0, 10); CHECK_OBJECT_PROPS (tckobj2, 80, 0, 60); /** * Rippling obj1 back to: 20 (getting to the exact same timeline as before */ fail_unless (ges_timeline_object_edit (obj1, NULL, -1, GES_EDIT_MODE_RIPPLE, GES_EDGE_NONE, 20) == TRUE); CHECK_OBJECT_PROPS (tckobj, 10, 0, 10); CHECK_OBJECT_PROPS (tckobj1, 20, 0, 10); CHECK_OBJECT_PROPS (tckobj2, 60, 0, 60); /** * Simple move obj to: 27 and obj2 to 35 * * New timeline: * ------------ * 0------------ * inpoints 0-------|--- obj 0--|---------- * | obj1 27 -|-----|-37 obj2 | * time 20-----------30 35-------------120 */ fail_unless (ges_timeline_object_edit (obj, NULL, -1, GES_EDIT_MODE_NORMAL, GES_EDGE_NONE, 27) == TRUE); fail_unless (ges_timeline_object_edit (obj2, NULL, -1, GES_EDIT_MODE_NORMAL, GES_EDGE_NONE, 35) == TRUE); CHECK_OBJECT_PROPS (tckobj, 27, 0, 10); CHECK_OBJECT_PROPS (tckobj1, 20, 0, 10); CHECK_OBJECT_PROPS (tckobj2, 35, 0, 60); /** * Trim start obj to: 32 and obj2 to 35 * * New timeline: * ------------ * 5-------- * inpoints 0----------- | obj 0--|---------- * | obj1 | 32----|-37 obj2 | * time 20-----------30 35-------------120 */ fail_unless (ges_timeline_object_edit (obj, NULL, -1, GES_EDIT_MODE_TRIM, GES_EDGE_START, 32) == TRUE); CHECK_OBJECT_PROPS (tckobj, 32, 5, 5); CHECK_OBJECT_PROPS (tckobj1, 20, 0, 10); CHECK_OBJECT_PROPS (tckobj2, 35, 0, 60); /* Ripple end obj to 42 * New timeline: * ------------ * 5-------- * inpoints 0----------- | obj 0--|---------- * | obj1 | 32----|-42 obj2 | * time 20-----------30 35-------------120 */ fail_unless (ges_timeline_object_edit (obj, NULL, -1, GES_EDIT_MODE_RIPPLE, GES_EDGE_END, 42) == TRUE); CHECK_OBJECT_PROPS (tckobj, 32, 5, 10); CHECK_OBJECT_PROPS (tckobj1, 20, 0, 10); CHECK_OBJECT_PROPS (tckobj2, 35, 0, 60); /** * New timeline: * ------------ * inpoints 0------- 5-------- 0----------- * | obj1 | | obj1 || obj2 | * time 20-------30 32--------52 ---------112 */ fail_unless (ges_timeline_object_edit (obj2, NULL, -1, GES_EDIT_MODE_NORMAL, GES_EDGE_NONE, 42) == TRUE); fail_unless (ges_timeline_object_edit (obj, NULL, -1, GES_EDIT_MODE_RIPPLE, GES_EDGE_END, 52) == TRUE); CHECK_OBJECT_PROPS (tckobj, 32, 5, 20); CHECK_OBJECT_PROPS (tckobj1, 20, 0, 10); CHECK_OBJECT_PROPS (tckobj2, 52, 0, 60); /** * New timeline: * ------------ * inpoints 0------- 5-------- 0------------ * | obj1 | | obj || obj2 | * time 20-------40 42--------62 ---------122 */ fail_unless (ges_timeline_object_edit (obj1, NULL, -1, GES_EDIT_MODE_RIPPLE, GES_EDGE_END, 40) == TRUE); CHECK_OBJECT_PROPS (tckobj, 42, 5, 20); CHECK_OBJECT_PROPS (tckobj1, 20, 0, 20); CHECK_OBJECT_PROPS (tckobj2, 62, 0, 60); /** * New timeline: * ------------ * inpoints 0------- 0-------- 0----------- * | obj1 || obj || obj2 | * time 20------ 25 ------ 62 ---------122 */ fail_unless (ges_timeline_object_edit (obj, NULL, -1, GES_EDIT_MODE_TRIM, GES_EDGE_START, 40) == TRUE); fail_unless (ges_timeline_object_edit (obj, NULL, -1, GES_EDIT_MODE_ROLL, GES_EDGE_START, 25) == TRUE); CHECK_OBJECT_PROPS (tckobj, 25, 0, 37); CHECK_OBJECT_PROPS (tckobj1, 20, 0, 5); CHECK_OBJECT_PROPS (tckobj2, 62, 0, 60); /* Make sure that not doing anything when not able to roll */ fail_unless (ges_timeline_object_edit (obj, NULL, -1, GES_EDIT_MODE_ROLL, GES_EDGE_START, 65) == TRUE); fail_unless (ges_timeline_object_edit (obj1, NULL, -1, GES_EDIT_MODE_ROLL, GES_EDGE_END, 65) == TRUE, 0); CHECK_OBJECT_PROPS (tckobj, 25, 0, 37); CHECK_OBJECT_PROPS (tckobj1, 20, 0, 5); CHECK_OBJECT_PROPS (tckobj2, 62, 0, 60); g_object_unref (timeline); g_object_unref (obj); g_object_unref (obj1); g_object_unref (obj2); } GST_END_TEST; GST_START_TEST (test_snapping) { GESTrack *track; GESTimeline *timeline; GESTrackObject *tckobj, *tckobj1, *tckobj2; GESTimelineObject *obj, *obj1, *obj2; GESTimelineLayer *layer; GList *tckobjs; ges_init (); track = ges_track_new (GES_TRACK_TYPE_CUSTOM, GST_CAPS_ANY); fail_unless (track != NULL); timeline = ges_timeline_new (); fail_unless (timeline != NULL); fail_unless (ges_timeline_add_track (timeline, track)); obj = create_custom_tlobj (); obj1 = create_custom_tlobj (); obj2 = create_custom_tlobj (); fail_unless (obj && obj1 && obj2); /** * Our timeline * ------------ * inpoints 0------- 0-------- 0----------- * | obj1 || obj || obj2 | * time 20------ 25 ------ 62 ---------122 */ g_object_set (obj, "start", (guint64) 25, "duration", (guint64) 37, "in-point", (guint64) 0, NULL); g_object_set (obj1, "start", (guint64) 20, "duration", (guint64) 15, "in-point", (guint64) 0, NULL); g_object_set (obj2, "start", (guint64) 62, "duration", (guint64) 60, "in-point", (guint64) 0, NULL); fail_unless ((layer = ges_timeline_append_layer (timeline)) != NULL); assert_equals_int (ges_timeline_layer_get_priority (layer), 0); fail_unless (ges_timeline_layer_add_object (layer, obj)); fail_unless ((tckobjs = ges_timeline_object_get_track_objects (obj)) != NULL); fail_unless ((tckobj = GES_TRACK_OBJECT (tckobjs->data)) != NULL); fail_unless (ges_track_object_get_track (tckobj) == track); assert_equals_uint64 (ges_track_object_get_duration (tckobj), 37); g_list_free_full (tckobjs, g_object_unref); /* We have 3 references to tckobj from: * track + timeline + obj */ ASSERT_OBJECT_REFCOUNT (tckobj, "First tckobj", 3); /* We have 1 ref to obj1: * + layer */ ASSERT_OBJECT_REFCOUNT (obj, "First tlobj", 1); fail_unless (ges_timeline_layer_add_object (layer, obj1)); fail_unless ((tckobjs = ges_timeline_object_get_track_objects (obj1)) != NULL); fail_unless ((tckobj1 = GES_TRACK_OBJECT (tckobjs->data)) != NULL); fail_unless (ges_track_object_get_track (tckobj1) == track); assert_equals_uint64 (ges_track_object_get_duration (tckobj1), 15); g_list_free_full (tckobjs, g_object_unref); /* Same ref logic */ ASSERT_OBJECT_REFCOUNT (tckobj1, "First tckobj", 3); ASSERT_OBJECT_REFCOUNT (obj1, "First tlobj", 1); fail_unless (ges_timeline_layer_add_object (layer, obj2)); fail_unless ((tckobjs = ges_timeline_object_get_track_objects (obj2)) != NULL); fail_unless ((tckobj2 = GES_TRACK_OBJECT (tckobjs->data)) != NULL); fail_unless (ges_track_object_get_track (tckobj2) == track); assert_equals_uint64 (ges_track_object_get_duration (tckobj2), 60); g_list_free_full (tckobjs, g_object_unref); /* Same ref logic */ ASSERT_OBJECT_REFCOUNT (tckobj2, "First tckobj", 3); ASSERT_OBJECT_REFCOUNT (obj2, "First tlobj", 1); /* Snaping to edge, so no move */ g_object_set (timeline, "snapping-distance", (guint64) 3, NULL); fail_unless (ges_timeline_object_edit (obj1, NULL, -1, GES_EDIT_MODE_TRIM, GES_EDGE_END, 27) == TRUE); CHECK_OBJECT_PROPS (tckobj, 25, 0, 37); CHECK_OBJECT_PROPS (tckobj1, 20, 0, 5); CHECK_OBJECT_PROPS (tckobj2, 62, 0, 60); /* Snaping to edge, so no move */ fail_unless (ges_timeline_object_edit (obj1, NULL, -1, GES_EDIT_MODE_TRIM, GES_EDGE_END, 27) == TRUE); CHECK_OBJECT_PROPS (tckobj, 25, 0, 37); CHECK_OBJECT_PROPS (tckobj1, 20, 0, 5); CHECK_OBJECT_PROPS (tckobj2, 62, 0, 60); /** * New timeline: * ------------ * 0----------- 0------------- * inpoints 0-------|-- obj || obj2 | * | obj1 25-|------- 62 -----------122 * time 20----------30 */ g_object_set (timeline, "snapping-distance", (guint64) 0, NULL); ges_timeline_object_set_duration (obj1, 10); CHECK_OBJECT_PROPS (tckobj, 25, 0, 37); CHECK_OBJECT_PROPS (tckobj1, 20, 0, 10); CHECK_OBJECT_PROPS (tckobj2, 62, 0, 60); /** * New timeline(the "layers" are just to help reading diagram, nothing else): * ------------ * 0---------- * | obj | * 25---------62 * inpoints 0----------------------- 10-------- * | obj1 || obj2 | * time 20---------------------- 72 --------122 */ /* Rolling involves only neighbour that are currently snapping */ fail_unless (ges_timeline_object_roll_end (obj1, 62)); fail_unless (ges_timeline_object_roll_end (obj1, 72) == TRUE); CHECK_OBJECT_PROPS (tckobj, 25, 0, 37); CHECK_OBJECT_PROPS (tckobj1, 20, 0, 52); CHECK_OBJECT_PROPS (tckobj2, 72, 10, 50); /** * 0---------- * | obj | * 25---------62 * inpoints 5--------------- 10-------- * | obj1 || obj2 | * time 25------------- 72 --------122 */ g_object_set (timeline, "snapping-distance", (guint64) 4, NULL); fail_unless (ges_timeline_object_trim_start (obj1, 28) == TRUE); CHECK_OBJECT_PROPS (tckobj, 25, 0, 37); CHECK_OBJECT_PROPS (tckobj1, 25, 5, 47); CHECK_OBJECT_PROPS (tckobj2, 72, 10, 50); /** * 0---------- * | obj | * 25---------62 * inpoints 5---------- 0--------- * | obj1 || obj2 | * time 25-------- 62 --------122 */ fail_unless (ges_timeline_object_roll_start (obj2, 59) == TRUE); CHECK_OBJECT_PROPS (tckobj, 25, 0, 37); CHECK_OBJECT_PROPS (tckobj1, 25, 5, 37); CHECK_OBJECT_PROPS (tckobj2, 62, 0, 60); /** * inpoints 0----------5---------- 0---------- * | obj || obj1 || obj2 | * time 25---------62-------- 99 --------170 */ fail_unless (ges_timeline_object_ripple (obj1, 58) == TRUE); CHECK_OBJECT_PROPS (tckobj, 25, 0, 37); CHECK_OBJECT_PROPS (tckobj1, 62, 5, 37); CHECK_OBJECT_PROPS (tckobj2, 99, 0, 60); /** * inpoints 0----------5---------- 0---------- * | obj || obj1 | | obj2 | * time 25---------62-------- 99 110--------170 */ ges_timeline_object_set_start (obj2, 110); CHECK_OBJECT_PROPS (tckobj, 25, 0, 37); CHECK_OBJECT_PROPS (tckobj1, 62, 5, 37); CHECK_OBJECT_PROPS (tckobj2, 110, 0, 60); /** * inpoints 0----------5 5 --------- 0---------- * | obj | | obj1 || obj2 | * time 25---------62 73---------110--------170 */ fail_unless (ges_timeline_object_edit (obj1, NULL, -1, GES_EDIT_MODE_NORMAL, GES_EDGE_NONE, 72) == TRUE); CHECK_OBJECT_PROPS (tckobj, 25, 0, 37); CHECK_OBJECT_PROPS (tckobj1, 73, 5, 37); CHECK_OBJECT_PROPS (tckobj2, 110, 0, 60); /** * inpoints 0----------5---------- 0---------- * | obj || obj1 | | obj2 | * time 25---------62-------- 99 110--------170 */ fail_unless (ges_timeline_object_edit (obj1, NULL, -1, GES_EDIT_MODE_NORMAL, GES_EDGE_NONE, 58) == TRUE); CHECK_OBJECT_PROPS (tckobj, 25, 0, 37); CHECK_OBJECT_PROPS (tckobj1, 62, 5, 37); CHECK_OBJECT_PROPS (tckobj2, 110, 0, 60); /** * inpoints 0----------5---------- 0---------- * | obj || obj1 || obj2 | * time 25---------62--------110--------170 */ g_object_set (obj1, "duration", 46, NULL); CHECK_OBJECT_PROPS (tckobj, 25, 0, 37); CHECK_OBJECT_PROPS (tckobj1, 62, 5, 48); CHECK_OBJECT_PROPS (tckobj2, 110, 0, 60); /** * inpoints 5----------- 0--------- 0---------- * | obj1 || obj2 || obj | * time 62---------110--------170--------207 */ g_object_set (obj, "start", 168, NULL); CHECK_OBJECT_PROPS (tckobj, 170, 0, 37); CHECK_OBJECT_PROPS (tckobj1, 62, 5, 48); CHECK_OBJECT_PROPS (tckobj2, 110, 0, 60); /* Check we didn't lose/screwed any references */ ASSERT_OBJECT_REFCOUNT (tckobj, "First tckobj", 3); ASSERT_OBJECT_REFCOUNT (tckobj1, "Second tckobj", 3); ASSERT_OBJECT_REFCOUNT (tckobj2, "Third tckobj", 3); ASSERT_OBJECT_REFCOUNT (obj, "First tlobj", 1); ASSERT_OBJECT_REFCOUNT (obj1, "Second tlobj", 1); ASSERT_OBJECT_REFCOUNT (obj2, "Third tlobj", 1); g_object_unref (timeline); /* Check we destroyed everything */ fail_if (G_IS_OBJECT (tckobj)); fail_if (G_IS_OBJECT (tckobj1)); fail_if (G_IS_OBJECT (tckobj2)); fail_if (G_IS_OBJECT (obj)); fail_if (G_IS_OBJECT (obj1)); fail_if (G_IS_OBJECT (obj2)); fail_if (G_IS_OBJECT (layer)); } GST_END_TEST; GST_START_TEST (test_timeline_edition_mode) { guint i; GESTrack *track; GESTimeline *timeline; GESTrackObject *tckobj, *tckobj1, *tckobj2; GESTimelineObject *obj, *obj1, *obj2; GESTimelineLayer *layer, *layer1, *layer2; GList *tckobjs, *layers, *tmp; ges_init (); track = ges_track_new (GES_TRACK_TYPE_CUSTOM, GST_CAPS_ANY); fail_unless (track != NULL); timeline = ges_timeline_new (); fail_unless (timeline != NULL); fail_unless (ges_timeline_add_track (timeline, track)); obj = create_custom_tlobj (); obj1 = create_custom_tlobj (); obj2 = create_custom_tlobj (); fail_unless (obj && obj1 && obj2); /** * Our timeline * * 0------- * layer: | obj | * 0-------10 * * 0-------- 0----------- * layer1: | obj1 | | obj2 | * 10--------20 50---------60 */ g_object_set (obj, "start", (guint64) 0, "duration", (guint64) 10, "in-point", (guint64) 0, NULL); g_object_set (obj1, "start", (guint64) 10, "duration", (guint64) 10, "in-point", (guint64) 0, NULL); g_object_set (obj2, "start", (guint64) 50, "duration", (guint64) 60, "in-point", (guint64) 0, NULL); fail_unless ((layer = ges_timeline_append_layer (timeline)) != NULL); assert_equals_int (ges_timeline_layer_get_priority (layer), 0); fail_unless (ges_timeline_layer_add_object (layer, obj)); fail_unless ((tckobjs = ges_timeline_object_get_track_objects (obj)) != NULL); fail_unless ((tckobj = GES_TRACK_OBJECT (tckobjs->data)) != NULL); fail_unless (ges_track_object_get_track (tckobj) == track); assert_equals_uint64 (ges_track_object_get_duration (tckobj), 10); g_list_free_full (tckobjs, g_object_unref); /* Add a new layer and add objects to it */ fail_unless ((layer1 = ges_timeline_append_layer (timeline)) != NULL); fail_unless (layer != layer1); assert_equals_int (ges_timeline_layer_get_priority (layer1), 1); fail_unless (ges_timeline_layer_add_object (layer1, obj1)); fail_unless ((tckobjs = ges_timeline_object_get_track_objects (obj1)) != NULL); fail_unless ((tckobj1 = GES_TRACK_OBJECT (tckobjs->data)) != NULL); fail_unless (ges_track_object_get_track (tckobj1) == track); assert_equals_uint64 (ges_track_object_get_duration (tckobj1), 10); g_list_free_full (tckobjs, g_object_unref); fail_unless (ges_timeline_layer_add_object (layer1, obj2)); fail_unless ((tckobjs = ges_timeline_object_get_track_objects (obj2)) != NULL); fail_unless ((tckobj2 = GES_TRACK_OBJECT (tckobjs->data)) != NULL); fail_unless (ges_track_object_get_track (tckobj2) == track); assert_equals_uint64 (ges_track_object_get_duration (tckobj2), 60); g_list_free_full (tckobjs, g_object_unref); /** * Simple rippling obj to: 10 * * New timeline: * ------------ * * inpoints 0------- * | obj | * time 10-------20 * * 0-------- 0----------- * | obj1 | | obj2 | * 20--------30 60--------120 */ fail_unless (ges_timeline_object_edit (obj, NULL, -1, GES_EDIT_MODE_RIPPLE, GES_EDGE_NONE, 10) == TRUE); CHECK_OBJECT_PROPS (tckobj, 10, 0, 10); CHECK_OBJECT_PROPS (tckobj1, 20, 0, 10); CHECK_OBJECT_PROPS (tckobj2, 60, 0, 60); /* FIXME find a way to check that we are using the same MovingContext * inside the GESTimeline */ fail_unless (ges_timeline_object_edit (obj1, NULL, 3, GES_EDIT_MODE_RIPPLE, GES_EDGE_NONE, 40) == TRUE); CHECK_OBJECT_PROPS (tckobj, 10, 0, 10); CHECK_OBJECT_PROPS (tckobj1, 40, 0, 10); CHECK_OBJECT_PROPS (tckobj2, 80, 0, 60); layer2 = ges_timeline_object_get_layer (obj1); assert_equals_int (ges_timeline_layer_get_priority (layer2), 3); /* obj2 should have moved layer too */ fail_unless (ges_timeline_object_get_layer (obj2) == layer2); /* We got 2 reference to the same object, unref them */ g_object_unref (layer2); g_object_unref (layer2); /** * Rippling obj1 back to: 20 (getting to the exact same timeline as before */ fail_unless (ges_timeline_object_edit (obj1, NULL, 1, GES_EDIT_MODE_RIPPLE, GES_EDGE_NONE, 20) == TRUE); CHECK_OBJECT_PROPS (tckobj, 10, 0, 10); CHECK_OBJECT_PROPS (tckobj1, 20, 0, 10); CHECK_OBJECT_PROPS (tckobj2, 60, 0, 60); layer2 = ges_timeline_object_get_layer (obj1); assert_equals_int (ges_timeline_layer_get_priority (layer2), 1); /* obj2 should have moved layer too */ fail_unless (ges_timeline_object_get_layer (obj2) == layer2); /* We got 2 reference to the same object, unref them */ g_object_unref (layer2); g_object_unref (layer2); /** * Simple move obj to 27 and obj2 to 35 * * New timeline: * ------------ * * inpoints 0------- * | obj | * time 27-------37 * * 0-------- 0----------- * | obj1 | | obj2 | * 20--------30 35---------95 */ fail_unless (ges_timeline_object_edit (obj, NULL, -1, GES_EDIT_MODE_NORMAL, GES_EDGE_NONE, 27) == TRUE); fail_unless (ges_timeline_object_edit (obj2, NULL, -1, GES_EDIT_MODE_NORMAL, GES_EDGE_NONE, 35) == TRUE); CHECK_OBJECT_PROPS (tckobj, 27, 0, 10); CHECK_OBJECT_PROPS (tckobj1, 20, 0, 10); CHECK_OBJECT_PROPS (tckobj2, 35, 0, 60); /** * Simple trimming start obj to: 32 * * New timeline: * ------------ * * 5------- * layer 0: | obj | * 32-------37 * * 0-------- 0----------- * layer 1 | obj1 | | obj2 | * 20--------30 35---------95 */ fail_unless (ges_timeline_object_edit (obj, NULL, -1, GES_EDIT_MODE_TRIM, GES_EDGE_START, 32) == TRUE); CHECK_OBJECT_PROPS (tckobj, 32, 5, 5); CHECK_OBJECT_PROPS (tckobj1, 20, 0, 10); CHECK_OBJECT_PROPS (tckobj2, 35, 0, 60); /* Ripple end obj to 35 and move to layer 2 * New timeline: * ------------ * * 0-------- 0----------- * layer 1: | obj1 | | obj2 | * 20--------30 35---------95 * * 5------ * layer 2: | obj | * 32------35 */ fail_unless (ges_timeline_object_edit (obj, NULL, 2, GES_EDIT_MODE_RIPPLE, GES_EDGE_END, 35) == TRUE); CHECK_OBJECT_PROPS (tckobj, 32, 5, 3); CHECK_OBJECT_PROPS (tckobj1, 20, 0, 10); CHECK_OBJECT_PROPS (tckobj2, 35, 0, 60); layer = ges_timeline_object_get_layer (obj); assert_equals_int (ges_timeline_layer_get_priority (layer), 2); g_object_unref (layer); /* Roll end obj to 50 * New timeline: * ------------ * * 0-------- 0----------- * layer 1: | obj1 | | obj2 | * 20--------30 50---------95 * * 5------ * layer 2: | obj | * 32------50 */ fail_unless (ges_timeline_object_edit (obj, NULL, 2, GES_EDIT_MODE_ROLL, GES_EDGE_END, 50) == TRUE); CHECK_OBJECT_PROPS (tckobj, 32, 5, 18); CHECK_OBJECT_PROPS (tckobj1, 20, 0, 10); CHECK_OBJECT_PROPS (tckobj2, 50, 15, 45); layer = ges_timeline_object_get_layer (obj); assert_equals_int (ges_timeline_layer_get_priority (layer), 2); g_object_unref (layer); /* Some more intensive roll testing */ for (i = 0; i < 20; i++) { gint32 random = g_random_int_range (35, 94); guint64 tck3_inpoint = random - 35; fail_unless (ges_timeline_object_edit (obj, NULL, -1, GES_EDIT_MODE_ROLL, GES_EDGE_END, random) == TRUE); CHECK_OBJECT_PROPS (tckobj, 32, 5, random - 32); CHECK_OBJECT_PROPS (tckobj1, 20, 0, 10); CHECK_OBJECT_PROPS (tckobj2, random, tck3_inpoint, 95 - random); } /* Roll end obj back to 35 * New timeline: * ------------ * * 0-------- 0----------- * layer 1: | obj1 | | obj2 | * 20--------30 35---------95 * * 5------ * layer 2: | obj | * 32------35 */ fail_unless (ges_timeline_object_edit (obj, NULL, 2, GES_EDIT_MODE_ROLL, GES_EDGE_END, 35) == TRUE); CHECK_OBJECT_PROPS (tckobj, 32, 5, 3); CHECK_OBJECT_PROPS (tckobj1, 20, 0, 10); CHECK_OBJECT_PROPS (tckobj2, 35, 0, 60); layer = ges_timeline_object_get_layer (obj); assert_equals_int (ges_timeline_layer_get_priority (layer), 2); g_object_unref (layer); /* Ripple obj end to 52 * New timeline: * ------------ * * 0-------- 0---------- * layer 1: | obj1 | | obj2 | * 20-------30 52---------112 * * 5------ * layer 2: | obj | * 32------52 * */ /* Can not move to the first layer as obj2 should move to a layer with priority < 0 */ fail_unless (ges_timeline_object_edit (obj, NULL, 0, GES_EDIT_MODE_RIPPLE, GES_EDGE_END, 52) == TRUE); CHECK_OBJECT_PROPS (tckobj, 32, 5, 20); CHECK_OBJECT_PROPS (tckobj1, 20, 0, 10); CHECK_OBJECT_PROPS (tckobj2, 52, 0, 60) layer = ges_timeline_object_get_layer (obj); assert_equals_int (ges_timeline_layer_get_priority (layer), 2); g_object_unref (layer); /* Little check that we have 4 layers in the timeline */ layers = ges_timeline_get_layers (timeline); assert_equals_int (g_list_length (layers), 4); /* Some refcount checkings */ /* We have a reference to each layer in layers */ for (tmp = layers; tmp; tmp = tmp->next) ASSERT_OBJECT_REFCOUNT (layer, "Layer", 2); g_list_free_full (layers, g_object_unref); /* We have 3 references: * track + timeline + obj */ ASSERT_OBJECT_REFCOUNT (tckobj, "First tckobj", 3); ASSERT_OBJECT_REFCOUNT (tckobj1, "Second tckobj", 3); ASSERT_OBJECT_REFCOUNT (tckobj2, "Third tckobj", 3); /* We have 1 ref: * + layer */ ASSERT_OBJECT_REFCOUNT (obj, "First tlobj", 1); ASSERT_OBJECT_REFCOUNT (obj1, "Second tlobj", 1); ASSERT_OBJECT_REFCOUNT (obj2, "Third tlobj", 1); /* Ripple obj end to 52 * New timeline: * ------------ * * 0-------- 0----------- * layer 0: | obj1 | | obj2 | * 20-------40 62----------112 * * 5------ * layer 1: | obj | * 42------60 * */ fail_unless (ges_timeline_object_edit (obj1, NULL, 0, GES_EDIT_MODE_RIPPLE, GES_EDGE_END, 40) == TRUE); CHECK_OBJECT_PROPS (tckobj, 42, 5, 20); CHECK_OBJECT_PROPS (tckobj1, 20, 0, 20); CHECK_OBJECT_PROPS (tckobj2, 62, 0, 60); /* Check that movement between layer has been done properly */ layer1 = ges_timeline_object_get_layer (obj); layer = ges_timeline_object_get_layer (obj1); assert_equals_int (ges_timeline_layer_get_priority (layer1), 1); assert_equals_int (ges_timeline_layer_get_priority (layer), 0); fail_unless (ges_timeline_object_get_layer (obj2) == layer); g_object_unref (layer1); /* We have 2 references to @layer that we do not need anymore */ ; g_object_unref (layer); g_object_unref (layer); /* Trim obj start to 40 * New timeline: * ------------ * * 0-------- 0----------- * layer 0: | obj1 | | obj2 | * 20-------40 62---------112 * * 0------ * layer 1: | obj | * 40------62 * */ fail_unless (ges_timeline_object_edit (obj, NULL, -1, GES_EDIT_MODE_TRIM, GES_EDGE_START, 40) == TRUE); CHECK_OBJECT_PROPS (tckobj, 40, 3, 22); CHECK_OBJECT_PROPS (tckobj1, 20, 0, 20); CHECK_OBJECT_PROPS (tckobj2, 62, 0, 60); /* Roll obj end to 25 * New timeline: * ------------ * * 0-------- 0----------- * layer 0: | obj1 | | obj2 | * 20-------25 62---------112 * * 0------ * layer 1: | obj | * 25------62 * */ fail_unless (ges_timeline_object_edit (obj1, NULL, -1, GES_EDIT_MODE_ROLL, GES_EDGE_END, 25) == TRUE); CHECK_OBJECT_PROPS (tckobj, 25, 0, 37); CHECK_OBJECT_PROPS (tckobj1, 20, 0, 5); CHECK_OBJECT_PROPS (tckobj2, 62, 0, 60); /* Make sure that not doing anything when not able to roll */ fail_unless (ges_timeline_object_edit (obj, NULL, -1, GES_EDIT_MODE_ROLL, GES_EDGE_START, 65) == TRUE); fail_unless (ges_timeline_object_edit (obj1, NULL, -1, GES_EDIT_MODE_ROLL, GES_EDGE_END, 65) == TRUE, 0); CHECK_OBJECT_PROPS (tckobj, 25, 0, 37); CHECK_OBJECT_PROPS (tckobj1, 20, 0, 5); CHECK_OBJECT_PROPS (tckobj2, 62, 0, 60); /* Snaping to edge, so no move */ g_object_set (timeline, "snapping-distance", (guint64) 3, NULL); fail_unless (ges_timeline_object_edit (obj1, NULL, -1, GES_EDIT_MODE_TRIM, GES_EDGE_END, 27) == TRUE); CHECK_OBJECT_PROPS (tckobj, 25, 0, 37); CHECK_OBJECT_PROPS (tckobj1, 20, 0, 5); CHECK_OBJECT_PROPS (tckobj2, 62, 0, 60); /* Snaping to edge, so no move */ fail_unless (ges_timeline_object_edit (obj1, NULL, -1, GES_EDIT_MODE_TRIM, GES_EDGE_END, 27) == TRUE); CHECK_OBJECT_PROPS (tckobj, 25, 0, 37); CHECK_OBJECT_PROPS (tckobj1, 20, 0, 5); CHECK_OBJECT_PROPS (tckobj2, 62, 0, 60); /** * New timeline: * ------------ * 0----------- 0------------- * inpoints 0-------|-- obj || obj2 | * | obj1 25-|------- 62 -----------122 * time 20----------30 */ g_object_set (timeline, "snapping-distance", (guint64) 0, NULL); fail_unless (ges_timeline_object_edit (obj1, NULL, -1, GES_EDIT_MODE_TRIM, GES_EDGE_END, 30) == TRUE); CHECK_OBJECT_PROPS (tckobj, 25, 0, 37); CHECK_OBJECT_PROPS (tckobj1, 20, 0, 10); CHECK_OBJECT_PROPS (tckobj2, 62, 0, 60); /** * New timeline * ------------ * 0---------- * | obj | * 25---------62 * inpoints 0----------------------- 10-------- * | obj1 || obj2 | * time 20---------------------- 72 --------122 */ /* Rolling involves only neighbours that are currently snapping */ fail_unless (ges_timeline_object_edit (obj1, NULL, -1, GES_EDIT_MODE_ROLL, GES_EDGE_END, 62) == TRUE); fail_unless (ges_timeline_object_edit (obj1, NULL, -1, GES_EDIT_MODE_ROLL, GES_EDGE_END, 72) == TRUE); CHECK_OBJECT_PROPS (tckobj, 25, 0, 37); CHECK_OBJECT_PROPS (tckobj1, 20, 0, 52); CHECK_OBJECT_PROPS (tckobj2, 72, 10, 50); /* Test Snapping */ /** * 0---------- * | obj | * 25---------62 * inpoints 5--------------- 10-------- * | obj1 || obj2 | * time 25------------- 72 --------122 */ g_object_set (timeline, "snapping-distance", (guint64) 4, NULL); fail_unless (ges_timeline_object_edit (obj1, NULL, -1, GES_EDIT_MODE_TRIM, GES_EDGE_START, 28) == TRUE); CHECK_OBJECT_PROPS (tckobj, 25, 0, 37); CHECK_OBJECT_PROPS (tckobj1, 25, 5, 47); CHECK_OBJECT_PROPS (tckobj2, 72, 10, 50); /** * 0---------- * | obj | * 25---------62 * inpoints 5---------- 0--------- * | obj1 || obj2 | * time 25-------- 62 --------122 */ fail_unless (ges_timeline_object_edit (obj2, NULL, -1, GES_EDIT_MODE_ROLL, GES_EDGE_START, 59) == TRUE); CHECK_OBJECT_PROPS (tckobj, 25, 0, 37); CHECK_OBJECT_PROPS (tckobj1, 25, 5, 37); CHECK_OBJECT_PROPS (tckobj2, 62, 0, 60); } GST_END_TEST; static Suite * ges_suite (void) { Suite *s = suite_create ("ges-timeline-edition"); TCase *tc_chain = tcase_create ("timeline-edition"); suite_add_tcase (s, tc_chain); tcase_add_test (tc_chain, test_basic_timeline_edition); tcase_add_test (tc_chain, test_snapping); tcase_add_test (tc_chain, test_timeline_edition_mode); return s; } int main (int argc, char **argv) { int nf; Suite *s = ges_suite (); SRunner *sr = srunner_create (s); gst_check_init (&argc, &argv); srunner_run_all (sr, CK_NORMAL); nf = srunner_ntests_failed (sr); srunner_free (sr); return nf; }