From 12290725a033035c45f4878a3adb7ae8db0fdc8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandru=20B=C4=83lu=C8=9B?= Date: Fri, 10 Sep 2021 09:22:04 +0200 Subject: [PATCH] timeline: Constrain duration of clips Make sure when adding new clips that the duration covers an exact number of frames. Fixes #2576 --- pitivi/timeline/timeline.py | 42 ++++++++++++++++++++++++------------- tests/test_medialibrary.py | 2 +- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py index d94dc118f..5dcfca382 100644 --- a/pitivi/timeline/timeline.py +++ b/pitivi/timeline/timeline.py @@ -16,6 +16,7 @@ # License along with this program; if not, see . import os from gettext import gettext as _ +from typing import Any from typing import List from typing import Optional @@ -323,7 +324,7 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): Zoomable.__init__(self) Loggable.__init__(self) - self.app = app + self.app: Any = app self._project = None self.ges_timeline = None self.editor_state = editor_state @@ -940,26 +941,35 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): for ges_layer in self.ges_timeline.get_layers(): ges_layer.ui.update_position() - def add_clip_to_layer(self, ges_layer, asset, start): + def add_clip_to_layer(self, ges_layer: GES.Layer, asset: GES.Asset, start: int) -> Optional[GES.Clip]: + """Creates a clip out of the asset on the specified layer. + + Shortens the duration so the clip covers an exact number of frames. + """ if asset.is_image(): - clip_duration = self.app.settings.imageClipLength * \ - Gst.SECOND / 1000.0 - max_duration = 0 + duration = self.app.settings.imageClipLength * Gst.SECOND / 1000.0 else: - clip_duration = asset_get_duration(asset) - max_duration = clip_duration + duration = asset_get_duration(asset) + + duration = self.mod_duration(duration) - ges_clip = ges_layer.add_asset(asset, start, 0, clip_duration, - asset.get_supported_formats()) + track_types = asset.get_supported_formats() + ges_clip = ges_layer.add_asset(asset, start, 0, duration, track_types) if not ges_clip: - return ges_clip + return None # Tell GES that the max duration is our newly compute max duration # so it has the proper information when doing timeline editing. - if max_duration and ges_clip.props.max_duration > max_duration: - ges_clip.props.max_duration = max_duration + if not asset.is_image(): + ges_clip.props.max_duration = min(ges_clip.props.max_duration, duration) + return ges_clip + def mod_duration(self, duration: int) -> int: + """Shortens the duration so it represents an exact number of frames.""" + duration_frames = self.ges_timeline.get_frame_at(duration) + return self.ges_timeline.get_frame_time(duration_frames) + def __create_clips(self, x, y): """Creates the clips for an asset drag operation. @@ -980,8 +990,7 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): for asset in assets: ges_layer, unused_on_sep = self.get_layer_at(y) if not placement: - placement = self.pixel_to_ns(x) - placement = max(0, placement) + placement = max(0, self.pixel_to_ns(x)) self.debug("Adding %s at %s on layer %s", asset.props.id, Gst.TIME_ARGS(placement), ges_layer) self.app.action_log.begin("Add one clip") @@ -1542,7 +1551,10 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable): if isinstance(obj, GES.Clip): obj.set_start(clip_position) layer.add_clip(obj) - duration = obj.get_duration() + original_duration = obj.get_duration() + duration = self.timeline.mod_duration(original_duration) + if duration != original_duration: + obj.set_duration(duration) elif isinstance(obj, GES.Asset): ges_clip = self.timeline.add_clip_to_layer(layer, obj, clip_position) duration = ges_clip.props.duration diff --git a/tests/test_medialibrary.py b/tests/test_medialibrary.py index df26a9b2a..ed107a543 100644 --- a/tests/test_medialibrary.py +++ b/tests/test_medialibrary.py @@ -110,7 +110,7 @@ class BaseTestMediaLibrary(common.TestCase): "notify::fraction", self._progress_bar_cb) self._create_assets(samples) - self.mainloop.run(timeout_seconds=10) + self.mainloop.run(timeout_seconds=15) self.assertFalse(self.medialibrary._progressbar.props.visible) def check_add_proxy(self, asset, scaled=False, w=160, h=120, -- GitLab