755 lines
17 KiB
Python
Executable File
755 lines
17 KiB
Python
Executable File
#! /ufs/guido/bin/sgi/python
|
|
|
|
# Video bag of tricks: record video(+audio) in various formats and modes
|
|
|
|
# XXX To do:
|
|
# - audio
|
|
# - improve user interface
|
|
# - help button?
|
|
# - command line options to set initial settings
|
|
# - save settings in a file
|
|
# - ...?
|
|
|
|
import sys
|
|
import time
|
|
import getopt
|
|
import string
|
|
import os
|
|
sts = os.system('makemap') # Must be before "import fl" to work
|
|
import sgi
|
|
import gl
|
|
import GL
|
|
import DEVICE
|
|
import fl
|
|
import FL
|
|
import flp
|
|
import watchcursor
|
|
import sv
|
|
import SV
|
|
import VFile
|
|
import VGrabber
|
|
import imageop
|
|
sys.path.append('/ufs/jack/src/av/vcr')
|
|
|
|
ARROW = 0
|
|
WATCH = 1
|
|
watchcursor.defwatch(WATCH)
|
|
|
|
def main():
|
|
## fl.set_graphics_mode(0, 1)
|
|
vb = VideoBagOfTricks().init()
|
|
while 1:
|
|
dummy = fl.do_forms()
|
|
[dummy]
|
|
|
|
StopCapture = 'StopCapture'
|
|
|
|
VideoFormatLabels = ['Video off', 'rgb8', 'grey8', 'grey4', 'grey2', \
|
|
'grey2 dith', 'mono dith', 'mono thresh']
|
|
VideoFormats = ['', 'rgb8', 'grey', 'grey4', 'grey2', \
|
|
'grey2', 'mono', 'mono']
|
|
|
|
VideoModeLabels = ['Continuous', 'Burst', 'Single frame', 'VCR sync']
|
|
[VM_CONT, VM_BURST, VM_SINGLE, VM_VCR] = range(1, 5)
|
|
|
|
AudioFormatLabels = ['Audio off', \
|
|
'16 bit mono', '16 bit stereo', '8 bit mono', '8 bit stereo']
|
|
[A_OFF, A_16_MONO, A_16_STEREO, A_8_MONO, A_8_STEREO] = range(1, 6)
|
|
|
|
class VideoBagOfTricks:
|
|
|
|
# Init/close stuff
|
|
|
|
def init(self):
|
|
formdef = flp.parse_form('VbForm', 'form')
|
|
flp.create_full_form(self, formdef)
|
|
self.g_cont.hide_object()
|
|
self.g_burst.hide_object()
|
|
self.g_single.hide_object()
|
|
self.g_vcr.hide_object()
|
|
self.setdefaults()
|
|
self.openvideo()
|
|
self.makewindow()
|
|
self.bindvideo()
|
|
self.showform()
|
|
fl.set_event_call_back(self.do_event)
|
|
return self
|
|
|
|
def close(self):
|
|
self.close_video()
|
|
self.close_audio()
|
|
raise SystemExit, 0
|
|
|
|
def showform(self):
|
|
# Get position of video window
|
|
gl.winset(self.window)
|
|
x, y = gl.getorigin()
|
|
width, height = gl.getsize()
|
|
# Calculate position of form window
|
|
x1 = x + width + 10
|
|
x2 = x1 + int(self.form.w) - 1
|
|
y2 = y + height - 1
|
|
y1 = y2 - int(self.form.h) + 1
|
|
# Position and show form window
|
|
gl.prefposition(x1, x2, y1, y2)
|
|
self.form.show_form(FL.PLACE_FREE, FL.TRUE, \
|
|
'Video Bag Of Tricks')
|
|
|
|
def setdefaults(self):
|
|
self.vcr = None
|
|
self.vout = None
|
|
self.capturing = 0
|
|
# Video defaults
|
|
self.vfile = 'film.video'
|
|
self.vmode = VM_CONT
|
|
self.mono_thresh = 128
|
|
self.vformat = 'rgb8'
|
|
self.c_vformat.clear_choice()
|
|
for label in VideoFormatLabels:
|
|
self.c_vformat.addto_choice(label)
|
|
self.c_vformat.set_choice(1 + VideoFormats.index(self.vformat))
|
|
self.c_vmode.clear_choice()
|
|
for label in VideoModeLabels:
|
|
self.c_vmode.addto_choice(label)
|
|
self.c_vmode.set_choice(self.vmode)
|
|
self.get_vformat()
|
|
self.b_drop.set_button(1)
|
|
self.in_rate.set_input('2')
|
|
self.in_maxmem.set_input('1.0')
|
|
self.in_nframes.set_input('0')
|
|
self.in_nframes_vcr.set_input('1')
|
|
self.in_rate_vcr.set_input('1')
|
|
# Audio defaults
|
|
self.aout = None
|
|
self.aport = None
|
|
self.afile = 'film.aiff'
|
|
self.aformat = A_OFF
|
|
self.c_aformat.clear_choice()
|
|
for label in AudioFormatLabels:
|
|
self.c_aformat.addto_choice(label)
|
|
self.c_aformat.set_choice(self.aformat)
|
|
self.get_aformat()
|
|
|
|
def openvideo(self):
|
|
try:
|
|
self.video = sv.OpenVideo()
|
|
except sv.error, msg:
|
|
print 'Error opening video:', msg
|
|
self.video = None
|
|
param = [SV.BROADCAST, SV.PAL]
|
|
if self.video: self.video.GetParam(param)
|
|
if param[1] == SV.PAL:
|
|
x = SV.PAL_XMAX
|
|
y = SV.PAL_YMAX
|
|
elif param[1] == SV.NTSC:
|
|
x = SV.NTSC_XMAX
|
|
y = SV.NTSC_YMAX
|
|
else:
|
|
print 'Unknown video standard:', param[1]
|
|
sys.exit(1)
|
|
self.maxx, self.maxy = x, y
|
|
|
|
def makewindow(self):
|
|
x, y = self.maxx, self.maxy
|
|
gl.foreground()
|
|
gl.maxsize(x, y)
|
|
gl.keepaspect(x, y)
|
|
gl.stepunit(8, 6)
|
|
width = 256 # XXX
|
|
if width:
|
|
height = width*3/4
|
|
x1 = 150
|
|
x2 = x1 + width-1
|
|
y2 = 768-150
|
|
y1 = y2-height+1
|
|
gl.prefposition(x1, x2, y1, y2)
|
|
self.window = gl.winopen('Vb: initializing')
|
|
self.settitle()
|
|
if width:
|
|
gl.maxsize(x, y)
|
|
gl.keepaspect(x, y)
|
|
gl.stepunit(8, 6)
|
|
gl.winconstraints()
|
|
gl.qdevice(DEVICE.LEFTMOUSE)
|
|
gl.qdevice(DEVICE.WINQUIT)
|
|
gl.qdevice(DEVICE.WINSHUT)
|
|
|
|
def bindvideo(self):
|
|
if not self.video: return
|
|
x, y = gl.getsize()
|
|
self.video.SetSize(x, y)
|
|
drop = self.b_drop.get_button()
|
|
if drop:
|
|
param = [SV.FIELDDROP, 1, SV.GENLOCK, SV.GENLOCK_OFF]
|
|
else:
|
|
param = [SV.FIELDDROP, 0, SV.GENLOCK, SV.GENLOCK_ON]
|
|
if self.rgb:
|
|
param = param+[SV.COLOR, SV.DEFAULT_COLOR, \
|
|
SV.DITHER, 1, \
|
|
SV.INPUT_BYPASS, 0]
|
|
else:
|
|
param = param+[SV.COLOR, SV.MONO, SV.DITHER, 0, \
|
|
SV.INPUT_BYPASS, 1]
|
|
self.video.BindGLWindow(self.window, SV.IN_REPLACE)
|
|
self.video.SetParam(param)
|
|
|
|
def rebindvideo(self):
|
|
gl.winset(self.window)
|
|
self.bindvideo()
|
|
|
|
def reset(self):
|
|
self.close_video()
|
|
self.close_audio()
|
|
if self.vcr:
|
|
try:
|
|
ok = self.vcr.still()
|
|
except VCR.error:
|
|
pass
|
|
self.vcr = None
|
|
self.b_capture.set_button(0)
|
|
|
|
# Event handler (catches resize of video window)
|
|
|
|
def do_event(self, dev, val):
|
|
#print 'Event:', dev, val
|
|
if dev in (DEVICE.WINSHUT, DEVICE.WINQUIT):
|
|
self.close()
|
|
if dev == DEVICE.REDRAW and val == self.window:
|
|
self.rebindvideo()
|
|
self.settitle()
|
|
|
|
# Video controls: format, mode, file
|
|
|
|
def cb_vformat(self, *args):
|
|
self.reset()
|
|
self.get_vformat()
|
|
if self.mono_use_thresh:
|
|
s = `self.mono_thresh`
|
|
s = fl.show_input('Please enter mono threshold', s)
|
|
if s:
|
|
try:
|
|
self.mono_thresh = string.atoi(s)
|
|
except string.atoi_error:
|
|
fl.show_message('Bad input, using', \
|
|
`self.mono_thresh`, '')
|
|
self.rebindvideo()
|
|
|
|
def cb_vmode(self, *args):
|
|
if self.vcr:
|
|
self.vcr = None
|
|
self.vmode = self.c_vmode.get_choice()
|
|
self.form.freeze_form()
|
|
self.g_cont.hide_object()
|
|
self.g_burst.hide_object()
|
|
self.g_single.hide_object()
|
|
self.g_vcr.hide_object()
|
|
if self.vmode == VM_CONT:
|
|
self.g_cont.show_object()
|
|
elif self.vmode == VM_BURST:
|
|
self.g_burst.show_object()
|
|
elif self.vmode == VM_SINGLE:
|
|
self.g_single.show_object()
|
|
elif self.vmode == VM_VCR:
|
|
self.g_vcr.show_object()
|
|
self.form.unfreeze_form()
|
|
|
|
def cb_vfile(self, *args):
|
|
filename = self.vfile
|
|
hd, tl = os.path.split(filename)
|
|
filename = fl.file_selector('Video save file:', hd, '', tl)
|
|
if filename:
|
|
self.reset()
|
|
hd, tl = os.path.split(filename)
|
|
if hd == os.getcwd():
|
|
filename = tl
|
|
self.vfile = filename
|
|
|
|
# Video mode specific video controls
|
|
|
|
def cb_rate(self, *args):
|
|
pass
|
|
|
|
def cb_drop(self, *args):
|
|
self.rebindvideo()
|
|
|
|
def cb_maxmem(self, *args):
|
|
pass
|
|
|
|
def cb_nframes(self, *args):
|
|
pass
|
|
|
|
def cb_fps(self, *args):
|
|
pass
|
|
|
|
def cb_nframes_vcr(self, *args):
|
|
pass
|
|
|
|
def cb_rate_vcr(self, *args):
|
|
pass
|
|
|
|
# Audio controls: format, file
|
|
|
|
def cb_aformat(self, *args):
|
|
self.get_aformat()
|
|
|
|
def cb_afile(self, *args):
|
|
filename = self.afile
|
|
hd, tl = os.path.split(filename)
|
|
filename = fl.file_selector('Audio save file:', hd, '', tl)
|
|
if filename:
|
|
self.reset()
|
|
hd, tl = os.path.split(filename)
|
|
if hd == os.getcwd():
|
|
filename = tl
|
|
self.afile = filename
|
|
|
|
# General controls: capture, reset, play, quit
|
|
|
|
def cb_capture(self, *args):
|
|
if self.capturing:
|
|
raise StopCapture
|
|
if not self.b_capture.get_button():
|
|
return
|
|
if not self.video or not self.vformat:
|
|
gl.ringbell()
|
|
return
|
|
if self.vmode == VM_CONT:
|
|
self.cont_capture()
|
|
elif self.vmode == VM_BURST:
|
|
self.burst_capture()
|
|
elif self.vmode == VM_SINGLE:
|
|
self.single_capture()
|
|
elif self.vmode == VM_VCR:
|
|
self.vcr_capture()
|
|
|
|
def cb_reset(self, *args):
|
|
self.reset()
|
|
|
|
def cb_play(self, *args):
|
|
self.reset()
|
|
sts = os.system('Vplay -q ' + self.vfile + ' &')
|
|
|
|
def cb_quit(self, *args):
|
|
self.close()
|
|
|
|
# Capture routines
|
|
|
|
def burst_capture(self):
|
|
self.setwatch()
|
|
gl.winset(self.window)
|
|
x, y = gl.getsize()
|
|
vformat = SV.RGB8_FRAMES
|
|
nframes = self.getint(self.in_nframes, 0)
|
|
if nframes == 0:
|
|
maxmem = self.getint(self.in_maxmem, 1.0)
|
|
memsize = int(maxmem * 1024 * 1024)
|
|
nframes = self.calcnframes()
|
|
info = (vformat, x, y, nframes, 1)
|
|
try:
|
|
info2, data, bitvec = self.video.CaptureBurst(info)
|
|
except sv.error, msg:
|
|
self.b_capture.set_button(0)
|
|
self.setarrow()
|
|
fl.show_message('Capture error:', str(msg), '')
|
|
return
|
|
if info <> info2: print info, '<>', info2
|
|
self.save_burst(info2, data, bitvec)
|
|
self.setarrow()
|
|
|
|
def calcnframes(self):
|
|
gl.winset(self.window)
|
|
x, y = gl.getsize()
|
|
pixels = x*y
|
|
pixels = pixels/2 # XXX always assume fields
|
|
if self.mono or self.grey:
|
|
n = memsize/pixels
|
|
else:
|
|
n = memsize/(4*pixels)
|
|
return max(1, n)
|
|
|
|
def save_burst(self, info, data, bitvec):
|
|
(vformat, x, y, nframes, rate) = info
|
|
self.open_if_closed()
|
|
fieldsize = x*y/2
|
|
nskipped = 0
|
|
realframeno = 0
|
|
tpf = 1000 / 50.0 # XXX
|
|
for frameno in range(0, nframes*2):
|
|
if frameno <> 0 and \
|
|
bitvec[frameno] == bitvec[frameno-1]:
|
|
nskipped = nskipped + 1
|
|
continue
|
|
#
|
|
# Save field.
|
|
# XXX Works only for fields and top-to-bottom
|
|
#
|
|
start = frameno*fieldsize
|
|
field = data[start:start+fieldsize]
|
|
realframeno = realframeno + 1
|
|
fn = int(realframeno*tpf)
|
|
if not self.write_frame(fn, field):
|
|
break
|
|
|
|
def cont_capture(self):
|
|
saved_label = self.b_capture.label
|
|
self.b_capture.label = 'Stop\n' + saved_label
|
|
self.open_if_closed()
|
|
self.init_cont()
|
|
fps = 59.64 # Fields per second
|
|
# XXX (fps of Indigo monitor, not of PAL or NTSC!)
|
|
tpf = 1000.0 / fps # Time per field in msec
|
|
self.capturing = 1
|
|
self.start_audio()
|
|
while 1:
|
|
try:
|
|
void = fl.check_forms()
|
|
except StopCapture:
|
|
break
|
|
try:
|
|
cd, id = self.video.GetCaptureData()
|
|
except sv.error:
|
|
sgi.nap(1)
|
|
continue
|
|
id = id + 2*self.rate
|
|
data = cd.InterleaveFields(1)
|
|
cd.UnlockCaptureData()
|
|
t = id*tpf
|
|
if not self.write_frame(t, data):
|
|
break
|
|
self.stop_audio()
|
|
self.capturing = 0
|
|
self.end_cont()
|
|
if self.aout:
|
|
# If recording audio, can't capture multiple sequences
|
|
self.reset()
|
|
self.b_capture.label = saved_label
|
|
|
|
def single_capture(self):
|
|
self.open_if_closed()
|
|
self.init_cont()
|
|
while 1:
|
|
try:
|
|
cd, id = self.video.GetCaptureData()
|
|
break
|
|
except sv.error:
|
|
pass
|
|
sgi.nap(1)
|
|
data = cd.InterleaveFields(1)
|
|
cd.UnlockCaptureData()
|
|
self.end_cont()
|
|
t = (self.nframes+1) * (1000/25)
|
|
return self.write_frame(t, data)
|
|
|
|
def vcr_capture(self):
|
|
if not self.vcr:
|
|
import VCR
|
|
try:
|
|
self.vcr = VCR.VCR().init()
|
|
self.vcr.wait()
|
|
if not (self.vcr.fmmode('dnr') and \
|
|
self.vcr.dmcontrol('digital slow')):
|
|
self.vcr_error('digital slow failed')
|
|
return
|
|
except VCR.error, msg:
|
|
self.vcr = None
|
|
self.vcr_error(msg)
|
|
return
|
|
if not self.vcr.still():
|
|
self.vcr_error('still failed')
|
|
return
|
|
# XXX for some reason calling where() too often hangs the VCR,
|
|
# XXX so we insert sleep(0.1) before every sense() call.
|
|
self.open_if_closed()
|
|
rate = self.getint(self.in_rate_vcr, 1)
|
|
rate = max(rate, 1)
|
|
self.speed_factor = rate
|
|
addr = self.vcr.sense()
|
|
if not self.single_capture():
|
|
return
|
|
print 'captured %02d:%02d:%02d:%02d' % self.vcr.addr2tc(addr)
|
|
count = self.getint(self.in_nframes_vcr, 1) - 1
|
|
if count <= 0:
|
|
while rate > 0:
|
|
if not self.vcr.step():
|
|
self.vcr_error('step failed')
|
|
here = self.vcr.sense()
|
|
if here > addr:
|
|
rate = rate - (here - addr)
|
|
addr = here
|
|
return
|
|
if not self.vcr.fwdshuttle(2): # one tenth speed
|
|
self.vcr_error('fwd shuttle failed')
|
|
return
|
|
cycle = 0
|
|
while count > 0:
|
|
time.sleep(0.1)
|
|
try:
|
|
here = self.vcr.sense()
|
|
except VCR.error, msg:
|
|
self.vcr_error(msg)
|
|
break
|
|
if here <> addr:
|
|
if here <> addr+1:
|
|
print 'Missed', here-addr-1,
|
|
print 'frame' + 's'*(here-addr-1 <> 1)
|
|
cycle = (cycle+1) % rate
|
|
if cycle == 0:
|
|
if not self.single_capture():
|
|
break
|
|
print 'captured %02d:%02d:%02d:%02d' \
|
|
% self.vcr.addr2tc(here)
|
|
count = count -1
|
|
addr = here
|
|
if self.vcr and not self.vcr.still():
|
|
self.vcr_error('still failed')
|
|
|
|
def vcr_error(self, msg):
|
|
self.reset()
|
|
fl.show_message('VCR error:', str(msg), '')
|
|
|
|
# Init/end continuous capture mode
|
|
|
|
def init_cont(self):
|
|
qsize = 1
|
|
if self.vmode == VM_CONT:
|
|
self.rate = self.getint(self.in_rate, 2)
|
|
else:
|
|
self.rate = 2
|
|
x, y = self.vout.getsize()
|
|
info = (SV.RGB8_FRAMES, x, y, qsize, self.rate)
|
|
info2 = self.video.InitContinuousCapture(info)
|
|
if info2 <> info:
|
|
# XXX This is really only debug info
|
|
print 'Info mismatch: requested', info, 'got', info2
|
|
|
|
def end_cont(self):
|
|
self.video.EndContinuousCapture()
|
|
|
|
# Misc stuff
|
|
|
|
def settitle(self):
|
|
gl.winset(self.window)
|
|
x, y = gl.getsize()
|
|
title = 'Vb:' + self.vfile + ' (%dx%d)' % (x, y)
|
|
gl.wintitle(title)
|
|
|
|
def get_vformat(self):
|
|
i = self.c_vformat.get_choice()
|
|
label = VideoFormatLabels[i-1]
|
|
format = VideoFormats[i-1]
|
|
self.vformat = format
|
|
if self.vformat == '':
|
|
self.form.freeze_form()
|
|
self.g_video.hide_object()
|
|
self.g_cont.hide_object()
|
|
self.g_burst.hide_object()
|
|
self.g_single.hide_object()
|
|
self.form.unfreeze_form()
|
|
return
|
|
else:
|
|
self.g_video.show_object()
|
|
if self.vmode == VM_CONT:
|
|
self.g_cont.show_object()
|
|
elif self.vmode == VM_BURST:
|
|
self.g_burst.show_object()
|
|
elif self.vmode == VM_SINGLE:
|
|
self.g_single.show_object()
|
|
#
|
|
self.rgb = (format[:3] == 'rgb')
|
|
self.mono = (format == 'mono')
|
|
self.grey = (format[:4] == 'grey')
|
|
self.mono_use_thresh = (label == 'mono thresh')
|
|
s = format[4:]
|
|
if s:
|
|
self.greybits = string.atoi(s)
|
|
else:
|
|
self.greybits = 8
|
|
if label == 'grey2 dith':
|
|
self.greybits = -2
|
|
#
|
|
convertor = None
|
|
if self.grey:
|
|
if self.greybits == 2:
|
|
convertor = imageop.grey2grey2
|
|
elif self.greybits == 4:
|
|
convertor = imageop.grey2grey4
|
|
elif self.greybits == -2:
|
|
convertor = imageop.dither2grey2
|
|
self.convertor = convertor
|
|
|
|
def get_aformat(self):
|
|
self.reset()
|
|
self.aformat = self.c_aformat.get_choice()
|
|
if self.aformat == A_OFF:
|
|
self.g_audio.hide_object()
|
|
else:
|
|
self.g_audio.show_object()
|
|
|
|
def open_if_closed(self):
|
|
if not self.vout:
|
|
self.open_video()
|
|
if not self.aout:
|
|
self.open_audio()
|
|
|
|
# File I/O handling
|
|
|
|
def open_video(self):
|
|
self.close_video()
|
|
gl.winset(self.window)
|
|
x, y = gl.getsize()
|
|
vout = VFile.VoutFile().init(self.vfile)
|
|
vout.setformat(self.vformat)
|
|
vout.setsize(x, y)
|
|
if self.vmode == VM_BURST:
|
|
vout.setpf((1, -2))
|
|
vout.writeheader()
|
|
self.vout = vout
|
|
self.nframes = 0
|
|
self.speed_factor = 1
|
|
self.t_nframes.label = `self.nframes`
|
|
|
|
def write_frame(self, t, data):
|
|
t = t * self.speed_factor
|
|
if not self.vout:
|
|
gl.ringbell()
|
|
return 0
|
|
if self.convertor:
|
|
data = self.convertor(data, len(data), 1)
|
|
elif self.mono:
|
|
if self.mono_use_thresh:
|
|
data = imageop.grey2mono(data, \
|
|
len(data), 1,\
|
|
self.mono_thresh)
|
|
else:
|
|
data = imageop.dither2mono(data, \
|
|
len(data), 1)
|
|
try:
|
|
self.vout.writeframe(int(t), data, None)
|
|
except IOError, msg:
|
|
self.reset()
|
|
if msg == (0, 'Error 0'):
|
|
msg = 'disk full??'
|
|
fl.show_message('IOError', str(msg), '')
|
|
return 0
|
|
self.nframes = self.nframes + 1
|
|
self.t_nframes.label = `self.nframes`
|
|
return 1
|
|
|
|
def close_video(self):
|
|
if not self.vout:
|
|
return
|
|
self.nframes = 0
|
|
self.t_nframes.label = ''
|
|
try:
|
|
self.vout.close()
|
|
except IOError, msg:
|
|
if msg == (0, 'Error 0'):
|
|
msg = 'disk full??'
|
|
fl.show_message('IOError', str(msg), '')
|
|
self.vout = None
|
|
|
|
# Watch cursor handling
|
|
|
|
def setwatch(self):
|
|
gl.winset(self.form.window)
|
|
gl.setcursor(WATCH, 0, 0)
|
|
gl.winset(self.window)
|
|
gl.setcursor(WATCH, 0, 0)
|
|
|
|
def setarrow(self):
|
|
gl.winset(self.form.window)
|
|
gl.setcursor(ARROW, 0, 0)
|
|
gl.winset(self.window)
|
|
gl.setcursor(ARROW, 0, 0)
|
|
|
|
# Numeric field handling
|
|
|
|
def getint(self, field, default):
|
|
try:
|
|
value = string.atoi(field.get_input())
|
|
except string.atoi_error:
|
|
value = default
|
|
field.set_input(`value`)
|
|
return value
|
|
|
|
def getfloat(self, field, default):
|
|
try:
|
|
value = float(eval(field.get_input()))
|
|
except:
|
|
value = float(default)
|
|
field.set_input(`value`)
|
|
return value
|
|
|
|
# Audio stuff
|
|
|
|
def open_audio(self):
|
|
if self.aformat == A_OFF:
|
|
return
|
|
import aifc
|
|
import al
|
|
import AL
|
|
import thread
|
|
self.close_audio()
|
|
params = [AL.INPUT_RATE, 0]
|
|
al.getparams(AL.DEFAULT_DEVICE, params)
|
|
rate = params[1]
|
|
self.aout = aifc.open(self.afile, 'w')
|
|
if self.aformat in (A_16_STEREO, A_8_STEREO):
|
|
nch = AL.STEREO
|
|
else:
|
|
nch = AL.MONO
|
|
if self.aformat in (A_16_STEREO, A_16_MONO):
|
|
width = AL.SAMPLE_16
|
|
else:
|
|
width = AL.SAMPLE_8
|
|
self.aout.setnchannels(nch)
|
|
self.aout.setsampwidth(width)
|
|
self.aout.setframerate(rate)
|
|
self.aout.writeframes('')
|
|
c = al.newconfig()
|
|
c.setqueuesize(8000)
|
|
c.setchannels(nch)
|
|
c.setwidth(width)
|
|
self.aport = al.openport('Vb audio record', 'r', c)
|
|
self.audio_stop = 0
|
|
self.audio_ok = 0
|
|
self.audio_busy = 1
|
|
thread.start_new_thread(self.record_audio, ())
|
|
|
|
def start_audio(self):
|
|
if self.aformat == A_OFF:
|
|
return
|
|
self.audio_ok = 1
|
|
|
|
def record_audio(self, *args):
|
|
# This function runs in a separate thread
|
|
# Currently no semaphores are used
|
|
while not self.audio_stop:
|
|
data = self.aport.readsamps(4000)
|
|
if self.audio_ok:
|
|
self.aout.writeframesraw(data)
|
|
data = None
|
|
self.audio_busy = 0
|
|
|
|
def stop_audio(self):
|
|
self.audio_ok = 0
|
|
|
|
def close_audio(self):
|
|
if self.aout:
|
|
self.audio_ok = 0
|
|
self.audio_stop = 1
|
|
while self.audio_busy:
|
|
time.sleep(0.1)
|
|
self.aout.close()
|
|
self.aout = None
|
|
if self.aport:
|
|
self.aport.closeport()
|
|
self.aport = None
|
|
|
|
|
|
try:
|
|
main()
|
|
except KeyboardInterrupt:
|
|
print '[Interrupt]'
|
|
sys.exit(1)
|