Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/glive.py
diff options
context:
space:
mode:
authorAleksey Lim <alsroot@member.fsf.org>2009-04-17 14:20:39 (GMT)
committer Aleksey Lim <alsroot@member.fsf.org>2009-04-17 14:20:39 (GMT)
commit7564597666a078d00ec7072d2abe2440e224e9c0 (patch)
tree5e2ccae70f58ce49892ab6f2f865ad3712a9d27b /glive.py
parentccca798196b9eef3e08c93826f4d4f8f4f85327e (diff)
Replate tabs by spaces
Diffstat (limited to 'glive.py')
-rw-r--r--glive.py920
1 files changed, 460 insertions, 460 deletions
diff --git a/glive.py b/glive.py
index ae7480c..7b7619f 100644
--- a/glive.py
+++ b/glive.py
@@ -40,519 +40,519 @@ import utils
import ui
class Glive:
- def __init__(self, pca):
- self.window = None
- self.ca = pca
- self._eos_cb = None
+ def __init__(self, pca):
+ self.window = None
+ self.ca = pca
+ self._eos_cb = None
- self.playing = False
- self.picExposureOpen = False
+ self.playing = False
+ self.picExposureOpen = False
- self.AUDIO_TRANSCODE_ID = 0
- self.TRANSCODE_ID = 0
- self.VIDEO_TRANSCODE_ID = 0
+ self.AUDIO_TRANSCODE_ID = 0
+ self.TRANSCODE_ID = 0
+ self.VIDEO_TRANSCODE_ID = 0
- self.PHOTO_MODE_PHOTO = 0
- self.PHOTO_MODE_AUDIO = 1
+ self.PHOTO_MODE_PHOTO = 0
+ self.PHOTO_MODE_AUDIO = 1
- self.TRANSCODE_UPDATE_INTERVAL = 200
+ self.TRANSCODE_UPDATE_INTERVAL = 200
- self.VIDEO_WIDTH_SMALL = 160
- self.VIDEO_HEIGHT_SMALL = 120
- self.VIDEO_FRAMERATE_SMALL = 10
+ self.VIDEO_WIDTH_SMALL = 160
+ self.VIDEO_HEIGHT_SMALL = 120
+ self.VIDEO_FRAMERATE_SMALL = 10
- self.VIDEO_WIDTH_LARGE = 200
- self.VIDEO_HEIGHT_LARGE = 150
- self.VIDEO_FRAMERATE_SMALL = 10
+ self.VIDEO_WIDTH_LARGE = 200
+ self.VIDEO_HEIGHT_LARGE = 150
+ self.VIDEO_FRAMERATE_SMALL = 10
- self.pipeline = gst.Pipeline("my-pipeline")
- self.createPhotoBin()
- self.createAudioBin()
- self.createVideoBin()
- self.createPipeline()
+ self.pipeline = gst.Pipeline("my-pipeline")
+ self.createPhotoBin()
+ self.createAudioBin()
+ self.createVideoBin()
+ self.createPipeline()
- self.thumbPipes = []
- self.muxPipes = []
+ self.thumbPipes = []
+ self.muxPipes = []
- bus = self.pipeline.get_bus()
- bus.enable_sync_message_emission()
- bus.add_signal_watch()
- self.SYNC_ID = bus.connect('sync-message::element', self._onSyncMessageCb)
- self.MESSAGE_ID = bus.connect('message', self._onMessageCb)
+ bus = self.pipeline.get_bus()
+ bus.enable_sync_message_emission()
+ bus.add_signal_watch()
+ self.SYNC_ID = bus.connect('sync-message::element', self._onSyncMessageCb)
+ self.MESSAGE_ID = bus.connect('message', self._onMessageCb)
- def createPhotoBin ( self ):
- queue = gst.element_factory_make("queue", "pbqueue")
- queue.set_property("leaky", True)
- queue.set_property("max-size-buffers", 1)
+ def createPhotoBin ( self ):
+ queue = gst.element_factory_make("queue", "pbqueue")
+ queue.set_property("leaky", True)
+ queue.set_property("max-size-buffers", 1)
- colorspace = gst.element_factory_make("ffmpegcolorspace", "pbcolorspace")
- jpeg = gst.element_factory_make("jpegenc", "pbjpeg")
+ colorspace = gst.element_factory_make("ffmpegcolorspace", "pbcolorspace")
+ jpeg = gst.element_factory_make("jpegenc", "pbjpeg")
- sink = gst.element_factory_make("fakesink", "pbsink")
- self.HANDOFF_ID = sink.connect("handoff", self.copyPic)
- sink.set_property("signal-handoffs", True)
+ sink = gst.element_factory_make("fakesink", "pbsink")
+ self.HANDOFF_ID = sink.connect("handoff", self.copyPic)
+ sink.set_property("signal-handoffs", True)
- self.photobin = gst.Bin("photobin")
- self.photobin.add(queue, colorspace, jpeg, sink)
+ self.photobin = gst.Bin("photobin")
+ self.photobin.add(queue, colorspace, jpeg, sink)
- gst.element_link_many(queue, colorspace, jpeg, sink)
+ gst.element_link_many(queue, colorspace, jpeg, sink)
- pad = queue.get_static_pad("sink")
- self.photobin.add_pad(gst.GhostPad("sink", pad))
+ pad = queue.get_static_pad("sink")
+ self.photobin.add_pad(gst.GhostPad("sink", pad))
- def createAudioBin ( self ):
- src = gst.element_factory_make("alsasrc", "absrc")
- srccaps = gst.Caps("audio/x-raw-int,rate=16000,channels=1,depth=16")
+ def createAudioBin ( self ):
+ src = gst.element_factory_make("alsasrc", "absrc")
+ srccaps = gst.Caps("audio/x-raw-int,rate=16000,channels=1,depth=16")
- enc = gst.element_factory_make("wavenc", "abenc")
+ enc = gst.element_factory_make("wavenc", "abenc")
- sink = gst.element_factory_make("filesink", "absink")
- sink.set_property("location", os.path.join(Instance.instancePath, "output.wav"))
+ sink = gst.element_factory_make("filesink", "absink")
+ sink.set_property("location", os.path.join(Instance.instancePath, "output.wav"))
- self.audiobin = gst.Bin("audiobin")
- self.audiobin.add(src, enc, sink)
+ self.audiobin = gst.Bin("audiobin")
+ self.audiobin.add(src, enc, sink)
- src.link(enc, srccaps)
- enc.link(sink)
+ src.link(enc, srccaps)
+ enc.link(sink)
- def createVideoBin ( self ):
- queue = gst.element_factory_make("queue", "vbqueue")
+ def createVideoBin ( self ):
+ queue = gst.element_factory_make("queue", "vbqueue")
- rate = gst.element_factory_make("videorate", "vbrate")
- ratecaps = gst.Caps('video/x-raw-yuv,framerate='+str(self.VIDEO_FRAMERATE_SMALL)+'/1')
+ rate = gst.element_factory_make("videorate", "vbrate")
+ ratecaps = gst.Caps('video/x-raw-yuv,framerate='+str(self.VIDEO_FRAMERATE_SMALL)+'/1')
- scale = gst.element_factory_make("videoscale", "vbscale")
- scalecaps = gst.Caps('video/x-raw-yuv,width='+str(self.VIDEO_WIDTH_SMALL)+',height='+str(self.VIDEO_HEIGHT_SMALL))
+ scale = gst.element_factory_make("videoscale", "vbscale")
+ scalecaps = gst.Caps('video/x-raw-yuv,width='+str(self.VIDEO_WIDTH_SMALL)+',height='+str(self.VIDEO_HEIGHT_SMALL))
- colorspace = gst.element_factory_make("ffmpegcolorspace", "vbcolorspace")
+ colorspace = gst.element_factory_make("ffmpegcolorspace", "vbcolorspace")
- enc = gst.element_factory_make("theoraenc", "vbenc")
- enc.set_property("quality", 16)
+ enc = gst.element_factory_make("theoraenc", "vbenc")
+ enc.set_property("quality", 16)
- mux = gst.element_factory_make("oggmux", "vbmux")
+ mux = gst.element_factory_make("oggmux", "vbmux")
- sink = gst.element_factory_make("filesink", "vbfile")
- sink.set_property("location", os.path.join(Instance.instancePath, "output.ogg"))
+ sink = gst.element_factory_make("filesink", "vbfile")
+ sink.set_property("location", os.path.join(Instance.instancePath, "output.ogg"))
- self.videobin = gst.Bin("videobin")
- self.videobin.add(queue, rate, scale, colorspace, enc, mux, sink)
+ self.videobin = gst.Bin("videobin")
+ self.videobin.add(queue, rate, scale, colorspace, enc, mux, sink)
- queue.link(rate)
- rate.link(scale, ratecaps)
- scale.link(colorspace, scalecaps)
- gst.element_link_many(colorspace, enc, mux, sink)
+ queue.link(rate)
+ rate.link(scale, ratecaps)
+ scale.link(colorspace, scalecaps)
+ gst.element_link_many(colorspace, enc, mux, sink)
- pad = queue.get_static_pad("sink")
- self.videobin.add_pad(gst.GhostPad("sink", pad))
+ pad = queue.get_static_pad("sink")
+ self.videobin.add_pad(gst.GhostPad("sink", pad))
- def createPipeline ( self ):
- src = gst.element_factory_make("v4l2src", "camsrc")
- try:
- # old gst-plugins-good does not have this property
- src.set_property("queue-size", 2)
- except:
- pass
+ def createPipeline ( self ):
+ src = gst.element_factory_make("v4l2src", "camsrc")
+ try:
+ # old gst-plugins-good does not have this property
+ src.set_property("queue-size", 2)
+ except:
+ pass
- tee = gst.element_factory_make("tee", "tee")
- queue = gst.element_factory_make("queue", "dispqueue")
- xvsink = gst.element_factory_make("xvimagesink", "xvsink")
- self.pipeline.add(src, tee, queue, xvsink)
- gst.element_link_many(src, tee, queue, xvsink)
+ tee = gst.element_factory_make("tee", "tee")
+ queue = gst.element_factory_make("queue", "dispqueue")
+ xvsink = gst.element_factory_make("xvimagesink", "xvsink")
+ self.pipeline.add(src, tee, queue, xvsink)
+ gst.element_link_many(src, tee, queue, xvsink)
- def thumbPipe(self):
- return self.thumbPipes[ len(self.thumbPipes)-1 ]
+ def thumbPipe(self):
+ return self.thumbPipes[ len(self.thumbPipes)-1 ]
- def thumbEl(self, name):
- return self.thumbPipe().get_by_name(name)
+ def thumbEl(self, name):
+ return self.thumbPipe().get_by_name(name)
- def muxPipe(self):
- return self.muxPipes[ len(self.muxPipes)-1 ]
+ def muxPipe(self):
+ return self.muxPipes[ len(self.muxPipes)-1 ]
- def muxEl(self, name):
- return self.muxPipe().get_by_name(name)
+ def muxEl(self, name):
+ return self.muxPipe().get_by_name(name)
- def play(self):
- self.pipeline.set_state(gst.STATE_PLAYING)
- self.playing = True
+ def play(self):
+ self.pipeline.set_state(gst.STATE_PLAYING)
+ self.playing = True
- def pause(self):
- self.pipeline.set_state(gst.STATE_PAUSED)
- self.playing = False
+ def pause(self):
+ self.pipeline.set_state(gst.STATE_PAUSED)
+ self.playing = False
- def stop(self):
- self.pipeline.set_state(gst.STATE_NULL)
- self.playing = False
+ def stop(self):
+ self.pipeline.set_state(gst.STATE_NULL)
+ self.playing = False
- def is_playing(self):
- return self.playing
+ def is_playing(self):
+ return self.playing
- def idlePlayElement(self, element):
- element.set_state(gst.STATE_PLAYING)
- return False
+ def idlePlayElement(self, element):
+ element.set_state(gst.STATE_PLAYING)
+ return False
- def stopRecordingAudio( self ):
- self.audiobin.set_state(gst.STATE_NULL)
- self.pipeline.remove(self.audiobin)
- gobject.idle_add( self.stoppedRecordingAudio )
-
-
- def stoppedRecordingVideo(self):
- if ( len(self.thumbPipes) > 0 ):
- thumbline = self.thumbPipes[len(self.thumbPipes)-1]
- thumbline.get_by_name('thumbFakesink').disconnect(self.THUMB_HANDOFF_ID)
-
- oggFilepath = os.path.join(Instance.instancePath, "output.ogg") #ogv
- if (not os.path.exists(oggFilepath)):
- self.record = False
- self.ca.m.cannotSaveVideo()
- self.ca.m.stoppedRecordingVideo()
- return
- oggSize = os.path.getsize(oggFilepath)
- if (oggSize <= 0):
- self.record = False
- self.ca.m.cannotSaveVideo()
- self.ca.m.stoppedRecordingVideo()
- return
-
- line = 'filesrc location=' + str(oggFilepath) + ' name=thumbFilesrc ! oggdemux name=thumbOggdemux ! theoradec name=thumbTheoradec ! tee name=thumbTee ! queue name=thumbQueue ! ffmpegcolorspace name=thumbFfmpegcolorspace ! jpegenc name=thumbJPegenc ! fakesink name=thumbFakesink'
- thumbline = gst.parse_launch(line)
- thumbQueue = thumbline.get_by_name('thumbQueue')
- thumbQueue.set_property("leaky", True)
- thumbQueue.set_property("max-size-buffers", 1)
- thumbTee = thumbline.get_by_name('thumbTee')
- thumbFakesink = thumbline.get_by_name('thumbFakesink')
- self.THUMB_HANDOFF_ID = thumbFakesink.connect("handoff", self.copyThumbPic)
- thumbFakesink.set_property("signal-handoffs", True)
- self.thumbPipes.append(thumbline)
- self.thumbExposureOpen = True
- gobject.idle_add( self.idlePlayElement, thumbline )
-
-
- def stoppedRecordingAudio( self ):
- record.Record.log.debug("stoppedRecordingAudio")
- if (self.audioPixbuf != None):
- audioFilepath = os.path.join(Instance.instancePath, "output.wav")#self.el("audioFilesink").get_property("location")
- if (not os.path.exists(audioFilepath)):
- self.record = False
- self.audio = False
- self.ca.m.cannotSaveVideo()
- return
- wavSize = os.path.getsize(audioFilepath)
- if (wavSize <= 0):
- self.record = False
- self.ca.m.cannotSaveVideo()
- return
-
- self.ca.ui.setPostProcessPixBuf(self.audioPixbuf)
-
- line = 'filesrc location=' + str(audioFilepath) + ' name=audioFilesrc ! wavparse name=audioWavparse ! audioconvert name=audioAudioconvert ! vorbisenc name=audioVorbisenc ! oggmux name=audioOggmux ! filesink name=audioFilesink'
- audioline = gst.parse_launch(line)
-
- taglist = self.getTags(Constants.TYPE_AUDIO)
- base64AudioSnapshot = utils.getStringFromPixbuf(self.audioPixbuf)
- taglist[gst.TAG_EXTENDED_COMMENT] = "coverart="+str(base64AudioSnapshot)
- vorbisEnc = audioline.get_by_name('audioVorbisenc')
- vorbisEnc.merge_tags(taglist, gst.TAG_MERGE_REPLACE_ALL)
-
- audioFilesink = audioline.get_by_name('audioFilesink')
- audioOggFilepath = os.path.join(Instance.instancePath, "output.ogg")
- audioFilesink.set_property("location", audioOggFilepath )
-
- audioBus = audioline.get_bus()
- audioBus.add_signal_watch()
- self.AUDIO_TRANSCODE_ID = audioBus.connect('message', self._onMuxedAudioMessageCb, audioline)
- self.TRANSCODE_ID = gobject.timeout_add(self.TRANSCODE_UPDATE_INTERVAL, self._transcodeUpdateCb, audioline)
- gobject.idle_add( self.idlePlayElement, audioline )
- else:
- self.record = False
- self.audio = False
- self.ca.m.cannotSaveVideo()
-
-
- def getTags( self, type ):
- tl = gst.TagList()
- tl[gst.TAG_ARTIST] = str(Instance.nickName)
- tl[gst.TAG_COMMENT] = "olpc"
- #this is unfortunately, unreliable
- #record.Record.log.debug("self.ca.metadata['title']->" + str(self.ca.metadata['title']) )
- tl[gst.TAG_ALBUM] = "olpc" #self.ca.metadata['title']
- tl[gst.TAG_DATE] = utils.getDateString(int(time.time()))
- stringType = Constants.mediaTypes[type][Constants.keyIstr]
- tl[gst.TAG_TITLE] = Constants.istrBy % {"1":stringType, "2":str(Instance.nickName)}
- return tl
-
- def blockedCb(self, x, y, z):
- pass
-
- def _takePhoto(self):
- if self.picExposureOpen:
- return
-
- self.picExposureOpen = True
- pad = self.photobin.get_static_pad("sink")
- pad.set_blocked_async(True, self.blockedCb, None)
- self.pipeline.add(self.photobin)
- self.photobin.set_state(gst.STATE_PLAYING)
- self.pipeline.get_by_name("tee").link(self.photobin)
- pad.set_blocked_async(False, self.blockedCb, None)
-
- def takePhoto(self):
- self.photoMode = self.PHOTO_MODE_PHOTO
- self._takePhoto()
-
- def copyPic(self, fsink, buffer, pad, user_data=None):
- if not self.picExposureOpen:
- return
-
- pad = self.photobin.get_static_pad("sink")
- pad.set_blocked_async(True, self.blockedCb, None)
- self.pipeline.get_by_name("tee").unlink(self.photobin)
- self.pipeline.remove(self.photobin)
- pad.set_blocked_async(False, self.blockedCb, None)
-
- self.picExposureOpen = False
- pic = gtk.gdk.pixbuf_loader_new_with_mime_type("image/jpeg")
- pic.write( buffer )
- pic.close()
- pixBuf = pic.get_pixbuf()
- del pic
-
- self.savePhoto( pixBuf )
-
-
- def savePhoto(self, pixbuf):
- if self.photoMode == self.PHOTO_MODE_AUDIO:
- self.audioPixbuf = pixbuf
- else:
- self.ca.m.savePhoto(pixbuf)
-
-
- def startRecordingVideo(self):
- self.record = True
- self.audio = True
-
- # It would be nicer to connect the video/audio-recording elements
- # without stopping the pipeline. However, that seems to cause a
- # very long delay at the start of the video recording where the first
- # frame is 'frozen' for several seconds. MikeS from #gstreamer
- # suggested that the videorate element might not be receiving a
- # "new segment" signal soon enough.
- #
- # Stopping the pipeline while we reshuffle neatly works around this
- # with minimal user experience impact.
- self.pipeline.set_state(gst.STATE_NULL)
- self.pipeline.add(self.videobin)
- self.pipeline.get_by_name("tee").link(self.videobin)
- self.pipeline.add(self.audiobin)
- self.pipeline.set_state(gst.STATE_PLAYING)
-
- def startRecordingAudio(self):
- self.audioPixbuf = None
-
- self.photoMode = self.PHOTO_MODE_AUDIO
- self._takePhoto()
-
- self.record = True
- self.pipeline.add(self.audiobin)
- self.audiobin.set_state(gst.STATE_PLAYING)
-
- def stopRecordingVideo(self):
- # Similarly to as when we start recording, we also stop the pipeline
- # while we are adjusting the pipeline to stop recording. If we do
- # it on-the-fly, the following video live feed to the screen becomes
- # several seconds delayed. Weird!
- self._eos_cb = self.stopRecordingVideoEOS
- self.pipeline.get_by_name('camsrc').send_event(gst.event_new_eos())
- self.audiobin.get_by_name('absrc').send_event(gst.event_new_eos())
-
- def stopRecordingVideoEOS(self):
- self.pipeline.set_state(gst.STATE_NULL)
- self.pipeline.get_by_name("tee").unlink(self.videobin)
- self.pipeline.remove(self.videobin)
- self.pipeline.remove(self.audiobin)
- self.pipeline.set_state(gst.STATE_PLAYING)
- gobject.idle_add( self.stoppedRecordingVideo )
-
-
- def copyThumbPic(self, fsink, buffer, pad, user_data=None):
- if (self.thumbExposureOpen):
- self.thumbExposureOpen = False
- pic = gtk.gdk.pixbuf_loader_new_with_mime_type("image/jpeg")
- pic.write(buffer)
- pic.close()
- self.thumbBuf = pic.get_pixbuf()
- del pic
- self.thumbEl('thumbTee').unlink(self.thumbEl('thumbQueue'))
-
- oggFilepath = os.path.join(Instance.instancePath, "output.ogg") #ogv
- if (self.audio):
- self.ca.ui.setPostProcessPixBuf(self.thumbBuf)
-
- wavFilepath = os.path.join(Instance.instancePath, "output.wav")
- muxFilepath = os.path.join(Instance.instancePath, "mux.ogg") #ogv
-
- muxline = gst.parse_launch('filesrc location=' + str(oggFilepath) + ' name=muxVideoFilesrc ! oggdemux name=muxOggdemux ! theoradec name=muxTheoradec ! theoraenc name=muxTheoraenc ! oggmux name=muxOggmux ! filesink location=' + str(muxFilepath) + ' name=muxFilesink filesrc location=' + str(wavFilepath) + ' name=muxAudioFilesrc ! wavparse name=muxWavparse ! audioconvert name=muxAudioconvert ! vorbisenc name=muxVorbisenc ! muxOggmux.')
- taglist = self.getTags(Constants.TYPE_VIDEO)
- vorbisEnc = muxline.get_by_name('muxVorbisenc')
- vorbisEnc.merge_tags(taglist, gst.TAG_MERGE_REPLACE_ALL)
-
- muxBus = muxline.get_bus()
- muxBus.add_signal_watch()
- self.VIDEO_TRANSCODE_ID = muxBus.connect('message', self._onMuxedVideoMessageCb, muxline)
- self.muxPipes.append(muxline)
- #add a listener here to monitor % of transcoding...
- self.TRANSCODE_ID = gobject.timeout_add(self.TRANSCODE_UPDATE_INTERVAL, self._transcodeUpdateCb, muxline)
- muxline.set_state(gst.STATE_PLAYING)
- else:
- self.record = False
- self.audio = False
- self.ca.m.saveVideo(self.thumbBuf, str(oggFilepath), self.VIDEO_WIDTH_SMALL, self.VIDEO_HEIGHT_SMALL)
- self.ca.m.stoppedRecordingVideo()
-
-
- def _transcodeUpdateCb( self, pipe ):
- position, duration = self.queryPosition( pipe )
- if position != gst.CLOCK_TIME_NONE:
- value = position * 100.0 / duration
- value = value/100.0
- self.ca.ui.progressWindow.updateProgress(value, Constants.istrSaving)
- return True
-
-
- def queryPosition( self, pipe ):
- try:
- position, format = pipe.query_position(gst.FORMAT_TIME)
- except:
- position = gst.CLOCK_TIME_NONE
-
- try:
- duration, format = pipe.query_duration(gst.FORMAT_TIME)
- except:
- duration = gst.CLOCK_TIME_NONE
-
- return (position, duration)
-
-
- def _onMuxedVideoMessageCb(self, bus, message, pipe):
- t = message.type
- if (t == gst.MESSAGE_EOS):
- self.record = False
- self.audio = False
- gobject.source_remove(self.VIDEO_TRANSCODE_ID)
- self.VIDEO_TRANSCODE_ID = 0
- gobject.source_remove(self.TRANSCODE_ID)
- self.TRANSCODE_ID = 0
- pipe.set_state(gst.STATE_NULL)
- pipe.get_bus().remove_signal_watch()
- pipe.get_bus().disable_sync_message_emission()
-
- wavFilepath = os.path.join(Instance.instancePath, "output.wav")
- oggFilepath = os.path.join(Instance.instancePath, "output.ogg") #ogv
- muxFilepath = os.path.join(Instance.instancePath, "mux.ogg") #ogv
- os.remove( wavFilepath )
- os.remove( oggFilepath )
- self.ca.m.saveVideo(self.thumbBuf, str(muxFilepath), self.VIDEO_WIDTH_SMALL, self.VIDEO_HEIGHT_SMALL)
- self.ca.m.stoppedRecordingVideo()
- return False
- else:
- return True
-
-
- def _onMuxedAudioMessageCb(self, bus, message, pipe):
- t = message.type
- if (t == gst.MESSAGE_EOS):
- record.Record.log.debug("audio gst.MESSAGE_EOS")
- self.record = False
- self.audio = False
- gobject.source_remove(self.AUDIO_TRANSCODE_ID)
- self.AUDIO_TRANSCODE_ID = 0
- gobject.source_remove(self.TRANSCODE_ID)
- self.TRANSCODE_ID = 0
- pipe.set_state(gst.STATE_NULL)
- pipe.get_bus().remove_signal_watch()
- pipe.get_bus().disable_sync_message_emission()
-
- wavFilepath = os.path.join(Instance.instancePath, "output.wav")
- oggFilepath = os.path.join(Instance.instancePath, "output.ogg")
- os.remove( wavFilepath )
- self.ca.m.saveAudio(oggFilepath, self.audioPixbuf)
- return False
- else:
- return True
-
-
- def _onSyncMessageCb(self, bus, message):
- if message.structure is None:
- return
- if message.structure.get_name() == 'prepare-xwindow-id':
- self.window.set_sink(message.src)
- message.src.set_property('force-aspect-ratio', True)
-
-
- def _onMessageCb(self, bus, message):
- t = message.type
- if t == gst.MESSAGE_EOS:
- if self._eos_cb:
- cb = self._eos_cb
- self._eos_cb = None
- cb()
- elif t == gst.MESSAGE_ERROR:
- #todo: if we come out of suspend/resume with errors, then get us back up and running...
- #todo: handle "No space left on the resource.gstfilesink.c"
- #err, debug = message.parse_error()
- pass
-
- def abandonMedia(self):
- self.stop()
-
- if (self.AUDIO_TRANSCODE_ID != 0):
- gobject.source_remove(self.AUDIO_TRANSCODE_ID)
- self.AUDIO_TRANSCODE_ID = 0
- if (self.TRANSCODE_ID != 0):
- gobject.source_remove(self.TRANSCODE_ID)
- self.TRANSCODE_ID = 0
- if (self.VIDEO_TRANSCODE_ID != 0):
- gobject.source_remove(self.VIDEO_TRANSCODE_ID)
- self.VIDEO_TRANSCODE_ID = 0
-
- wavFilepath = os.path.join(Instance.instancePath, "output.wav")
- if (os.path.exists(wavFilepath)):
- os.remove(wavFilepath)
- oggFilepath = os.path.join(Instance.instancePath, "output.ogg") #ogv
- if (os.path.exists(oggFilepath)):
- os.remove(oggFilepath)
- muxFilepath = os.path.join(Instance.instancePath, "mux.ogg") #ogv
- if (os.path.exists(muxFilepath)):
- os.remove(muxFilepath)
+ def stopRecordingAudio( self ):
+ self.audiobin.set_state(gst.STATE_NULL)
+ self.pipeline.remove(self.audiobin)
+ gobject.idle_add( self.stoppedRecordingAudio )
+
+
+ def stoppedRecordingVideo(self):
+ if ( len(self.thumbPipes) > 0 ):
+ thumbline = self.thumbPipes[len(self.thumbPipes)-1]
+ thumbline.get_by_name('thumbFakesink').disconnect(self.THUMB_HANDOFF_ID)
+
+ oggFilepath = os.path.join(Instance.instancePath, "output.ogg") #ogv
+ if (not os.path.exists(oggFilepath)):
+ self.record = False
+ self.ca.m.cannotSaveVideo()
+ self.ca.m.stoppedRecordingVideo()
+ return
+ oggSize = os.path.getsize(oggFilepath)
+ if (oggSize <= 0):
+ self.record = False
+ self.ca.m.cannotSaveVideo()
+ self.ca.m.stoppedRecordingVideo()
+ return
+
+ line = 'filesrc location=' + str(oggFilepath) + ' name=thumbFilesrc ! oggdemux name=thumbOggdemux ! theoradec name=thumbTheoradec ! tee name=thumbTee ! queue name=thumbQueue ! ffmpegcolorspace name=thumbFfmpegcolorspace ! jpegenc name=thumbJPegenc ! fakesink name=thumbFakesink'
+ thumbline = gst.parse_launch(line)
+ thumbQueue = thumbline.get_by_name('thumbQueue')
+ thumbQueue.set_property("leaky", True)
+ thumbQueue.set_property("max-size-buffers", 1)
+ thumbTee = thumbline.get_by_name('thumbTee')
+ thumbFakesink = thumbline.get_by_name('thumbFakesink')
+ self.THUMB_HANDOFF_ID = thumbFakesink.connect("handoff", self.copyThumbPic)
+ thumbFakesink.set_property("signal-handoffs", True)
+ self.thumbPipes.append(thumbline)
+ self.thumbExposureOpen = True
+ gobject.idle_add( self.idlePlayElement, thumbline )
+
+
+ def stoppedRecordingAudio( self ):
+ record.Record.log.debug("stoppedRecordingAudio")
+ if (self.audioPixbuf != None):
+ audioFilepath = os.path.join(Instance.instancePath, "output.wav")#self.el("audioFilesink").get_property("location")
+ if (not os.path.exists(audioFilepath)):
+ self.record = False
+ self.audio = False
+ self.ca.m.cannotSaveVideo()
+ return
+ wavSize = os.path.getsize(audioFilepath)
+ if (wavSize <= 0):
+ self.record = False
+ self.ca.m.cannotSaveVideo()
+ return
+
+ self.ca.ui.setPostProcessPixBuf(self.audioPixbuf)
+
+ line = 'filesrc location=' + str(audioFilepath) + ' name=audioFilesrc ! wavparse name=audioWavparse ! audioconvert name=audioAudioconvert ! vorbisenc name=audioVorbisenc ! oggmux name=audioOggmux ! filesink name=audioFilesink'
+ audioline = gst.parse_launch(line)
+
+ taglist = self.getTags(Constants.TYPE_AUDIO)
+ base64AudioSnapshot = utils.getStringFromPixbuf(self.audioPixbuf)
+ taglist[gst.TAG_EXTENDED_COMMENT] = "coverart="+str(base64AudioSnapshot)
+ vorbisEnc = audioline.get_by_name('audioVorbisenc')
+ vorbisEnc.merge_tags(taglist, gst.TAG_MERGE_REPLACE_ALL)
+
+ audioFilesink = audioline.get_by_name('audioFilesink')
+ audioOggFilepath = os.path.join(Instance.instancePath, "output.ogg")
+ audioFilesink.set_property("location", audioOggFilepath )
+
+ audioBus = audioline.get_bus()
+ audioBus.add_signal_watch()
+ self.AUDIO_TRANSCODE_ID = audioBus.connect('message', self._onMuxedAudioMessageCb, audioline)
+ self.TRANSCODE_ID = gobject.timeout_add(self.TRANSCODE_UPDATE_INTERVAL, self._transcodeUpdateCb, audioline)
+ gobject.idle_add( self.idlePlayElement, audioline )
+ else:
+ self.record = False
+ self.audio = False
+ self.ca.m.cannotSaveVideo()
+
+
+ def getTags( self, type ):
+ tl = gst.TagList()
+ tl[gst.TAG_ARTIST] = str(Instance.nickName)
+ tl[gst.TAG_COMMENT] = "olpc"
+ #this is unfortunately, unreliable
+ #record.Record.log.debug("self.ca.metadata['title']->" + str(self.ca.metadata['title']) )
+ tl[gst.TAG_ALBUM] = "olpc" #self.ca.metadata['title']
+ tl[gst.TAG_DATE] = utils.getDateString(int(time.time()))
+ stringType = Constants.mediaTypes[type][Constants.keyIstr]
+ tl[gst.TAG_TITLE] = Constants.istrBy % {"1":stringType, "2":str(Instance.nickName)}
+ return tl
+
+ def blockedCb(self, x, y, z):
+ pass
+
+ def _takePhoto(self):
+ if self.picExposureOpen:
+ return
+
+ self.picExposureOpen = True
+ pad = self.photobin.get_static_pad("sink")
+ pad.set_blocked_async(True, self.blockedCb, None)
+ self.pipeline.add(self.photobin)
+ self.photobin.set_state(gst.STATE_PLAYING)
+ self.pipeline.get_by_name("tee").link(self.photobin)
+ pad.set_blocked_async(False, self.blockedCb, None)
+
+ def takePhoto(self):
+ self.photoMode = self.PHOTO_MODE_PHOTO
+ self._takePhoto()
+
+ def copyPic(self, fsink, buffer, pad, user_data=None):
+ if not self.picExposureOpen:
+ return
+
+ pad = self.photobin.get_static_pad("sink")
+ pad.set_blocked_async(True, self.blockedCb, None)
+ self.pipeline.get_by_name("tee").unlink(self.photobin)
+ self.pipeline.remove(self.photobin)
+ pad.set_blocked_async(False, self.blockedCb, None)
+
+ self.picExposureOpen = False
+ pic = gtk.gdk.pixbuf_loader_new_with_mime_type("image/jpeg")
+ pic.write( buffer )
+ pic.close()
+ pixBuf = pic.get_pixbuf()
+ del pic
+
+ self.savePhoto( pixBuf )
+
+
+ def savePhoto(self, pixbuf):
+ if self.photoMode == self.PHOTO_MODE_AUDIO:
+ self.audioPixbuf = pixbuf
+ else:
+ self.ca.m.savePhoto(pixbuf)
+
+
+ def startRecordingVideo(self):
+ self.record = True
+ self.audio = True
+
+ # It would be nicer to connect the video/audio-recording elements
+ # without stopping the pipeline. However, that seems to cause a
+ # very long delay at the start of the video recording where the first
+ # frame is 'frozen' for several seconds. MikeS from #gstreamer
+ # suggested that the videorate element might not be receiving a
+ # "new segment" signal soon enough.
+ #
+ # Stopping the pipeline while we reshuffle neatly works around this
+ # with minimal user experience impact.
+ self.pipeline.set_state(gst.STATE_NULL)
+ self.pipeline.add(self.videobin)
+ self.pipeline.get_by_name("tee").link(self.videobin)
+ self.pipeline.add(self.audiobin)
+ self.pipeline.set_state(gst.STATE_PLAYING)
+
+ def startRecordingAudio(self):
+ self.audioPixbuf = None
+
+ self.photoMode = self.PHOTO_MODE_AUDIO
+ self._takePhoto()
+
+ self.record = True
+ self.pipeline.add(self.audiobin)
+ self.audiobin.set_state(gst.STATE_PLAYING)
+
+ def stopRecordingVideo(self):
+ # Similarly to as when we start recording, we also stop the pipeline
+ # while we are adjusting the pipeline to stop recording. If we do
+ # it on-the-fly, the following video live feed to the screen becomes
+ # several seconds delayed. Weird!
+ self._eos_cb = self.stopRecordingVideoEOS
+ self.pipeline.get_by_name('camsrc').send_event(gst.event_new_eos())
+ self.audiobin.get_by_name('absrc').send_event(gst.event_new_eos())
+
+ def stopRecordingVideoEOS(self):
+ self.pipeline.set_state(gst.STATE_NULL)
+ self.pipeline.get_by_name("tee").unlink(self.videobin)
+ self.pipeline.remove(self.videobin)
+ self.pipeline.remove(self.audiobin)
+ self.pipeline.set_state(gst.STATE_PLAYING)
+ gobject.idle_add( self.stoppedRecordingVideo )
+
+
+ def copyThumbPic(self, fsink, buffer, pad, user_data=None):
+ if (self.thumbExposureOpen):
+ self.thumbExposureOpen = False
+ pic = gtk.gdk.pixbuf_loader_new_with_mime_type("image/jpeg")
+ pic.write(buffer)
+ pic.close()
+ self.thumbBuf = pic.get_pixbuf()
+ del pic
+ self.thumbEl('thumbTee').unlink(self.thumbEl('thumbQueue'))
+
+ oggFilepath = os.path.join(Instance.instancePath, "output.ogg") #ogv
+ if (self.audio):
+ self.ca.ui.setPostProcessPixBuf(self.thumbBuf)
+
+ wavFilepath = os.path.join(Instance.instancePath, "output.wav")
+ muxFilepath = os.path.join(Instance.instancePath, "mux.ogg") #ogv
+
+ muxline = gst.parse_launch('filesrc location=' + str(oggFilepath) + ' name=muxVideoFilesrc ! oggdemux name=muxOggdemux ! theoradec name=muxTheoradec ! theoraenc name=muxTheoraenc ! oggmux name=muxOggmux ! filesink location=' + str(muxFilepath) + ' name=muxFilesink filesrc location=' + str(wavFilepath) + ' name=muxAudioFilesrc ! wavparse name=muxWavparse ! audioconvert name=muxAudioconvert ! vorbisenc name=muxVorbisenc ! muxOggmux.')
+ taglist = self.getTags(Constants.TYPE_VIDEO)
+ vorbisEnc = muxline.get_by_name('muxVorbisenc')
+ vorbisEnc.merge_tags(taglist, gst.TAG_MERGE_REPLACE_ALL)
+
+ muxBus = muxline.get_bus()
+ muxBus.add_signal_watch()
+ self.VIDEO_TRANSCODE_ID = muxBus.connect('message', self._onMuxedVideoMessageCb, muxline)
+ self.muxPipes.append(muxline)
+ #add a listener here to monitor % of transcoding...
+ self.TRANSCODE_ID = gobject.timeout_add(self.TRANSCODE_UPDATE_INTERVAL, self._transcodeUpdateCb, muxline)
+ muxline.set_state(gst.STATE_PLAYING)
+ else:
+ self.record = False
+ self.audio = False
+ self.ca.m.saveVideo(self.thumbBuf, str(oggFilepath), self.VIDEO_WIDTH_SMALL, self.VIDEO_HEIGHT_SMALL)
+ self.ca.m.stoppedRecordingVideo()
+
+
+ def _transcodeUpdateCb( self, pipe ):
+ position, duration = self.queryPosition( pipe )
+ if position != gst.CLOCK_TIME_NONE:
+ value = position * 100.0 / duration
+ value = value/100.0
+ self.ca.ui.progressWindow.updateProgress(value, Constants.istrSaving)
+ return True
+
+
+ def queryPosition( self, pipe ):
+ try:
+ position, format = pipe.query_position(gst.FORMAT_TIME)
+ except:
+ position = gst.CLOCK_TIME_NONE
+
+ try:
+ duration, format = pipe.query_duration(gst.FORMAT_TIME)
+ except:
+ duration = gst.CLOCK_TIME_NONE
+
+ return (position, duration)
+
+
+ def _onMuxedVideoMessageCb(self, bus, message, pipe):
+ t = message.type
+ if (t == gst.MESSAGE_EOS):
+ self.record = False
+ self.audio = False
+ gobject.source_remove(self.VIDEO_TRANSCODE_ID)
+ self.VIDEO_TRANSCODE_ID = 0
+ gobject.source_remove(self.TRANSCODE_ID)
+ self.TRANSCODE_ID = 0
+ pipe.set_state(gst.STATE_NULL)
+ pipe.get_bus().remove_signal_watch()
+ pipe.get_bus().disable_sync_message_emission()
+
+ wavFilepath = os.path.join(Instance.instancePath, "output.wav")
+ oggFilepath = os.path.join(Instance.instancePath, "output.ogg") #ogv
+ muxFilepath = os.path.join(Instance.instancePath, "mux.ogg") #ogv
+ os.remove( wavFilepath )
+ os.remove( oggFilepath )
+ self.ca.m.saveVideo(self.thumbBuf, str(muxFilepath), self.VIDEO_WIDTH_SMALL, self.VIDEO_HEIGHT_SMALL)
+ self.ca.m.stoppedRecordingVideo()
+ return False
+ else:
+ return True
+
+
+ def _onMuxedAudioMessageCb(self, bus, message, pipe):
+ t = message.type
+ if (t == gst.MESSAGE_EOS):
+ record.Record.log.debug("audio gst.MESSAGE_EOS")
+ self.record = False
+ self.audio = False
+ gobject.source_remove(self.AUDIO_TRANSCODE_ID)
+ self.AUDIO_TRANSCODE_ID = 0
+ gobject.source_remove(self.TRANSCODE_ID)
+ self.TRANSCODE_ID = 0
+ pipe.set_state(gst.STATE_NULL)
+ pipe.get_bus().remove_signal_watch()
+ pipe.get_bus().disable_sync_message_emission()
+
+ wavFilepath = os.path.join(Instance.instancePath, "output.wav")
+ oggFilepath = os.path.join(Instance.instancePath, "output.ogg")
+ os.remove( wavFilepath )
+ self.ca.m.saveAudio(oggFilepath, self.audioPixbuf)
+ return False
+ else:
+ return True
+
+
+ def _onSyncMessageCb(self, bus, message):
+ if message.structure is None:
+ return
+ if message.structure.get_name() == 'prepare-xwindow-id':
+ self.window.set_sink(message.src)
+ message.src.set_property('force-aspect-ratio', True)
+
+
+ def _onMessageCb(self, bus, message):
+ t = message.type
+ if t == gst.MESSAGE_EOS:
+ if self._eos_cb:
+ cb = self._eos_cb
+ self._eos_cb = None
+ cb()
+ elif t == gst.MESSAGE_ERROR:
+ #todo: if we come out of suspend/resume with errors, then get us back up and running...
+ #todo: handle "No space left on the resource.gstfilesink.c"
+ #err, debug = message.parse_error()
+ pass
+
+ def abandonMedia(self):
+ self.stop()
+
+ if (self.AUDIO_TRANSCODE_ID != 0):
+ gobject.source_remove(self.AUDIO_TRANSCODE_ID)
+ self.AUDIO_TRANSCODE_ID = 0
+ if (self.TRANSCODE_ID != 0):
+ gobject.source_remove(self.TRANSCODE_ID)
+ self.TRANSCODE_ID = 0
+ if (self.VIDEO_TRANSCODE_ID != 0):
+ gobject.source_remove(self.VIDEO_TRANSCODE_ID)
+ self.VIDEO_TRANSCODE_ID = 0
+
+ wavFilepath = os.path.join(Instance.instancePath, "output.wav")
+ if (os.path.exists(wavFilepath)):
+ os.remove(wavFilepath)
+ oggFilepath = os.path.join(Instance.instancePath, "output.ogg") #ogv
+ if (os.path.exists(oggFilepath)):
+ os.remove(oggFilepath)
+ muxFilepath = os.path.join(Instance.instancePath, "mux.ogg") #ogv
+ if (os.path.exists(muxFilepath)):
+ os.remove(muxFilepath)
class LiveVideoWindow(gtk.Window):
- def __init__(self, bgd ):
- gtk.Window.__init__(self)
+ def __init__(self, bgd ):
+ gtk.Window.__init__(self)
- self.imagesink = None
- self.glive = None
+ self.imagesink = None
+ self.glive = None
- self.modify_bg( gtk.STATE_NORMAL, bgd )
- self.modify_bg( gtk.STATE_INSENSITIVE, bgd )
- self.unset_flags(gtk.DOUBLE_BUFFERED)
- self.set_flags(gtk.APP_PAINTABLE)
+ self.modify_bg( gtk.STATE_NORMAL, bgd )
+ self.modify_bg( gtk.STATE_INSENSITIVE, bgd )
+ self.unset_flags(gtk.DOUBLE_BUFFERED)
+ self.set_flags(gtk.APP_PAINTABLE)
- def set_glive(self, pglive):
- self.glive = pglive
- self.glive.window = self
+ def set_glive(self, pglive):
+ self.glive = pglive
+ self.glive.window = self
- def set_sink(self, sink):
- if (self.imagesink != None):
- assert self.window.xid
- self.imagesink = None
- del self.imagesink
+ def set_sink(self, sink):
+ if (self.imagesink != None):
+ assert self.window.xid
+ self.imagesink = None
+ del self.imagesink
- self.imagesink = sink
- self.imagesink.set_xwindow_id(self.window.xid)
+ self.imagesink = sink
+ self.imagesink.set_xwindow_id(self.window.xid)