[pitivi: 6/14] Initial implementation of command line preview option
- From: Edward Hervey <edwardrv src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pitivi: 6/14] Initial implementation of command line preview option
- Date: Mon, 20 Sep 2010 09:44:09 +0000 (UTC)
commit b3dd49fd8d2a5ea64d540aae7f6bd08b263d4bb7
Author: Robert Swain <robert swain collabora co uk>
Date: Tue Aug 24 12:00:29 2010 +0200
Initial implementation of command line preview option
Also refactor Renderer class into Actioner for common parts so that the code
can be reused for a Previewer class
pitivi/application.py | 57 +++++++++---
pitivi/render.py | 203 ++++++++++++++++++++++++++-----------------
pitivi/ui/encodingdialog.py | 6 +-
3 files changed, 170 insertions(+), 96 deletions(-)
---
diff --git a/pitivi/application.py b/pitivi/application.py
index 6700e25..ec9b1ef 100644
--- a/pitivi/application.py
+++ b/pitivi/application.py
@@ -54,7 +54,8 @@ from pitivi.undo import UndoableActionLog, DebugActionLogObserver
from pitivi.timeline.timeline_undo import TimelineLogObserver
from pitivi.sourcelist_undo import SourceListLogObserver
from pitivi.undo import UndoableAction
-from pitivi.render import Renderer
+from pitivi.ui.viewer import PitiviViewer
+from pitivi.render import Renderer, Previewer
# FIXME : Speedup loading time
# Currently we load everything in one go
@@ -223,6 +224,7 @@ class Pitivi(Loggable, Signallable):
class InteractivePitivi(Pitivi):
usage = _("""
%prog [-r OUTPUT_FILE] [PROJECT_FILE]
+ %prog -p [PROJECT_FILE]
%prog -i [-a] [MEDIA_FILE]...""")
description = _("""Starts the video editor, optionally loading PROJECT_FILE. If
@@ -239,20 +241,28 @@ When -r is specified, the given project file is rendered without opening the GUI
no_ui_help = _("""Run pitivi with no gui""")
render_help = _("""Render the given project file to OUTPUT_FILE with no GUI.""")
+ preview_help = _("""Preview the given project file without the full UI.""")
def __init__(self):
Pitivi.__init__(self)
self.mainloop = gobject.MainLoop()
+ self.actioner = None
def _newProjectLoaded(self, project):
if self.render_output:
# create renderer and set output file
- self.renderer = Renderer(self.current, pipeline=None, outfile=self.output_file)
- self.renderer.connect("eos", self._eosCb)
+ self.actioner = Renderer(self.current, pipeline=None, outfile=self.output_file)
+ elif self.preview:
+ # create previewer and set ui
+ self.actioner = Previewer(self.current, pipeline=None, ui=self.gui)
+ # hack to make the gtk.HScale seek slider UI behave properly
+ self.gui._durationChangedCb(None, project.timeline.duration)
+ if self.actioner:
+ self.actioner.connect("eos", self._eosCb)
# on error, all we need to do is shutdown which is the same as we do for EOS
- self.renderer.connect("error", self._eosCb)
- # configure the renderer and start rendering!
- self.renderer.startRender()
+ self.actioner.connect("error", self._eosCb)
+ # configure the actioner and start acting!
+ self.actioner.startAction()
def run(self, argv):
# check for dependencies
@@ -272,19 +282,17 @@ When -r is specified, the given project file is rendered without opening the GUI
# validate options
self.render_output = options.render_output
+ self.preview = options.preview
if options.render_output:
options.no_ui = True
n_args += 1
- if options.no_ui:
- self.gui = None
- else:
- # create the ui
- self.gui = PitiviMainWindow(self)
- self.gui.show()
+ if options.render_output and options.preview:
+ parser.error("-p and -r cannot be used simultaneously")
+ return
- if options.import_sources and options.render_output:
- parser.error("-r and -i are incompatible")
+ if options.import_sources and (options.render_output or options.preview):
+ parser.error("-r or -p and -i are incompatible")
return
if not options.import_sources and options.add_to_timeline:
@@ -296,6 +304,20 @@ When -r is specified, the given project file is rendered without opening the GUI
parser.error("invalid arguments")
return
+ if options.no_ui:
+ self.gui = None
+ elif options.preview:
+ # init ui for previewing
+ self.gui = PitiviViewer()
+ self.window = gtk.Window()
+ self.window.connect("delete-event", self._deleteCb)
+ self.window.add(self.gui)
+ self.window.show_all()
+ else:
+ # create the ui
+ self.gui = PitiviMainWindow(self)
+ self.gui.show()
+
if not options.import_sources and args:
index = 0
if options.render_output:
@@ -318,9 +340,14 @@ When -r is specified, the given project file is rendered without opening the GUI
# run the mainloop
self.mainloop.run()
+ def _deleteCb(self, unused_widget, unused_data):
+ self.shutdown()
+
def _eosCb(self, unused_obj):
if self.gui is None:
self.shutdown()
+ elif self.window is not None:
+ self.gui.seek(0)
def shutdown(self):
if Pitivi.shutdown(self):
@@ -343,6 +370,8 @@ When -r is specified, the given project file is rendered without opening the GUI
action="store_true", default=False)
parser.add_option("-r", "--render", help=self.render_help,
dest="render_output", action="store_true", default=False)
+ parser.add_option("-p", "--preview", help=self.preview_help,
+ action="store_true", default=False)
return parser
diff --git a/pitivi/render.py b/pitivi/render.py
index 6c752fe..cdabe51 100644
--- a/pitivi/render.py
+++ b/pitivi/render.py
@@ -36,15 +36,18 @@ from pitivi.settings import export_settings_to_render_settings
from pitivi.stream import VideoStream, AudioStream
from pitivi.utils import beautify_length
-class Renderer(Loggable, Signallable):
- """ Rendering helper methods """
+class Actioner(Loggable, Signallable):
+ """ Previewer/Renderer helper methods """
__signals__ = {
"eos" : None,
"error" : None
}
- def __init__(self, project, pipeline=None, outfile=None):
+ RENDERER = 0
+ PREVIEWER = 1
+
+ def __init__(self, project, pipeline=None):
Loggable.__init__(self)
# grab the Pipeline and settings
self.project = project
@@ -52,128 +55,170 @@ class Renderer(Loggable, Signallable):
self.pipeline = pipeline
else:
self.pipeline = self.project.pipeline
- self.outfile = outfile
- self.detectStreamTypes()
-
- self.rendering = False
- self.renderaction = None
+ self.acting = False
+ self.action = None
self.settings = project.getSettings()
- def detectStreamTypes(self):
- self.have_video = False
- self.have_audio = False
-
- # we can only render TimelineSourceFactory
- if len(self.pipeline.factories) == 0:
- timeline_source = self.project.factory
- else:
- sources = [factory for factory in self.pipeline.factories.keys()
- if isinstance(factory, SourceFactory)]
- timeline_source = sources[0]
- assert isinstance(timeline_source, TimelineSourceFactory)
-
- for track in timeline_source.timeline.tracks:
- if isinstance(track.stream, AudioStream) and track.duration > 0:
- self.have_audio = True
- elif isinstance(track.stream, VideoStream) and \
- track.duration > 0:
- self.have_video = True
-
def _eosCb(self, unused_pipeline):
self.debug("eos !")
- self.rendering = False
- self.updateUIOnEOS()
- self.removeRecordAction()
+ if self.actioner != self.PREVIEWER:
+ self.shutdown()
self.emit("eos")
+ def shutdown(self):
+ self.acting = False
+ self.updateUIOnEOS()
+ self.removeAction()
+
def updateUIOnEOS(self):
pass
def _errorCb(self, pipeline, error, detail):
self.debug("error !")
- self.rendering = False
+ self.acting = False
self.updateUIOnError()
- self.removeRecordAction()
+ self.removeAction()
self.emit("error")
def updateUIOnError(self):
pass
- def _positionCb(self, unused_pipeline, position):
- self.debug("%r %r", unused_pipeline, position)
- fraction = None
- text = None
- timediff = time.time() - self.timestarted
- length = self.project.timeline.duration
- fraction = float(min(position, length)) / float(length)
- if timediff > 5.0 and position:
- # only display ETA after 5s in order to have enough averaging and
- # if the position is non-null
- totaltime = (timediff * float(length) / float(position)) - timediff
- text = beautify_length(int(totaltime * gst.SECOND))
- self.updatePosition(fraction, text)
-
- def updatePosition(self, fraction, text):
- pass
-
def _changeSourceSettings(self, settings):
videocaps = settings.getVideoCaps()
for source in self.project.sources.getSources():
source.setFilterCaps(videocaps)
- def addRecordAction(self):
- self.debug("renderaction %r", self.renderaction)
- if self.renderaction == None:
- self.pipeline.connect('position', self._positionCb)
+ def addAction(self):
+ self.debug("action %r", self.action)
+ if self.action == None:
+ if self.actioner == self.RENDERER:
+ self.pipeline.connect('position', self._positionCb)
self.pipeline.connect('eos', self._eosCb)
self.pipeline.connect('error', self._errorCb)
self.debug("Setting pipeline to STOP")
self.pipeline.stop()
- settings = export_settings_to_render_settings(self.settings,
- self.have_video, self.have_audio)
- self.debug("Creating RenderAction")
+ self.debug("Creating action")
if len(self.pipeline.factories) == 0:
sources = [self.project.factory]
else:
sources = [factory for factory in self.pipeline.factories
if isinstance(factory, SourceFactory)]
- self.renderaction = render_action_for_uri(self.outfile,
- settings, *sources)
+ if self.actioner == self.PREVIEWER:
+ self.action = ViewAction()
+ self.action.addProducers(*sources)
+ self.ui.setAction(self.action)
+ self.ui.setPipeline(self.pipeline)
+ elif self.actioner == self.RENDERER:
+ settings = export_settings_to_render_settings(self.settings,
+ self.have_video, self.have_audio)
+ self.action = render_action_for_uri(self.outfile,
+ settings, *sources)
+ #else:
+ # BIG FAT ERROR HERE
+
self.debug("setting action on pipeline")
- self.pipeline.addAction(self.renderaction)
- self.debug("Activating render action")
- self.renderaction.activate()
- self.debug("Setting all active ViewAction to sync=False")
- for ac in self.pipeline.actions:
- if isinstance(ac, ViewAction) and ac.isActive():
- ac.setSync(False)
+ self.pipeline.addAction(self.action)
+ self.debug("Activating action")
+ self.action.activate()
+ if self.actioner == self.RENDERER:
+ self.debug("Setting all active ViewAction to sync=False")
+ for ac in self.pipeline.actions:
+ if isinstance(ac, ViewAction) and ac.isActive():
+ ac.setSync(False)
self.debug("Updating all sources to render settings")
self._changeSourceSettings(self.settings)
self.debug("setting pipeline to PAUSE")
self.pipeline.pause()
self.debug("done")
- def removeRecordAction(self):
- self.debug("renderaction %r", self.renderaction)
- if self.renderaction:
+
+ def removeAction(self):
+ self.debug("action %r", self.action)
+ if self.action:
self.pipeline.stop()
- self.renderaction.deactivate()
- self.pipeline.removeAction(self.renderaction)
+ self.action.deactivate()
+ self.pipeline.removeAction(self.action)
self.debug("putting all active ViewActions back to sync=True")
for ac in self.pipeline.actions:
if isinstance(ac, ViewAction) and ac.isActive():
ac.setSync(True)
self._changeSourceSettings(self.project.getSettings())
self.pipeline.pause()
- self.pipeline.disconnect_by_function(self._positionCb)
+ if self.actioner == self.RENDERER:
+ self.pipeline.disconnect_by_function(self._positionCb)
self.pipeline.disconnect_by_function(self._eosCb)
self.pipeline.disconnect_by_function(self._errorCb)
- self.renderaction = None
+ self.action = None
- def startRender(self):
+ def _startAction(self):
+ self.addAction()
+ self.pipeline.play()
+ self.timestarted = time.time()
+ self.acting = True
+
+class Renderer(Actioner):
+ """ Rendering helper methods """
+
+ def __init__(self, project, pipeline=None, outfile=None):
+ self.actioner = self.RENDERER
+ Actioner.__init__(self, project, pipeline)
+ self.detectStreamTypes()
+ self.outfile = outfile
+
+ def setOutfile(self):
+ self.outfile = outfile
+
+ def detectStreamTypes(self):
+ self.have_video = False
+ self.have_audio = False
+
+ # we can only render TimelineSourceFactory
+ if len(self.pipeline.factories) == 0:
+ timeline_source = self.project.factory
+ else:
+ sources = [factory for factory in self.pipeline.factories.keys()
+ if isinstance(factory, SourceFactory)]
+ timeline_source = sources[0]
+ assert isinstance(timeline_source, TimelineSourceFactory)
+
+ for track in timeline_source.timeline.tracks:
+ if isinstance(track.stream, AudioStream) and track.duration > 0:
+ self.have_audio = True
+ elif isinstance(track.stream, VideoStream) and \
+ track.duration > 0:
+ self.have_video = True
+
+ def _positionCb(self, unused_pipeline, position):
+ self.debug("%r %r", unused_pipeline, position)
+ fraction = None
+ text = None
+ timediff = time.time() - self.timestarted
+ length = self.project.timeline.duration
+ fraction = float(min(position, length)) / float(length)
+ if timediff > 5.0 and position:
+ # only display ETA after 5s in order to have enough averaging and
+ # if the position is non-null
+ totaltime = (timediff * float(length) / float(position)) - timediff
+ text = beautify_length(int(totaltime * gst.SECOND))
+ self.updatePosition(fraction, text)
+
+ def updatePosition(self, fraction, text):
+ pass
+
+ def startAction(self):
self.debug("Rendering")
- if self.outfile and not self.rendering:
- self.addRecordAction()
- self.pipeline.play()
- self.timestarted = time.time()
- self.rendering = True
+ if not self.acting and self.outfile:
+ self._startAction()
+
+class Previewer(Actioner):
+ """ Previewing helper methods """
+
+ def __init__(self, project, pipeline=None, ui=None):
+ self.actioner = self.PREVIEWER
+ Actioner.__init__(self, project, pipeline)
+ self.ui = ui
+
+ def startAction(self):
+ self.debug("Previewing")
+ if not self.acting and self.ui:
+ self._startAction()
diff --git a/pitivi/ui/encodingdialog.py b/pitivi/ui/encodingdialog.py
index 1356507..47ff5df 100644
--- a/pitivi/ui/encodingdialog.py
+++ b/pitivi/ui/encodingdialog.py
@@ -73,7 +73,7 @@ class EncodingDialog(GladeWindow, Renderer):
def _shutDown(self):
self.debug("shutting down")
# Abort recording
- self.removeRecordAction()
+ self.removeAction()
self.destroy()
def _displaySettings(self):
@@ -118,8 +118,8 @@ class EncodingDialog(GladeWindow, Renderer):
self.progressbar.set_text(_("About %s left") % text)
def _recordButtonClickedCb(self, unused_button):
- self.startRender()
- if self.rendering:
+ self.startAction()
+ if self.acting:
self.cancelbutton.set_label("gtk-cancel")
self.progressbar.set_text(_("Rendering"))
self.recordbutton.set_sensitive(False)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]