From bd142e285d11110cc97d2d63a9c5d25ec8463a36 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 18 Mar 2018 11:03:00 -0300 Subject: [PATCH] clip: Make sure to create transition after a clip is splitted In the (now tested) scenario where we have a transition on the right side of a clip we are splitting, auto transitions can't be created because we resize the clip after adding the new one, meaning that there are 3 elements in the "transition zone", we need to force auto transition creation after the splitting. Fixes https://gitlab.gnome.org/GNOME/pitivi/issues/2142 --- ges/ges-clip.c | 7 ++++ ges/ges-internal.h | 3 ++ ges/ges-timeline.c | 11 +++--- tests/check/python/common.py | 19 ++++++++- tests/check/python/test_timeline.py | 78 +++++++++++++++++++++++++++++++++---- 5 files changed, 103 insertions(+), 15 deletions(-) diff --git a/ges/ges-clip.c b/ges/ges-clip.c index 34ac6fa..70c7ee3 100644 --- a/ges/ges-clip.c +++ b/ges/ges-clip.c @@ -1385,6 +1385,13 @@ ges_clip_split (GESClip * clip, guint64 position) _set_duration0 (GES_TIMELINE_ELEMENT (clip), old_duration); + if (GES_TIMELINE_ELEMENT_TIMELINE (clip)) { + for (tmp = GES_CONTAINER_CHILDREN (new_object); tmp; tmp = tmp->next) { + timeline_create_transitions (GES_TIMELINE_ELEMENT_TIMELINE (tmp->data), + tmp->data); + } + } + return new_object; } diff --git a/ges/ges-internal.h b/ges/ges-internal.h index 9eaf01f..502b11b 100644 --- a/ges/ges-internal.h +++ b/ges/ges-internal.h @@ -125,6 +125,9 @@ G_GNUC_INTERNAL void timeline_fill_gaps (GESTimeline *timeline); +G_GNUC_INTERNAL void +timeline_create_transitions (GESTimeline * timeline, GESTrackElement * track_element); + G_GNUC_INTERNAL void track_resort_and_fill_gaps (GESTrack *track); diff --git a/ges/ges-timeline.c b/ges/ges-timeline.c index 9febf1f..aba5788 100644 --- a/ges/ges-timeline.c +++ b/ges/ges-timeline.c @@ -1065,8 +1065,9 @@ _create_transitions_on_layer (GESTimeline * timeline, GESLayer * layer, } /* @track_element must be a GESSource */ -static void -create_transitions (GESTimeline * timeline, GESTrackElement * track_element) +void +timeline_create_transitions (GESTimeline * timeline, + GESTrackElement * track_element) { GESTrack *track; GList *layer_node; @@ -1220,7 +1221,7 @@ start_tracking_track_element (GESTimeline * timeline, timeline->priv->movecontext.needs_move_ctx = TRUE; timeline_update_duration (timeline); - create_transitions (timeline, trackelement); + timeline_create_transitions (timeline, trackelement); } } @@ -2598,7 +2599,7 @@ trackelement_start_changed_cb (GESTrackElement * child, timeline->priv->snapping_distance == 0) timeline->priv->movecontext.needs_move_ctx = TRUE; - create_transitions (timeline, child); + timeline_create_transitions (timeline, child); } } @@ -2668,7 +2669,7 @@ trackelement_duration_changed_cb (GESTrackElement * child, timeline->priv->movecontext.needs_move_ctx = TRUE; } - create_transitions (timeline, child); + timeline_create_transitions (timeline, child); } } diff --git a/tests/check/python/common.py b/tests/check/python/common.py index 23d81e9..81e7855 100644 --- a/tests/check/python/common.py +++ b/tests/check/python/common.py @@ -55,6 +55,7 @@ def create_main_loop(): mainloop.run = run return mainloop + def create_project(with_group=False, saved=False): """Creates a project with two clips in a group.""" project = GES.Project() @@ -78,6 +79,7 @@ def create_project(with_group=False, saved=False): return timeline + class GESTest(unittest.TestCase): def _log(self, func, format, *args): string = format @@ -105,9 +107,22 @@ class GESTest(unittest.TestCase): class GESSimpleTimelineTest(GESTest): + def __init__(self, *args): + self.track_types = [GES.TrackType.AUDIO, GES.TrackType.VIDEO] + super(GESSimpleTimelineTest, self).__init__(*args) + def setUp(self): - self.timeline = GES.Timeline.new_audio_video() - self.assertEqual(len(self.timeline.get_tracks()), 2) + self.timeline = GES.Timeline.new() + for track_type in self.track_types: + self.assertIn( + track_type, [GES.TrackType.AUDIO, GES.TrackType.VIDEO]) + if track_type == GES.TrackType.AUDIO: + self.timeline.add_track(GES.AudioTrack.new()) + else: + self.timeline.add_track(GES.VideoTrack.new()) + + self.assertEqual(len(self.timeline.get_tracks()), + len(self.track_types)) self.layer = self.timeline.append_layer() def add_clip(self, start, in_point, duration): diff --git a/tests/check/python/test_timeline.py b/tests/check/python/test_timeline.py index f7d3556..1769b5f 100644 --- a/tests/check/python/test_timeline.py +++ b/tests/check/python/test_timeline.py @@ -45,6 +45,7 @@ class TestTimeline(unittest.TestCase): project = GES.Project.new(uri=timeline.get_asset().props.uri) loaded_called = False + def loaded(unused_project, unused_timeline): nonlocal loaded_called loaded_called = True @@ -62,6 +63,59 @@ class TestTimeline(unittest.TestCase): self.assertTrue(loaded_called) handle.assert_not_called() + +class TestSplitting(GESSimpleTimelineTest): + def setUp(self): + self.track_types = [GES.TrackType.AUDIO] + super(TestSplitting, self).setUp() + + def assertTimelineTopology(self, topology): + res = [] + for layer in self.timeline.get_layers(): + layer_timings = [] + for clip in layer.get_clips(): + layer_timings.append( + (type(clip), clip.props.start, clip.props.duration)) + + res.append(layer_timings) + + self.assertEqual(topology, res) + return res + + def test_spliting_with_auto_transition_on_the_left(self): + self.timeline.props.auto_transition = True + clip1 = self.add_clip(0, 0, 100) + clip2 = self.add_clip(50, 0, 100) + self.assertTimelineTopology([ + [ # Unique layer + (GES.TestClip, 0, 100), + (GES.TransitionClip, 50, 50), + (GES.TestClip, 50, 100) + ] + ]) + + clip1.split(25) + self.assertTimelineTopology([ + [ # Unique layer + (GES.TestClip, 0, 25), + (GES.TestClip, 25, 75), + (GES.TransitionClip, 50, 50), + (GES.TestClip, 50, 100), + ] + ]) + + clip2.split(125) + self.assertTimelineTopology([ + [ # Unique layer + (GES.TestClip, 0, 25), + (GES.TestClip, 25, 75), + (GES.TransitionClip, 50, 50), + (GES.TestClip, 50, 75), + (GES.TestClip, 125, 25), + ] + ]) + + class TestEditing(GESSimpleTimelineTest): def test_transition_disappears_when_moving_to_another_layer(self): @@ -71,7 +125,8 @@ class TestEditing(GESSimpleTimelineTest): self.assertEquals(len(self.layer.get_clips()), 4) layer2 = self.timeline.append_layer() - clip2.edit([], layer2.get_priority(), GES.EditMode.EDIT_NORMAL, GES.Edge.EDGE_NONE, clip2.props.start) + clip2.edit([], layer2.get_priority(), GES.EditMode.EDIT_NORMAL, + GES.Edge.EDGE_NONE, clip2.props.start) self.assertEquals(len(self.layer.get_clips()), 1) self.assertEquals(len(layer2.get_clips()), 1) @@ -83,7 +138,8 @@ class TestEditing(GESSimpleTimelineTest): self.assertEquals(len(all_clips), 4) layer2 = self.timeline.append_layer() - clip1.edit([], layer2.get_priority(), GES.EditMode.EDIT_RIPPLE, GES.Edge.EDGE_NONE, clip1.props.start) + clip1.edit([], layer2.get_priority(), GES.EditMode.EDIT_RIPPLE, + GES.Edge.EDGE_NONE, clip1.props.start) self.assertEquals(self.layer.get_clips(), []) self.assertEquals(set(layer2.get_clips()), set(all_clips)) @@ -94,7 +150,8 @@ class TestEditing(GESSimpleTimelineTest): all_clips = self.layer.get_clips() self.assertEquals(len(all_clips), 4) - clip1.edit([], self.layer.get_priority(), GES.EditMode.EDIT_RIPPLE, GES.Edge.EDGE_NONE, clip2.props.start + 1) + clip1.edit([], self.layer.get_priority(), GES.EditMode.EDIT_RIPPLE, + GES.Edge.EDGE_NONE, clip2.props.start + 1) self.assertEquals(set(self.layer.get_clips()), set(all_clips)) def test_transition_rippling_over_does_not_create_another_transition(self): @@ -103,14 +160,17 @@ class TestEditing(GESSimpleTimelineTest): clip1 = self.add_clip(0, 0, 17 * Gst.SECOND) clip2 = clip1.split(7.0 * Gst.SECOND) # Make a transition between the two clips - clip1.edit([], self.layer.get_priority(), GES.EditMode.EDIT_NORMAL, GES.Edge.EDGE_NONE, 4.5 * Gst.SECOND) + clip1.edit([], self.layer.get_priority(), + GES.EditMode.EDIT_NORMAL, GES.Edge.EDGE_NONE, 4.5 * Gst.SECOND) # Rippl clip1 and check that transitions ar always the sames all_clips = self.layer.get_clips() self.assertEquals(len(all_clips), 4) - clip1.edit([], self.layer.get_priority(), GES.EditMode.EDIT_RIPPLE, GES.Edge.EDGE_NONE, 41.5 * Gst.SECOND) + clip1.edit([], self.layer.get_priority(), GES.EditMode.EDIT_RIPPLE, + GES.Edge.EDGE_NONE, 41.5 * Gst.SECOND) self.assertEquals(len(self.layer.get_clips()), 4) - clip1.edit([], self.layer.get_priority(), GES.EditMode.EDIT_RIPPLE, GES.Edge.EDGE_NONE, 35 * Gst.SECOND) + clip1.edit([], self.layer.get_priority(), + GES.EditMode.EDIT_RIPPLE, GES.Edge.EDGE_NONE, 35 * Gst.SECOND) self.assertEquals(len(self.layer.get_clips()), 4) @@ -156,7 +216,9 @@ class TestTransitions(GESSimpleTimelineTest): clip2.connect("notify::start", property_changed_cb) # Move clip2 to create a transition with clip1. - clip2.edit([], self.layer.get_priority(), GES.EditMode.EDIT_NORMAL, GES.Edge.EDGE_NONE, 50) + clip2.edit([], self.layer.get_priority(), + GES.EditMode.EDIT_NORMAL, GES.Edge.EDGE_NONE, 50) # The clip-added signal is emitted twice, once for the video # transition and once for the audio transition. - self.assertEqual(signals, ["notify::start", "clip-added", "clip-added"]) + self.assertEqual( + signals, ["notify::start", "clip-added", "clip-added"]) -- 2.7.4