diff --git a/light9/vidref/main.py b/light9/vidref/main.py --- a/light9/vidref/main.py +++ b/light9/vidref/main.py @@ -10,23 +10,16 @@ import pygst pygst.require("0.10") import gst, gobject, time, jsonlib, restkit, logging, os, traceback from decimal import Decimal -from bisect import bisect_left -import pygtk import gtk from twisted.python.util import sibpath import Image from threading import Thread from Queue import Queue from light9 import networking +from light9.vidref.replay import ReplayViews 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 @@ -44,6 +37,8 @@ class MusicTime(object): """ dict with 't' and 'song', etc. """ + if not hasattr(self, 'position'): + return {'t' : 0, 'song' : None} pos = self.position.copy() if pos['playing']: pos['t'] = pos['t'] + (time.time() - self.positionFetchTime) @@ -56,26 +51,6 @@ class MusicTime(object): 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", @@ -109,7 +84,6 @@ class VideoRecordSink(gst.Element): t.start() def chainfunc(self, pad, buffer): - return gst.FLOW_OK global nextImageCb self.info("%s timestamp(buffer):%d" % (pad, buffer.timestamp)) @@ -160,25 +134,31 @@ gobject.type_register(VideoRecordSink) class Main(object): def __init__(self): - global otherPic wtree = gtk.Builder() wtree.add_from_file(sibpath(__file__, "vidref.glade")) mainwin = wtree.get_object("MainWindow") - otherPic = wtree.get_object("liveVideo") mainwin.connect("destroy", gtk.main_quit) wtree.connect_signals(self) - # other sources: videotestsrc, v4l2src device=/dev/video0 - ## if 0: - ## source = makeElem("videotestsrc", "video") - ## else: - ## source = makeElem("v4l2src", "vsource") - ## source.set_property("device", "/dev/video0") + self.replayViews = ReplayViews(wtree.get_object("image1"))#"replayScroll")) + + mainwin.show_all() + self.liveVideoXid = wtree.get_object("vid3").window.xid + + self.setInput('dv') + + def getInputs(self): + return ['auto', 'dv', 'video0'] - dv = "dv1394src name=src1 ! dvdemux ! dvdec" - v4l = "v4l2src device=/dev/video0 ! hqdn3d" + def setInput(self, name): + sourcePipe = { + "auto": "autovideosrc name=src1", + "testpattern" : "videotestsrc name=src1", + "dv": "dv1394src name=src1 ! dvdemux ! dvdec", + "v4l": "v4l2src device=/dev/video0 name=src1 ! hqdn3d" , + }[name] - cam = (dv + " ! " + cam = (sourcePipe + " ! " "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") @@ -191,8 +171,7 @@ class Main(object): return e sink = makeElem("xvimagesink") - replay = ReplayFrames() - recSink = VideoRecordSink(replay) + recSink = VideoRecordSink(self.replayViews) self.pipeline.add(recSink) tee = makeElem("tee") @@ -202,12 +181,8 @@ class Main(object): 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) - - self.pipeline.set_state(gst.STATE_PLAYING) + sink.set_xwindow_id(self.liveVideoXid) + self.pipeline.set_state(gst.STATE_PLAYING) def on_liveVideoEnabled_toggled(self, widget): if widget.get_active(): diff --git a/light9/vidref/replay.py b/light9/vidref/replay.py new file mode 100644 --- /dev/null +++ b/light9/vidref/replay.py @@ -0,0 +1,62 @@ +import os, gtk +from bisect import bisect_left +from decimal import Decimal + +existingDir = "/tmp/vidref/play-_my_proj_light9_show_dance2010_music_01-chorusmix.wav-1276415052" +existingFrames = sorted([Decimal(f.split('.jpg')[0]) + for f in os.listdir(existingDir)]) + + +class ReplayViews(object): + """ + the whole list of replay windows. parent is the scrolling area for + these windows to be added + """ + def __init__(self, parent): + self.out = ReplayView(parent, Replay(existingDir)) + return + for x in range(1000): + lab = gtk.Label() + lab.set_text("hello") + parent.add_with_viewport(lab) + + def update(self, position): + """ + freshen all replay windows. We get called this about every + time there's a new live video frame. + + may be responsible for making new children if we change song + """ + self.out.updatePic(position) + +class Replay(object): + """ + model for one of the replay widgets + """ + def __init__(self, sourceDir): + self.sourceDir = sourceDir + + 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 ReplayView(object): + """ + one of the replay widgets + """ + def __init__(self, parent, replay): + self.replay = replay +# self.loadWindwos + self.picWidget = parent + + def updatePic(self, position): + inPic = self.replay.findClosestFrame(position['t']+.25) + with gtk.gdk.lock: + self.picWidget.set_from_file(inPic) + if 0: + # force redraw of that widget + self.picWidget.queue_draw_area(0,0,320,240) + self.picWidget.get_window().process_updates(True) + diff --git a/light9/vidref/vidref.glade b/light9/vidref/vidref.glade --- a/light9/vidref/vidref.glade +++ b/light9/vidref/vidref.glade @@ -6,60 +6,286 @@ 500 500 - + True - - 336 - 277 + True - 0 - out - + + 336 + 277 + True + 0 + out + + + True + 0 + none + 1.3300000429153442 + + + 320 + 240 + True + + + + + + + True + <b>Live view</b> + True + + + + + False + 0 + + + + True - - 320 - 240 + + Enabled + 110 + 36 True + True + True + True + - 7 - 8 + False + 0 + + + + + True + + + 75 + 20 + True + Frame rate + + + 0 + + + + + 52 + 25 + True + True + + True + + + 1 + + + + + False + 1 + + + + + True + + + 85 + 20 + True + Input source + + + 0 + + + + + 100 + True + + + 1 + + + + + False + 2 - - - - True - <b>Live view</b> - True - + + False + 1 + - 15 - 10 + False + 0 - + 336 259 True 0 out - + + 571 + 367 True - 12 + True + automatic + automatic + out - - 320 - 240 + True + queue + + + True + + + 273 + True + + + True + + + 320 + 240 + True + 0 + out + 1.3300000429153442 + + + 320 + 240 + True + gtk-missing-image + + + + + 0 + + + + + True + + + True + + + True + Started: + + + False + False + 0 + + + + + True + True + False + + 12 + Sat 14:22:25 + + + False + False + 1 + + + + + False + 0 + + + + + Enabled + True + True + True + + + False + 1 + + + + + Delete + True + True + True + image2 + + + False + 2 + + + + + Pin to top + True + True + False + True + + + False + 3 + + + + + 1 + + + + + + + 0 + + + + + + + + + + @@ -73,92 +299,14 @@ - 373 - 23 - - - - - Enabled - 110 - 36 - True - True - True - True - - - - 20 - 307 - - - - - 52 - 25 - True - True - - True - - - 96 - 360 - - - - - 75 - 20 - True - Frame rate - - - 16 - 363 - - - - - 100 - True - - - 114 - 405 - - - - - 85 - 20 - True - Input source - - - 20 - 407 - - - - - 336 - 310 - True - True - automatic - automatic - - - - - - 383 - 323 + 1 + + True + gtk-delete +