blob: 5cdde9e6211f0bbb06f9fc47368b79e5da3369f2 [file] [log] [blame]
Guido van Rossumf06ee5f1996-11-27 19:52:01 +00001#! /usr/bin/env python
Guido van Rossum6e0e6681992-12-23 15:41:38 +00002
Guido van Rossum3f2ef091993-02-05 15:34:22 +00003# Capture a CMIF movie using the Indigo video library and board in burst mode
Guido van Rossum6e0e6681992-12-23 15:41:38 +00004
5
6# User interface:
7#
8# Start the application. Resize the window to the desired movie size.
9# Press the left mouse button to start recording, release it to end
10# recording. You can record as many times as you wish, but each time
11# you overwrite the output file(s), so only the last recording is
12# kept.
13#
14# Press ESC or select the window manager Quit or Close window option
15# to quit. If you quit before recording anything, the output file(s)
16# are not touched.
17
18
19import sys
20sys.path.append('/ufs/guido/src/video')
21import sv, SV
22import VFile
23import gl, GL, DEVICE
24import al, AL
25import time
26import posix
27import getopt
28import string
29import imageop
30import sgi
31
Guido van Rossum3f2ef091993-02-05 15:34:22 +000032
33# Usage and help functions (keep this up-to-date if you change the program!)
34
35def usage():
Jack Jansen09bf3e31993-02-24 16:08:21 +000036 print 'Usage: Vrecb [options] [moviefile [audiofile]]'
Guido van Rossum3f2ef091993-02-05 15:34:22 +000037 print
38 print 'Options:'
Jack Jansen09bf3e31993-02-24 16:08:21 +000039 print '-a : record audio as well'
Guido van Rossum3f2ef091993-02-05 15:34:22 +000040 print '-r rate : capture 1 out of every "rate" frames', \
41 '(default and min 1)'
42 print '-w width : initial window width', \
Guido van Rossum85f7bd51993-02-25 16:10:16 +000043 '(default 256, use 0 for interactive placement)'
Guido van Rossum3f2ef091993-02-05 15:34:22 +000044 print '-d : drop fields if needed'
45 print '-g bits : greyscale (2, 4 or 8 bits)'
46 print '-G : 2-bit greyscale dithered'
47 print '-m : monochrome dithered'
Thomas Wouters7e474022000-07-16 12:04:32 +000048 print '-M value : monochrome thresholded with value'
Guido van Rossum3f2ef091993-02-05 15:34:22 +000049 print '-f : Capture fields (instead of frames)'
50 print '-n number : Capture this many frames (default 60)'
Guido van Rossumc17c84f1993-05-10 15:45:49 +000051 print '-N memsize : Capture frames fitting in this many kbytes'
Guido van Rossum3f2ef091993-02-05 15:34:22 +000052 print 'moviefile : here goes the movie data (default film.video)'
53
54def help():
55 print 'Press the left mouse button to start recording.'
56 print 'Recording time is determined by the -n option.'
57 print 'You can record as many times as you wish, but each'
58 print 'recording overwrites the output file(s) -- only the'
59 print 'last recording is kept.'
60 print
61 print 'Press ESC or use the window manager Quit or Close window option'
62 print 'to quit. If you quit before recording anything, the output'
63 print 'file(s) are not touched.'
64
65
Guido van Rossum6e0e6681992-12-23 15:41:38 +000066# Main program
67
68def main():
69 format = SV.RGB8_FRAMES
Jack Jansen09bf3e31993-02-24 16:08:21 +000070 audio = 0
Guido van Rossum6e0e6681992-12-23 15:41:38 +000071 rate = 1
Guido van Rossum85f7bd51993-02-25 16:10:16 +000072 width = 256
Guido van Rossum6e0e6681992-12-23 15:41:38 +000073 drop = 0
74 mono = 0
75 grey = 0
76 greybits = 0
77 monotreshold = -1
78 fields = 0
Guido van Rossumc17c84f1993-05-10 15:45:49 +000079 number = 0
80 memsize = 0
Guido van Rossum6e0e6681992-12-23 15:41:38 +000081
Guido van Rossum3f2ef091993-02-05 15:34:22 +000082 try:
Guido van Rossumc17c84f1993-05-10 15:45:49 +000083 opts, args = getopt.getopt(sys.argv[1:], 'ar:w:dg:mM:Gfn:N:')
Guido van Rossum3f2ef091993-02-05 15:34:22 +000084 except getopt.error, msg:
85 sys.stdout = sys.stderr
86 print 'Error:', msg, '\n'
87 usage()
88 sys.exit(2)
89
90 try:
91 for opt, arg in opts:
Jack Jansen09bf3e31993-02-24 16:08:21 +000092 if opt == '-a':
93 audio = 1
Guido van Rossum3f2ef091993-02-05 15:34:22 +000094 if opt == '-r':
95 rate = string.atoi(arg)
96 if rate < 1:
97 sys.stderr.write('-r rate must be >= 1\n')
98 sys.exit(2)
99 elif opt == '-w':
100 width = string.atoi(arg)
101 elif opt == '-d':
102 drop = 1
103 elif opt == '-g':
104 grey = 1
105 greybits = string.atoi(arg)
106 if not greybits in (2,4,8):
107 sys.stderr.write( \
108 'Only 2, 4 or 8 bit greyscale supported\n')
109 sys.exit(2)
110 elif opt == '-G':
111 grey = 1
112 greybits = -2
113 elif opt == '-m':
114 mono = 1
115 elif opt == '-M':
116 mono = 1
117 monotreshold = string.atoi(arg)
118 elif opt == '-f':
119 fields = 1
120 elif opt == '-n':
121 number = string.atoi(arg)
Guido van Rossumc17c84f1993-05-10 15:45:49 +0000122 elif opt == '-N':
123 memsize = string.atoi(arg)
124 if 0 < memsize < 1024:
125 memsize = memsize * 1024
126 if 0 < memsize < 1024*1024:
127 memsize = memsize * 1024
128 print 'memsize', memsize
Guido van Rossum3f2ef091993-02-05 15:34:22 +0000129 except string.atoi_error:
130 sys.stdout = sys.stderr
131 print 'Option', opt, 'requires integer argument'
132 sys.exit(2)
133
Guido van Rossumc17c84f1993-05-10 15:45:49 +0000134 if number <> 0 and memsize <> 0:
135 sys.stderr.write('-n and -N are mutually exclusive\n')
136 sys.exit(2)
137 if number == 0 and memsize == 0:
138 number = 60
139
Guido van Rossum3f2ef091993-02-05 15:34:22 +0000140 if not fields:
Jack Jansen09bf3e31993-02-24 16:08:21 +0000141 print '-f option assumed until somebody fixes it'
Guido van Rossum3f2ef091993-02-05 15:34:22 +0000142 fields = 1
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000143
144 if args[2:]:
Jack Jansen09bf3e31993-02-24 16:08:21 +0000145 sys.stderr.write('usage: Vrecb [options] [file [audiofile]]\n')
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000146 sys.exit(2)
147
148 if args:
149 filename = args[0]
150 else:
151 filename = 'film.video'
152
Jack Jansen09bf3e31993-02-24 16:08:21 +0000153 if args[1:] and not audio:
154 sys.stderr.write('-a turned on by appearance of 2nd file\n')
155 audio = 1
156
157 if audio:
158 if args[1:]:
159 audiofilename = args[1]
160 else:
161 audiofilename = 'film.aiff'
162 else:
163 audiofilename = None
164
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000165 v = sv.OpenVideo()
166 # Determine maximum window size based on signal standard
167 param = [SV.BROADCAST, 0]
168 v.GetParam(param)
169 if param[1] == SV.PAL:
170 x = SV.PAL_XMAX
171 y = SV.PAL_YMAX
172 elif param[1] == SV.NTSC:
173 x = SV.NTSC_XMAX
174 y = SV.NTSC_YMAX
175 else:
176 print 'Unknown video standard', param[1]
177 sys.exit(1)
178
179 gl.foreground()
180 gl.maxsize(x, y)
181 gl.keepaspect(x, y)
182 gl.stepunit(8, 6)
183 if width:
Guido van Rossum85f7bd51993-02-25 16:10:16 +0000184 height = width*3/4
185 x1 = 150
186 x2 = x1 + width-1
187 y2 = 768-150
188 y1 = y2-height+1
189 gl.prefposition(x1, x2, y1, y2)
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000190 win = gl.winopen(filename)
191 if width:
192 gl.maxsize(x, y)
193 gl.keepaspect(x, y)
194 gl.stepunit(8, 6)
195 gl.winconstraints()
196 x, y = gl.getsize()
197 print x, 'x', y
Guido van Rossumc17c84f1993-05-10 15:45:49 +0000198 if memsize:
199 number = calcnumber(x, y, grey or mono, memsize)
200 print number, 'frames'
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000201 v.SetSize(x, y)
202
203 if drop:
204 param = [SV.FIELDDROP, 1, SV.GENLOCK, SV.GENLOCK_OFF]
205 else:
206 param = [SV.FIELDDROP, 0, SV.GENLOCK, SV.GENLOCK_ON]
207 if mono or grey:
Guido van Rossum85f7bd51993-02-25 16:10:16 +0000208 param = param+[SV.COLOR, SV.MONO, SV.DITHER, 0, \
209 SV.INPUT_BYPASS, 1]
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000210 else:
211 param = param+[SV.COLOR, SV.DEFAULT_COLOR, SV.INPUT_BYPASS, 0]
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000212
213 v.BindGLWindow(win, SV.IN_REPLACE)
Guido van Rossum85f7bd51993-02-25 16:10:16 +0000214 v.SetParam(param)
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000215
216 gl.qdevice(DEVICE.LEFTMOUSE)
217 gl.qdevice(DEVICE.WINQUIT)
218 gl.qdevice(DEVICE.WINSHUT)
219 gl.qdevice(DEVICE.ESCKEY)
220
Guido van Rossum3f2ef091993-02-05 15:34:22 +0000221 help()
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000222
223 while 1:
224 dev, val = gl.qread()
225 if dev == DEVICE.LEFTMOUSE:
226 if val == 1:
227 info = format, x, y, number, rate
Jack Jansen09bf3e31993-02-24 16:08:21 +0000228 record(v, info, filename, audiofilename, \
229 mono, grey, \
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000230 greybits, monotreshold, fields)
231 elif dev == DEVICE.REDRAW:
232 # Window resize (or move)
233 x, y = gl.getsize()
234 print x, 'x', y
Guido van Rossumc17c84f1993-05-10 15:45:49 +0000235 if memsize:
236 number = calcnumber(x, y, grey or mono, memsize)
237 print number, 'frames'
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000238 v.SetSize(x, y)
239 v.BindGLWindow(win, SV.IN_REPLACE)
240 elif dev in (DEVICE.ESCKEY, DEVICE.WINQUIT, DEVICE.WINSHUT):
241 # Quit
242 v.CloseVideo()
243 gl.winclose(win)
244 break
245
246
Guido van Rossumc17c84f1993-05-10 15:45:49 +0000247def calcnumber(x, y, grey, memsize):
248 pixels = x*y
249 pixels = pixels/2 # XXX always assume fields
250 if grey: n = memsize/pixels
251 else: n = memsize/(4*pixels)
252 return max(1, n)
253
254
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000255# Record until the mouse is released (or any other GL event)
256# XXX audio not yet supported
257
Jack Jansen09bf3e31993-02-24 16:08:21 +0000258def record(v, info, filename, audiofilename, \
259 mono, grey, greybits, monotreshold, fields):
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000260 import thread
261 format, x, y, number, rate = info
262 fps = 59.64 # Fields per second
263 # XXX (Strange: need fps of Indigo monitor, not of PAL or NTSC!)
264 tpf = 1000.0 / fps # Time per field in msec
265 #
266 # Go grab
267 #
Jack Jansen09bf3e31993-02-24 16:08:21 +0000268 if audiofilename:
269 gl.wintitle('(start audio) ' + filename)
270 audiodone = thread.allocate_lock()
271 audiodone.acquire_lock()
272 audiostart = thread.allocate_lock()
273 audiostart.acquire_lock()
274 audiostop = []
275 initaudio(audiofilename, audiostop, audiostart, audiodone)
276 audiostart.acquire_lock()
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000277 gl.wintitle('(rec) ' + filename)
278 try:
279 ninfo, data, bitvec = v.CaptureBurst(info)
280 except sv.error, arg:
281 print 'CaptureBurst failed:', arg
282 print 'info:', info
283 gl.wintitle(filename)
284 return
285 gl.wintitle('(save) '+ filename)
286 #
287 # Check results
288 #
289 if info <> ninfo:
290 print 'Sorry, format changed.'
291 print 'Wanted:',info
292 print 'Got :',ninfo
293 gl.wintitle(filename)
294 return
295 # print bitvec
296 if x*y*number <> len(data):
297 print 'Funny data length: wanted',x,'*',y,'*', number,'=',\
298 x*y*number,'got',len(data)
299 gl.wintitle(filename)
300 return
301 #
302 # Save
303 #
Jack Jansen09bf3e31993-02-24 16:08:21 +0000304 if filename and audiofilename:
305 audiostop.append(None)
306 audiodone.acquire_lock()
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000307 if filename:
308 #
309 # Construct header and write it
310 #
Guido van Rossum852cc221993-02-15 17:33:36 +0000311 try:
Guido van Rossum21a3ff91993-12-17 15:11:41 +0000312 vout = VFile.VoutFile(filename)
Guido van Rossum852cc221993-02-15 17:33:36 +0000313 except IOError, msg:
314 print filename, ':', msg
315 sys.exit(1)
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000316 if mono:
317 vout.format = 'mono'
318 elif grey and greybits == 8:
319 vout.format = 'grey'
320 elif grey:
321 vout.format = 'grey'+`abs(greybits)`
322 else:
323 vout.format = 'rgb8'
324 vout.width = x
325 vout.height = y
326 if fields:
327 vout.packfactor = (1,-2)
328 else:
329 print 'Sorry, can only save fields at the moment'
Guido van Rossum3f2ef091993-02-05 15:34:22 +0000330 print '(i.e. you *must* use the -f option)'
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000331 gl.wintitle(filename)
332 return
333 vout.writeheader()
334 #
335 # Compute convertor, if needed
336 #
337 convertor = None
338 if grey:
339 if greybits == 2:
340 convertor = imageop.grey2grey2
341 elif greybits == 4:
342 convertor = imageop.grey2grey4
343 elif greybits == -2:
344 convertor = imageop.dither2grey2
345 fieldsize = x*y/2
346 nskipped = 0
347 realframeno = 0
348 tpf = 1000 / 50.0 #XXXX
Guido van Rossumc17c84f1993-05-10 15:45:49 +0000349 # Trying to find the pattern in frame skipping
350 okstretch = 0
351 skipstretch = 0
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000352 for frameno in range(0, number*2):
353 if frameno <> 0 and \
354 bitvec[frameno] == bitvec[frameno-1]:
355 nskipped = nskipped + 1
Guido van Rossumc17c84f1993-05-10 15:45:49 +0000356 if okstretch:
357 print okstretch, 'ok',
358 okstretch = 0
359 skipstretch = skipstretch + 1
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000360 continue
Guido van Rossumc17c84f1993-05-10 15:45:49 +0000361 if skipstretch:
362 print skipstretch, 'skipped'
363 skipstretch = 0
364 okstretch = okstretch + 1
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000365 #
366 # Save field.
367 # XXXX Works only for fields and top-to-bottom
368 #
369 start = frameno*fieldsize
370 field = data[start:start+fieldsize]
371 if convertor:
Guido van Rossum852cc221993-02-15 17:33:36 +0000372 field = convertor(field, len(field), 1)
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000373 elif mono and monotreshold >= 0:
Guido van Rossum852cc221993-02-15 17:33:36 +0000374 field = imageop.grey2mono( \
375 field, len(field), 1, monotreshold)
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000376 elif mono:
Guido van Rossum852cc221993-02-15 17:33:36 +0000377 field = imageop.dither2mono( \
378 field, len(field), 1)
Guido van Rossum852cc221993-02-15 17:33:36 +0000379 realframeno = realframeno + 1
Guido van Rossumc17c84f1993-05-10 15:45:49 +0000380 vout.writeframe(int(realframeno*tpf), field, None)
381 print okstretch, 'ok',
382 print skipstretch, 'skipped'
383 print 'Skipped', nskipped, 'duplicate frames'
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000384 vout.close()
385
386 gl.wintitle('(done) ' + filename)
Jack Jansen09bf3e31993-02-24 16:08:21 +0000387# Initialize audio recording
388
389AQSIZE = 8*8000 # XXX should be a user option
390
391def initaudio(filename, stop, start, done):
Guido van Rossum21a3ff91993-12-17 15:11:41 +0000392 import thread, aifc
393 afile = aifc.open(filename, 'w')
Sjoerd Mullenderd6b9ce91993-12-22 11:44:49 +0000394 afile.setnchannels(AL.MONO)
395 afile.setsampwidth(AL.SAMPLE_8)
Jack Jansen09bf3e31993-02-24 16:08:21 +0000396 params = [AL.INPUT_RATE, 0]
397 al.getparams(AL.DEFAULT_DEVICE, params)
398 print 'audio sampling rate =', params[1]
Sjoerd Mullenderd6b9ce91993-12-22 11:44:49 +0000399 afile.setframerate(params[1])
Jack Jansen09bf3e31993-02-24 16:08:21 +0000400 c = al.newconfig()
401 c.setchannels(AL.MONO)
402 c.setqueuesize(AQSIZE)
403 c.setwidth(AL.SAMPLE_8)
404 aport = al.openport(filename, 'r', c)
405 thread.start_new_thread(audiorecord, (afile, aport, stop, start, done))
406
407
408# Thread to record audio samples
409
Jack Jansen09bf3e31993-02-24 16:08:21 +0000410def audiorecord(afile, aport, stop, start, done):
411 start.release_lock()
412 leeway = 4
413 while leeway > 0:
414 if stop:
415 leeway = leeway - 1
416 data = aport.readsamps(AQSIZE/8)
Sjoerd Mullenderd6b9ce91993-12-22 11:44:49 +0000417 afile.writesampsraw(data)
Jack Jansen09bf3e31993-02-24 16:08:21 +0000418 del data
Sjoerd Mullenderd6b9ce91993-12-22 11:44:49 +0000419 afile.close()
Jack Jansen09bf3e31993-02-24 16:08:21 +0000420 print 'Done writing audio'
421 done.release_lock()
422
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000423
424# Don't forget to call the main program
425
426try:
427 main()
428except KeyboardInterrupt:
429 print '[Interrupt]'