blob: 164e89e14729bec29da2f1bea4c4a70f4ff45bc1 [file] [log] [blame]
Guido van Rossum180924d1992-08-20 11:46:28 +00001#! /ufs/guido/bin/sgi/python
Guido van Rossumec706ad1992-12-24 11:39:00 +00002#! /ufs/guido/bin/sgi/python-405
Guido van Rossum180924d1992-08-20 11:46:28 +00003
4# Capture a CMIF movie using the Indigo video library and board
5
Guido van Rossumec706ad1992-12-24 11:39:00 +00006# The CMIF video file format is documented in cmif-film.ms.
7# Audio data is recorded in AIFF format, using the input sampling
8# rate, source and volume set by the audio panel, in mono, 8
9# bits/sample.
Guido van Rossum180924d1992-08-20 11:46:28 +000010
11
Guido van Rossumec706ad1992-12-24 11:39:00 +000012# Usage and help functions (keep this up-to-date if you change the program!)
13
14def usage():
15 print 'Usage: Vrec [options] [moviefile [audiofile]]'
16 print
17 print 'Options:'
18 print '-a : record audio as well'
19 print '-q queuesize : set the capture queue size (default 2)'
20 print '-r rate : capture 1 out of every "rate" frames', \
21 '(default and min 2)'
22 print '-w width : initial window width', \
Guido van Rossum85f7bd51993-02-25 16:10:16 +000023 '(default 256, use 0 for interactive placement)'
Guido van Rossumec706ad1992-12-24 11:39:00 +000024 print '-n : Don\'t write to file, only timing info'
25 print '-d : drop fields if needed'
26 print '-g bits : greyscale (2, 4 or 8 bits)'
27 print '-G : 2-bit greyscale dithered'
28 print '-m : monochrome dithered'
29 print '-M value : monochrome tresholded with value'
30 print '-f : Capture fields (in stead of frames)'
31 print '-P frames : preallocate space for "frames" frames'
32 print 'moviefile : here goes the movie data (default film.video)'
33 print 'audiofile : with -a, here goes the audio data', \
34 '(default film.aiff)'
35
36def help():
37 print 'Press the left mouse button to start recording, release it to'
38 print 'end recording. You can record as many times as you wish, but'
39 print 'each recording overwrites the output file(s) -- only the last'
40 print 'recording is kept.'
41 print
42 print 'Press ESC or use the window manager Quit or Close window option'
43 print 'to quit. If you quit before recording anything, the output'
44 print 'file(s) are not touched.'
Guido van Rossum180924d1992-08-20 11:46:28 +000045
46
Guido van Rossumec706ad1992-12-24 11:39:00 +000047# Imported modules
Guido van Rossum180924d1992-08-20 11:46:28 +000048
49import sys
50sys.path.append('/ufs/guido/src/video')
51import sv, SV
52import VFile
53import gl, GL, DEVICE
54import al, AL
55import time
56import posix
57import getopt
58import string
Jack Jansen3b253711992-12-14 12:25:21 +000059import imageop
Jack Jansen6bc8c7f1992-12-23 15:37:20 +000060import sgi
Guido van Rossum180924d1992-08-20 11:46:28 +000061
Guido van Rossumec706ad1992-12-24 11:39:00 +000062
Guido van Rossum180924d1992-08-20 11:46:28 +000063# Main program
64
65def main():
Guido van Rossum62f6bc81992-09-03 16:56:04 +000066 format = SV.RGB8_FRAMES
67 qsize = 2
Guido van Rossum180924d1992-08-20 11:46:28 +000068 audio = 0
Guido van Rossum62f6bc81992-09-03 16:56:04 +000069 rate = 2
Guido van Rossum32517f91992-09-04 13:26:59 +000070 width = 0
Jack Jansen3b253711992-12-14 12:25:21 +000071 norecord = 0
72 drop = 0
73 mono = 0
74 grey = 0
Jack Jansen6bc8c7f1992-12-23 15:37:20 +000075 greybits = 0
Jack Jansen3b253711992-12-14 12:25:21 +000076 monotreshold = -1
Jack Jansen6bc8c7f1992-12-23 15:37:20 +000077 fields = 0
78 preallocspace = 0
Guido van Rossum180924d1992-08-20 11:46:28 +000079
Guido van Rossumec706ad1992-12-24 11:39:00 +000080 # Parse command line
81 try:
82 opts, args = getopt.getopt(sys.argv[1:], 'aq:r:w:ndg:mM:GfP:')
83 except getopt.error, msg:
84 sys.stdout = sys.stderr
85 print 'Error:', msg, '\n'
86 usage()
Guido van Rossum8a861be1992-08-20 14:46:46 +000087 sys.exit(2)
88
Guido van Rossumec706ad1992-12-24 11:39:00 +000089 # Interpret options
90 try:
91 for opt, arg in opts:
92 if opt == '-a':
93 audio = 1
94 elif opt == '-q':
95 qsize = string.atoi(arg)
96 elif opt == '-r':
97 rate = string.atoi(arg)
98 if rate < 2:
99 sys.stderr.write( \
100 '-r rate must be >= 2\n')
101 sys.exit(2)
102 elif opt == '-w':
103 width = string.atoi(arg)
104 elif opt == '-n':
105 norecord = 1
106 elif opt == '-d':
107 drop = 1
108 elif opt == '-g':
109 grey = 1
110 greybits = string.atoi(arg)
111 if not greybits in (2, 4, 8):
112 sys.stderr.write( \
113 'Only 2, 4 or 8 bit greyscale supported\n')
114 sys.exit(2)
115 elif opt == '-G':
116 grey = 1
117 greybits = -2
118 elif opt == '-m':
119 mono = 1
120 elif opt == '-M':
121 mono = 1
122 monotreshold = string.atoi(arg)
123 elif opt == '-f':
124 fields = 1
125 elif opt == '-P':
126 preallocspace = string.atoi(arg)
127 except string.atoi_error:
128 sys.stdout = sys.stderr
129 print 'Option', opt, 'requires integer argument'
130 sys.exit(2)
131
132 # Check excess arguments
133 # If norecord is on, refuse filename arguments
134 if norecord:
135 if args:
136 sys.stdout = sys.stderr
137 print 'With -n, no filename arguments are used\n'
138 usage()
139 sys.exit(2)
140 elif args[2:]:
141 sys.stdout = sys.stderr
142 print 'Too many filename arguments\n'
143 usage()
144 sys.exit(2)
145
146 # Process file arguments
Guido van Rossum180924d1992-08-20 11:46:28 +0000147 if args:
148 filename = args[0]
149 else:
150 filename = 'film.video'
151
Guido van Rossum8a861be1992-08-20 14:46:46 +0000152 if args[1:] and not audio:
153 sys.stderr.write('-a turned on by appearance of 2nd file\n')
154 audio = 1
155
Guido van Rossum180924d1992-08-20 11:46:28 +0000156 if audio:
157 if args[1:]:
158 audiofilename = args[1]
159 else:
160 audiofilename = 'film.aiff'
161 else:
162 audiofilename = None
163
Jack Jansen3b253711992-12-14 12:25:21 +0000164 if norecord:
165 filename = audiofilename = ''
Guido van Rossumec706ad1992-12-24 11:39:00 +0000166
167 # Open video
Guido van Rossum32517f91992-09-04 13:26:59 +0000168 v = sv.OpenVideo()
169 # Determine maximum window size based on signal standard
170 param = [SV.BROADCAST, 0]
171 v.GetParam(param)
172 if param[1] == SV.PAL:
173 x = SV.PAL_XMAX
174 y = SV.PAL_YMAX
175 elif param[1] == SV.NTSC:
176 x = SV.NTSC_XMAX
177 y = SV.NTSC_YMAX
178 else:
179 print 'Unknown video standard', param[1]
180 sys.exit(1)
181
Guido van Rossum180924d1992-08-20 11:46:28 +0000182 gl.foreground()
Guido van Rossum32517f91992-09-04 13:26:59 +0000183 gl.maxsize(x, y)
184 gl.keepaspect(x, y)
Guido van Rossum180924d1992-08-20 11:46:28 +0000185 gl.stepunit(8, 6)
Guido van Rossum32517f91992-09-04 13:26:59 +0000186 if width:
Guido van Rossum85f7bd51993-02-25 16:10:16 +0000187 height = width*3/4
188 x1 = 150
189 x2 = x1 + width-1
190 y2 = 768-150
191 y1 = y2-height+1
192 gl.prefposition(x1, x2, y1, y2)
Guido van Rossum180924d1992-08-20 11:46:28 +0000193 win = gl.winopen(filename)
Guido van Rossum32517f91992-09-04 13:26:59 +0000194 if width:
195 gl.maxsize(x, y)
196 gl.keepaspect(x, y)
197 gl.stepunit(8, 6)
198 gl.winconstraints()
Guido van Rossum180924d1992-08-20 11:46:28 +0000199 x, y = gl.getsize()
200 print x, 'x', y
201
Guido van Rossum180924d1992-08-20 11:46:28 +0000202 v.SetSize(x, y)
Jack Jansen3b253711992-12-14 12:25:21 +0000203
204 if drop:
205 param = [SV.FIELDDROP, 1, SV.GENLOCK, SV.GENLOCK_OFF]
206 else:
207 param = [SV.FIELDDROP, 0, SV.GENLOCK, SV.GENLOCK_ON]
208 if mono or grey:
Guido van Rossum85f7bd51993-02-25 16:10:16 +0000209 param = param+[SV.COLOR, SV.MONO, SV.DITHER, 0, \
210 SV.INPUT_BYPASS, 1]
Jack Jansen3b253711992-12-14 12:25:21 +0000211 else:
212 param = param+[SV.COLOR, SV.DEFAULT_COLOR, SV.INPUT_BYPASS, 0]
Guido van Rossumff3da051992-12-09 22:16:35 +0000213
Guido van Rossum180924d1992-08-20 11:46:28 +0000214 v.BindGLWindow(win, SV.IN_REPLACE)
Guido van Rossum85f7bd51993-02-25 16:10:16 +0000215 v.SetParam(param)
Guido van Rossum180924d1992-08-20 11:46:28 +0000216
Guido van Rossum180924d1992-08-20 11:46:28 +0000217 gl.qdevice(DEVICE.LEFTMOUSE)
218 gl.qdevice(DEVICE.WINQUIT)
219 gl.qdevice(DEVICE.WINSHUT)
220 gl.qdevice(DEVICE.ESCKEY)
221
Guido van Rossumec706ad1992-12-24 11:39:00 +0000222 help()
Guido van Rossum180924d1992-08-20 11:46:28 +0000223
Guido van Rossum180924d1992-08-20 11:46:28 +0000224 while 1:
225 dev, val = gl.qread()
226 if dev == DEVICE.LEFTMOUSE:
227 if val == 1:
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000228 info = format, x, y, qsize, rate
Jack Jansen3b253711992-12-14 12:25:21 +0000229 record(v, info, filename, audiofilename,\
Jack Jansen6bc8c7f1992-12-23 15:37:20 +0000230 mono, grey, greybits, monotreshold, \
231 fields, preallocspace)
Guido van Rossum180924d1992-08-20 11:46:28 +0000232 elif dev == DEVICE.REDRAW:
233 # Window resize (or move)
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000234 x, y = gl.getsize()
235 print x, 'x', y
236 v.SetSize(x, y)
237 v.BindGLWindow(win, SV.IN_REPLACE)
Guido van Rossum180924d1992-08-20 11:46:28 +0000238 elif dev in (DEVICE.ESCKEY, DEVICE.WINQUIT, DEVICE.WINSHUT):
239 # Quit
Guido van Rossum180924d1992-08-20 11:46:28 +0000240 v.CloseVideo()
241 gl.winclose(win)
242 break
243
244
245# Record until the mouse is released (or any other GL event)
246# XXX audio not yet supported
247
Jack Jansen6bc8c7f1992-12-23 15:37:20 +0000248def record(v, info, filename, audiofilename, mono, grey, greybits, \
249 monotreshold, fields, preallocspace):
Guido van Rossum180924d1992-08-20 11:46:28 +0000250 import thread
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000251 format, x, y, qsize, rate = info
252 fps = 59.64 # Fields per second
253 # XXX (Strange: need fps of Indigo monitor, not of PAL or NTSC!)
254 tpf = 1000.0 / fps # Time per field in msec
Jack Jansen3b253711992-12-14 12:25:21 +0000255 if filename:
256 vout = VFile.VoutFile().init(filename)
257 if mono:
Guido van Rossum0caf46b1993-03-02 12:07:34 +0000258 format = 'mono'
Jack Jansen6bc8c7f1992-12-23 15:37:20 +0000259 elif grey and greybits == 8:
Guido van Rossum0caf46b1993-03-02 12:07:34 +0000260 format = 'grey'
Jack Jansen6bc8c7f1992-12-23 15:37:20 +0000261 elif grey:
Guido van Rossum0caf46b1993-03-02 12:07:34 +0000262 format = 'grey'+`abs(greybits)`
Jack Jansen3b253711992-12-14 12:25:21 +0000263 else:
Guido van Rossum0caf46b1993-03-02 12:07:34 +0000264 format = 'rgb8'
265 vout.setformat(format)
266 vout.setsize(x, y)
Jack Jansen6bc8c7f1992-12-23 15:37:20 +0000267 if fields:
Guido van Rossumf48b4191993-03-02 12:16:56 +0000268 vout.setpf((1, -2))
Jack Jansen3b253711992-12-14 12:25:21 +0000269 vout.writeheader()
Jack Jansen6bc8c7f1992-12-23 15:37:20 +0000270 if preallocspace:
271 print 'Preallocating space...'
272 vout.prealloc(preallocspace)
273 print 'done.'
Jack Jansen3b253711992-12-14 12:25:21 +0000274 MAXSIZE = 20 # XXX should be a user option
275 import Queue
276 queue = Queue.Queue().init(MAXSIZE)
277 done = thread.allocate_lock()
278 done.acquire_lock()
Jack Jansen6bc8c7f1992-12-23 15:37:20 +0000279 convertor = None
280 if grey:
281 if greybits == 2:
282 convertor = imageop.grey2grey2
283 elif greybits == 4:
284 convertor = imageop.grey2grey4
285 elif greybits == -2:
286 convertor = imageop.dither2grey2
Jack Jansen3b253711992-12-14 12:25:21 +0000287 thread.start_new_thread(saveframes, \
Jack Jansen6bc8c7f1992-12-23 15:37:20 +0000288 (vout, queue, done, mono, monotreshold, convertor))
Jack Jansen3b253711992-12-14 12:25:21 +0000289 if audiofilename:
290 audiodone = thread.allocate_lock()
291 audiodone.acquire_lock()
292 audiostop = []
293 initaudio(audiofilename, audiostop, audiodone)
Guido van Rossum180924d1992-08-20 11:46:28 +0000294 gl.wintitle('(rec) ' + filename)
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000295 lastid = 0
Guido van Rossum180924d1992-08-20 11:46:28 +0000296 t0 = time.millitimer()
Jack Jansen3b253711992-12-14 12:25:21 +0000297 count = 0
Jack Jansen3b253711992-12-14 12:25:21 +0000298 ids = []
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000299 v.InitContinuousCapture(info)
Guido van Rossum180924d1992-08-20 11:46:28 +0000300 while not gl.qtest():
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000301 try:
302 cd, id = v.GetCaptureData()
Guido van Rossum42e07af1992-09-22 15:01:43 +0000303 except sv.error:
Jack Jansen6bc8c7f1992-12-23 15:37:20 +0000304 #time.millisleep(10) # XXX is this necessary?
305 sgi.nap(1) # XXX Try by Jack
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000306 continue
Jack Jansen3b253711992-12-14 12:25:21 +0000307 ids.append(id)
308
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000309 id = id + 2*rate
310## if id <> lastid + 2*rate:
311## print lastid, id
312 lastid = id
Jack Jansen3b253711992-12-14 12:25:21 +0000313 count = count+1
Jack Jansen6bc8c7f1992-12-23 15:37:20 +0000314 if fields:
315 data1, data2 = cd.GetFields()
316 cd.UnlockCaptureData()
317 if filename:
318 queue.put((data1, int(id*tpf)))
319 queue.put((data2, int((id+1)*tpf)))
320 else:
321 data = cd.InterleaveFields(1)
322 cd.UnlockCaptureData()
323 if filename:
324 queue.put((data, int(id*tpf)))
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000325 t1 = time.millitimer()
326 gl.wintitle('(busy) ' + filename)
327 print lastid, 'fields in', t1-t0, 'msec',
328 print '--', 0.1 * int(lastid * 10000.0 / (t1-t0)), 'fields/sec'
Guido van Rossum9533ebe1992-12-14 12:29:43 +0000329 print 'Captured',count*2, 'fields,',
330 print 0.1*int(count*20000.0/(t1-t0)), 'f/s',
331 if lastid:
332 print count*200.0/lastid, '%,',
333 print count*rate*200.0/lastid, '% of wanted rate',
334 print
Guido van Rossum852cc221993-02-15 17:33:36 +0000335 if ids:
336 print 'Ids:',
337 t0 = ids[0]
338 del ids[0]
339 for t1 in ids:
340 print t1-t0,
341 t0 = t1
342 print
Jack Jansen3b253711992-12-14 12:25:21 +0000343 if filename and audiofilename:
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000344 audiostop.append(None)
345 audiodone.acquire_lock()
346 v.EndContinuousCapture()
Jack Jansen3b253711992-12-14 12:25:21 +0000347 if filename:
348 queue.put(None) # Sentinel
349 done.acquire_lock()
Guido van Rossum180924d1992-08-20 11:46:28 +0000350 gl.wintitle('(done) ' + filename)
351
352
353# Thread to save the frames to the file
354
Jack Jansen6bc8c7f1992-12-23 15:37:20 +0000355def saveframes(vout, queue, done, mono, monotreshold, convertor):
Guido van Rossum180924d1992-08-20 11:46:28 +0000356 while 1:
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000357 x = queue.get()
358 if not x:
359 break
360 data, t = x
Jack Jansen6bc8c7f1992-12-23 15:37:20 +0000361 if convertor:
362 data = convertor(data, len(data), 1)
363 elif mono and monotreshold >= 0:
Jack Jansen3b253711992-12-14 12:25:21 +0000364 data = imageop.grey2mono(data, len(data), 1,\
365 monotreshold)
366 elif mono:
367 data = imageop.dither2mono(data, len(data), 1)
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000368 vout.writeframe(t, data, None)
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000369 sys.stderr.write('Done writing video\n')
Guido van Rossum180924d1992-08-20 11:46:28 +0000370 vout.close()
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000371 done.release_lock()
Guido van Rossum180924d1992-08-20 11:46:28 +0000372
373
Guido van Rossum8a861be1992-08-20 14:46:46 +0000374# Initialize audio recording
375
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000376AQSIZE = 8000 # XXX should be a user option
Guido van Rossum8a861be1992-08-20 14:46:46 +0000377
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000378def initaudio(filename, stop, done):
Guido van Rossum8a861be1992-08-20 14:46:46 +0000379 import thread, aiff
380 afile = aiff.Aiff().init(filename, 'w')
381 afile.nchannels = AL.MONO
382 afile.sampwidth = AL.SAMPLE_8
383 params = [AL.INPUT_RATE, 0]
384 al.getparams(AL.DEFAULT_DEVICE, params)
385 print 'audio sampling rate =', params[1]
386 afile.samprate = params[1]
387 c = al.newconfig()
388 c.setchannels(AL.MONO)
389 c.setqueuesize(AQSIZE)
390 c.setwidth(AL.SAMPLE_8)
391 aport = al.openport(filename, 'r', c)
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000392 thread.start_new_thread(audiorecord, (afile, aport, stop, done))
Guido van Rossum8a861be1992-08-20 14:46:46 +0000393
394
395# Thread to record audio samples
396
397# XXX should use writesampsraw for efficiency, but then destroy doesn't
398# XXX seem to set the #samples in the header correctly
399
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000400def audiorecord(afile, aport, stop, done):
401 while not stop:
Guido van Rossum8a861be1992-08-20 14:46:46 +0000402 data = aport.readsamps(AQSIZE/2)
403## afile.writesampsraw(data)
404 afile.writesamps(data)
405 del data
406 afile.destroy()
407 print 'Done writing audio'
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000408 done.release_lock()
Guido van Rossum8a861be1992-08-20 14:46:46 +0000409
410
Guido van Rossum180924d1992-08-20 11:46:28 +0000411# Don't forget to call the main program
412
Guido van Rossume0be2b31992-09-01 14:45:57 +0000413try:
414 main()
415except KeyboardInterrupt:
416 print '[Interrupt]'