diff --git a/bin/vidref b/bin/vidref
--- a/bin/vidref
+++ b/bin/vidref
@@ -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()
diff --git a/light9/vidref/main.py b/light9/vidref/main.py
--- a/light9/vidref/main.py
+++ b/light9/vidref/main.py
@@ -18,34 +18,84 @@ import Image
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 @@ class VideoRecordSink(gst.Element):
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 @@ class VideoRecordSink(gst.Element):
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 @@ class VideoRecordSink(gst.Element):
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 @@ class Main(object):
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 @@ class Main(object):
## 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()
diff --git a/light9/vidref/vidref.glade b/light9/vidref/vidref.glade
--- a/light9/vidref/vidref.glade
+++ b/light9/vidref/vidref.glade
@@ -77,6 +77,87 @@
23
+
+
+
+ 20
+ 307
+
+
+
+
+
+ 96
+ 360
+
+
+
+
+
+ 16
+ 363
+
+
+
+
+
+ 114
+ 405
+
+
+
+
+
+ 20
+ 407
+
+
+
+
+
+ 383
+ 323
+
+