Getting colder with our second freeze... it's 3.31.91 release day and string freeze, upload a tarball and lock those strings 🏂

Commit d32d0276 authored by Thibault Saunier's avatar Thibault Saunier

Do not commit timeline during splitting section

If we commit a timeline while splitting clips we might end up commiting
"half splited" clips. This happens because while splitting, the keyframe
are moved and `KeyframeCurve.__controlSourceChangedCb` is called.

Introduce a context manager on the pipeline so that we ensure that
a section of code is commited atomically.

Fixes #2251
parent 6b78b26d
Pipeline #43137 failed with stages
in 54 minutes and 21 seconds
......@@ -1836,19 +1836,23 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable):
position = self._project.pipeline.getPosition()
splitted = False
with self._project.pipeline.commit_timeline_after():
for clip in clips:
start = clip.get_start()
end = start + clip.get_duration()
if start < position and end > position:
clip.get_layer().splitting_object = True
layer = clip.get_layer()
layer.splitting_object = True
try:
self.app.write_action("split-clip",
clip_name=clip.get_name(),
position=float(position / Gst.SECOND))
clip.split(position)
clip.get_layer().splitting_object = False
splitted = True
finally:
layer.splitting_object = False
if not splitted and splitting_selection:
self._splitElements()
......
......@@ -19,6 +19,7 @@
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
"""High-level pipelines."""
import contextlib
import os
from gi.repository import GES
......@@ -533,6 +534,7 @@ class Pipeline(GES.Pipeline, SimplePipeline):
self._was_empty = False
self._commit_wanted = False
self._prevent_commits = 0
if "watchdog" in os.environ.get("PITIVI_UNSTABLE_FEATURES", ''):
watchdog = Gst.ElementFactory.make("watchdog", None)
......@@ -623,8 +625,18 @@ class Pipeline(GES.Pipeline, SimplePipeline):
else:
SimplePipeline._busMessageCb(self, bus, message)
@contextlib.contextmanager
def commit_timeline_after(self):
self._prevent_commits += 1
self.info("Disabling commits during action execution")
try:
yield
finally:
self._prevent_commits -= 1
self.commit_timeline()
def commit_timeline(self):
if self.getState() == Gst.State.NULL:
if self._prevent_commits > 0 or self.getState() == Gst.State.NULL:
# No need to commit. NLE will do it automatically when
# changing state from READY to PAUSED.
return
......
......@@ -133,3 +133,25 @@ class TestPipeline(common.TestCase):
self.assertEqual(pipe._recovery_state, SimplePipeline.RecoveryState.NOT_RECOVERING)
self.assertFalse(pipe._busy_async)
self.assertIsNone(pipe._next_seek)
def test_commit_timeline_after(self):
"""Checks the recovery mechanism."""
pipe = Pipeline(common.create_pitivi_mock())
timeline = GES.Timeline()
pipe.set_timeline(timeline)
with mock.patch.object(pipe, "getState") as get_state:
get_state.return_value = (0, Gst.State.PAUSED, 0)
with mock.patch.object(timeline, "commit") as commit:
with pipe.commit_timeline_after():
pipe.commit_timeline()
self.assertEqual(commit.call_count, 1)
with mock.patch.object(timeline, "commit") as commit:
with pipe.commit_timeline_after():
self.assertEqual(pipe._prevent_commits, 1)
with pipe.commit_timeline_after():
self.assertEqual(pipe._prevent_commits, 2)
pipe.commit_timeline()
self.assertEqual(commit.call_count, 0)
self.assertEqual(commit.call_count, 1)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment