Commit 03e15b44 authored by Alexandru Băluț's avatar Alexandru Băluț
Browse files

viewer: Avoid messing with the project pipeline when previewing trims

Once the viewer container is connected to a project, it does not even
have to keep a reference to the project pipeline, now that it keeps a
separate reference to the temporary AssetPipeline used when trimming.

Gets rid of a few fields, and avoids setting the project pipeline to
state NULL, thus avoiding a flicker when switching state from NULL to
PAUSED.
parent 42a7dc01
...@@ -27,7 +27,6 @@ from gi.repository import Gtk ...@@ -27,7 +27,6 @@ from gi.repository import Gtk
from pitivi.settings import GlobalSettings from pitivi.settings import GlobalSettings
from pitivi.utils.loggable import Loggable from pitivi.utils.loggable import Loggable
from pitivi.utils.misc import format_ns
from pitivi.utils.pipeline import AssetPipeline from pitivi.utils.pipeline import AssetPipeline
from pitivi.utils.ui import SPACING from pitivi.utils.ui import SPACING
from pitivi.utils.widgets import TimeWidget from pitivi.utils.widgets import TimeWidget
...@@ -84,20 +83,15 @@ class ViewerContainer(Gtk.Box, Loggable): ...@@ -84,20 +83,15 @@ class ViewerContainer(Gtk.Box, Loggable):
self.log("New ViewerContainer") self.log("New ViewerContainer")
self.project = None self.project = None
self.pipeline = None self.trim_pipeline = None
self.docked = True self.docked = True
self.target = None self.target = None
self._compactMode = False self._compactMode = False
# Only used for restoring the pipeline position after a live clip trim
# preview:
self._oldTimelinePos = None
self._haveUI = False self._haveUI = False
self._createUi() self._createUi()
self.__owning_pipeline = False
if not self.settings.viewerDocked: if not self.settings.viewerDocked:
self.undock() self.undock()
...@@ -111,8 +105,7 @@ class ViewerContainer(Gtk.Box, Loggable): ...@@ -111,8 +105,7 @@ class ViewerContainer(Gtk.Box, Loggable):
def _project_manager_new_project_loaded_cb(self, unused_project_manager, project): def _project_manager_new_project_loaded_cb(self, unused_project_manager, project):
project.connect("rendering-settings-changed", project.connect("rendering-settings-changed",
self._project_rendering_settings_changed_cb) self._project_rendering_settings_changed_cb)
self.project = project self.set_project(project)
self.setPipeline(project.pipeline)
def _projectManagerProjectClosedCb(self, unused_project_manager, project): def _projectManagerProjectClosedCb(self, unused_project_manager, project):
if self.project == project: if self.project == project:
...@@ -128,16 +121,13 @@ class ViewerContainer(Gtk.Box, Loggable): ...@@ -128,16 +121,13 @@ class ViewerContainer(Gtk.Box, Loggable):
self.target.update_aspect_ratio(project) self.target.update_aspect_ratio(project)
self.timecode_entry.setFramerate(project.videorate) self.timecode_entry.setFramerate(project.videorate)
def setPipeline(self, pipeline, position=None): def set_project(self, project):
"""Sets the displayed pipeline. """Sets the displayed project.
Properly switches the currently set action to that new Pipeline.
Args: Args:
pipeline (Pipeline): The Pipeline to switch to. project (Project): The Project to switch to.
position (Optional[int]): The position to seek to initially.
""" """
self.debug("Setting pipeline: %r", pipeline) self.debug("Setting project: %r", project)
self._disconnectFromPipeline() self._disconnectFromPipeline()
if self.target: if self.target:
...@@ -145,21 +135,20 @@ class ViewerContainer(Gtk.Box, Loggable): ...@@ -145,21 +135,20 @@ class ViewerContainer(Gtk.Box, Loggable):
if parent: if parent:
parent.remove(self.target) parent.remove(self.target)
self.pipeline = pipeline project.pipeline.connect("state-change", self._pipelineStateChangedCb)
self.pipeline.connect("state-change", self._pipelineStateChangedCb) project.pipeline.connect("position", self._positionCb)
self.pipeline.connect("position", self._positionCb) project.pipeline.connect("duration-changed", self._durationChangedCb)
self.pipeline.connect("duration-changed", self._durationChangedCb) self.project = project
self.__owning_pipeline = False
self.__createNewViewer() self.__createNewViewer()
self._setUiActive() self._setUiActive()
if position: # This must be done at the end, otherwise the created sink widget
self.pipeline.simple_seek(position) # appears in a separate window.
self.pipeline.pause() project.pipeline.pause()
def __createNewViewer(self): def __createNewViewer(self):
_, sink_widget = self.pipeline.create_sink() _, sink_widget = self.project.pipeline.create_sink()
self.overlay_stack = OverlayStack(self.app, sink_widget) self.overlay_stack = OverlayStack(self.app, sink_widget)
self.target = ViewerWidget(self.overlay_stack) self.target = ViewerWidget(self.overlay_stack)
...@@ -178,18 +167,14 @@ class ViewerContainer(Gtk.Box, Loggable): ...@@ -178,18 +167,14 @@ class ViewerContainer(Gtk.Box, Loggable):
GLib.timeout_add(1000, self.__viewer_realization_done_cb, None) GLib.timeout_add(1000, self.__viewer_realization_done_cb, None)
def _disconnectFromPipeline(self): def _disconnectFromPipeline(self):
if self.pipeline is None: if self.project is None:
# silently return, there's nothing to disconnect from
return return
self.debug("Disconnecting from: %r", self.pipeline) pipeline = self.project.pipeline
self.pipeline.disconnect_by_func(self._pipelineStateChangedCb) self.debug("Disconnecting from: %r", pipeline)
self.pipeline.disconnect_by_func(self._positionCb) pipeline.disconnect_by_func(self._pipelineStateChangedCb)
self.pipeline.disconnect_by_func(self._durationChangedCb) pipeline.disconnect_by_func(self._positionCb)
pipeline.disconnect_by_func(self._durationChangedCb)
if self.__owning_pipeline:
self.pipeline.release()
self.pipeline = None
def _setUiActive(self, active=True): def _setUiActive(self, active=True):
self.debug("active %r", active) self.debug("active %r", active)
...@@ -428,10 +413,10 @@ class ViewerContainer(Gtk.Box, Loggable): ...@@ -428,10 +413,10 @@ class ViewerContainer(Gtk.Box, Loggable):
self.settings.viewerDocked = False self.settings.viewerDocked = False
self.remove(self.buttons_container) self.remove(self.buttons_container)
position = None position = None
if self.pipeline: if self.project:
self.overlay_stack.enable_resize_status(False) self.overlay_stack.enable_resize_status(False)
position = self.pipeline.getPosition() position = self.project.pipeline.getPosition()
self.pipeline.setState(Gst.State.NULL) self.project.pipeline.setState(Gst.State.NULL)
self.remove(self.target) self.remove(self.target)
self.__createNewViewer() self.__createNewViewer()
self.buttons_container.set_margin_bottom(SPACING) self.buttons_container.set_margin_bottom(SPACING)
...@@ -452,9 +437,9 @@ class ViewerContainer(Gtk.Box, Loggable): ...@@ -452,9 +437,9 @@ class ViewerContainer(Gtk.Box, Loggable):
self.external_window.move(self.settings.viewerX, self.settings.viewerY) self.external_window.move(self.settings.viewerX, self.settings.viewerY)
self.external_window.resize( self.external_window.resize(
self.settings.viewerWidth, self.settings.viewerHeight) self.settings.viewerWidth, self.settings.viewerHeight)
if self.pipeline: if self.project:
self.pipeline.pause() self.project.pipeline.pause()
self.pipeline.simple_seek(position) self.project.pipeline.simple_seek(position)
def __viewer_realization_done_cb(self, unused_data): def __viewer_realization_done_cb(self, unused_data):
self.overlay_stack.enable_resize_status(True) self.overlay_stack.enable_resize_status(True)
...@@ -469,10 +454,10 @@ class ViewerContainer(Gtk.Box, Loggable): ...@@ -469,10 +454,10 @@ class ViewerContainer(Gtk.Box, Loggable):
self.settings.viewerDocked = True self.settings.viewerDocked = True
position = None position = None
if self.pipeline: if self.project:
self.overlay_stack.enable_resize_status(False) self.overlay_stack.enable_resize_status(False)
position = self.pipeline.getPosition() position = self.project.pipeline.getPosition()
self.pipeline.setState(Gst.State.NULL) self.project.pipeline.setState(Gst.State.NULL)
self.external_vbox.remove(self.target) self.external_vbox.remove(self.target)
self.__createNewViewer() self.__createNewViewer()
...@@ -484,9 +469,9 @@ class ViewerContainer(Gtk.Box, Loggable): ...@@ -484,9 +469,9 @@ class ViewerContainer(Gtk.Box, Loggable):
self.show() self.show()
self.external_window.hide() self.external_window.hide()
if self.pipeline: if self.project.pipeline:
self.pipeline.pause() self.project.pipeline.pause()
self.pipeline.simple_seek(position) self.project.pipeline.simple_seek(position)
def _toggleFullscreen(self, widget): def _toggleFullscreen(self, widget):
if widget.get_active(): if widget.get_active():
...@@ -517,29 +502,32 @@ class ViewerContainer(Gtk.Box, Loggable): ...@@ -517,29 +502,32 @@ class ViewerContainer(Gtk.Box, Loggable):
self.log("Not previewing trim for image or title clip: %s", clip) self.log("Not previewing trim for image or title clip: %s", clip)
return False return False
if self.pipeline == self.app.project_manager.current_project.pipeline: if self.project.pipeline.getState() == Gst.State.PLAYING:
self.debug("Creating temporary pipeline for clip %s, position %s", self.project.pipeline.setState(Gst.State.PAUSED)
clip.props.uri, format_ns(position))
self._oldTimelinePos = self.pipeline.getPosition(False)
self.pipeline.set_state(Gst.State.NULL)
self.setPipeline(AssetPipeline(clip))
self.__owning_pipeline = True
self.pipeline.simple_seek(position) if self.trim_pipeline and clip is not self.trim_pipeline.clip:
return False # Seems to be the trim preview pipeline for a different clip.
self.trim_pipeline.release()
self.trim_pipeline = None
if not self.trim_pipeline:
self.debug("Creating temporary pipeline for clip %s", clip.props.uri)
self.trim_pipeline = AssetPipeline(clip)
video_sink, sink_widget = self.trim_pipeline.create_sink()
self.target.switch_widget(sink_widget)
self.trim_pipeline.setState(Gst.State.PAUSED)
self.trim_pipeline.simple_seek(position)
def clipTrimPreviewFinished(self): def clipTrimPreviewFinished(self):
"""Switches back to the project pipeline following a clip trimming.""" """Switches back to the project pipeline following a clip trimming."""
if self.pipeline is not self.app.project_manager.current_project.pipeline: if not self.trim_pipeline:
self.debug("Going back to the project's pipeline") return
self.pipeline.setState(Gst.State.NULL) self.target.switch_widget(self.overlay_stack)
# Using pipeline.getPosition() here does not work because for some self.trim_pipeline.release()
# reason it's a bit off, that's why we need self._oldTimelinePos. self.trim_pipeline = None
self.setPipeline(
self.app.project_manager.current_project.pipeline, self._oldTimelinePos) def _pipelineStateChangedCb(self, pipeline, state, old_state):
self._oldTimelinePos = None
def _pipelineStateChangedCb(self, unused_pipeline, state, old_state):
"""Updates the widgets when the playback starts or stops.""" """Updates the widgets when the playback starts or stops."""
if state == Gst.State.PLAYING: if state == Gst.State.PLAYING:
st = Gst.Structure.new_empty("play") st = Gst.Structure.new_empty("play")
...@@ -553,8 +541,8 @@ class ViewerContainer(Gtk.Box, Loggable): ...@@ -553,8 +541,8 @@ class ViewerContainer(Gtk.Box, Loggable):
if old_state != Gst.State.PAUSED: if old_state != Gst.State.PAUSED:
st = Gst.Structure.new_empty("pause") st = Gst.Structure.new_empty("pause")
if old_state == Gst.State.PLAYING: if old_state == Gst.State.PLAYING:
st.set_value("playback_time", position_seconds = pipeline.getPosition() / Gst.SECOND
self.pipeline.getPosition() / Gst.SECOND) st.set_value("playback_time", position_seconds)
self.app.write_action(st) self.app.write_action(st)
self.playpause_button.setPlay() self.playpause_button.setPlay()
...@@ -589,6 +577,13 @@ class ViewerWidget(Gtk.AspectFrame, Loggable): ...@@ -589,6 +577,13 @@ class ViewerWidget(Gtk.AspectFrame, Loggable):
# would show through the non-double-buffered widget! # would show through the non-double-buffered widget!
self.hide() self.hide()
def switch_widget(self, widget):
child = self.get_child()
if child:
self.remove(child)
widget.show_all()
self.add(widget)
def update_aspect_ratio(self, project): def update_aspect_ratio(self, project):
"""Forces the DAR of the project on the child widget.""" """Forces the DAR of the project on the child widget."""
ratio_fraction = project.getDAR() ratio_fraction = project.getDAR()
......
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