[pitivi] Allow editing nested timelines
- From: Alexandru Băluț <alexbalut src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pitivi] Allow editing nested timelines
- Date: Mon, 23 Sep 2019 11:13:29 +0000 (UTC)
commit 268d88f4eb029c5731f69821769cce368d5c9999
Author: Swayamjeet <swayam1998 gmail com>
Date: Wed Aug 14 23:57:02 2019 +0530
Allow editing nested timelines
This is done by starting up another Pitivi instance.
pitivi/editorperspective.py | 26 ++++++++++++++++++++++++--
pitivi/medialibrary.py | 36 ++++++++++++++++++++++++++++++++++++
pitivi/timeline/elements.py | 5 +++++
pitivi/timeline/previewers.py | 42 ++++++++++++++++++++++++++++++++++++++++++
pitivi/utils/proxy.py | 2 +-
5 files changed, 108 insertions(+), 3 deletions(-)
---
diff --git a/pitivi/editorperspective.py b/pitivi/editorperspective.py
index da3386db..793f4538 100644
--- a/pitivi/editorperspective.py
+++ b/pitivi/editorperspective.py
@@ -37,6 +37,7 @@ from pitivi.perspective import Perspective
from pitivi.project import ProjectSettingsDialog
from pitivi.settings import GlobalSettings
from pitivi.tabsmanager import BaseTabs
+from pitivi.timeline.previewers import ThumbnailCache
from pitivi.timeline.timeline import TimelineContainer
from pitivi.titleeditor import TitleEditor
from pitivi.transitions import TransitionsListWidget
@@ -45,8 +46,6 @@ from pitivi.utils.misc import path_from_uri
from pitivi.utils.ui import beautify_time_delta
from pitivi.utils.ui import EDITOR_PERSPECTIVE_CSS
from pitivi.utils.ui import info_name
-from pitivi.utils.ui import PADDING
-from pitivi.utils.ui import SPACING
from pitivi.viewer.viewer import ViewerContainer
@@ -102,6 +101,7 @@ class EditorPerspective(Perspective, Loggable):
"""Sets up the UI."""
self.__setup_css()
self._createUi()
+ self.app.gui.connect("focus-in-event", self.__focus_in_event_cb)
self.app.gui.connect("destroy", self._destroyedCb)
def refresh(self):
@@ -116,6 +116,28 @@ class EditorPerspective(Perspective, Loggable):
style_context.add_provider_for_screen(screen, css_provider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
+ def __focus_in_event_cb(self, unused_widget, unused_event):
+ ges_timeline = self.timeline_ui.timeline.ges_timeline
+ if not ges_timeline:
+ # Nothing to work with, Pitivi is starting up.
+ return
+
+ # Commit the timeline so its nested timelines assets are refreshed.
+ ges_timeline.commit()
+
+ # We need to track the changed assets ourselves.
+ changed_files_uris = ThumbnailCache.update_caches()
+ if changed_files_uris:
+ self.medialibrary.update_asset_thumbs(changed_files_uris)
+
+ for ges_layer in ges_timeline.get_layers():
+ for ges_clip in ges_layer.get_clips():
+ if ges_clip.get_asset().props.id in changed_files_uris:
+ if ges_clip.ui._audioSource:
+ ges_clip.ui._audioSource.update_previewer()
+ if ges_clip.ui._videoSource:
+ ges_clip.ui._videoSource.update_previewer()
+
def _destroyedCb(self, unused_main_window):
"""Cleanup before destroying this window."""
pm = self.app.project_manager
diff --git a/pitivi/medialibrary.py b/pitivi/medialibrary.py
index 6d519a17..5a1082d7 100644
--- a/pitivi/medialibrary.py
+++ b/pitivi/medialibrary.py
@@ -19,6 +19,8 @@
# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
# Boston, MA 02110-1301, USA.
import os
+import subprocess
+import sys
import time
from gettext import gettext as _
from gettext import ngettext
@@ -208,6 +210,15 @@ class AssetThumbnail(GObject.Object, Loggable):
self.src_small, self.src_large = self.__get_thumbnails()
self.decorate()
+ def disregard_previewer(self):
+ if self.__previewer:
+ self.__previewer.disconnect_by_func(self.__done_cb)
+ self.__previewer.stop_generation()
+ self.__previewer = None
+
+ self.refresh()
+ self.emit("thumb-updated")
+
def __get_thumbnails(self):
"""Gets the base source thumbnails.
@@ -801,6 +812,11 @@ class MediaLibraryWidget(Gtk.Box, Loggable):
filter.add_custom(Gtk.FileFilterFlags.URI |
Gtk.FileFilterFlags.MIME_TYPE,
self.__filter_unsupported)
+ for formatter in GES.list_assets(GES.Formatter):
+ for extension in formatter.get_meta("extension").split(","):
+ if not extension:
+ continue
+ filter.add_pattern("*.%s" % extension)
dialog.add_filter(filter)
# ...and allow the user to override our whitelists
@@ -830,6 +846,11 @@ class MediaLibraryWidget(Gtk.Box, Loggable):
if self._project.loaded:
self._flushPendingAssets()
+ def update_asset_thumbs(self, asset_uris):
+ for row in self.storemodel:
+ if row[COL_ASSET].props.id in asset_uris:
+ row[COL_THUMB_DECORATOR].disregard_previewer()
+
def _flushPendingAssets(self):
self.debug("Flushing %d pending model rows", len(self._pending_assets))
for asset in self._pending_assets:
@@ -1231,6 +1252,14 @@ class MediaLibraryWidget(Gtk.Box, Loggable):
parent_path = os.path.dirname(path_from_uri(assets[0].get_id()))
Gio.AppInfo.launch_default_for_uri(Gst.filename_to_uri(parent_path), None)
+ def __edit_nested_clip_cb(self, unused_action, unused_parameter):
+ assets = self.getSelectedAssets()
+ if len(assets) != 1:
+ return
+
+ path = os.path.abspath(path_from_uri(assets[0].get_id()))
+ subprocess.Popen([sys.argv[0], path])
+
def __createMenuModel(self):
if self.app.proxy_manager.proxyingUnsupported:
return None, None
@@ -1249,6 +1278,13 @@ class MediaLibraryWidget(Gtk.Box, Loggable):
text = _("Open containing folder")
menu_model.append(text, "assets.%s" % action.get_name().replace(" ", "."))
+ if len(assets) == 1 and assets[0].props.is_nested_timeline:
+ action = Gio.SimpleAction.new("edit-nested-clip", None)
+ action.connect("activate", self.__edit_nested_clip_cb)
+ action_group.insert(action)
+ text = _("Edit")
+ menu_model.append(text, "assets.%s" % action.get_name().replace(" ", "."))
+
image_assets = [asset for asset in assets
if asset.is_image()]
diff --git a/pitivi/timeline/elements.py b/pitivi/timeline/elements.py
index 0b5de8fd..bd1cf47e 100644
--- a/pitivi/timeline/elements.py
+++ b/pitivi/timeline/elements.py
@@ -636,6 +636,11 @@ class TimelineElement(Gtk.Layout, Zoomable, Loggable):
# and override that one.
self.showDefaultKeyframes(lazy_render=True)
+ def update_previewer(self):
+ """Refreshes the previewer widget."""
+ if self.__previewer:
+ self.__previewer.refresh()
+
def release(self):
if self.__previewer:
self.__previewer.release()
diff --git a/pitivi/timeline/previewers.py b/pitivi/timeline/previewers.py
index ec9a7fe0..74f35366 100644
--- a/pitivi/timeline/previewers.py
+++ b/pitivi/timeline/previewers.py
@@ -740,6 +740,16 @@ class AssetPreviewer(Previewer, Loggable):
self.failures.add(self.position)
self.position = -1
self._schedule_next_thumb_generation()
+ elif message.type == Gst.MessageType.STREAM_COLLECTION and isinstance(message.src, GES.Timeline):
+ # Make sure we only work with the video track when thumbnailing
+ # nested timelines.
+ collection = message.parse_stream_collection()
+ for i in range(collection.get_size()):
+ stream = collection.get_stream(i)
+ if stream.get_stream_type() == Gst.StreamType.VIDEO:
+ message.src.send_event(Gst.Event.new_select_streams([stream.get_stream_id()]))
+ break
+
return Gst.BusSyncReply.PASS
def __preroll_timed_out_cb(self):
@@ -822,6 +832,12 @@ class VideoPreviewer(Gtk.Layout, AssetPreviewer, Zoomable):
for thumb in self.get_children():
thumb.props.opacity = opacity
+ def refresh(self):
+ """Recreates the thumbnails cache."""
+ self.stop_generation()
+ self.thumb_cache = ThumbnailCache.get(self.uri)
+ self._update_thumbnails()
+
def _update_thumbnails(self):
"""Updates the thumbnail widgets for the clip at the current zoom."""
if not self.thumb_width:
@@ -934,6 +950,22 @@ class ThumbnailCache(Loggable):
thumbs_cache_dir = get_dir(os.path.join(xdg_cache_home(), "thumbs"))
return os.path.join(thumbs_cache_dir, filename)
+ @classmethod
+ def update_caches(cls):
+ """Trashes the obsolete caches, for assets which changed.
+
+ Returns:
+ list[str]: The URIs of the assets which changed.
+ """
+ changed_files_uris = []
+ for uri, cache in cls.caches_by_uri.items():
+ dbfile = cls.dbfile_name(uri)
+ if cache.dbfile != dbfile:
+ changed_files_uris.append(uri)
+ for uri in changed_files_uris:
+ del cls.caches_by_uri[uri]
+ return changed_files_uris
+
@classmethod
def get(cls, obj):
"""Gets a ThumbnailCache for the specified object.
@@ -1086,6 +1118,16 @@ class AudioPreviewer(Gtk.Layout, Previewer, Zoomable, Loggable):
self._num_failures = 0
self.become_controlled()
+ def refresh(self):
+ """Discards the audio samples so they are recreated."""
+ self.stop_generation()
+
+ self.samples = None
+ self.surface = None
+ self.queue_draw()
+
+ self.become_controlled()
+
def _startLevelsDiscovery(self):
filename = get_wavefile_location_for_uri(self._uri)
if os.path.exists(filename):
diff --git a/pitivi/utils/proxy.py b/pitivi/utils/proxy.py
index f823380e..0eae303e 100644
--- a/pitivi/utils/proxy.py
+++ b/pitivi/utils/proxy.py
@@ -85,7 +85,7 @@ class ProxyManager(GObject.Object, Loggable):
"error-preparing-asset": (GObject.SignalFlags.RUN_LAST, None, (object, object, object)),
}
- WHITELIST_CONTAINER_CAPS = ["video/quicktime", "application/ogg",
+ WHITELIST_CONTAINER_CAPS = ["video/quicktime", "application/ogg", "application/xges",
"video/x-matroska", "video/webm"]
WHITELIST_AUDIO_CAPS = ["audio/mpeg", "audio/x-vorbis",
"audio/x-raw", "audio/x-flac",
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]