~ubuntu-branches/ubuntu/utopic/pitivi/utopic

« back to all changes in this revision

Viewing changes to pitivi/actioner.py

  • Committer: Package Import Robot
  • Author(s): Sebastian Dröge
  • Date: 2014-04-05 15:28:16 UTC
  • mfrom: (6.1.13 sid)
  • Revision ID: package-import@ubuntu.com-20140405152816-6lijoax4cngiz5j5
Tags: 0.93-3
* debian/control:
  + Depend on python-gi (>= 3.10), older versions do not work
    with pitivi (Closes: #732813).
  + Add missing dependency on gir1.2-clutter-gst-2.0 (Closes: #743692).
  + Add suggests on gir1.2-notify-0.7 and gir1.2-gnomedesktop-3.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# PiTiVi , Non-linear video editor
2
 
#
3
 
#       pitivi/actioner.py
4
 
#
5
 
# Copyright (c) 2005, Edward Hervey <bilboed@bilboed.com>
6
 
# Copyright (c) 2010, Robert Swain <rob@opendot.cl>
7
 
#
8
 
# This program is free software; you can redistribute it and/or
9
 
# modify it under the terms of the GNU Lesser General Public
10
 
# License as published by the Free Software Foundation; either
11
 
# version 2.1 of the License, or (at your option) any later version.
12
 
#
13
 
# This program is distributed in the hope that it will be useful,
14
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 
# Lesser General Public License for more details.
17
 
#
18
 
# You should have received a copy of the GNU Lesser General Public
19
 
# License along with this program; if not, write to the
20
 
# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21
 
# Boston, MA 02110-1301, USA.
22
 
 
23
 
"""
24
 
Rendering helpers
25
 
"""
26
 
 
27
 
import time
28
 
import gst
29
 
 
30
 
from pitivi.action import RenderAction, ViewAction
31
 
from pitivi.encode import RenderFactory, RenderSinkFactory
32
 
from pitivi.factories.base import SourceFactory
33
 
from pitivi.factories.file import URISinkFactory
34
 
from pitivi.factories.timeline import TimelineSourceFactory
35
 
from pitivi.log.loggable import Loggable
36
 
from pitivi.settings import export_settings_to_render_settings
37
 
from pitivi.signalinterface import Signallable
38
 
from pitivi.stream import AudioStream, VideoStream
39
 
from pitivi.utils import beautify_ETA
40
 
 
41
 
 
42
 
class Actioner(Loggable, Signallable):
43
 
    """ Previewer/Renderer helper methods """
44
 
 
45
 
    __signals__ = {
46
 
        "eos": None,
47
 
        "error": None
48
 
        }
49
 
 
50
 
    def __init__(self, project, pipeline=None, settings=None):
51
 
        Loggable.__init__(self)
52
 
        # grab the Pipeline and settings
53
 
        self.project = project
54
 
        if pipeline != None:
55
 
            self.pipeline = pipeline
56
 
        else:
57
 
            self.pipeline = self.project.pipeline
58
 
        self.acting = False
59
 
        self.action = None
60
 
        if settings:
61
 
            self.settings = settings
62
 
        else:
63
 
            self.settings = project.getSettings()
64
 
        self.timestarted = 0
65
 
 
66
 
    def _eosCb(self, unused_pipeline):
67
 
        self.debug("eos !")
68
 
        self.emit("eos")
69
 
 
70
 
    def shutdown(self):
71
 
        self.acting = False
72
 
        self.updateUIOnEOS()
73
 
        self.removeAction()
74
 
 
75
 
    def updateUIOnEOS(self):
76
 
        pass
77
 
 
78
 
    def _errorCb(self, pipeline, error, detail):
79
 
        self.debug("error !")
80
 
        self.acting = False
81
 
        self.updateUIOnError()
82
 
        self.removeAction()
83
 
        self.emit("error")
84
 
 
85
 
    def updateUIOnError(self):
86
 
        pass
87
 
 
88
 
    def _changeSourceSettings(self, settings):
89
 
        videocaps = settings.getVideoCaps()
90
 
        for source in self.project.sources.getSources():
91
 
            source.setFilterCaps(videocaps)
92
 
 
93
 
    def addAction(self):
94
 
        self.debug("action %r", self.action)
95
 
        if self.action:
96
 
            return
97
 
        self._connectFunctions()
98
 
        self.debug("Setting pipeline to STOP")
99
 
        self.pipeline.stop()
100
 
        self.debug("Creating action")
101
 
        sources = self._getSources()
102
 
        self.action = self._createAction(sources)
103
 
 
104
 
        self.debug("Setting action on pipeline")
105
 
        self.pipeline.addAction(self.action)
106
 
        self.debug("Activating action")
107
 
        self._activateAction()
108
 
        self.debug("Updating all sources to render settings")
109
 
        self._changeSourceSettings(self.settings)
110
 
        self.debug("Setting pipeline to PAUSE")
111
 
        self.pipeline.pause()
112
 
        self.debug("Done")
113
 
 
114
 
    def _getSources(self):
115
 
        if not self.pipeline.factories:
116
 
            return [self.project.factory]
117
 
        return [factory
118
 
                for factory in self.pipeline.factories
119
 
                if isinstance(factory, SourceFactory)]
120
 
 
121
 
    def _connectFunctions(self):
122
 
        self.pipeline.connect('eos', self._eosCb)
123
 
        self.pipeline.connect('error', self._errorCb)
124
 
 
125
 
    def _disconnectFunctions(self):
126
 
        self.pipeline.disconnect_by_function(self._eosCb)
127
 
        self.pipeline.disconnect_by_function(self._errorCb)
128
 
 
129
 
    def _activateAction(self):
130
 
        self.action.activate()
131
 
 
132
 
    def removeAction(self):
133
 
        self.debug("action %r", self.action)
134
 
        if not self.action:
135
 
            return
136
 
        self.pipeline.stop()
137
 
        self.action.deactivate()
138
 
        self.pipeline.removeAction(self.action)
139
 
        self.debug("putting all active ViewActions back to sync=True")
140
 
        for ac in self.pipeline.actions:
141
 
            if isinstance(ac, ViewAction) and ac.isActive():
142
 
                ac.setSync(True)
143
 
        self._changeSourceSettings(self.project.getSettings())
144
 
        self.pipeline.pause()
145
 
        self._disconnectFunctions()
146
 
        self.action = None
147
 
 
148
 
    def startAction(self):
149
 
        if not self._isReady():
150
 
            return
151
 
        self.addAction()
152
 
        self.pipeline.play()
153
 
        self.timestarted = time.time()
154
 
        self.acting = True
155
 
 
156
 
    def _isReady(self):
157
 
        """ Whether the @action can be started """
158
 
        raise NotImplementedError()
159
 
 
160
 
    def _createAction(self, sources):
161
 
        """ Create the @action for this Actioner
162
 
 
163
 
        @param sources: The source factories
164
 
        @type sources: L{SourceFactory}
165
 
        """
166
 
        raise NotImplementedError()
167
 
 
168
 
 
169
 
class Renderer(Actioner):
170
 
    """ Rendering helper methods """
171
 
 
172
 
    def __init__(self, project, pipeline=None, settings=None, outfile=None):
173
 
        """
174
 
        @param settings: The export settings to be used, or None to use
175
 
        the default export settings of the project.
176
 
        @type settings: ExportSettings
177
 
        @param outfile: The destination URI
178
 
        @type outfile: C{URI}
179
 
        """
180
 
        Actioner.__init__(self, project, pipeline, settings)
181
 
        self.detectStreamTypes()
182
 
        self.outfile = outfile
183
 
 
184
 
    def detectStreamTypes(self):
185
 
        self.have_video = False
186
 
        self.have_audio = False
187
 
 
188
 
        # we can only render TimelineSourceFactory
189
 
        if len(self.pipeline.factories) == 0:
190
 
            timeline_source = self.project.factory
191
 
        else:
192
 
            sources = [factory for factory in self.pipeline.factories.keys()
193
 
                    if isinstance(factory, SourceFactory)]
194
 
            timeline_source = sources[0]
195
 
        assert isinstance(timeline_source, TimelineSourceFactory)
196
 
 
197
 
        for track in timeline_source.timeline.tracks:
198
 
            if isinstance(track.stream, AudioStream) and track.duration > 0:
199
 
                self.have_audio = True
200
 
            elif isinstance(track.stream, VideoStream) and \
201
 
                    track.duration > 0:
202
 
                self.have_video = True
203
 
 
204
 
    def _positionCb(self, unused_pipeline, position):
205
 
        self.debug("%r %r", unused_pipeline, position)
206
 
        text = None
207
 
        timediff = time.time() - self.timestarted
208
 
        length = self.project.timeline.duration
209
 
        fraction = float(min(position, length)) / float(length)
210
 
        if timediff > 5.0 and position:
211
 
            # only display ETA after 5s in order to have enough averaging and
212
 
            # if the position is non-null
213
 
            totaltime = (timediff * float(length) / float(position)) - timediff
214
 
            text = beautify_ETA(int(totaltime * gst.SECOND))
215
 
        self.updatePosition(fraction, text)
216
 
 
217
 
    def updatePosition(self, fraction, text):
218
 
        pass
219
 
 
220
 
    def _isReady(self):
221
 
        return bool(not self.acting and self.outfile)
222
 
 
223
 
    def _eosCb(self, unused_pipeline):
224
 
        self.shutdown()
225
 
        Actioner._eosCb(self, unused_pipeline)
226
 
 
227
 
    def _createAction(self, sources):
228
 
        """Creates a L{RenderAction}."""
229
 
        settings = export_settings_to_render_settings(self.settings,
230
 
                self.have_video, self.have_audio)
231
 
        sf = RenderSinkFactory(RenderFactory(settings=settings),
232
 
                               URISinkFactory(uri=self.outfile))
233
 
        a = RenderAction()
234
 
        a.addProducers(*sources)
235
 
        a.addConsumers(sf)
236
 
 
237
 
        return a
238
 
 
239
 
    def _connectFunctions(self):
240
 
        self.pipeline.connect('position', self._positionCb)
241
 
        Actioner._connectFunctions(self)
242
 
 
243
 
    def _disconnectFunctions(self):
244
 
        self.pipeline.disconnect_by_function(self._positionCb)
245
 
        Actioner._disconnectFunctions(self)
246
 
 
247
 
    def _activateAction(self):
248
 
        Actioner._activateAction(self)
249
 
        self.debug("Setting all active ViewAction to sync=False")
250
 
        for action in self.pipeline.actions:
251
 
            if isinstance(action, ViewAction) and action.isActive():
252
 
                action.setSync(False)
253
 
 
254
 
 
255
 
class Previewer(Actioner):
256
 
    """ Previewing helper methods """
257
 
 
258
 
    def __init__(self, project, pipeline=None, ui=None):
259
 
        Actioner.__init__(self, project, pipeline=pipeline)
260
 
        self.ui = ui
261
 
 
262
 
    def _isReady(self):
263
 
        return bool(not self.acting and self.ui)
264
 
 
265
 
    def _createAction(self, sources):
266
 
        action = ViewAction()
267
 
        action.addProducers(*sources)
268
 
        self.ui.setAction(action)
269
 
        self.ui.setPipeline(self.pipeline)
270
 
        return action