mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-03-30 04:45:36 +00:00
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:
parent
31e7ca2ef7
commit
bd142e285d
5 changed files with 103 additions and 15 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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"])
|
||||
|
|
Loading…
Reference in a new issue