Mercurial > code > home > repos > light9
changeset 534:6f1eb6437c96
vidref refactor, start to add more widgets
Ignore-this: b81bc966dffb486cb8b20f975a4b4b2a
author | drewp@bigasterisk.com |
---|---|
date | Sat, 12 Jun 2010 09:32:09 +0000 |
parents | 846bc4712cf7 |
children | 481aa9a970b3 |
files | bin/vidref light9/vidref/main.py light9/vidref/vidref.glade |
diffstat | 3 files changed, 185 insertions(+), 59 deletions(-) [+] |
line wrap: on
line diff
--- a/bin/vidref Sat Jun 12 08:03:00 2010 +0000 +++ b/bin/vidref Sat Jun 12 09:32:09 2010 +0000 @@ -2,11 +2,17 @@ import gobject gobject.threads_init() import gtk -import sys +import sys, logging sys.path.append(".") from light9.vidref.main import Main +logging.basicConfig() +log = logging.getLogger() +log.setLevel(logging.DEBUG) +logging.getLogger("restkit.client").setLevel(logging.WARN) + + start=Main() gtk.main()
--- a/light9/vidref/main.py Sat Jun 12 08:03:00 2010 +0000 +++ b/light9/vidref/main.py Sat Jun 12 09:32:09 2010 +0000 @@ -18,34 +18,84 @@ from threading import Thread from Queue import Queue from light9 import networking -logging.basicConfig(level=logging.WARN) -logging.getLogger().setLevel(logging.WARN) -#restkit.set_logging(logging.WARN) -existingDir = "/tmp/vidref/play-light9.bigasterisk.com_show_dance2010_song7-1276065914" +log = logging.getLogger() + +existingDir = "/tmp/vidref/play-_my_proj_light9_show_dance2010_music_07-jacksonmix-complete.wav-1276331148" existingFrames = sorted([Decimal(f.split('.jpg')[0]) for f in os.listdir(existingDir)]) otherPic = None +class MusicTime(object): + """ + fetch times from ascoltami in a background thread; return times + upon request, adjusted to be more precise with the system clock + """ + def __init__(self, period=.2): + """period is the seconds between http time requests.""" + self.period = period + self.musicResource = restkit.Resource(networking.musicUrl()) + t = Thread(target=self._timeUpdate) + t.setDaemon(True) + t.start() + + def getLatest(self): + """ + dict with 't' and 'song', etc. + """ + pos = self.position.copy() + if pos['playing']: + pos['t'] = pos['t'] + (time.time() - self.positionFetchTime) + return pos + + def _timeUpdate(self): + while True: + position = jsonlib.loads(self.musicResource.get("time").body, + use_float=True) + self.positionFetchTime = time.time() + self.position = position + time.sleep(self.period) + +class ReplayFrames(object): + """ + supplies all the frames from disk for the replay videos + """ + def update(self, position): + inPic = self.findClosestFrame(position['t']+.2) + with gtk.gdk.lock: + otherPic.set_from_file(inPic) + if 0: + # force redraw of that widget + otherPic.queue_draw_area(0,0,320,240) + otherPic.get_window().process_updates(True) + + def findClosestFrame(self, t): + i = bisect_left(existingFrames, Decimal(str(t))) + if i >= len(existingFrames): + i = len(existingFrames) - 1 + return os.path.join(existingDir, "%08.03f.jpg" % existingFrames[i]) + + class VideoRecordSink(gst.Element): _sinkpadtemplate = gst.PadTemplate ("sinkpadtemplate", gst.PAD_SINK, gst.PAD_ALWAYS, gst.caps_new_any()) - def __init__(self): + def __init__(self, replay): gst.Element.__init__(self) + self.replay = replay self.sinkpad = gst.Pad(self._sinkpadtemplate, "sink") self.add_pad(self.sinkpad) self.sinkpad.set_chain_function(self.chainfunc) self.lastTime = 0 - self.musicResource = restkit.Resource(networking.musicUrl(api='rest')) + self.musicTime = MusicTime() self.imagesToSave = Queue() self.startBackgroundImageSaver(self.imagesToSave) - + def startBackgroundImageSaver(self, imagesToSave): """do image saves in another thread to not block gst""" def imageSaver(): @@ -57,18 +107,19 @@ t = Thread(target=imageSaver) t.setDaemon(True) t.start() - + def chainfunc(self, pad, buffer): + return gst.FLOW_OK global nextImageCb self.info("%s timestamp(buffer):%d" % (pad, buffer.timestamp)) + position = self.musicTime.getLatest() + + if not position['song']: + print "no song" + return gst.FLOW_OK + try: - position = jsonlib.loads(self.musicResource.get("position").body, - use_float=True) - if not position['song']: - return gst.FLOW_OK - - cap = buffer.caps[0] img = Image.fromstring('RGB', (cap['width'], cap['height']), buffer.data) @@ -77,10 +128,10 @@ traceback.print_exc() try: - self.updateOtherFrames(position) + self.replay.update(position) except: traceback.print_exc() - + return gst.FLOW_OK def saveImg(self, position, img, bufferTimestamp): @@ -99,28 +150,12 @@ img.save(outFilename) now = time.time() - print "wrote %s delay of %.2fms %s" % (outFilename, - (now - self.lastTime) * 1000, - bufferTimestamp) + log.info("wrote %s delay of %.2fms %s", + outFilename, + (now - self.lastTime) * 1000, + bufferTimestamp) self.lastTime = now - def updateOtherFrames(self, position): - inPic = self.findClosestFrame(position['t']+.2) - #print "load", inPic - with gtk.gdk.lock: - otherPic.set_from_file(inPic) - if 0: - otherPic.queue_draw_area(0,0,320,240) - otherPic.get_window().process_updates(True) - - def findClosestFrame(self, t): - i = bisect_left(existingFrames, Decimal(str(t))) - if i >= len(existingFrames): - i = len(existingFrames) - 1 - return os.path.join(existingDir, "%08.03f.jpg" % existingFrames[i]) - - - gobject.type_register(VideoRecordSink) class Main(object): @@ -131,9 +166,7 @@ mainwin = wtree.get_object("MainWindow") otherPic = wtree.get_object("liveVideo") mainwin.connect("destroy", gtk.main_quit) - wtree.connect_signals({ - "foo" : self.OnPlay, - }) + wtree.connect_signals(self) # other sources: videotestsrc, v4l2src device=/dev/video0 ## if 0: @@ -142,43 +175,49 @@ ## source = makeElem("v4l2src", "vsource") ## source.set_property("device", "/dev/video0") - dv = "dv1394src ! dvdemux ! dvdec ! videoscale ! video/x-raw-yuv,width=320,height=240;video/x-raw-rgb,width=320,height=240 ! queue name=vid" - v4l = "v4l2src device=/dev/video0 ! hqdn3d name=vid" + dv = "dv1394src name=src1 ! dvdemux ! dvdec" + v4l = "v4l2src device=/dev/video0 ! hqdn3d" - pipeline = gst.parse_launch(dv) + cam = (dv + " ! " + "videorate ! video/x-raw-yuv,framerate=15/1 ! " + "videoscale ! video/x-raw-yuv,width=320,height=240;video/x-raw-rgb,width=320,height=240 ! " + "queue name=vid") + + self.pipeline = gst.parse_launch(cam) def makeElem(t, n=None): e = gst.element_factory_make(t, n) - pipeline.add(e) + self.pipeline.add(e) return e sink = makeElem("xvimagesink") - recSink = VideoRecordSink() - pipeline.add(recSink) + replay = ReplayFrames() + recSink = VideoRecordSink(replay) + self.pipeline.add(recSink) tee = makeElem("tee") caps = makeElem("capsfilter") caps.set_property('caps', gst.caps_from_string('video/x-raw-rgb')) - gst.element_link_many(pipeline.get_by_name("vid"), tee, sink) + gst.element_link_many(self.pipeline.get_by_name("vid"), tee, sink) gst.element_link_many(tee, makeElem("ffmpegcolorspace"), caps, recSink) mainwin.show_all() sink.set_xwindow_id(wtree.get_object("vid3").window.xid) - pipeline.set_state(gst.STATE_PLAYING) - - def OnPlay(self, widget): - print "play" - # Tell the video sink to display the output in our DrawingArea - self.sinkx.set_xwindow_id(self.da.window.xid) self.pipeline.set_state(gst.STATE_PLAYING) - def OnStop(self, widget): - print "stop" - self.pipeline.set_state(gst.STATE_READY) - - def OnQuit(self, widget): - gtk.main_quit() + def on_liveVideoEnabled_toggled(self, widget): + if widget.get_active(): + self.pipeline.set_state(gst.STATE_PLAYING) + # this is an attempt to bring the dv1394 source back, but + # it doesn't work right. + self.pipeline.get_by_name("src1").seek_simple( + gst.FORMAT_TIME, gst.SEEK_FLAG_FLUSH, 0 * gst.SECOND) + else: + self.pipeline.set_state(gst.STATE_READY) + + def on_liveFrameRate_value_changed(self, widget): + print widget.get_value()
--- a/light9/vidref/vidref.glade Sat Jun 12 08:03:00 2010 +0000 +++ b/light9/vidref/vidref.glade Sat Jun 12 09:32:09 2010 +0000 @@ -77,6 +77,87 @@ <property name="y">23</property> </packing> </child> + <child> + <object class="GtkToggleButton" id="liveVideoEnabled"> + <property name="label" translatable="yes">Enabled</property> + <property name="width_request">110</property> + <property name="height_request">36</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="active">True</property> + <signal name="toggled" handler="on_liveVideoEnabled_toggled"/> + </object> + <packing> + <property name="x">20</property> + <property name="y">307</property> + </packing> + </child> + <child> + <object class="GtkSpinButton" id="liveFrameRate"> + <property name="width_request">52</property> + <property name="height_request">25</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="invisible_char">●</property> + <property name="numeric">True</property> + </object> + <packing> + <property name="x">96</property> + <property name="y">360</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label1"> + <property name="width_request">75</property> + <property name="height_request">20</property> + <property name="visible">True</property> + <property name="label" translatable="yes">Frame rate</property> + </object> + <packing> + <property name="x">16</property> + <property name="y">363</property> + </packing> + </child> + <child> + <object class="GtkComboBox" id="videoSource"> + <property name="width_request">100</property> + <property name="visible">True</property> + </object> + <packing> + <property name="x">114</property> + <property name="y">405</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label4"> + <property name="width_request">85</property> + <property name="height_request">20</property> + <property name="visible">True</property> + <property name="label" translatable="yes">Input source</property> + </object> + <packing> + <property name="x">20</property> + <property name="y">407</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow" id="scrolledwindow1"> + <property name="width_request">336</property> + <property name="height_request">310</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">automatic</property> + <property name="vscrollbar_policy">automatic</property> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="x">383</property> + <property name="y">323</property> + </packing> + </child> </object> </child> </object>