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
This commit is contained in:
Thibault Saunier 2018-03-18 11:03:00 -03:00
parent 31e7ca2ef7
commit bd142e285d
5 changed files with 103 additions and 15 deletions

View file

@ -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;
}

View file

@ -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);

View file

@ -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);
}
}

View file

@ -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):

View file

@ -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"])