blob: ef7bc37c135258b4e1216df08dd5477ba9442f18 [file] [log] [blame]
Guido van Rossum6e0e6681992-12-23 15:41:38 +00001#! /ufs/guido/bin/sgi/python
2
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'
48 print '-M value : monochrome tresholded with value'
49 print '-f : Capture fields (instead of frames)'
50 print '-n number : Capture this many frames (default 60)'
51 print 'moviefile : here goes the movie data (default film.video)'
52
53def help():
54 print 'Press the left mouse button to start recording.'
55 print 'Recording time is determined by the -n option.'
56 print 'You can record as many times as you wish, but each'
57 print 'recording overwrites the output file(s) -- only the'
58 print 'last recording is kept.'
59 print
60 print 'Press ESC or use the window manager Quit or Close window option'
61 print 'to quit. If you quit before recording anything, the output'
62 print 'file(s) are not touched.'
63
64
Guido van Rossum6e0e6681992-12-23 15:41:38 +000065# Main program
66
67def main():
68 format = SV.RGB8_FRAMES
Jack Jansen09bf3e31993-02-24 16:08:21 +000069 audio = 0
Guido van Rossum6e0e6681992-12-23 15:41:38 +000070 rate = 1
Guido van Rossum85f7bd51993-02-25 16:10:16 +000071 width = 256
Guido van Rossum6e0e6681992-12-23 15:41:38 +000072 drop = 0
73 mono = 0
74 grey = 0
75 greybits = 0
76 monotreshold = -1
77 fields = 0
78 number = 60
79
Guido van Rossum3f2ef091993-02-05 15:34:22 +000080 try:
Jack Jansen09bf3e31993-02-24 16:08:21 +000081 opts, args = getopt.getopt(sys.argv[1:], 'ar:w:dg:mM:Gfn:')
Guido van Rossum3f2ef091993-02-05 15:34:22 +000082 except getopt.error, msg:
83 sys.stdout = sys.stderr
84 print 'Error:', msg, '\n'
85 usage()
86 sys.exit(2)
87
88 try:
89 for opt, arg in opts:
Jack Jansen09bf3e31993-02-24 16:08:21 +000090 if opt == '-a':
91 audio = 1
Guido van Rossum3f2ef091993-02-05 15:34:22 +000092 if opt == '-r':
93 rate = string.atoi(arg)
94 if rate < 1:
95 sys.stderr.write('-r rate must be >= 1\n')
96 sys.exit(2)
97 elif opt == '-w':
98 width = string.atoi(arg)
99 elif opt == '-d':
100 drop = 1
101 elif opt == '-g':
102 grey = 1
103 greybits = string.atoi(arg)
104 if not greybits in (2,4,8):
105 sys.stderr.write( \
106 'Only 2, 4 or 8 bit greyscale supported\n')
107 sys.exit(2)
108 elif opt == '-G':
109 grey = 1
110 greybits = -2
111 elif opt == '-m':
112 mono = 1
113 elif opt == '-M':
114 mono = 1
115 monotreshold = string.atoi(arg)
116 elif opt == '-f':
117 fields = 1
118 elif opt == '-n':
119 number = string.atoi(arg)
120 except string.atoi_error:
121 sys.stdout = sys.stderr
122 print 'Option', opt, 'requires integer argument'
123 sys.exit(2)
124
125 if not fields:
Jack Jansen09bf3e31993-02-24 16:08:21 +0000126 print '-f option assumed until somebody fixes it'
Guido van Rossum3f2ef091993-02-05 15:34:22 +0000127 fields = 1
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000128
129 if args[2:]:
Jack Jansen09bf3e31993-02-24 16:08:21 +0000130 sys.stderr.write('usage: Vrecb [options] [file [audiofile]]\n')
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000131 sys.exit(2)
132
133 if args:
134 filename = args[0]
135 else:
136 filename = 'film.video'
137
Jack Jansen09bf3e31993-02-24 16:08:21 +0000138 if args[1:] and not audio:
139 sys.stderr.write('-a turned on by appearance of 2nd file\n')
140 audio = 1
141
142 if audio:
143 if args[1:]:
144 audiofilename = args[1]
145 else:
146 audiofilename = 'film.aiff'
147 else:
148 audiofilename = None
149
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000150 v = sv.OpenVideo()
151 # Determine maximum window size based on signal standard
152 param = [SV.BROADCAST, 0]
153 v.GetParam(param)
154 if param[1] == SV.PAL:
155 x = SV.PAL_XMAX
156 y = SV.PAL_YMAX
157 elif param[1] == SV.NTSC:
158 x = SV.NTSC_XMAX
159 y = SV.NTSC_YMAX
160 else:
161 print 'Unknown video standard', param[1]
162 sys.exit(1)
163
164 gl.foreground()
165 gl.maxsize(x, y)
166 gl.keepaspect(x, y)
167 gl.stepunit(8, 6)
168 if width:
Guido van Rossum85f7bd51993-02-25 16:10:16 +0000169 height = width*3/4
170 x1 = 150
171 x2 = x1 + width-1
172 y2 = 768-150
173 y1 = y2-height+1
174 gl.prefposition(x1, x2, y1, y2)
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000175 win = gl.winopen(filename)
176 if width:
177 gl.maxsize(x, y)
178 gl.keepaspect(x, y)
179 gl.stepunit(8, 6)
180 gl.winconstraints()
181 x, y = gl.getsize()
182 print x, 'x', y
183
184 v.SetSize(x, y)
185
186 if drop:
187 param = [SV.FIELDDROP, 1, SV.GENLOCK, SV.GENLOCK_OFF]
188 else:
189 param = [SV.FIELDDROP, 0, SV.GENLOCK, SV.GENLOCK_ON]
190 if mono or grey:
Guido van Rossum85f7bd51993-02-25 16:10:16 +0000191 param = param+[SV.COLOR, SV.MONO, SV.DITHER, 0, \
192 SV.INPUT_BYPASS, 1]
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000193 else:
194 param = param+[SV.COLOR, SV.DEFAULT_COLOR, SV.INPUT_BYPASS, 0]
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000195
196 v.BindGLWindow(win, SV.IN_REPLACE)
Guido van Rossum85f7bd51993-02-25 16:10:16 +0000197 v.SetParam(param)
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000198
199 gl.qdevice(DEVICE.LEFTMOUSE)
200 gl.qdevice(DEVICE.WINQUIT)
201 gl.qdevice(DEVICE.WINSHUT)
202 gl.qdevice(DEVICE.ESCKEY)
203
Guido van Rossum3f2ef091993-02-05 15:34:22 +0000204 help()
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000205
206 while 1:
207 dev, val = gl.qread()
208 if dev == DEVICE.LEFTMOUSE:
209 if val == 1:
210 info = format, x, y, number, rate
Jack Jansen09bf3e31993-02-24 16:08:21 +0000211 record(v, info, filename, audiofilename, \
212 mono, grey, \
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000213 greybits, monotreshold, fields)
214 elif dev == DEVICE.REDRAW:
215 # Window resize (or move)
216 x, y = gl.getsize()
217 print x, 'x', y
218 v.SetSize(x, y)
219 v.BindGLWindow(win, SV.IN_REPLACE)
220 elif dev in (DEVICE.ESCKEY, DEVICE.WINQUIT, DEVICE.WINSHUT):
221 # Quit
222 v.CloseVideo()
223 gl.winclose(win)
224 break
225
226
227# Record until the mouse is released (or any other GL event)
228# XXX audio not yet supported
229
Jack Jansen09bf3e31993-02-24 16:08:21 +0000230def record(v, info, filename, audiofilename, \
231 mono, grey, greybits, monotreshold, fields):
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000232 import thread
233 format, x, y, number, rate = info
234 fps = 59.64 # Fields per second
235 # XXX (Strange: need fps of Indigo monitor, not of PAL or NTSC!)
236 tpf = 1000.0 / fps # Time per field in msec
237 #
238 # Go grab
239 #
Jack Jansen09bf3e31993-02-24 16:08:21 +0000240 if audiofilename:
241 gl.wintitle('(start audio) ' + filename)
242 audiodone = thread.allocate_lock()
243 audiodone.acquire_lock()
244 audiostart = thread.allocate_lock()
245 audiostart.acquire_lock()
246 audiostop = []
247 initaudio(audiofilename, audiostop, audiostart, audiodone)
248 audiostart.acquire_lock()
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000249 gl.wintitle('(rec) ' + filename)
250 try:
251 ninfo, data, bitvec = v.CaptureBurst(info)
252 except sv.error, arg:
253 print 'CaptureBurst failed:', arg
254 print 'info:', info
255 gl.wintitle(filename)
256 return
257 gl.wintitle('(save) '+ filename)
258 #
259 # Check results
260 #
261 if info <> ninfo:
262 print 'Sorry, format changed.'
263 print 'Wanted:',info
264 print 'Got :',ninfo
265 gl.wintitle(filename)
266 return
267 # print bitvec
268 if x*y*number <> len(data):
269 print 'Funny data length: wanted',x,'*',y,'*', number,'=',\
270 x*y*number,'got',len(data)
271 gl.wintitle(filename)
272 return
273 #
274 # Save
275 #
Jack Jansen09bf3e31993-02-24 16:08:21 +0000276 if filename and audiofilename:
277 audiostop.append(None)
278 audiodone.acquire_lock()
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000279 if filename:
280 #
281 # Construct header and write it
282 #
Guido van Rossum852cc221993-02-15 17:33:36 +0000283 try:
284 vout = VFile.VoutFile().init(filename)
285 except IOError, msg:
286 print filename, ':', msg
287 sys.exit(1)
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000288 if mono:
289 vout.format = 'mono'
290 elif grey and greybits == 8:
291 vout.format = 'grey'
292 elif grey:
293 vout.format = 'grey'+`abs(greybits)`
294 else:
295 vout.format = 'rgb8'
296 vout.width = x
297 vout.height = y
298 if fields:
299 vout.packfactor = (1,-2)
300 else:
301 print 'Sorry, can only save fields at the moment'
Guido van Rossum3f2ef091993-02-05 15:34:22 +0000302 print '(i.e. you *must* use the -f option)'
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000303 gl.wintitle(filename)
304 return
305 vout.writeheader()
306 #
307 # Compute convertor, if needed
308 #
309 convertor = None
310 if grey:
311 if greybits == 2:
312 convertor = imageop.grey2grey2
313 elif greybits == 4:
314 convertor = imageop.grey2grey4
315 elif greybits == -2:
316 convertor = imageop.dither2grey2
317 fieldsize = x*y/2
318 nskipped = 0
319 realframeno = 0
320 tpf = 1000 / 50.0 #XXXX
321 for frameno in range(0, number*2):
322 if frameno <> 0 and \
323 bitvec[frameno] == bitvec[frameno-1]:
324 nskipped = nskipped + 1
325 continue
326 #
327 # Save field.
328 # XXXX Works only for fields and top-to-bottom
329 #
330 start = frameno*fieldsize
331 field = data[start:start+fieldsize]
332 if convertor:
Guido van Rossum852cc221993-02-15 17:33:36 +0000333 field = convertor(field, len(field), 1)
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000334 elif mono and monotreshold >= 0:
Guido van Rossum852cc221993-02-15 17:33:36 +0000335 field = imageop.grey2mono( \
336 field, len(field), 1, monotreshold)
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000337 elif mono:
Guido van Rossum852cc221993-02-15 17:33:36 +0000338 field = imageop.dither2mono( \
339 field, len(field), 1)
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000340 vout.writeframe(int(realframeno*tpf), field, None)
Guido van Rossum852cc221993-02-15 17:33:36 +0000341 realframeno = realframeno + 1
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000342 print 'Skipped',nskipped,'duplicate frames'
343 vout.close()
344
345 gl.wintitle('(done) ' + filename)
Jack Jansen09bf3e31993-02-24 16:08:21 +0000346# Initialize audio recording
347
348AQSIZE = 8*8000 # XXX should be a user option
349
350def initaudio(filename, stop, start, done):
351 import thread, aiff
352 afile = aiff.Aiff().init(filename, 'w')
353 afile.nchannels = AL.MONO
354 afile.sampwidth = AL.SAMPLE_8
355 params = [AL.INPUT_RATE, 0]
356 al.getparams(AL.DEFAULT_DEVICE, params)
357 print 'audio sampling rate =', params[1]
358 afile.samprate = params[1]
359 c = al.newconfig()
360 c.setchannels(AL.MONO)
361 c.setqueuesize(AQSIZE)
362 c.setwidth(AL.SAMPLE_8)
363 aport = al.openport(filename, 'r', c)
364 thread.start_new_thread(audiorecord, (afile, aport, stop, start, done))
365
366
367# Thread to record audio samples
368
369# XXX should use writesampsraw for efficiency, but then destroy doesn't
370# XXX seem to set the #samples in the header correctly
371
372def audiorecord(afile, aport, stop, start, done):
373 start.release_lock()
374 leeway = 4
375 while leeway > 0:
376 if stop:
377 leeway = leeway - 1
378 data = aport.readsamps(AQSIZE/8)
379## afile.writesampsraw(data)
380 afile.writesamps(data)
381 del data
382 afile.destroy()
383 print 'Done writing audio'
384 done.release_lock()
385
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000386
387# Don't forget to call the main program
388
389try:
390 main()
391except KeyboardInterrupt:
392 print '[Interrupt]'