def testSaveTimeline(self): video_stream = VideoStream(gst.Caps("video/x-raw-yuv")) audio_stream = AudioStream(gst.Caps("audio/x-raw-int")) source1 = VideoTestSourceFactory() source1.addOutputStream(video_stream) self.formatter._saveSource(source1) self.formatter._saveStream(video_stream) track_object = SourceTrackObject(source1, video_stream, start=10 * gst.SECOND, duration=20 * gst.SECOND, in_point=5 * gst.SECOND, media_duration=15 * gst.SECOND, priority=10) track = Track(video_stream) track.addTrackObject(track_object) self.formatter._saveTrackObject(track_object) timeline_object = TimelineObject(source1) timeline_object.addTrackObject(track_object) self.formatter._saveTimelineObject(timeline_object) timeline = Timeline() timeline.addTrack(track) element = self.formatter._saveTimeline(timeline) self.failUnlessEqual(element.tag, "timeline") tracks = element.find("tracks") self.failUnlessEqual(len(tracks), 1)
def testPads(self): timeline = Timeline() stream1 = VideoStream(gst.Caps('video/x-raw-rgb'), 'src0') stream2 = AudioStream(gst.Caps('audio/x-raw-int'), 'src1') track1 = Track(stream1) track2 = Track(stream2) timeline.addTrack(track1) timeline.addTrack(track2) factory = TimelineSourceFactory(timeline) bin = factory.makeBin() self.failUnlessEqual(len(list(bin.src_pads())), 0) pad1 = gst.Pad('src0', gst.PAD_SRC) pad1.set_caps(gst.Caps('asd')) pad1.set_active(True) track1.composition.add_pad(pad1) pad2 = gst.Pad('src0', gst.PAD_SRC) pad2.set_caps(gst.Caps('asd')) pad2.set_active(True) track2.composition.add_pad(pad2) self.failUnlessEqual(len(list(bin.src_pads())), 2) track1.composition.remove_pad(pad1) self.failUnlessEqual(len(list(bin.src_pads())), 1) track2.composition.remove_pad(pad2) self.failUnlessEqual(len(list(bin.src_pads())), 0) factory.clean()
def test_layer_removed(self): timeline_ui = Timeline(container=None, app=None) timeline_ui.setProject(self.app.project_manager.current_project) layer1 = self.layer layer2 = self.timeline.append_layer() layer3 = self.timeline.append_layer() self.assertEqual([layer1, layer2, layer3], self.timeline.get_layers()) self.assertEqual([l.props.priority for l in [layer1, layer2, layer3]], list(range(3))) with self.action_log.started("layer removed"): self.timeline.remove_layer(layer2) self.assertEqual([layer1, layer3], self.timeline.get_layers()) self.assertEqual([l.props.priority for l in [layer1, layer3]], list(range(2))) self.action_log.undo() self.assertEqual([layer1, layer2, layer3], self.timeline.get_layers()) self.assertEqual([l.props.priority for l in [layer1, layer2, layer3]], list(range(3))) self.action_log.redo() self.assertEqual([layer1, layer3], self.timeline.get_layers()) self.assertEqual([l.props.priority for l in [layer1, layer3]], list(range(2)))
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 testConnectionAndDisconnection(self): timeline = Timeline() stream = new_stream() factory = new_source_factory() track = Track(stream) track_object1 = SourceTrackObject(factory, stream) track.addTrackObject(track_object1) timeline.addTrack(track) timeline_object1 = TimelineObject(factory) timeline_object1.addTrackObject(track_object1) timeline.addTimelineObject(timeline_object1) self.observer.startObserving(timeline) self.failUnless(timeline.connected) self.failUnless(timeline_object1.connected) timeline.removeTimelineObject(timeline_object1) self.failIf(timeline_object1.connected) timeline.addTimelineObject(timeline_object1) self.failUnless(timeline_object1) self.observer.stopObserving(timeline) self.failIf(timeline.connected) self.failIf(timeline_object1.connected)
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 testLayerMoved(self): layer1 = self.layer layer2 = self.timeline.append_layer() layer3 = self.timeline.append_layer() self.assertEqual(self.timeline.get_layers(), [layer1, layer2, layer3]) timeline_ui = Timeline(app=self.app, size_group=mock.Mock()) timeline_ui.setProject(self.app.project_manager.current_project) # Click and drag a layer control box to move the layer. with mock.patch.object(Gtk, 'get_event_widget') as get_event_widget: event = mock.Mock() event.get_button.return_value = True, 1 get_event_widget.return_value = layer1.control_ui timeline_ui._button_press_event_cb(None, event=event) with mock.patch.object(layer1.control_ui, "translate_coordinates") as translate_coordinates: translate_coordinates.return_value = (0, 0) with mock.patch.object(timeline_ui, "_get_layer_at") as _get_layer_at: _get_layer_at.return_value = layer3, None timeline_ui._motion_notify_event_cb(None, event=event) timeline_ui._button_release_event_cb(None, event=event) self.check_layers([layer2, layer3, layer1]) self.action_log.undo() self.check_layers([layer1, layer2, layer3]) self.action_log.redo() self.check_layers([layer2, layer3, layer1])
def testTracks(self): timeline = Timeline() stream1 = VideoStream(gst.Caps('video/x-raw-rgb'), 'src0') stream2 = AudioStream(gst.Caps('audio/x-raw-int'), 'src1') track1 = Track(stream1) track2 = Track(stream2) # start with 2 tracks timeline.addTrack(track1) timeline.addTrack(track2) factory = TimelineSourceFactory(timeline) bin = factory.makeBin() self.failUnlessEqual(len(list(bin)), 2) self.failUnlessEqual(set(factory.getOutputStreams()), set([stream1, stream2])) # add a new track stream3 = AudioStream(gst.Caps('audio/x-raw-int'), 'src2') track3 = Track(stream3) timeline.addTrack(track3) self.failUnlessEqual(len(list(bin)), 3) self.failUnlessEqual(set(factory.getOutputStreams()), set([stream1, stream2, stream3])) # remove a track timeline.removeTrack(track3) self.failUnlessEqual(len(list(bin)), 2) self.failUnlessEqual(set(factory.getOutputStreams()), set([stream1, stream2])) factory.clean()
def createTimeline(self, layers_heights): project_manager = ProjectManager(app=None) project_manager.newBlankProject() project = project_manager.current_project timeline = Timeline(container=None, app=None) timeline.get_parent = mock.MagicMock() timeline.setProject(project) y = 0 for priority, height in enumerate(layers_heights): bLayer = timeline.createLayer(priority=priority) rect = Gdk.Rectangle() rect.y = y rect.height = height bLayer.ui.set_allocation(rect) y += height + SEPARATOR_HEIGHT return timeline
def testAudioOnly(self): audio_factory1 = AudioTestSourceFactory(3) audio_factory1.duration = 10 * gst.SECOND stream = AudioStream(gst.Caps('audio/x-raw-int'), 'src0') audio_factory1.addOutputStream(stream) timeline = Timeline() track = Track(stream) track_object1 = SourceTrackObject(audio_factory1, stream) track_object1.start = 2 * gst.SECOND track.addTrackObject(track_object1) timeline.addTrack(track) factory = TimelineSourceFactory(timeline) bin = factory.makeBin() self.failUnlessEqual(len(list(bin)), 1) self.failUnlessEqual(factory.duration, 12 * gst.SECOND) fakesink = gst.element_factory_make('fakesink') def bin_pad_added_cb(bin, pad): pad.link(fakesink.get_pad('sink')) bin.connect('pad-added', bin_pad_added_cb) def error_cb(bus, message): gerror, debug = message.parse_error() self.fail('%s: %s' % (gerror.message, debug)) def eos_cb(bus, message): self.loop.quit() pipeline = gst.Pipeline() bus = pipeline.get_bus() bus.add_signal_watch() bus.connect('message::error', error_cb) bus.connect('message::eos', eos_cb) pipeline.add(bin) pipeline.add(fakesink) pipeline.set_state(gst.STATE_PLAYING) self.loop.run() pipeline.set_state(gst.STATE_NULL) factory.clean()
def testCheckMediaTypesWhenNoUI(self): ges_layer = GES.Layer() png = common.get_sample_uri("flat_colour1_640x480.png") video_clip = GES.UriClipAsset.request_sync(png).extract() self.assertTrue(ges_layer.add_clip(video_clip)) self.assertEqual(len(ges_layer.get_clips()), 1) timeline = Timeline(container=None, app=None) layer = Layer(ges_layer, timeline)
def testLoadProject(self): video_stream = VideoStream(gst.Caps("video/x-raw-yuv")) audio_stream = AudioStream(gst.Caps("audio/x-raw-int")) source1 = VideoTestSourceFactory() self.formatter._saveSource(source1) self.formatter._saveStream(video_stream) track_object = SourceTrackObject(source1, video_stream, start=10 * gst.SECOND, duration=20 * gst.SECOND, in_point=5 * gst.SECOND, media_duration=15 * gst.SECOND, priority=10) track = Track(video_stream) track.addTrackObject(track_object) self.formatter._saveTrackObject(track_object) timeline_object = TimelineObject(source1) timeline_object.addTrackObject(track_object) self.formatter._saveTimelineObject(timeline_object) timeline = Timeline() timeline.addTrack(track) self.formatter._saveTimeline(timeline) project = Project() project.timeline = timeline project.sources.addFactory(source1) element = self.formatter._serializeProject(project) self.failUnlessEqual(element.tag, "pitivi") self.failIfEqual(element.find("factories"), None) self.failIfEqual(element.find("timeline"), None) indent(element) f = file("/tmp/untitled.pptv", "w") f.write(tostring(element)) f.close()
def testEmpty(self): timeline = Timeline() factory = TimelineSourceFactory(timeline) bin = factory.makeBin() self.failUnlessRaises(ObjectFactoryError, factory.makeBin) self.failUnlessEqual(len(list(bin)), 0) factory.clean()
def setUp(self): self.stream = new_stream() self.factory = new_source_factory() self.effect_factory = TestEffectFactory(self.stream) self.track1 = Track(self.stream) self.track2 = Track(self.stream) self.timeline = Timeline() self.timeline.addTrack(self.track1) self.timeline.addTrack(self.track2) self.track_object1 = SourceTrackObject(self.factory, self.stream) self.track_object2 = SourceTrackObject(self.factory, self.stream) self.track_effect1 = TrackEffect(self.effect_factory, self.stream) self.track_effect2 = TrackEffect(self.effect_factory, self.stream) self.track1.addTrackObject(self.track_object1) self.track2.addTrackObject(self.track_object2) self.timeline_object1 = TimelineObject(self.factory) self.timeline_object1.addTrackObject(self.track_object1) self.timeline_object1.addTrackObject(self.track_object2) self.action_log = UndoableActionLog() self.observer = TestTimelineLogObserver(self.action_log) self.observer.startObserving(self.timeline)
def setUp(self): self.stream = new_stream() self.factory = new_factory() self.track1 = Track(self.stream) self.track2 = Track(self.stream) self.timeline = Timeline() self.timeline.addTrack(self.track1) self.timeline.addTrack(self.track2) self.track_object1 = SourceTrackObject(self.factory, self.stream) self.track_object2 = SourceTrackObject(self.factory, self.stream) self.track1.addTrackObject(self.track_object1) self.track2.addTrackObject(self.track_object2) self.timeline_object1 = TimelineObject(self.factory) self.timeline_object1.addTrackObject(self.track_object1) self.timeline_object1.addTrackObject(self.track_object2) self.action_log = UndoableActionLog() self.observer = TestTimelineLogObserver(self.action_log) self.observer.startObserving(self.timeline)
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 TestTimelineUndo(TestCase): def setUp(self): self.stream = new_stream() self.factory = new_source_factory() self.effect_factory = TestEffectFactory(self.stream) self.track1 = Track(self.stream) self.track2 = Track(self.stream) self.timeline = Timeline() self.timeline.addTrack(self.track1) self.timeline.addTrack(self.track2) self.track_object1 = SourceTrackObject(self.factory, self.stream) self.track_object2 = SourceTrackObject(self.factory, self.stream) self.track_effect1 = TrackEffect(self.effect_factory, self.stream) self.track_effect2 = TrackEffect(self.effect_factory, self.stream) self.track1.addTrackObject(self.track_object1) self.track2.addTrackObject(self.track_object2) self.timeline_object1 = TimelineObject(self.factory) self.timeline_object1.addTrackObject(self.track_object1) self.timeline_object1.addTrackObject(self.track_object2) self.action_log = UndoableActionLog() self.observer = TestTimelineLogObserver(self.action_log) self.observer.startObserving(self.timeline) def testAddTimelineObject(self): stacks = [] def commitCb(action_log, stack, nested): stacks.append(stack) self.action_log.connect("commit", commitCb) self.action_log.begin("add clip") self.timeline.addTimelineObject(self.timeline_object1) 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, TimelineObjectAdded)) self.failUnless(self.timeline_object1 \ in self.timeline.timeline_objects) self.action_log.undo() self.failIf(self.timeline_object1 \ in self.timeline.timeline_objects) self.action_log.redo() self.failUnless(self.timeline_object1 \ in self.timeline.timeline_objects) def testRemoveTimelineObject(self): stacks = [] def commitCb(action_log, stack, nested): stacks.append(stack) self.action_log.connect("commit", commitCb) self.timeline.addTimelineObject(self.timeline_object1) self.action_log.begin("remove clip") self.timeline.removeTimelineObject(self.timeline_object1, deep=True) 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, TimelineObjectRemoved)) self.failIf(self.timeline_object1 \ in self.timeline.timeline_objects) self.action_log.undo() self.failUnless(self.timeline_object1 \ in self.timeline.timeline_objects) self.action_log.redo() self.failIf(self.timeline_object1 \ in self.timeline.timeline_objects) 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 testTimelineObjectPropertyChange(self): stacks = [] def commitCb(action_log, stack, nested): stacks.append(stack) self.action_log.connect("commit", commitCb) self.timeline_object1.start = 5 * gst.SECOND self.timeline_object1.duration = 20 * gst.SECOND self.timeline.addTimelineObject(self.timeline_object1) self.action_log.begin("modify clip") self.timeline_object1.start = 10 * gst.SECOND 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, TimelineObjectPropertyChanged)) self.failUnlessEqual(self.timeline_object1.start, 10 * gst.SECOND) self.action_log.undo() self.failUnlessEqual(self.timeline_object1.start, 5 * gst.SECOND) self.action_log.redo() self.failUnlessEqual(self.timeline_object1.start, 10 * gst.SECOND) self.timeline_object1.priority = 10 self.action_log.begin("priority change") self.timeline_object1.priority = 20 self.action_log.commit() self.failUnlessEqual(self.timeline_object1.priority, 20) self.action_log.undo() self.failUnlessEqual(self.timeline_object1.priority, 10) self.action_log.redo() self.failUnlessEqual(self.timeline_object1.priority, 20) def testUngroup(self): self.timeline_object1.start = 5 * gst.SECOND self.timeline_object1.duration = 20 * gst.SECOND self.timeline.addTimelineObject(self.timeline_object1) self.timeline.setSelectionToObj(self.track_object1, SELECT_ADD) self.failUnlessEqual(len(self.timeline.timeline_objects), 1) self.failUnlessEqual(self.timeline.timeline_objects[0].start, 5 * gst.SECOND) self.failUnlessEqual(self.timeline.timeline_objects[0].duration, 20 * gst.SECOND) self.action_log.begin("ungroup") self.timeline.ungroupSelection() self.action_log.commit() self.failUnlessEqual(len(self.timeline.timeline_objects), 2) self.failUnlessEqual(self.timeline.timeline_objects[0].start, 5 * gst.SECOND) self.failUnlessEqual(self.timeline.timeline_objects[0].duration, 20 * gst.SECOND) self.failUnlessEqual(self.timeline.timeline_objects[1].start, 5 * gst.SECOND) self.failUnlessEqual(self.timeline.timeline_objects[1].duration, 20 * gst.SECOND) self.action_log.undo() self.failUnlessEqual(len(self.timeline.timeline_objects), 1) self.failUnlessEqual(self.timeline.timeline_objects[0].start, 5 * gst.SECOND) self.failUnlessEqual(self.timeline.timeline_objects[0].duration, 20 * gst.SECOND)
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)
class TestGap(TestCase): def setUp(self): self.factory = StubFactory() self.stream = AudioStream(gst.Caps('audio/x-raw-int')) self.factory.addOutputStream(self.stream) self.track1 = Track(self.stream) self.timeline = Timeline() def makeTimelineObject(self): track_object = SourceTrackObject(self.factory, self.stream) self.track1.addTrackObject(track_object) timeline_object = TimelineObject(self.factory) timeline_object.addTrackObject(track_object) self.timeline.addTimelineObject(timeline_object) return timeline_object def testGapCmp(self): gap1 = Gap(None, None, start=10, duration=5) gap2 = Gap(None, None, start=10, duration=5) self.failUnlessEqual(gap1, gap2) gap2 = Gap(None, None, start=15, duration=4) self.failUnless(gap1 > gap2) self.failUnless(gap2 < gap1) def testFindAroundObject(self): timeline_object1 = self.makeTimelineObject() timeline_object2 = self.makeTimelineObject() timeline_object1.start = 5 * gst.SECOND timeline_object1.duration = 10 * gst.SECOND timeline_object2.start = 20 * gst.SECOND timeline_object2.duration = 10 * gst.SECOND left_gap, right_gap = Gap.findAroundObject(timeline_object1) self.failUnlessEqual(left_gap.left_object, None) self.failUnlessEqual(left_gap.right_object, timeline_object1) self.failUnlessEqual(left_gap.start, 0 * gst.SECOND) self.failUnlessEqual(left_gap.duration, 5 * gst.SECOND) self.failUnlessEqual(right_gap.left_object, timeline_object1) self.failUnlessEqual(right_gap.right_object, timeline_object2) self.failUnlessEqual(right_gap.start, 15 * gst.SECOND) self.failUnlessEqual(right_gap.duration, 5 * gst.SECOND) left_gap, right_gap = Gap.findAroundObject(timeline_object2) self.failUnlessEqual(left_gap.left_object, timeline_object1) self.failUnlessEqual(left_gap.right_object, timeline_object2) self.failUnlessEqual(left_gap.start, 15 * gst.SECOND) self.failUnlessEqual(left_gap.duration, 5 * gst.SECOND) self.failUnlessEqual(right_gap.left_object, timeline_object2) self.failUnlessEqual(right_gap.right_object, None) self.failUnlessEqual(right_gap.start, 30 * gst.SECOND) self.failUnlessEqual(right_gap.duration, infinity) # make the objects overlap timeline_object2.start = 10 * gst.SECOND left_gap, right_gap = Gap.findAroundObject(timeline_object1) self.failUnlessEqual(right_gap.left_object, timeline_object1) self.failUnlessEqual(right_gap.right_object, timeline_object2) self.failUnlessEqual(right_gap.start, 15 * gst.SECOND) self.failUnlessEqual(right_gap.duration, -5 * gst.SECOND) def testGapFinder(self): timeline_object1 = self.makeTimelineObject() timeline_object2 = self.makeTimelineObject() timeline_object3 = self.makeTimelineObject() timeline_object4 = self.makeTimelineObject() timeline_object1.start = 5 * gst.SECOND timeline_object1.duration = 10 * gst.SECOND timeline_object1.priority = 1 timeline_object2.start = 20 * gst.SECOND timeline_object2.duration = 10 * gst.SECOND timeline_object2.priority = 1 timeline_object3.start = 31 * gst.SECOND timeline_object3.duration = 10 * gst.SECOND timeline_object3.priority = 2 timeline_object4.start = 50 * gst.SECOND timeline_object4.duration = 10 * gst.SECOND timeline_object4.priority = 2 gap_finder = SmallestGapsFinder( set([timeline_object2, timeline_object3])) gap_finder.update(*Gap.findAroundObject(timeline_object2)) gap_finder.update(*Gap.findAroundObject(timeline_object3)) left_gap = gap_finder.left_gap right_gap = gap_finder.right_gap self.failUnlessEqual(left_gap.left_object, timeline_object1) self.failUnlessEqual(left_gap.right_object, timeline_object2) self.failUnlessEqual(left_gap.start, 15 * gst.SECOND) self.failUnlessEqual(left_gap.duration, 5 * gst.SECOND) self.failUnlessEqual(right_gap.left_object, timeline_object3) self.failUnlessEqual(right_gap.right_object, timeline_object4) self.failUnlessEqual(right_gap.start, 41 * gst.SECOND) self.failUnlessEqual(right_gap.duration, 9 * gst.SECOND) # make timeline_object3 and timeline_object4 overlap timeline_object3.duration = 20 * gst.SECOND gap_finder = SmallestGapsFinder(set([timeline_object4])) gap_finder.update(*Gap.findAroundObject(timeline_object4)) left_gap = gap_finder.left_gap right_gap = gap_finder.right_gap self.failUnlessEqual(left_gap, invalid_gap) self.failUnlessEqual(right_gap.left_object, timeline_object4) self.failUnlessEqual(right_gap.right_object, None) self.failUnlessEqual(right_gap.start, 60 * gst.SECOND) self.failUnlessEqual(right_gap.duration, infinity) gap_finder = SmallestGapsFinder(set([timeline_object3])) gap_finder.update(*Gap.findAroundObject(timeline_object3)) left_gap = gap_finder.left_gap right_gap = gap_finder.right_gap self.failUnlessEqual(left_gap.left_object, None) self.failUnlessEqual(left_gap.right_object, timeline_object3) self.failUnlessEqual(left_gap.start, 0 * gst.SECOND) self.failUnlessEqual(left_gap.duration, 31 * gst.SECOND) self.failUnlessEqual(right_gap, invalid_gap) def testFindAllGaps(self): simple = ((3 * gst.SECOND, 1 * gst.SECOND), (1 * gst.SECOND, 1 * gst.SECOND)) objs = [] for start, duration in simple: obj = self.makeTimelineObject() obj.start = start obj.duration = duration objs.append(obj) result = [(g.start, g.initial_duration) for g in Gap.findAllGaps(objs)] self.assertEquals(result, [ (0 * gst.SECOND, 1 * gst.SECOND), (2 * gst.SECOND, 1 * gst.SECOND), ]) complex = [ (1 * gst.SECOND, 2 * gst.SECOND), (6 * gst.SECOND, 2 * gst.SECOND), (10 * gst.SECOND, 2 * gst.SECOND), (8 * gst.SECOND, 2 * gst.SECOND), (14 * gst.SECOND, 1 * gst.SECOND), (4 * gst.SECOND, 1 * gst.SECOND), ] objs = [] for start, duration in complex: obj = self.makeTimelineObject() obj.start = start obj.duration = duration objs.append(obj) result = [(g.start, g.initial_duration) for g in Gap.findAllGaps(objs)] self.assertEquals(result, [ (0 * gst.SECOND, 1 * gst.SECOND), (3 * gst.SECOND, 1 * gst.SECOND), (5 * gst.SECOND, 1 * gst.SECOND), (12 * gst.SECOND, 2 * gst.SECOND), ]) complex.append((2 * gst.SECOND, 5 * gst.SECOND)) objs = [] for start, duration in complex: obj = self.makeTimelineObject() obj.start = start obj.duration = duration objs.append(obj) result = [(g.start, g.initial_duration) for g in Gap.findAllGaps(objs)] self.assertEquals(result, [ (0 * gst.SECOND, 1 * gst.SECOND), (12 * gst.SECOND, 2 * gst.SECOND), ])
def setUp(self): self.factory = StubFactory() self.stream = AudioStream(gst.Caps('audio/x-raw-int')) self.factory.addOutputStream(self.stream) self.track1 = Track(self.stream) self.timeline = Timeline()
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 TestGap(TestCase): def setUp(self): self.factory = StubFactory() self.stream = AudioStream(gst.Caps('audio/x-raw-int')) self.factory.addOutputStream(self.stream) self.track1 = Track(self.stream) self.timeline = Timeline() def makeTimelineObject(self): track_object = SourceTrackObject(self.factory, self.stream) self.track1.addTrackObject(track_object) timeline_object = TimelineObject(self.factory) timeline_object.addTrackObject(track_object) self.timeline.addTimelineObject(timeline_object) return timeline_object def testGapCmp(self): gap1 = Gap(None, None, start=10, duration=5) gap2 = Gap(None, None, start=10, duration=5) self.failUnlessEqual(gap1, gap2) gap2 = Gap(None, None, start=15, duration=4) self.failUnless(gap1 > gap2) self.failUnless(gap2 < gap1) def testFindAroundObject(self): timeline_object1 = self.makeTimelineObject() timeline_object2 = self.makeTimelineObject() timeline_object1.start = 5 * gst.SECOND timeline_object1.duration = 10 * gst.SECOND timeline_object2.start = 20 * gst.SECOND timeline_object2.duration = 10 * gst.SECOND left_gap, right_gap = Gap.findAroundObject(timeline_object1) self.failUnlessEqual(left_gap.left_object, None) self.failUnlessEqual(left_gap.right_object, timeline_object1) self.failUnlessEqual(left_gap.start, 0 * gst.SECOND) self.failUnlessEqual(left_gap.duration, 5 * gst.SECOND) self.failUnlessEqual(right_gap.left_object, timeline_object1) self.failUnlessEqual(right_gap.right_object, timeline_object2) self.failUnlessEqual(right_gap.start, 15 * gst.SECOND) self.failUnlessEqual(right_gap.duration, 5 * gst.SECOND) left_gap, right_gap = Gap.findAroundObject(timeline_object2) self.failUnlessEqual(left_gap.left_object, timeline_object1) self.failUnlessEqual(left_gap.right_object, timeline_object2) self.failUnlessEqual(left_gap.start, 15 * gst.SECOND) self.failUnlessEqual(left_gap.duration, 5 * gst.SECOND) self.failUnlessEqual(right_gap.left_object, timeline_object2) self.failUnlessEqual(right_gap.right_object, None) self.failUnlessEqual(right_gap.start, 30 * gst.SECOND) self.failUnlessEqual(right_gap.duration, infinity) # make the objects overlap timeline_object2.start = 10 * gst.SECOND left_gap, right_gap = Gap.findAroundObject(timeline_object1) self.failUnlessEqual(right_gap.left_object, timeline_object1) self.failUnlessEqual(right_gap.right_object, timeline_object2) self.failUnlessEqual(right_gap.start, 15 * gst.SECOND) self.failUnlessEqual(right_gap.duration, -5 * gst.SECOND) def testGapFinder(self): timeline_object1 = self.makeTimelineObject() timeline_object2 = self.makeTimelineObject() timeline_object3 = self.makeTimelineObject() timeline_object4 = self.makeTimelineObject() timeline_object1.start = 5 * gst.SECOND timeline_object1.duration = 10 * gst.SECOND timeline_object1.priority = 1 timeline_object2.start = 20 * gst.SECOND timeline_object2.duration = 10 * gst.SECOND timeline_object2.priority = 1 timeline_object3.start = 31 * gst.SECOND timeline_object3.duration = 10 * gst.SECOND timeline_object3.priority = 2 timeline_object4.start = 50 * gst.SECOND timeline_object4.duration = 10 * gst.SECOND timeline_object4.priority = 2 gap_finder = SmallestGapsFinder(set([timeline_object2, timeline_object3])) gap_finder.update(*Gap.findAroundObject(timeline_object2)) gap_finder.update(*Gap.findAroundObject(timeline_object3)) left_gap = gap_finder.left_gap right_gap = gap_finder.right_gap self.failUnlessEqual(left_gap.left_object, timeline_object1) self.failUnlessEqual(left_gap.right_object, timeline_object2) self.failUnlessEqual(left_gap.start, 15 * gst.SECOND) self.failUnlessEqual(left_gap.duration, 5 * gst.SECOND) self.failUnlessEqual(right_gap.left_object, timeline_object3) self.failUnlessEqual(right_gap.right_object, timeline_object4) self.failUnlessEqual(right_gap.start, 41 * gst.SECOND) self.failUnlessEqual(right_gap.duration, 9 * gst.SECOND) # make timeline_object3 and timeline_object4 overlap timeline_object3.duration = 20 * gst.SECOND gap_finder = SmallestGapsFinder(set([timeline_object4])) gap_finder.update(*Gap.findAroundObject(timeline_object4)) left_gap = gap_finder.left_gap right_gap = gap_finder.right_gap self.failUnlessEqual(left_gap, invalid_gap) self.failUnlessEqual(right_gap.left_object, timeline_object4) self.failUnlessEqual(right_gap.right_object, None) self.failUnlessEqual(right_gap.start, 60 * gst.SECOND) self.failUnlessEqual(right_gap.duration, infinity) gap_finder = SmallestGapsFinder(set([timeline_object3])) gap_finder.update(*Gap.findAroundObject(timeline_object3)) left_gap = gap_finder.left_gap right_gap = gap_finder.right_gap self.failUnlessEqual(left_gap.left_object, None) self.failUnlessEqual(left_gap.right_object, timeline_object3) self.failUnlessEqual(left_gap.start, 0 * gst.SECOND) self.failUnlessEqual(left_gap.duration, 31 * gst.SECOND) self.failUnlessEqual(right_gap, invalid_gap) def testFindAllGaps(self): simple = ( (3 * gst.SECOND, 1 * gst.SECOND), (1 * gst.SECOND, 1 * gst.SECOND) ) objs = [] for start, duration in simple: obj = self.makeTimelineObject() obj.start = start obj.duration = duration objs.append(obj) result = [(g.start, g.initial_duration) for g in Gap.findAllGaps(objs)] self.assertEquals(result, [ (0 * gst.SECOND, 1 * gst.SECOND), (2 * gst.SECOND, 1 * gst.SECOND), ]) complex = [ (1 * gst.SECOND, 2 * gst.SECOND), (6 * gst.SECOND, 2 * gst.SECOND), (10 * gst.SECOND, 2 * gst.SECOND), (8 * gst.SECOND, 2 * gst.SECOND), (14 * gst.SECOND, 1 * gst.SECOND), (4 * gst.SECOND, 1 * gst.SECOND), ] objs = [] for start, duration in complex: obj = self.makeTimelineObject() obj.start = start obj.duration = duration objs.append(obj) result = [(g.start, g.initial_duration) for g in Gap.findAllGaps(objs)] self.assertEquals(result, [ (0 * gst.SECOND, 1 * gst.SECOND), (3 * gst.SECOND, 1 * gst.SECOND), (5 * gst.SECOND, 1 * gst.SECOND), (12 * gst.SECOND, 2 * gst.SECOND), ]) complex.append((2 * gst.SECOND, 5 * gst.SECOND)) objs = [] for start, duration in complex: obj = self.makeTimelineObject() obj.start = start obj.duration = duration objs.append(obj) result = [(g.start, g.initial_duration) for g in Gap.findAllGaps(objs)] self.assertEquals(result, [ (0 * gst.SECOND, 1 * gst.SECOND), (12 * gst.SECOND, 2 * gst.SECOND), ])
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 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()
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 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)