blob: 43a5ddf3a706f063613c4187cb995e245371af57 [file] [log] [blame]
Guido van Rossum6e0e6681992-12-23 15:41:38 +00001#! /ufs/guido/bin/sgi/python-405
2#! /ufs/guido/bin/sgi/python
3
Guido van Rossum3f2ef091993-02-05 15:34:22 +00004# Capture a CMIF movie using the Indigo video library and board in burst mode
Guido van Rossum6e0e6681992-12-23 15:41:38 +00005
6
7# User interface:
8#
9# Start the application. Resize the window to the desired movie size.
10# Press the left mouse button to start recording, release it to end
11# recording. You can record as many times as you wish, but each time
12# you overwrite the output file(s), so only the last recording is
13# kept.
14#
15# Press ESC or select the window manager Quit or Close window option
16# to quit. If you quit before recording anything, the output file(s)
17# are not touched.
18
19
20import sys
21sys.path.append('/ufs/guido/src/video')
22import sv, SV
23import VFile
24import gl, GL, DEVICE
25import al, AL
26import time
27import posix
28import getopt
29import string
30import imageop
31import sgi
32
Guido van Rossum3f2ef091993-02-05 15:34:22 +000033
34# Usage and help functions (keep this up-to-date if you change the program!)
35
36def usage():
Jack Jansen09bf3e31993-02-24 16:08:21 +000037 print 'Usage: Vrecb [options] [moviefile [audiofile]]'
Guido van Rossum3f2ef091993-02-05 15:34:22 +000038 print
39 print 'Options:'
Jack Jansen09bf3e31993-02-24 16:08:21 +000040 print '-a : record audio as well'
Guido van Rossum3f2ef091993-02-05 15:34:22 +000041 print '-r rate : capture 1 out of every "rate" frames', \
42 '(default and min 1)'
43 print '-w width : initial window width', \
44 '(default interactive placement)'
45 print '-d : drop fields if needed'
46 print '-g bits : greyscale (2, 4 or 8 bits)'
47 print '-G : 2-bit greyscale dithered'
48 print '-m : monochrome dithered'
49 print '-M value : monochrome tresholded with value'
50 print '-f : Capture fields (instead of frames)'
51 print '-n number : Capture this many frames (default 60)'
52 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
72 width = 0
73 drop = 0
74 mono = 0
75 grey = 0
76 greybits = 0
77 monotreshold = -1
78 fields = 0
79 number = 60
80
Guido van Rossum3f2ef091993-02-05 15:34:22 +000081 try:
Jack Jansen09bf3e31993-02-24 16:08:21 +000082 opts, args = getopt.getopt(sys.argv[1:], 'ar:w:dg:mM:Gfn:')
Guido van Rossum3f2ef091993-02-05 15:34:22 +000083 except getopt.error, msg:
84 sys.stdout = sys.stderr
85 print 'Error:', msg, '\n'
86 usage()
87 sys.exit(2)
88
89 try:
90 for opt, arg in opts:
Jack Jansen09bf3e31993-02-24 16:08:21 +000091 if opt == '-a':
92 audio = 1
Guido van Rossum3f2ef091993-02-05 15:34:22 +000093 if opt == '-r':
94 rate = string.atoi(arg)
95 if rate < 1:
96 sys.stderr.write('-r rate must be >= 1\n')
97 sys.exit(2)
98 elif opt == '-w':
99 width = string.atoi(arg)
100 elif opt == '-d':
101 drop = 1
102 elif opt == '-g':
103 grey = 1
104 greybits = string.atoi(arg)
105 if not greybits in (2,4,8):
106 sys.stderr.write( \
107 'Only 2, 4 or 8 bit greyscale supported\n')
108 sys.exit(2)
109 elif opt == '-G':
110 grey = 1
111 greybits = -2
112 elif opt == '-m':
113 mono = 1
114 elif opt == '-M':
115 mono = 1
116 monotreshold = string.atoi(arg)
117 elif opt == '-f':
118 fields = 1
119 elif opt == '-n':
120 number = string.atoi(arg)
121 except string.atoi_error:
122 sys.stdout = sys.stderr
123 print 'Option', opt, 'requires integer argument'
124 sys.exit(2)
125
126 if not fields:
Jack Jansen09bf3e31993-02-24 16:08:21 +0000127 print '-f option assumed until somebody fixes it'
Guido van Rossum3f2ef091993-02-05 15:34:22 +0000128 fields = 1
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000129
130 if args[2:]:
Jack Jansen09bf3e31993-02-24 16:08:21 +0000131 sys.stderr.write('usage: Vrecb [options] [file [audiofile]]\n')
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000132 sys.exit(2)
133
134 if args:
135 filename = args[0]
136 else:
137 filename = 'film.video'
138
Jack Jansen09bf3e31993-02-24 16:08:21 +0000139 if args[1:] and not audio:
140 sys.stderr.write('-a turned on by appearance of 2nd file\n')
141 audio = 1
142
143 if audio:
144 if args[1:]:
145 audiofilename = args[1]
146 else:
147 audiofilename = 'film.aiff'
148 else:
149 audiofilename = None
150
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000151 v = sv.OpenVideo()
152 # Determine maximum window size based on signal standard
153 param = [SV.BROADCAST, 0]
154 v.GetParam(param)
155 if param[1] == SV.PAL:
156 x = SV.PAL_XMAX
157 y = SV.PAL_YMAX
158 elif param[1] == SV.NTSC:
159 x = SV.NTSC_XMAX
160 y = SV.NTSC_YMAX
161 else:
162 print 'Unknown video standard', param[1]
163 sys.exit(1)
164
165 gl.foreground()
166 gl.maxsize(x, y)
167 gl.keepaspect(x, y)
168 gl.stepunit(8, 6)
169 if width:
170 gl.prefsize(width, width*3/4)
171 win = gl.winopen(filename)
172 if width:
173 gl.maxsize(x, y)
174 gl.keepaspect(x, y)
175 gl.stepunit(8, 6)
176 gl.winconstraints()
177 x, y = gl.getsize()
178 print x, 'x', y
179
180 v.SetSize(x, y)
181
182 if drop:
183 param = [SV.FIELDDROP, 1, SV.GENLOCK, SV.GENLOCK_OFF]
184 else:
185 param = [SV.FIELDDROP, 0, SV.GENLOCK, SV.GENLOCK_ON]
186 if mono or grey:
187 param = param+[SV.COLOR, SV.MONO, SV.INPUT_BYPASS, 1]
188 else:
189 param = param+[SV.COLOR, SV.DEFAULT_COLOR, SV.INPUT_BYPASS, 0]
190 v.SetParam(param)
191
192 v.BindGLWindow(win, SV.IN_REPLACE)
193
194 gl.qdevice(DEVICE.LEFTMOUSE)
195 gl.qdevice(DEVICE.WINQUIT)
196 gl.qdevice(DEVICE.WINSHUT)
197 gl.qdevice(DEVICE.ESCKEY)
198
Guido van Rossum3f2ef091993-02-05 15:34:22 +0000199 help()
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000200
201 while 1:
202 dev, val = gl.qread()
203 if dev == DEVICE.LEFTMOUSE:
204 if val == 1:
205 info = format, x, y, number, rate
Jack Jansen09bf3e31993-02-24 16:08:21 +0000206 record(v, info, filename, audiofilename, \
207 mono, grey, \
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000208 greybits, monotreshold, fields)
209 elif dev == DEVICE.REDRAW:
210 # Window resize (or move)
211 x, y = gl.getsize()
212 print x, 'x', y
213 v.SetSize(x, y)
214 v.BindGLWindow(win, SV.IN_REPLACE)
215 elif dev in (DEVICE.ESCKEY, DEVICE.WINQUIT, DEVICE.WINSHUT):
216 # Quit
217 v.CloseVideo()
218 gl.winclose(win)
219 break
220
221
222# Record until the mouse is released (or any other GL event)
223# XXX audio not yet supported
224
Jack Jansen09bf3e31993-02-24 16:08:21 +0000225def record(v, info, filename, audiofilename, \
226 mono, grey, greybits, monotreshold, fields):
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000227 import thread
228 format, x, y, number, rate = info
229 fps = 59.64 # Fields per second
230 # XXX (Strange: need fps of Indigo monitor, not of PAL or NTSC!)
231 tpf = 1000.0 / fps # Time per field in msec
232 #
233 # Go grab
234 #
Jack Jansen09bf3e31993-02-24 16:08:21 +0000235 if audiofilename:
236 gl.wintitle('(start audio) ' + filename)
237 audiodone = thread.allocate_lock()
238 audiodone.acquire_lock()
239 audiostart = thread.allocate_lock()
240 audiostart.acquire_lock()
241 audiostop = []
242 initaudio(audiofilename, audiostop, audiostart, audiodone)
243 audiostart.acquire_lock()
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000244 gl.wintitle('(rec) ' + filename)
245 try:
246 ninfo, data, bitvec = v.CaptureBurst(info)
247 except sv.error, arg:
248 print 'CaptureBurst failed:', arg
249 print 'info:', info
250 gl.wintitle(filename)
251 return
252 gl.wintitle('(save) '+ filename)
253 #
254 # Check results
255 #
256 if info <> ninfo:
257 print 'Sorry, format changed.'
258 print 'Wanted:',info
259 print 'Got :',ninfo
260 gl.wintitle(filename)
261 return
262 # print bitvec
263 if x*y*number <> len(data):
264 print 'Funny data length: wanted',x,'*',y,'*', number,'=',\
265 x*y*number,'got',len(data)
266 gl.wintitle(filename)
267 return
268 #
269 # Save
270 #
Jack Jansen09bf3e31993-02-24 16:08:21 +0000271 if filename and audiofilename:
272 audiostop.append(None)
273 audiodone.acquire_lock()
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000274 if filename:
275 #
276 # Construct header and write it
277 #
Guido van Rossum852cc221993-02-15 17:33:36 +0000278 try:
279 vout = VFile.VoutFile().init(filename)
280 except IOError, msg:
281 print filename, ':', msg
282 sys.exit(1)
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000283 if mono:
284 vout.format = 'mono'
285 elif grey and greybits == 8:
286 vout.format = 'grey'
287 elif grey:
288 vout.format = 'grey'+`abs(greybits)`
289 else:
290 vout.format = 'rgb8'
291 vout.width = x
292 vout.height = y
293 if fields:
294 vout.packfactor = (1,-2)
295 else:
296 print 'Sorry, can only save fields at the moment'
Guido van Rossum3f2ef091993-02-05 15:34:22 +0000297 print '(i.e. you *must* use the -f option)'
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000298 gl.wintitle(filename)
299 return
300 vout.writeheader()
301 #
302 # Compute convertor, if needed
303 #
304 convertor = None
305 if grey:
306 if greybits == 2:
307 convertor = imageop.grey2grey2
308 elif greybits == 4:
309 convertor = imageop.grey2grey4
310 elif greybits == -2:
311 convertor = imageop.dither2grey2
312 fieldsize = x*y/2
313 nskipped = 0
314 realframeno = 0
315 tpf = 1000 / 50.0 #XXXX
316 for frameno in range(0, number*2):
317 if frameno <> 0 and \
318 bitvec[frameno] == bitvec[frameno-1]:
319 nskipped = nskipped + 1
320 continue
321 #
322 # Save field.
323 # XXXX Works only for fields and top-to-bottom
324 #
325 start = frameno*fieldsize
326 field = data[start:start+fieldsize]
327 if convertor:
Guido van Rossum852cc221993-02-15 17:33:36 +0000328 field = convertor(field, len(field), 1)
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000329 elif mono and monotreshold >= 0:
Guido van Rossum852cc221993-02-15 17:33:36 +0000330 field = imageop.grey2mono( \
331 field, len(field), 1, monotreshold)
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000332 elif mono:
Guido van Rossum852cc221993-02-15 17:33:36 +0000333 field = imageop.dither2mono( \
334 field, len(field), 1)
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000335 vout.writeframe(int(realframeno*tpf), field, None)
Guido van Rossum852cc221993-02-15 17:33:36 +0000336 realframeno = realframeno + 1
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000337 print 'Skipped',nskipped,'duplicate frames'
338 vout.close()
339
340 gl.wintitle('(done) ' + filename)
Jack Jansen09bf3e31993-02-24 16:08:21 +0000341# Initialize audio recording
342
343AQSIZE = 8*8000 # XXX should be a user option
344
345def initaudio(filename, stop, start, done):
346 import thread, aiff
347 afile = aiff.Aiff().init(filename, 'w')
348 afile.nchannels = AL.MONO
349 afile.sampwidth = AL.SAMPLE_8
350 params = [AL.INPUT_RATE, 0]
351 al.getparams(AL.DEFAULT_DEVICE, params)
352 print 'audio sampling rate =', params[1]
353 afile.samprate = params[1]
354 c = al.newconfig()
355 c.setchannels(AL.MONO)
356 c.setqueuesize(AQSIZE)
357 c.setwidth(AL.SAMPLE_8)
358 aport = al.openport(filename, 'r', c)
359 thread.start_new_thread(audiorecord, (afile, aport, stop, start, done))
360
361
362# Thread to record audio samples
363
364# XXX should use writesampsraw for efficiency, but then destroy doesn't
365# XXX seem to set the #samples in the header correctly
366
367def audiorecord(afile, aport, stop, start, done):
368 start.release_lock()
369 leeway = 4
370 while leeway > 0:
371 if stop:
372 leeway = leeway - 1
373 data = aport.readsamps(AQSIZE/8)
374## afile.writesampsraw(data)
375 afile.writesamps(data)
376 del data
377 afile.destroy()
378 print 'Done writing audio'
379 done.release_lock()
380
Guido van Rossum6e0e6681992-12-23 15:41:38 +0000381
382# Don't forget to call the main program
383
384try:
385 main()
386except KeyboardInterrupt:
387 print '[Interrupt]'