blob: b647bd35dfe2b83c3e8951f84e42eba2c5fcb6b6 [file] [log] [blame]
Guido van Rossumf06ee5f1996-11-27 19:52:01 +00001#! /usr/bin/env 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:
Guido van Rossum21a3ff91993-12-17 15:11:41 +0000256 vout = VFile.VoutFile(filename)
Jack Jansen3b253711992-12-14 12:25:21 +0000257 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
Guido van Rossum21a3ff91993-12-17 15:11:41 +0000276 queue = Queue.Queue(MAXSIZE)
Jack Jansen3b253711992-12-14 12:25:21 +0000277 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 Rossum0efafb31993-12-28 21:36:18 +0000296 t0 = time.time()
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:
Guido van Rossum0efafb31993-12-28 21:36:18 +0000304 #time.sleep(0.010) # XXX is this necessary?
Jack Jansen6bc8c7f1992-12-23 15:37:20 +0000305 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 Rossum0efafb31993-12-28 21:36:18 +0000325 t1 = time.time()
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000326 gl.wintitle('(busy) ' + filename)
Guido van Rossum0efafb31993-12-28 21:36:18 +0000327 print lastid, 'fields in', round(t1-t0, 3), 'sec',
328 print '--', round(lastid/(t1-t0), 1), 'fields/sec'
Guido van Rossum9533ebe1992-12-14 12:29:43 +0000329 print 'Captured',count*2, 'fields,',
Guido van Rossum0efafb31993-12-28 21:36:18 +0000330 print round(count*2/(t1-t0), 1), 'f/s',
Guido van Rossum9533ebe1992-12-14 12:29:43 +0000331 if lastid:
Guido van Rossum0efafb31993-12-28 21:36:18 +0000332 print '(',
333 print round(count*200.0/lastid), '%, or',
334 print round(count*rate*200.0/lastid), '% of wanted rate )',
Guido van Rossum9533ebe1992-12-14 12:29:43 +0000335 print
Guido van Rossum852cc221993-02-15 17:33:36 +0000336 if ids:
337 print 'Ids:',
338 t0 = ids[0]
339 del ids[0]
340 for t1 in ids:
341 print t1-t0,
342 t0 = t1
343 print
Jack Jansen3b253711992-12-14 12:25:21 +0000344 if filename and audiofilename:
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000345 audiostop.append(None)
346 audiodone.acquire_lock()
347 v.EndContinuousCapture()
Jack Jansen3b253711992-12-14 12:25:21 +0000348 if filename:
349 queue.put(None) # Sentinel
350 done.acquire_lock()
Guido van Rossum180924d1992-08-20 11:46:28 +0000351 gl.wintitle('(done) ' + filename)
352
353
354# Thread to save the frames to the file
355
Jack Jansen6bc8c7f1992-12-23 15:37:20 +0000356def saveframes(vout, queue, done, mono, monotreshold, convertor):
Guido van Rossum180924d1992-08-20 11:46:28 +0000357 while 1:
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000358 x = queue.get()
359 if not x:
360 break
361 data, t = x
Jack Jansen6bc8c7f1992-12-23 15:37:20 +0000362 if convertor:
363 data = convertor(data, len(data), 1)
364 elif mono and monotreshold >= 0:
Jack Jansen3b253711992-12-14 12:25:21 +0000365 data = imageop.grey2mono(data, len(data), 1,\
366 monotreshold)
367 elif mono:
368 data = imageop.dither2mono(data, len(data), 1)
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000369 vout.writeframe(t, data, None)
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000370 sys.stderr.write('Done writing video\n')
Guido van Rossum180924d1992-08-20 11:46:28 +0000371 vout.close()
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000372 done.release_lock()
Guido van Rossum180924d1992-08-20 11:46:28 +0000373
374
Guido van Rossum8a861be1992-08-20 14:46:46 +0000375# Initialize audio recording
376
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000377AQSIZE = 8000 # XXX should be a user option
Guido van Rossum8a861be1992-08-20 14:46:46 +0000378
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000379def initaudio(filename, stop, done):
Guido van Rossum21a3ff91993-12-17 15:11:41 +0000380 import thread, aifc
381 afile = aifc.open(filename, 'w')
Sjoerd Mullenderd6b9ce91993-12-22 11:44:49 +0000382 afile.setnchannels(AL.MONO)
383 afile.setsampwidth(AL.SAMPLE_8)
Guido van Rossum8a861be1992-08-20 14:46:46 +0000384 params = [AL.INPUT_RATE, 0]
385 al.getparams(AL.DEFAULT_DEVICE, params)
386 print 'audio sampling rate =', params[1]
Sjoerd Mullenderd6b9ce91993-12-22 11:44:49 +0000387 afile.setframerate(params[1])
Guido van Rossum8a861be1992-08-20 14:46:46 +0000388 c = al.newconfig()
389 c.setchannels(AL.MONO)
390 c.setqueuesize(AQSIZE)
391 c.setwidth(AL.SAMPLE_8)
392 aport = al.openport(filename, 'r', c)
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000393 thread.start_new_thread(audiorecord, (afile, aport, stop, done))
Guido van Rossum8a861be1992-08-20 14:46:46 +0000394
395
396# Thread to record audio samples
397
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000398def audiorecord(afile, aport, stop, done):
399 while not stop:
Guido van Rossum8a861be1992-08-20 14:46:46 +0000400 data = aport.readsamps(AQSIZE/2)
Sjoerd Mullenderd6b9ce91993-12-22 11:44:49 +0000401 afile.writesampsraw(data)
Guido van Rossum8a861be1992-08-20 14:46:46 +0000402 del data
Sjoerd Mullenderd6b9ce91993-12-22 11:44:49 +0000403 afile.close()
Guido van Rossum8a861be1992-08-20 14:46:46 +0000404 print 'Done writing audio'
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000405 done.release_lock()
Guido van Rossum8a861be1992-08-20 14:46:46 +0000406
407
Guido van Rossum180924d1992-08-20 11:46:28 +0000408# Don't forget to call the main program
409
Guido van Rossume0be2b31992-09-01 14:45:57 +0000410try:
411 main()
412except KeyboardInterrupt:
413 print '[Interrupt]'