def __init__(self, name="", uri=None, **kwargs): """ name : the name of the project uri : the uri of the project """ Loggable.__init__(self) self.log("name:%s, uri:%s", name, uri) self.name = name self.settings = None self.description = "" self.uri = uri self.urichanged = False self.format = None self.sources = SourceList() self.sources.connect("source-removed", self._sourceRemovedCb) self.settingssigid = 0 self._dirty = False self.timeline = Timeline() self.factory = TimelineSourceFactory(self.timeline) self.pipeline = Pipeline() self.view_action = ViewAction() self.view_action.addProducers(self.factory)
def testPendingLink(self): a = Action() p = Pipeline() src = common.FakeGnlFactory() src.addOutputStream( VideoStream(gst.Caps("video/x-raw-yuv"), pad_name="src")) sink = common.FakeSinkFactory() sink.addInputStream(MultimediaStream(gst.Caps("any"), pad_name="sink")) # set the link, it will be activated once the pad is added a.setLink(src, sink) # Let's see if the link is present self.assertEquals(a._links, [(src, sink, None, None)]) p.setAction(a) gst.debug("about to activate action") a.activate() # only the producer and the consumer are created, the other elements are # created dinamically self.assertEquals(len(list(p._pipeline.elements())), 2) p.setState(STATE_PLAYING) time.sleep(1) # and make sure that all other elements were created (4) # FIXME if it's failing here, run the test a few times trying to raise # the time.sleep() above, it may just be racy... self.assertEquals(len(list(p._pipeline.elements())), 4) a.deactivate() p.setState(STATE_NULL) self.assertEquals(len(list(p._pipeline.elements())), 0) p.release()
def __init__(self, name="", uri=None, **kwargs): """ @param name: the name of the project @param uri: the uri of the project """ Loggable.__init__(self) self.log("name:%s, uri:%s", name, uri) self.name = name self.settings = None self.description = "" self.uri = uri self.urichanged = False self.format = None self.sources = SourceList() self.sources.connect("source-added", self._sourceAddedCb) self.sources.connect("source-removed", self._sourceRemovedCb) self._dirty = False self.timeline = Timeline() self.factory = TimelineSourceFactory(self.timeline) self.pipeline = Pipeline() self.view_action = ViewAction() self.view_action.addProducers(self.factory) self.seeker = Seeker(80) self.settings = ExportSettings() self._videocaps = self.settings.getVideoCaps()
def testMultiple(self): """Test a dual stream encoding with separates sources""" settings = RenderSettings(settings=[self.asettings, self.vsettings], muxer="oggmux") sf = RenderSinkFactory(RenderFactory(settings=settings), common.FakeSinkFactory()) a = RenderAction() a.addConsumers(sf) a.addProducers(self.vsrc, self.asrc) p = Pipeline() a.setPipeline(p) a.activate() self.assertEquals(len(a._links), 2) p.play() time.sleep(3) p.getState() p.stop() a.deactivate() a.unsetPipeline() p.release()
def testSimpleStreams(self): """Test a RenderSettings with exact stream settings""" # let's force the video to some unusual size outs = VideoStream( gst.Caps("video/x-raw-yuv,width=624,height=230,framerate=10/1")) fset = StreamEncodeSettings(encoder="theoraenc", input_stream=outs) settings = RenderSettings(settings=[fset], muxer="oggmux") sf = RenderSinkFactory(RenderFactory(settings=settings), common.FakeSinkFactory()) a = RenderAction() a.addConsumers(sf) a.addProducers(self.vsrc) p = Pipeline() a.setPipeline(p) a.activate() self.assertEquals(len(a._links), 1) p.play() time.sleep(3) p.getState() p.stop() a.deactivate() p.release()
def setUp(self): TestCase.setUp(self) gst.debug("start") self.pipeline = Pipeline() self.monitor = SignalMonitor(self.pipeline, 'action-added', 'action-removed', 'factory-added', 'factory-removed', 'state-changed') self.assertEquals(self.monitor.action_added_count, 0) self.assertEquals(self.monitor.action_added_collect, [])
def testPendingLink(self): a = Action() p = Pipeline() src = common.FakeGnlFactory() src.addOutputStream(VideoStream(gst.Caps("video/x-raw-yuv"), pad_name="src")) sink = common.FakeSinkFactory() sink.addInputStream(MultimediaStream(gst.Caps("any"), pad_name="sink")) # set the link, it will be activated once the pad is added a.setLink(src, sink) # Let's see if the link is present self.assertEquals(a._links, [(src, sink, None, None)]) p.setAction(a) gst.debug("about to activate action") a.activate() # only the producer and the consumer are created, the other elements are # created dinamically self.assertEquals(len(list(p._pipeline.elements())), 2) p.setState(STATE_PLAYING) time.sleep(1) # and make sure that all other elements were created (4) # FIXME if it's failing here, run the test a few times trying to raise # the time.sleep() above, it may just be racy... self.assertEquals(len(list(p._pipeline.elements())), 4) a.deactivate() p.setState(STATE_NULL) self.assertEquals(len(list(p._pipeline.elements())), 0) p.release()
def testSimpleStreams(self): """Test a RenderSettings with exact stream settings""" # let's force the video to some unusual size outs = VideoStream(gst.Caps("video/x-raw-yuv,width=624,height=230,framerate=10/1")) fset = StreamEncodeSettings(encoder="theoraenc", input_stream=outs) settings = RenderSettings(settings=[fset], muxer="oggmux") sf = RenderSinkFactory(RenderFactory(settings=settings), common.FakeSinkFactory()) a = RenderAction() a.addConsumers(sf) a.addProducers(self.vsrc) p = Pipeline() a.setPipeline(p) a.activate() self.assertEquals(len(a._links), 1) p.play() time.sleep(3) p.getState() p.stop() a.deactivate() p.release()
def testSettingFactoriesSimple(self): """Simple add/remove Factory tests""" ac = Action() p = Pipeline() src = common.FakeSourceFactory() sink = common.FakeSinkFactory() # you can't set a Sink element as a producer self.failUnlessRaises(ActionError, ac.addProducers, sink) # you can't set a Source element as a consumer self.failUnlessRaises(ActionError, ac.addConsumers, src) # if the action is active, you can't add anything ac.state = STATE_ACTIVE self.failUnlessRaises(ActionError, ac.addProducers, src) self.failUnlessRaises(ActionError, ac.addConsumers, sink) ac.state = STATE_NOT_ACTIVE # Set a producer and consumer on the action ac.addProducers(src) ac.addConsumers(sink) self.assertEquals(ac.producers, [src]) self.assertEquals(ac.consumers, [sink]) self.failUnlessRaises(ActionError, ac.removeProducers, sink) self.failUnlessRaises(ActionError, ac.removeConsumers, src) self.assertEquals(ac.producers, [src]) self.assertEquals(ac.consumers, [sink]) # you can't remove anything from an active action ac.state = STATE_ACTIVE self.failUnlessRaises(ActionError, ac.removeProducers, src) self.failUnlessRaises(ActionError, ac.removeConsumers, sink) ac.state = STATE_NOT_ACTIVE # finally, attempt correct removal ac.removeProducers(src) self.assertEquals(ac.producers, []) self.assertEquals(ac.consumers, [sink]) ac.removeConsumers(sink) self.assertEquals(ac.producers, []) self.assertEquals(ac.consumers, []) p.release()
def testAddRemoveActionAdvanced(self): """ Advanced add/remove of Actions """ ac1 = BogusAction() ac2 = BogusAction() p2 = Pipeline() res = self.pipeline.addAction(ac1) self.assertEquals(self.pipeline.actions, [ac1]) # we can't add an action to two pipelines at the same time self.failUnlessRaises(PipelineError, p2.addAction, ac1) self.pipeline.removeAction(ac1) self.assertEquals(self.pipeline.actions, []) res = self.pipeline.setAction(ac1) self.assertEquals(res, ac1) self.assertEquals(self.pipeline.actions, [ac1]) # calling setAction while a similar action is already set should # return the existing action and not change anything else res = self.pipeline.setAction(ac2) self.assertEquals(res, ac1) self.assertEquals(self.pipeline.actions, [ac1]) # we can't remove active actions while in PAUSED/PLAYING self.pipeline.setState(STATE_PAUSED) ac1.state = STATE_ACTIVE self.assertEquals(self.pipeline.getState(), STATE_PAUSED) self.failUnlessRaises(PipelineError, self.pipeline.removeAction, ac1) # but we can remove deactivated actions while in PAUSED/PLAYING self.pipeline.setState(STATE_PAUSED) ac1.state = STATE_NOT_ACTIVE self.assertEquals(self.pipeline.getState(), STATE_PAUSED) self.pipeline.removeAction(ac1) # we can add actions while in PAUSED/PLAYING res = self.pipeline.addAction(ac2) self.assertEquals(res, ac2) self.assertEquals(self.pipeline.actions, [ac2]) self.pipeline.removeAction(ac2) p2.release()
def testPipelineSimple(self): """ Test setPipeline and unsetPipeline """ ac = Action() p = Pipeline() p2 = Pipeline() # set a Pipeline ac.setPipeline(p) self.assertEquals(ac.pipeline, p) # Setting a different Pipeline should fail... self.failUnlessRaises(ActionError, ac.setPipeline, p2) # ... but setting the same Pipeline again should silently succeed ac.setPipeline(p) # remove the Pipeline ac.unsetPipeline() self.assertEquals(ac.pipeline, None) # and now setting the other Pipeline should succeed ac.setPipeline(p2) self.assertEquals(ac.pipeline, p2) # remove the Pipeline again ac.unsetPipeline() self.assertEquals(ac.pipeline, None) # internally set the state to ACTIVE ac.state = STATE_ACTIVE # now setting any Pipeline should fail ! self.failUnlessRaises(ActionError, ac.setPipeline, p) # internally set the state to NOT_ACTIVE ac.state = STATE_NOT_ACTIVE self.assertEquals(ac.isActive(), False) # Set a pipeline ac.setPipeline(p) self.assertEquals(ac.pipeline, p) # interally set the state to ACTIVE ac.state = STATE_ACTIVE # we shouldn't be able to unset a pipeline from an active Action self.failUnlessRaises(ActionError, ac.unsetPipeline) # cleanup ac.state = STATE_NOT_ACTIVE ac.unsetPipeline() p.release() p2.release()
def _viewFactory(self, factory): # FIXME: we change the viewer pipeline unconditionally for now # we need a pipeline for playback pipeline = Pipeline() action = ViewAction() action.addProducers(factory) self.viewer.setPipeline(None) # FIXME: why do I have to call viewer.setAction ? self.viewer.setAction(action) self.viewer.setPipeline(pipeline) self.viewer.play()
def testAddEffectToTimelineObject(self): stacks = [] pipeline = Pipeline() def commitCb(action_log, stack, nested): stacks.append(stack) self.action_log.connect("commit", commitCb) self.observer.pipeline = pipeline #FIXME Should I commit it and check there are 2 elements #in the stacks self.timeline.addTimelineObject(self.timeline_object1) self.track1.addTrackObject(self.track_effect1) self.action_log.begin("add effect") self.timeline_object1.addTrackObject(self.track_effect1) self.action_log.commit() self.failUnlessEqual(len(stacks), 1) stack = stacks[0] self.failUnlessEqual(len(stack.done_actions), 1) action = stack.done_actions[0] self.failUnless(isinstance(action, TrackEffectAdded)) self.failUnless(self.track_effect1 \ in self.timeline_object1.track_objects) self.failUnless(self.track_effect1 \ in self.track1.track_objects) self.failUnless(len([effect for effect in \ self.timeline_object1.track_objects if isinstance(effect, TrackEffect)]) == 1) self.failUnless(len([effect for effect in self.track1.track_objects if isinstance(effect, TrackEffect)]) == 1) self.action_log.undo() self.failIf(self.track_effect1 \ in self.timeline_object1.track_objects) self.failIf(self.track_effect1 \ in self.track1.track_objects) self.action_log.redo() self.failUnless(len([effect for effect in self.timeline_object1.track_objects if isinstance(effect, TrackEffect)]) == 1) self.failUnless(len([effect for effect in self.track1.track_objects if isinstance(effect, TrackEffect)]) == 1) self.timeline.removeTimelineObject(self.timeline_object1, deep=True)
def setUp(self): self.mainloop = GObject.MainLoop() samples = os.path.join(os.path.dirname(__file__), "samples") self.facs = [] self.facs.append([PictureFileSourceFactory('file://' + os.path.join(samples, "flat_colour1_640x480.png")), VideoStream(Gst.Caps("video/x-raw-rgb,bpp=(int)24,depth=(int)24,endianness=(int)4321,red_mask=(int)16711680,green_mask=(int)65280,blue_mask=(int)255"))]) self.facs.append([PictureFileSourceFactory('file://' + os.path.join(samples, "flat_colour2_640x480.png")), VideoStream(Gst.Caps("video/x-raw-rgb,bpp=(int)24,depth=(int)24,endianness=(int)4321,red_mask=(int)16711680,green_mask=(int)65280,blue_mask=(int)255"))]) self.facs.append([PictureFileSourceFactory('file://' + os.path.join(samples, "flat_colour3_320x180.png")), VideoStream(Gst.Caps("video/x-raw-rgb,bpp=(int)24,depth=(int)24,endianness=(int)4321,red_mask=(int)16711680,green_mask=(int)65280,blue_mask=(int)255"))]) # one video with a different resolution self.facs.append([VideoTestSourceFactory(), VideoStream(Gst.Caps('video/x-raw-yuv,width=(int)640,height=(int)480,format=(fourcc)I420'))]) # configure durations and add output streams to factories for fac in self.facs: factory = fac[0] stream = fac[1] factory.duration = self.clip_duration factory.addOutputStream(stream) self.track_objects = [] self.track = Track(self.facs[0][1]) self.timeline = Timeline() self.timeline.addTrack(self.track) vsettings = StreamEncodeSettings(renderer="theoraenc") rsettings = RenderSettings(settings=[vsettings], muxer="oggmux") self.fakesink = common.FakeSinkFactory() rendersink = RenderSinkFactory(RenderFactory(settings=rsettings), self.fakesink) self.render = RenderAction() self.pipeline = Pipeline() self.pipeline.connect("eos", self._renderEOSCb) self.pipeline.connect("error", self._renderErrorCb) self.pipeline.addAction(self.render) self.render.addConsumers(rendersink) timeline_factory = TimelineSourceFactory(self.timeline) self.render.addProducers(timeline_factory)
class TestPipeline(TestCase): def setUp(self): TestCase.setUp(self) gst.debug("start") self.pipeline = Pipeline() self.monitor = SignalMonitor(self.pipeline, 'action-added', 'action-removed', 'factory-added', 'factory-removed', 'state-changed') self.assertEquals(self.monitor.action_added_count, 0) self.assertEquals(self.monitor.action_added_collect, []) def tearDown(self): self.pipeline.setState(STATE_NULL) self.pipeline.release() self.monitor.disconnectFromObj(self.pipeline) del self.pipeline del self.monitor TestCase.tearDown(self) def testAddRemoveActionSimple(self): """ Simple add/remove of Actions """ ac1 = BogusAction() # add the action to the pipeline res = self.pipeline.addAction(ac1) # the returned value should be the given action self.assertEquals(res, ac1) # it should now be in the list of actions... self.failUnlessEqual(self.pipeline.actions, [ac1]) # ... and the action should be set to that pipeline self.failUnlessEqual(ac1.pipeline, self.pipeline) # the 'action-added' signal should be triggered once self.assertEquals(self.monitor.action_added_count, 1) # And it contained our action self.assertEquals(self.monitor.action_added_collect, [(ac1, )]) # if we try to add that action again, it should be silently ignored res = self.pipeline.addAction(ac1) self.assertEquals(res, ac1) # the list of actions shouldn't have changed self.failUnlessEqual(self.pipeline.actions, [ac1]) # it shouldn't have changed the pipeline set on action self.failUnlessEqual(ac1.pipeline, self.pipeline) # the 'action-added' signal should NOT have been triggered again self.assertEquals(self.monitor.action_added_count, 1) # And now to remove it self.pipeline.removeAction(ac1) # the 'action-removed' signal should have been triggered once.. self.assertEquals(self.monitor.action_removed_count, 1) # .. with the action as an argument self.assertEquals(self.monitor.action_removed_collect, [(ac1, )]) # And there should be no actions left on the pipeline self.assertEquals(self.pipeline.actions, []) def testAddRemoveActionAdvanced(self): """ Advanced add/remove of Actions """ ac1 = BogusAction() ac2 = BogusAction() p2 = Pipeline() res = self.pipeline.addAction(ac1) self.assertEquals(self.pipeline.actions, [ac1]) # we can't add an action to two pipelines at the same time self.failUnlessRaises(PipelineError, p2.addAction, ac1) self.pipeline.removeAction(ac1) self.assertEquals(self.pipeline.actions, []) res = self.pipeline.setAction(ac1) self.assertEquals(res, ac1) self.assertEquals(self.pipeline.actions, [ac1]) # calling setAction while a similar action is already set should # return the existing action and not change anything else res = self.pipeline.setAction(ac2) self.assertEquals(res, ac1) self.assertEquals(self.pipeline.actions, [ac1]) # we can't remove active actions while in PAUSED/PLAYING self.pipeline.setState(STATE_PAUSED) ac1.state = STATE_ACTIVE self.assertEquals(self.pipeline.getState(), STATE_PAUSED) self.failUnlessRaises(PipelineError, self.pipeline.removeAction, ac1) # but we can remove deactivated actions while in PAUSED/PLAYING self.pipeline.setState(STATE_PAUSED) ac1.state = STATE_NOT_ACTIVE self.assertEquals(self.pipeline.getState(), STATE_PAUSED) self.pipeline.removeAction(ac1) # we can add actions while in PAUSED/PLAYING res = self.pipeline.addAction(ac2) self.assertEquals(res, ac2) self.assertEquals(self.pipeline.actions, [ac2]) self.pipeline.removeAction(ac2) p2.release() def testStateChange(self): loop = gobject.MainLoop() bag = {"last_state": None} def state_changed_cb(pipeline, state, bag, loop): bag["last_state"] = state loop.quit() self.pipeline.connect('state-changed', state_changed_cb, bag, loop) # playing self.pipeline.setState(STATE_PLAYING) loop.run() self.failUnlessEqual(bag["last_state"], STATE_PLAYING) self.failUnlessEqual(self.pipeline.getState(), STATE_PLAYING) self.assertEquals(self.monitor.state_changed_count, 1) # playing again self.pipeline.setState(STATE_PLAYING) self.assertEquals(self.monitor.state_changed_count, 1) # ready self.pipeline.setState(STATE_READY) loop.run() self.failUnlessEqual(bag["last_state"], STATE_READY) self.failUnlessEqual(self.pipeline.getState(), STATE_READY) self.assertEquals(self.monitor.state_changed_count, 2) # PLAYING self.pipeline.play() loop.run() self.failUnlessEqual(bag["last_state"], STATE_PLAYING) self.failUnlessEqual(self.pipeline.getState(), STATE_PLAYING) self.assertEquals(self.monitor.state_changed_count, 3) # PAUSE self.pipeline.pause() loop.run() self.failUnlessEqual(bag["last_state"], STATE_PAUSED) self.failUnlessEqual(self.pipeline.getState(), STATE_PAUSED) self.assertEquals(self.monitor.state_changed_count, 4) self.pipeline.stop() loop.run() self.failUnlessEqual(bag["last_state"], STATE_READY) self.failUnlessEqual(self.pipeline.getState(), STATE_READY) self.assertEquals(self.monitor.state_changed_count, 5) def testGetReleaseBinForFactoryStream(self): factory = VideoTestSourceFactory() stream = VideoStream(gst.Caps('video/x-raw-rgb; video/x-raw-yuv'), 'src0') factory.addOutputStream(stream) # try to get a cached instance self.failUnlessRaises(PipelineError, self.pipeline.getBinForFactoryStream, factory, stream, False) # create a bin bin1 = self.pipeline.getBinForFactoryStream(factory, stream, True) self.failUnless(isinstance(bin1, gst.Element)) # return the cached instance bin2 = self.pipeline.getBinForFactoryStream(factory, stream, True) self.failUnlessEqual(id(bin1), id(bin2)) self.pipeline.releaseBinForFactoryStream(factory, stream) self.pipeline.releaseBinForFactoryStream(factory, stream) # the bin has been destroyed at this point self.failUnlessRaises(PipelineError, self.pipeline.releaseBinForFactoryStream, factory, stream) # we should get a new instance bin2 = self.pipeline.getBinForFactoryStream(factory, stream, True) self.pipeline.releaseBinForFactoryStream(factory, stream) def testGetReleaseTeeForFactoryStream(self): factory = VideoTestSourceFactory() stream = VideoStream(gst.Caps('video/x-raw-rgb; video/x-raw-yuv'), 'src') factory.addOutputStream(stream) self.failUnlessRaises(PipelineError, self.pipeline.getTeeForFactoryStream, factory, stream, True) # getBinForFactoryStream(factory, stream) must be called before self.failUnlessRaises(PipelineError, self.pipeline.getTeeForFactoryStream, factory, stream, True) # create the bin bin1 = self.pipeline.getBinForFactoryStream(factory, stream, True) # try to get a cached tee self.failUnlessRaises(PipelineError, self.pipeline.getTeeForFactoryStream, factory, stream, False) # create tee tee1 = self.pipeline.getTeeForFactoryStream(factory, stream, True) self.failUnless(isinstance(tee1, gst.Element)) # get the cached instance tee2 = self.pipeline.getTeeForFactoryStream(factory, stream, True) self.failUnlessEqual(id(tee1), id(tee2)) # release self.pipeline.releaseTeeForFactoryStream(factory, stream) # there's still a tee alive, so we can't release the bin #self.failUnlessRaises(PipelineError, # self.pipeline.releaseBinForFactoryStream, factory, stream) self.pipeline.releaseTeeForFactoryStream(factory, stream) self.failUnlessRaises(PipelineError, self.pipeline.releaseTeeForFactoryStream, factory, stream) # should always fail with a sink bin factory2 = FakeSinkFactory() stream2 = VideoStream(gst.Caps('video/x-raw-rgb; video/x-raw-yuv'), 'src') factory2.addInputStream(stream2) self.failUnlessRaises(PipelineError, self.pipeline.getTeeForFactoryStream, factory2, stream2, True) self.pipeline.releaseBinForFactoryStream(factory, stream) def testGetReleaseQueueForFactoryStream(self): factory = FakeSinkFactory() stream = VideoStream(gst.Caps('any'), 'sink') factory.addInputStream(stream) self.failUnlessRaises(PipelineError, self.pipeline.getQueueForFactoryStream, factory, stream, True) # getBinForFactoryStream(factory, stream) must be called before self.failUnlessRaises(PipelineError, self.pipeline.getQueueForFactoryStream, factory, stream, True) # create the bin bin1 = self.pipeline.getBinForFactoryStream(factory, stream, True) # try to get a cached queue self.failUnlessRaises(PipelineError, self.pipeline.getQueueForFactoryStream, factory, stream, False) # create queue queue1 = self.pipeline.getQueueForFactoryStream(factory, stream, True) self.failUnless(isinstance(queue1, gst.Element)) gst.debug("pouet") # get the cached instance queue2 = self.pipeline.getQueueForFactoryStream(factory, stream, True) self.failUnlessEqual(id(queue1), id(queue2)) # release self.pipeline.releaseQueueForFactoryStream(factory, stream) gst.debug("pouet") # there's still a queue alive, so we can't release the bin self.failUnlessRaises(PipelineError, self.pipeline.releaseBinForFactoryStream, factory, stream) self.pipeline.releaseQueueForFactoryStream(factory, stream) gst.debug("pouet2") self.failUnlessRaises(PipelineError, self.pipeline.releaseQueueForFactoryStream, factory, stream) # should always fail with a src bin factory2 = VideoTestSourceFactory() stream2 = VideoStream(gst.Caps('any'), 'src') factory2.addOutputStream(stream2) bin1 = self.pipeline.getBinForFactoryStream(factory, stream, True) self.failUnlessRaises(PipelineError, self.pipeline.getQueueForFactoryStream, factory2, stream2, True) self.pipeline.releaseBinForFactoryStream(factory, stream) self.pipeline.releaseBinForFactoryStream(factory, stream) self.assertEquals(factory.current_bins, 0)
class TestStillImage(TestCase): clip_duration = 3 * Gst.SECOND def setUp(self): self.mainloop = GObject.MainLoop() samples = os.path.join(os.path.dirname(__file__), "samples") self.facs = [] self.facs.append([PictureFileSourceFactory('file://' + os.path.join(samples, "flat_colour1_640x480.png")), VideoStream(Gst.Caps("video/x-raw-rgb,bpp=(int)24,depth=(int)24,endianness=(int)4321,red_mask=(int)16711680,green_mask=(int)65280,blue_mask=(int)255"))]) self.facs.append([PictureFileSourceFactory('file://' + os.path.join(samples, "flat_colour2_640x480.png")), VideoStream(Gst.Caps("video/x-raw-rgb,bpp=(int)24,depth=(int)24,endianness=(int)4321,red_mask=(int)16711680,green_mask=(int)65280,blue_mask=(int)255"))]) self.facs.append([PictureFileSourceFactory('file://' + os.path.join(samples, "flat_colour3_320x180.png")), VideoStream(Gst.Caps("video/x-raw-rgb,bpp=(int)24,depth=(int)24,endianness=(int)4321,red_mask=(int)16711680,green_mask=(int)65280,blue_mask=(int)255"))]) # one video with a different resolution self.facs.append([VideoTestSourceFactory(), VideoStream(Gst.Caps('video/x-raw-yuv,width=(int)640,height=(int)480,format=(fourcc)I420'))]) # configure durations and add output streams to factories for fac in self.facs: factory = fac[0] stream = fac[1] factory.duration = self.clip_duration factory.addOutputStream(stream) self.track_objects = [] self.track = Track(self.facs[0][1]) self.timeline = Timeline() self.timeline.addTrack(self.track) vsettings = StreamEncodeSettings(renderer="theoraenc") rsettings = RenderSettings(settings=[vsettings], muxer="oggmux") self.fakesink = common.FakeSinkFactory() rendersink = RenderSinkFactory(RenderFactory(settings=rsettings), self.fakesink) self.render = RenderAction() self.pipeline = Pipeline() self.pipeline.connect("eos", self._renderEOSCb) self.pipeline.connect("error", self._renderErrorCb) self.pipeline.addAction(self.render) self.render.addConsumers(rendersink) timeline_factory = TimelineSourceFactory(self.timeline) self.render.addProducers(timeline_factory) def tearDown(self): self.mainloop.quit() def configureStreams(self, inputs, offsets): count = 0 for i in inputs: factory = self.facs[i][0] stream = self.facs[i][1] track_object = SourceTrackObject(factory, stream) self.track_objects.append(track_object) track_object.start = offsets[count] self.track.addTrackObject(track_object) count += 1 def startRender(self): self.render.activate() self.data_written = 0 self.fakesink.bins[0].props.signal_handoffs = True self.fakesink.bins[0].connect("handoff", self._fakesinkHandoffCb) self.pipeline.play() self.mainloop.run() def _fakesinkHandoffCb(self, fakesink, buf, pad): self.data_written += buf.size def _renderEOSCb(self, obj): self.mainloop.quit() # check the render was successful self.assertTrue(self.data_written > 0) def _renderErrorCb(self, obj, error, details): print "Error: %s\nDetails: %s" % (str(error), str(details)) self.fail("Pipeline rendering error") def cleanUp(self): self.render.deactivate() self.track.removeAllTrackObjects() self.track_objects = [] def testRendering(self): # use one of the still image streams self.configureStreams(range(1), [0]) self.startRender() self.cleanUp() # use two images with the same resolution and concatenate them self.configureStreams(range(2), [0, self.clip_duration]) self.startRender() self.cleanUp() # concatenate images with different resolutions self.configureStreams(range(3), [0, self.clip_duration, 2 * self.clip_duration]) self.startRender() self.cleanUp() # mix images with different resolutions by overlapping self.configureStreams(range(3), [0, self.clip_duration // 2, self.clip_duration]) self.startRender() self.cleanUp() # mix images and videos with the same resolution self.configureStreams([0, 1, 3], [0, self.clip_duration, 2 * self.clip_duration]) self.startRender() self.cleanUp() # mix images and videos with different resolutions self.configureStreams(range(4), [0, self.clip_duration, 2 * self.clip_duration, 3 * self.clip_duration]) self.startRender() self.cleanUp() # mix images and videos with different resolutions by overlapping self.configureStreams(range(4), [0, self.clip_duration // 2, self.clip_duration, (3 * self.clip_duration) // 2]) self.startRender() self.cleanUp()
class Project(Signallable, Loggable): """The base class for PiTiVi projects @ivar name: The name of the project @type name: C{str} @ivar description: A description of the project @type description: C{str} @ivar sources: The sources used by this project @type sources: L{SourceList} @ivar timeline: The timeline @type timeline: L{Timeline} @ivar pipeline: The timeline's pipeline @type pipeline: L{Pipeline} @ivar factory: The timeline factory @type factory: L{TimelineSourceFactory} @ivar format: The format under which the project is currently stored. @type format: L{FormatterClass} @ivar loaded: Whether the project is fully loaded or not. @type loaded: C{bool} Signals: - C{loaded} : The project is now fully loaded. """ __signals__ = { "settings-changed": ['old', 'new'], "project-changed": [], } def __init__(self, name="", uri=None, **kwargs): """ @param name: the name of the project @param uri: the uri of the project """ Loggable.__init__(self) self.log("name:%s, uri:%s", name, uri) self.name = name self.settings = None self.description = "" self.uri = uri self.urichanged = False self.format = None self.sources = SourceList() self.sources.connect("source-added", self._sourceAddedCb) self.sources.connect("source-removed", self._sourceRemovedCb) self._dirty = False self.timeline = Timeline() self.factory = TimelineSourceFactory(self.timeline) self.pipeline = Pipeline() self.view_action = ViewAction() self.view_action.addProducers(self.factory) self.seeker = Seeker(80) self.settings = ExportSettings() self._videocaps = self.settings.getVideoCaps() def release(self): self.pipeline.release() self.pipeline = None #{ Settings methods def getSettings(self): """ return the currently configured settings. """ self.debug("self.settings %s", self.settings) return self.settings def setSettings(self, settings): """ Sets the given settings as the project's settings. @param settings: The new settings for the project. @type settings: ExportSettings """ assert settings self.log("Setting %s as the project's settings", settings) oldsettings = self.settings self.settings = settings self._projectSettingsChanged() self.emit('settings-changed', oldsettings, settings) #} #{ Save and Load features def setModificationState(self, state): self._dirty = state if state: self.emit('project-changed') def hasUnsavedModifications(self): return self._dirty def _projectSettingsChanged(self): settings = self.getSettings() self._videocaps = settings.getVideoCaps() if self.timeline: self.timeline.updateVideoCaps(self._videocaps) for fact in self.sources.getSources(): fact.setFilterCaps(self._videocaps) if self.pipeline.getState() != gst.STATE_NULL: self.pipeline.stop() self.pipeline.pause() def _sourceAddedCb(self, sourcelist, factory): factory.setFilterCaps(self._videocaps) def _sourceRemovedCb(self, sourclist, uri, factory): self.timeline.removeFactory(factory)
class Project(Signallable, Loggable): """The base class for PiTiVi projects @ivar name: The name of the project @type name: C{str} @ivar description: A description of the project @type description: C{str} @ivar sources: The sources used by this project @type sources: L{SourceList} @ivar timeline: The timeline @type timeline: L{Timeline} @ivar pipeline: The timeline's pipeline @type pipeline: L{Pipeline} @ivar factory: The timeline factory @type factory: L{TimelineSourceFactory} @ivar format: The format under which the project is currently stored. @type format: L{FormatterClass} @ivar loaded: Whether the project is fully loaded or not. @type loaded: C{bool} Signals: - C{loaded} : The project is now fully loaded. """ __signals__ = { "settings-changed" : ['old', 'new'], } def __init__(self, name="", uri=None, **kwargs): """ name : the name of the project uri : the uri of the project """ Loggable.__init__(self) self.log("name:%s, uri:%s", name, uri) self.name = name self.settings = None self.description = "" self.uri = uri self.urichanged = False self.format = None self.sources = SourceList() self.sources.connect("source-added", self._sourceAddedCb) self.sources.connect("source-removed", self._sourceRemovedCb) self._dirty = False self.timeline = Timeline() self.factory = TimelineSourceFactory(self.timeline) self.pipeline = Pipeline() self.view_action = ViewAction() self.view_action.addProducers(self.factory) self.seeker = Seeker(80) self.getCapsFromSettings() def getCapsFromSettings(self): settings = self.getSettings() #formatstr = "video/x-raw-rgb,width=(int)%d,height=(int)%d;"\ # "video/x-raw-yuv,width=(int)%d,height=(int)%d" #capstr = formatstr % ( # settings.videowidth, # settings.videoheight, # settings.videowidth, # settings.videoheight) #self._videocaps = gst.Caps(capstr) self._videocaps = settings.getVideoCaps() def release(self): self.pipeline.release() self.pipeline = None #{ Settings methods def getSettings(self): """ return the currently configured settings. If no setting have been explicitely set, some smart settings will be chosen. """ self.debug("self.settings %s", self.settings) return self.settings or self.getAutoSettings() def setSettings(self, settings): """ Sets the given settings as the project's settings. If settings is None, the current settings will be unset """ self.log("Setting %s as the project's settings", settings) oldsettings = self.settings self.settings = settings self._projectSettingsChanged() self.emit('settings-changed', oldsettings, settings) def unsetSettings(self, unused_settings): """ Remove the currently configured settings.""" self.setSettings(None) def getAutoSettings(self): """ Computes and returns smart settings for the project. If the project only has one source, it will be that source's settings. If it has more than one, it will return the largest setting that suits all contained sources. """ settings = ExportSettings() if not self.timeline: self.warning("project doesn't have a timeline, returning default settings") return settings # FIXME: this is ugly, but rendering for now assumes at most one audio # and one video tracks have_audio = have_video = False for track in self.timeline.tracks: if isinstance(track.stream, VideoStream) and track.duration != 0: have_video = True elif isinstance(track.stream, AudioStream) and track.duration != 0: have_audio = True if not have_audio: settings.aencoder = None if not have_video: settings.vencoder = None return settings #} #{ Save and Load features def save(self, location=None, overwrite=False): """ Save the project to the given location. @param location: The location to write to. If not specified, the current project location will be used (if set). @type location: C{URI} @param overwrite: Whether to overwrite existing location. @type overwrite: C{bool} """ # import here to break circular import from pitivi.formatters.format import save_project from pitivi.formatters.base import FormatterError self.log("saving...") location = location or self.uri if location == None: raise FormatterError("Location unknown") save_project(self, location or self.uri, self.format, overwrite) self.uri = location def setModificationState(self, state): self._dirty = state def hasUnsavedModifications(self): return self._dirty def _projectSettingsChanged(self): self.getCapsFromSettings() for fact in self.sources.getSources(): fact.setFilterCaps(self._videocaps) if self.pipeline.getState() != gst.STATE_NULL: self.pipeline.stop() self.pipeline.pause() def _sourceAddedCb(self, sourcelist, factory): factory.setFilterCaps(self._videocaps) def _sourceRemovedCb(self, sourclist, uri, factory): self.timeline.removeFactory(factory)
class Project(Signallable, Loggable): """The base class for PiTiVi projects @ivar name: The name of the project @type name: C{str} @ivar description: A description of the project @type description: C{str} @ivar sources: The sources used by this project @type sources: L{SourceList} @ivar timeline: The timeline @type timeline: L{Timeline} @ivar pipeline: The timeline's pipeline @type pipeline: L{Pipeline} @ivar factory: The timeline factory @type factory: L{TimelineSourceFactory} @ivar format: The format under which the project is currently stored. @type format: L{FormatterClass} @ivar loaded: Whether the project is fully loaded or not. @type loaded: C{bool} Signals: - C{loaded} : The project is now fully loaded. """ __signals__ = { "settings-changed" : ['old', 'new'], "project-changed" : [], } def __init__(self, name="", uri=None, **kwargs): """ @param name: the name of the project @param uri: the uri of the project """ Loggable.__init__(self) self.log("name:%s, uri:%s", name, uri) self.name = name self.settings = None self.description = "" self.uri = uri self.urichanged = False self.format = None self.sources = SourceList() self.sources.connect("source-added", self._sourceAddedCb) self.sources.connect("source-removed", self._sourceRemovedCb) self._dirty = False self.timeline = Timeline() self.factory = TimelineSourceFactory(self.timeline) self.pipeline = Pipeline() self.view_action = ViewAction() self.view_action.addProducers(self.factory) self.seeker = Seeker(80) self.settings = ExportSettings() self._videocaps = self.settings.getVideoCaps() def release(self): self.pipeline.release() self.pipeline = None #{ Settings methods def getSettings(self): """ return the currently configured settings. """ self.debug("self.settings %s", self.settings) return self.settings def setSettings(self, settings): """ Sets the given settings as the project's settings. @param settings: The new settings for the project. @type settings: ExportSettings """ assert settings self.log("Setting %s as the project's settings", settings) oldsettings = self.settings self.settings = settings self._projectSettingsChanged() self.emit('settings-changed', oldsettings, settings) #} #{ Save and Load features def setModificationState(self, state): self._dirty = state if state: self.emit('project-changed') def hasUnsavedModifications(self): return self._dirty def _projectSettingsChanged(self): settings = self.getSettings() self._videocaps = settings.getVideoCaps() if self.timeline: self.timeline.updateVideoCaps(self._videocaps) for fact in self.sources.getSources(): fact.setFilterCaps(self._videocaps) if self.pipeline.getState() != gst.STATE_NULL: self.pipeline.stop() self.pipeline.pause() def _sourceAddedCb(self, sourcelist, factory): factory.setFilterCaps(self._videocaps) def _sourceRemovedCb(self, sourclist, uri, factory): self.timeline.removeFactory(factory)
def testPipelineAction(self): """Testing pipeline state interaction""" p = Pipeline() a = Action() src = VideoTestSourceFactory() sink = common.FakeSinkFactory() sink.addInputStream(MultimediaStream(gst.Caps("any"), pad_name="sink")) # set the Action on the Pipeline p.setAction(a) self.assertEquals(p.actions, [a]) # set the Producer and Consumer a.addProducers(src) a.addConsumers(sink) a.setLink(src, sink) # activate the Action a.activate() self.failUnlessEqual(src.current_bins, 1) self.failUnlessEqual(sink.current_bins, 1) # call get*ForFactoryStream(..., automake=False). They will raise # exceptions if the action didn't create the elements. bin = p.getBinForFactoryStream(src, automake=False) p.releaseBinForFactoryStream(src) tee = p.getTeeForFactoryStream(src, automake=False) p.releaseTeeForFactoryStream(src) bin = p.getBinForFactoryStream(sink, automake=False) queue = p.getQueueForFactoryStream(sink, automake=False) self.failUnlessEqual(queue.get_pad('src').get_peer().get_parent(), bin) p.releaseBinForFactoryStream(sink) p.releaseQueueForFactoryStream(sink) # switch to PLAYING p.setState(STATE_PLAYING) # wait half a second # switch to READY p.setState(STATE_READY) # deactivate action a.deactivate() # since we're the last Action to be release, the tees # and queues should have gone self.failUnlessEqual(src.current_bins, 0) self.failUnlessEqual(sink.current_bins, 0) # remove the action from the pipeline p.removeAction(a) # the gst.Pipeline should be empty ! self.assertEquals(list(p._pipeline.elements()), []) p.release()
def testDynamicLink(self): a = DynamicAction() p = Pipeline() src = common.FakeGnlFactory() src.addOutputStream(VideoStream(gst.Caps("video/x-raw-yuv"), pad_name="src")) # the link will be added dynamically self.assertEquals(a._links, []) p.setAction(a) a.addProducers(src) self.assertEquals(len(list(p._pipeline.elements())), 0) a.activate() # theoretically... there shouldn't only be the source, since # the pad for the source hasn't been created yet (and therefore not # requiring a consumer self.assertEquals(len(list(p._pipeline.elements())), 1) p.setState(STATE_PLAYING) time.sleep(1) p.getState() # and make sure that all other elements were created (4) self.assertEquals(len(list(p._pipeline.elements())), 4) p.setState(STATE_READY) time.sleep(1) a.deactivate() self.assertEquals(len(list(p._pipeline.elements())), 0) p.setState(STATE_NULL) p.release()
def setUp(self): self.mainloop = gobject.MainLoop() samples = os.path.join(os.path.dirname(__file__), "samples") self.facs = [] self.facs.append([ PictureFileSourceFactory( 'file://' + os.path.join(samples, "flat_colour1_640x480.png")), VideoStream( gst.Caps( "video/x-raw-rgb,bpp=(int)24,depth=(int)24,endianness=(int)4321,red_mask=(int)16711680,green_mask=(int)65280,blue_mask=(int)255" )) ]) self.facs.append([ PictureFileSourceFactory( 'file://' + os.path.join(samples, "flat_colour2_640x480.png")), VideoStream( gst.Caps( "video/x-raw-rgb,bpp=(int)24,depth=(int)24,endianness=(int)4321,red_mask=(int)16711680,green_mask=(int)65280,blue_mask=(int)255" )) ]) self.facs.append([ PictureFileSourceFactory( 'file://' + os.path.join(samples, "flat_colour3_320x180.png")), VideoStream( gst.Caps( "video/x-raw-rgb,bpp=(int)24,depth=(int)24,endianness=(int)4321,red_mask=(int)16711680,green_mask=(int)65280,blue_mask=(int)255" )) ]) # one video with a different resolution self.facs.append([ VideoTestSourceFactory(), VideoStream( gst.Caps( 'video/x-raw-yuv,width=(int)640,height=(int)480,format=(fourcc)I420' )) ]) # configure durations and add output streams to factories for fac in self.facs: factory = fac[0] stream = fac[1] factory.duration = self.clip_duration factory.addOutputStream(stream) self.track_objects = [] self.track = Track(self.facs[0][1]) self.timeline = Timeline() self.timeline.addTrack(self.track) vsettings = StreamEncodeSettings(encoder="theoraenc") rsettings = RenderSettings(settings=[vsettings], muxer="oggmux") self.fakesink = common.FakeSinkFactory() rendersink = RenderSinkFactory(RenderFactory(settings=rsettings), self.fakesink) self.render = RenderAction() self.pipeline = Pipeline() self.pipeline.connect("eos", self._renderEOSCb) self.pipeline.connect("error", self._renderErrorCb) self.pipeline.addAction(self.render) self.render.addConsumers(rendersink) timeline_factory = TimelineSourceFactory(self.timeline) self.render.addProducers(timeline_factory)
class TestStillImage(TestCase): clip_duration = 3 * gst.SECOND def setUp(self): self.mainloop = gobject.MainLoop() samples = os.path.join(os.path.dirname(__file__), "samples") self.facs = [] self.facs.append([ PictureFileSourceFactory( 'file://' + os.path.join(samples, "flat_colour1_640x480.png")), VideoStream( gst.Caps( "video/x-raw-rgb,bpp=(int)24,depth=(int)24,endianness=(int)4321,red_mask=(int)16711680,green_mask=(int)65280,blue_mask=(int)255" )) ]) self.facs.append([ PictureFileSourceFactory( 'file://' + os.path.join(samples, "flat_colour2_640x480.png")), VideoStream( gst.Caps( "video/x-raw-rgb,bpp=(int)24,depth=(int)24,endianness=(int)4321,red_mask=(int)16711680,green_mask=(int)65280,blue_mask=(int)255" )) ]) self.facs.append([ PictureFileSourceFactory( 'file://' + os.path.join(samples, "flat_colour3_320x180.png")), VideoStream( gst.Caps( "video/x-raw-rgb,bpp=(int)24,depth=(int)24,endianness=(int)4321,red_mask=(int)16711680,green_mask=(int)65280,blue_mask=(int)255" )) ]) # one video with a different resolution self.facs.append([ VideoTestSourceFactory(), VideoStream( gst.Caps( 'video/x-raw-yuv,width=(int)640,height=(int)480,format=(fourcc)I420' )) ]) # configure durations and add output streams to factories for fac in self.facs: factory = fac[0] stream = fac[1] factory.duration = self.clip_duration factory.addOutputStream(stream) self.track_objects = [] self.track = Track(self.facs[0][1]) self.timeline = Timeline() self.timeline.addTrack(self.track) vsettings = StreamEncodeSettings(encoder="theoraenc") rsettings = RenderSettings(settings=[vsettings], muxer="oggmux") self.fakesink = common.FakeSinkFactory() rendersink = RenderSinkFactory(RenderFactory(settings=rsettings), self.fakesink) self.render = RenderAction() self.pipeline = Pipeline() self.pipeline.connect("eos", self._renderEOSCb) self.pipeline.connect("error", self._renderErrorCb) self.pipeline.addAction(self.render) self.render.addConsumers(rendersink) timeline_factory = TimelineSourceFactory(self.timeline) self.render.addProducers(timeline_factory) def tearDown(self): self.mainloop.quit() def configureStreams(self, inputs, offsets): count = 0 for i in inputs: factory = self.facs[i][0] stream = self.facs[i][1] track_object = SourceTrackObject(factory, stream) self.track_objects.append(track_object) track_object.start = offsets[count] self.track.addTrackObject(track_object) count += 1 def startRender(self): self.render.activate() self.data_written = 0 self.fakesink.bins[0].props.signal_handoffs = True self.fakesink.bins[0].connect("handoff", self._fakesinkHandoffCb) self.pipeline.play() self.mainloop.run() def _fakesinkHandoffCb(self, fakesink, buf, pad): self.data_written += buf.size def _renderEOSCb(self, obj): self.mainloop.quit() # check the render was successful self.assertTrue(self.data_written > 0) def _renderErrorCb(self, obj, error, details): print "Error: %s\nDetails: %s" % (str(error), str(details)) self.fail("Pipeline rendering error") def cleanUp(self): self.render.deactivate() self.track.removeAllTrackObjects() self.track_objects = [] def testRendering(self): # use one of the still image streams self.configureStreams(range(1), [0]) self.startRender() self.cleanUp() # use two images with the same resolution and concatenate them self.configureStreams(range(2), [0, self.clip_duration]) self.startRender() self.cleanUp() # concatenate images with different resolutions self.configureStreams(range(3), [0, self.clip_duration, 2 * self.clip_duration]) self.startRender() self.cleanUp() # mix images with different resolutions by overlapping self.configureStreams(range(3), [0, self.clip_duration // 2, self.clip_duration]) self.startRender() self.cleanUp() # mix images and videos with the same resolution self.configureStreams([0, 1, 3], [0, self.clip_duration, 2 * self.clip_duration]) self.startRender() self.cleanUp() # mix images and videos with different resolutions self.configureStreams(range(4), [ 0, self.clip_duration, 2 * self.clip_duration, 3 * self.clip_duration ]) self.startRender() self.cleanUp() # mix images and videos with different resolutions by overlapping self.configureStreams(range(4), [ 0, self.clip_duration // 2, self.clip_duration, (3 * self.clip_duration) // 2 ]) self.startRender() self.cleanUp()
class Project(Signallable, Loggable): """The base class for PiTiVi projects @ivar name: The name of the project @type name: C{str} @ivar description: A description of the project @type description: C{str} @ivar sources: The sources used by this project @type sources: L{SourceList} @ivar timeline: The timeline @type timeline: L{Timeline} @ivar pipeline: The timeline's pipeline @type pipeline: L{Pipeline} @ivar factory: The timeline factory @type factory: L{TimelineSourceFactory} @ivar format: The format under which the project is currently stored. @type format: L{FormatterClass} @ivar loaded: Whether the project is fully loaded or not. @type loaded: C{bool} Signals: - C{loaded} : The project is now fully loaded. """ __signals__ = { "settings-changed": None, } def __init__(self, name="", uri=None, **kwargs): """ name : the name of the project uri : the uri of the project """ Loggable.__init__(self) self.log("name:%s, uri:%s", name, uri) self.name = name self.settings = None self.description = "" self.uri = uri self.urichanged = False self.format = None self.sources = SourceList() self.sources.connect("source-removed", self._sourceRemovedCb) self.settingssigid = 0 self._dirty = False self.timeline = Timeline() self.factory = TimelineSourceFactory(self.timeline) self.pipeline = Pipeline() self.view_action = ViewAction() self.view_action.addProducers(self.factory) def release(self): self.pipeline.release() self.pipeline = None #{ Settings methods def _settingsChangedCb(self, unused_settings): self.emit('settings-changed') def getSettings(self): """ return the currently configured settings. If no setting have been explicitely set, some smart settings will be chosen. """ self.debug("self.settings %s", self.settings) return self.settings or self.getAutoSettings() def setSettings(self, settings): """ Sets the given settings as the project's settings. If settings is None, the current settings will be unset """ self.log("Setting %s as the project's settings", settings) if self.settings: self.settings.disconnect(self.settingssigid) self.settings = settings self.emit('settings-changed') self.settingssigid = self.settings.connect('settings-changed', self._settingsChangedCb) def unsetSettings(self, unused_settings): """ Remove the currently configured settings.""" self.setSettings(None) def getAutoSettings(self): """ Computes and returns smart settings for the project. If the project only has one source, it will be that source's settings. If it has more than one, it will return the largest setting that suits all contained sources. """ settings = ExportSettings() if not self.timeline: self.warning( "project doesn't have a timeline, returning default settings") return settings # FIXME: this is ugly, but rendering for now assumes at most one audio # and one video tracks have_audio = have_video = False for track in self.timeline.tracks: if isinstance(track.stream, VideoStream) and track.duration != 0: have_video = True elif isinstance(track.stream, AudioStream) and track.duration != 0: have_audio = True if not have_audio: settings.aencoder = None if not have_video: settings.vencoder = None return settings #} #{ Save and Load features def save(self, location=None, overwrite=False): """ Save the project to the given location. @param location: The location to write to. If not specified, the current project location will be used (if set). @type location: C{URI} @param overwrite: Whether to overwrite existing location. @type overwrite: C{bool} """ # import here to break circular import from pitivi.formatters.format import save_project from pitivi.formatters.base import FormatterError self.log("saving...") location = location or self.uri if location == None: raise FormatterError("Location unknown") save_project(self, location or self.uri, self.format, overwrite) self.uri = location def setModificationState(self, state): self._dirty = state def hasUnsavedModifications(self): return self._dirty def _sourceRemovedCb(self, sourclist, uri, factory): self.timeline.removeFactory(factory)