Adapted to new video library -- different capture interface, no bugs.
Also use locks and Queues for communication with other threads.
This commit is contained in:
parent
da3eee99e8
commit
62f6bc8e55
|
@ -12,9 +12,8 @@
|
||||||
# Options:
|
# Options:
|
||||||
#
|
#
|
||||||
# -a : record audio as well
|
# -a : record audio as well
|
||||||
# -q queuesize : set the capture queue size (default and max 16)
|
# -q queuesize : set the capture queue size (default 2)
|
||||||
# -r n/d : capture n out of every d frames (default 1/1)
|
# -r rate : capture 1 out of every n frames (default and min 2)
|
||||||
# XXX doesn't work yet
|
|
||||||
#
|
#
|
||||||
# moviefile : here goes the movie data (default film.video);
|
# moviefile : here goes the movie data (default film.video);
|
||||||
# the format is documented in cmif-film.ms
|
# the format is documented in cmif-film.ms
|
||||||
|
@ -28,19 +27,13 @@
|
||||||
#
|
#
|
||||||
# Start the application. Resize the window to the desired movie size.
|
# Start the application. Resize the window to the desired movie size.
|
||||||
# Press the left mouse button to start recording, release it to end
|
# Press the left mouse button to start recording, release it to end
|
||||||
# recording. XXX For now, you must restart the program to record again.
|
# recording. You can record as many times as you wish, but each time
|
||||||
# You can't resize the window once you have made a recording.
|
# you overwrite the output file(s), so only the last recording is
|
||||||
|
# kept.
|
||||||
#
|
#
|
||||||
# Press ESC or select the window manager Quit or Close window option
|
# Press ESC or select the window manager Quit or Close window option
|
||||||
# to quit. (You can do this without recording -- then the output
|
# to quit. If you quit before recording anything, the output file(s)
|
||||||
# files are untouched.) XXX Don't press ESC before the program has
|
# are not touched.
|
||||||
# finished writing the output file -- it prints "Done writing" when it
|
|
||||||
# is done.
|
|
||||||
|
|
||||||
|
|
||||||
# XXX To do:
|
|
||||||
#
|
|
||||||
# add audio
|
|
||||||
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
@ -58,22 +51,22 @@ import string
|
||||||
# Main program
|
# Main program
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
QSIZE = 16
|
format = SV.RGB8_FRAMES
|
||||||
TIME = 5
|
qsize = 2
|
||||||
audio = 0
|
audio = 0
|
||||||
num, den = 1, 1
|
rate = 2
|
||||||
|
|
||||||
opts, args = getopt.getopt(sys.argv[1:], 'aq:r:t:')
|
opts, args = getopt.getopt(sys.argv[1:], 'aq:r:')
|
||||||
for opt, arg in opts:
|
for opt, arg in opts:
|
||||||
if opt == '-a':
|
if opt == '-a':
|
||||||
audio = 1
|
audio = 1
|
||||||
elif opt == '-q':
|
elif opt == '-q':
|
||||||
QSIZE = string.atoi(arg)
|
qsize = string.atoi(arg)
|
||||||
elif opt == '-r':
|
elif opt == '-r':
|
||||||
[nstr, dstr] = string.splitfields(arg, '/')
|
rate = string.atoi(arg)
|
||||||
num, den = string.atoi(nstr), string.atoi(dstr)
|
if rate < 2:
|
||||||
elif opt == '-t':
|
sys.stderr.write('-r rate must be >= 2\n')
|
||||||
TIME = string.atoi(arg)
|
sys.exit(2)
|
||||||
|
|
||||||
if args[2:]:
|
if args[2:]:
|
||||||
sys.stderr.write('usage: Vrec [options] [file [audiofile]]\n')
|
sys.stderr.write('usage: Vrec [options] [file [audiofile]]\n')
|
||||||
|
@ -98,6 +91,8 @@ def main():
|
||||||
|
|
||||||
gl.foreground()
|
gl.foreground()
|
||||||
|
|
||||||
|
# XXX should remove PAL dependencies
|
||||||
|
|
||||||
x, y = SV.PAL_XMAX / 4, SV.PAL_YMAX / 4
|
x, y = SV.PAL_XMAX / 4, SV.PAL_YMAX / 4
|
||||||
print x, 'x', y
|
print x, 'x', y
|
||||||
|
|
||||||
|
@ -110,21 +105,9 @@ def main():
|
||||||
print x, 'x', y
|
print x, 'x', y
|
||||||
|
|
||||||
v = sv.OpenVideo()
|
v = sv.OpenVideo()
|
||||||
v.BindGLWindow(win, SV.IN_REPLACE)
|
|
||||||
v.SetSize(x, y)
|
v.SetSize(x, y)
|
||||||
v.BindGLWindow(win, SV.IN_REPLACE)
|
v.BindGLWindow(win, SV.IN_REPLACE)
|
||||||
|
|
||||||
v.SetCaptureFormat(SV.RGB_FRAMES)
|
|
||||||
v.SetCaptureMode(SV.BLOCKING_CAPTURE)
|
|
||||||
v.SetQueueSize(QSIZE)
|
|
||||||
|
|
||||||
v.InitCapture()
|
|
||||||
if v.GetQueueSize() != QSIZE:
|
|
||||||
QSIZE = v.GetQueueSize()
|
|
||||||
print 'Warning: QSIZE reduced to', QSIZE
|
|
||||||
|
|
||||||
### v.SetSamplingRate(num, den) # XXX dumps core
|
|
||||||
|
|
||||||
gl.qdevice(DEVICE.LEFTMOUSE)
|
gl.qdevice(DEVICE.LEFTMOUSE)
|
||||||
gl.qdevice(DEVICE.WINQUIT)
|
gl.qdevice(DEVICE.WINQUIT)
|
||||||
gl.qdevice(DEVICE.WINSHUT)
|
gl.qdevice(DEVICE.WINSHUT)
|
||||||
|
@ -132,35 +115,20 @@ def main():
|
||||||
|
|
||||||
print 'Press left mouse to start recording, release it to stop'
|
print 'Press left mouse to start recording, release it to stop'
|
||||||
|
|
||||||
recorded = 0
|
|
||||||
|
|
||||||
while 1:
|
while 1:
|
||||||
dev, val = gl.qread()
|
dev, val = gl.qread()
|
||||||
if dev == DEVICE.LEFTMOUSE:
|
if dev == DEVICE.LEFTMOUSE:
|
||||||
if val == 1:
|
if val == 1:
|
||||||
if recorded:
|
info = format, x, y, qsize, rate
|
||||||
# XXX This would dump core
|
record(v, info, filename, audiofilename)
|
||||||
gl.ringbell()
|
|
||||||
continue
|
|
||||||
# Fix the window's size now
|
|
||||||
gl.prefsize(x, y)
|
|
||||||
gl.winconstraints()
|
|
||||||
record(v, filename, audiofilename)
|
|
||||||
recorded = 1
|
|
||||||
print 'Wait until "Done writing" is printed!'
|
|
||||||
elif dev == DEVICE.REDRAW:
|
elif dev == DEVICE.REDRAW:
|
||||||
# Window resize (or move)
|
# Window resize (or move)
|
||||||
if not recorded:
|
|
||||||
x, y = gl.getsize()
|
x, y = gl.getsize()
|
||||||
print x, 'x', y
|
print x, 'x', y
|
||||||
v.SetSize(x, y)
|
v.SetSize(x, y)
|
||||||
v.BindGLWindow(win, SV.IN_REPLACE)
|
v.BindGLWindow(win, SV.IN_REPLACE)
|
||||||
elif dev in (DEVICE.ESCKEY, DEVICE.WINQUIT, DEVICE.WINSHUT):
|
elif dev in (DEVICE.ESCKEY, DEVICE.WINQUIT, DEVICE.WINSHUT):
|
||||||
# Quit
|
# Quit
|
||||||
if not recorded:
|
|
||||||
# XXX Avoid core dump in EndCapture
|
|
||||||
posix._exit(0)
|
|
||||||
v.EndCapture()
|
|
||||||
v.CloseVideo()
|
v.CloseVideo()
|
||||||
gl.winclose(win)
|
gl.winclose(win)
|
||||||
break
|
break
|
||||||
|
@ -169,64 +137,78 @@ def main():
|
||||||
# Record until the mouse is released (or any other GL event)
|
# Record until the mouse is released (or any other GL event)
|
||||||
# XXX audio not yet supported
|
# XXX audio not yet supported
|
||||||
|
|
||||||
def record(v, filename, audiofilename):
|
def record(v, info, filename, audiofilename):
|
||||||
import thread
|
import thread
|
||||||
x, y = gl.getsize()
|
format, x, y, qsize, rate = info
|
||||||
|
fps = 59.64 # Fields per second
|
||||||
|
# XXX (Strange: need fps of Indigo monitor, not of PAL or NTSC!)
|
||||||
|
tpf = 1000.0 / fps # Time per field in msec
|
||||||
vout = VFile.VoutFile().init(filename)
|
vout = VFile.VoutFile().init(filename)
|
||||||
vout.format = 'rgb8'
|
vout.format = 'rgb8'
|
||||||
vout.width = x
|
vout.width = x
|
||||||
vout.height = y
|
vout.height = y
|
||||||
vout.writeheader()
|
vout.writeheader()
|
||||||
buffer = []
|
MAXSIZE = 20 # XXX should be a user option
|
||||||
thread.start_new_thread(saveframes, (vout, buffer))
|
import Queue
|
||||||
|
queue = Queue.Queue().init(MAXSIZE)
|
||||||
|
done = thread.allocate_lock()
|
||||||
|
done.acquire_lock()
|
||||||
|
thread.start_new_thread(saveframes, (vout, queue, done))
|
||||||
if audiofilename:
|
if audiofilename:
|
||||||
initaudio(audiofilename, buffer)
|
audiodone = thread.allocate_lock()
|
||||||
|
audiodone.acquire_lock()
|
||||||
|
audiostop = []
|
||||||
|
initaudio(audiofilename, audiostop, audiodone)
|
||||||
gl.wintitle('(rec) ' + filename)
|
gl.wintitle('(rec) ' + filename)
|
||||||
v.StartCapture()
|
lastid = 0
|
||||||
t0 = time.millitimer()
|
t0 = time.millitimer()
|
||||||
|
v.InitContinuousCapture(info)
|
||||||
while not gl.qtest():
|
while not gl.qtest():
|
||||||
if v.GetCaptured() > 2:
|
try:
|
||||||
t = time.millitimer() - t0
|
cd, id = v.GetCaptureData()
|
||||||
cd, st = v.GetCaptureData()
|
except RuntimeError:
|
||||||
data = cd.interleave(x, y)
|
time.millisleep(10) # XXX is this necessary?
|
||||||
|
continue
|
||||||
|
id = id + 2*rate
|
||||||
|
## if id <> lastid + 2*rate:
|
||||||
|
## print lastid, id
|
||||||
|
lastid = id
|
||||||
|
data = cd.InterleaveFields(1)
|
||||||
cd.UnlockCaptureData()
|
cd.UnlockCaptureData()
|
||||||
buffer.append(data, t)
|
queue.put(data, int(id*tpf))
|
||||||
else:
|
t1 = time.millitimer()
|
||||||
time.millisleep(10)
|
gl.wintitle('(busy) ' + filename)
|
||||||
v.StopCapture()
|
print lastid, 'fields in', t1-t0, 'msec',
|
||||||
while v.GetCaptured() > 0:
|
print '--', 0.1 * int(lastid * 10000.0 / (t1-t0)), 'fields/sec'
|
||||||
t = time.millitimer() - t0
|
if audiofilename:
|
||||||
cd, st = v.GetCaptureData()
|
audiostop.append(None)
|
||||||
data = cd.interleave(x, y)
|
audiodone.acquire_lock()
|
||||||
cd.UnlockCaptureData()
|
v.EndContinuousCapture()
|
||||||
buffer.append(data, t)
|
queue.put(None) # Sentinel
|
||||||
buffer.append(None) # Sentinel
|
done.acquire_lock()
|
||||||
gl.wintitle('(done) ' + filename)
|
gl.wintitle('(done) ' + filename)
|
||||||
|
|
||||||
|
|
||||||
# Thread to save the frames to the file
|
# Thread to save the frames to the file
|
||||||
|
|
||||||
def saveframes(vout, buffer):
|
def saveframes(vout, queue, done):
|
||||||
while 1:
|
while 1:
|
||||||
if not buffer:
|
x = queue.get()
|
||||||
time.millisleep(10)
|
|
||||||
else:
|
|
||||||
x = buffer[0]
|
|
||||||
if not x:
|
if not x:
|
||||||
break
|
break
|
||||||
del buffer[0]
|
|
||||||
data, t = x
|
data, t = x
|
||||||
vout.writeframe(t, data, None)
|
vout.writeframe(t, data, None)
|
||||||
del data
|
del data
|
||||||
sys.stderr.write('Done writing\n')
|
sys.stderr.write('Done writing video\n')
|
||||||
vout.close()
|
vout.close()
|
||||||
|
done.release_lock()
|
||||||
|
|
||||||
|
|
||||||
# Initialize audio recording
|
# Initialize audio recording
|
||||||
|
|
||||||
AQSIZE = 8000
|
AQSIZE = 8000 # XXX should be a user option
|
||||||
|
|
||||||
def initaudio(filename, buffer):
|
def initaudio(filename, stop, done):
|
||||||
import thread, aiff
|
import thread, aiff
|
||||||
afile = aiff.Aiff().init(filename, 'w')
|
afile = aiff.Aiff().init(filename, 'w')
|
||||||
afile.nchannels = AL.MONO
|
afile.nchannels = AL.MONO
|
||||||
|
@ -240,7 +222,7 @@ def initaudio(filename, buffer):
|
||||||
c.setqueuesize(AQSIZE)
|
c.setqueuesize(AQSIZE)
|
||||||
c.setwidth(AL.SAMPLE_8)
|
c.setwidth(AL.SAMPLE_8)
|
||||||
aport = al.openport(filename, 'r', c)
|
aport = al.openport(filename, 'r', c)
|
||||||
thread.start_new_thread(audiorecord, (afile, aport, buffer))
|
thread.start_new_thread(audiorecord, (afile, aport, stop, done))
|
||||||
|
|
||||||
|
|
||||||
# Thread to record audio samples
|
# Thread to record audio samples
|
||||||
|
@ -248,14 +230,15 @@ def initaudio(filename, buffer):
|
||||||
# XXX should use writesampsraw for efficiency, but then destroy doesn't
|
# XXX should use writesampsraw for efficiency, but then destroy doesn't
|
||||||
# XXX seem to set the #samples in the header correctly
|
# XXX seem to set the #samples in the header correctly
|
||||||
|
|
||||||
def audiorecord(afile, aport, buffer):
|
def audiorecord(afile, aport, stop, done):
|
||||||
while buffer[-1:] <> [None]:
|
while not stop:
|
||||||
data = aport.readsamps(AQSIZE/2)
|
data = aport.readsamps(AQSIZE/2)
|
||||||
## afile.writesampsraw(data)
|
## afile.writesampsraw(data)
|
||||||
afile.writesamps(data)
|
afile.writesamps(data)
|
||||||
del data
|
del data
|
||||||
afile.destroy()
|
afile.destroy()
|
||||||
print 'Done writing audio'
|
print 'Done writing audio'
|
||||||
|
done.release_lock()
|
||||||
|
|
||||||
|
|
||||||
# Don't forget to call the main program
|
# Don't forget to call the main program
|
||||||
|
|
Loading…
Reference in New Issue