blob: e90a4bd030daf08af7d6a76e9a55305fb4fa35dc [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', \
23 '(default interactive placement)'
24 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:
187 gl.prefsize(width, width*3/4)
Guido van Rossum180924d1992-08-20 11:46:28 +0000188 win = gl.winopen(filename)
Guido van Rossum32517f91992-09-04 13:26:59 +0000189 if width:
190 gl.maxsize(x, y)
191 gl.keepaspect(x, y)
192 gl.stepunit(8, 6)
193 gl.winconstraints()
Guido van Rossum180924d1992-08-20 11:46:28 +0000194 x, y = gl.getsize()
195 print x, 'x', y
196
Guido van Rossum180924d1992-08-20 11:46:28 +0000197 v.SetSize(x, y)
Jack Jansen3b253711992-12-14 12:25:21 +0000198
199 if drop:
200 param = [SV.FIELDDROP, 1, SV.GENLOCK, SV.GENLOCK_OFF]
201 else:
202 param = [SV.FIELDDROP, 0, SV.GENLOCK, SV.GENLOCK_ON]
203 if mono or grey:
204 param = param+[SV.COLOR, SV.MONO, SV.INPUT_BYPASS, 1]
205 else:
206 param = param+[SV.COLOR, SV.DEFAULT_COLOR, SV.INPUT_BYPASS, 0]
207 v.SetParam(param)
Guido van Rossumff3da051992-12-09 22:16:35 +0000208
Guido van Rossum180924d1992-08-20 11:46:28 +0000209 v.BindGLWindow(win, SV.IN_REPLACE)
210
Guido van Rossum180924d1992-08-20 11:46:28 +0000211 gl.qdevice(DEVICE.LEFTMOUSE)
212 gl.qdevice(DEVICE.WINQUIT)
213 gl.qdevice(DEVICE.WINSHUT)
214 gl.qdevice(DEVICE.ESCKEY)
215
Guido van Rossumec706ad1992-12-24 11:39:00 +0000216 help()
Guido van Rossum180924d1992-08-20 11:46:28 +0000217
Guido van Rossum180924d1992-08-20 11:46:28 +0000218 while 1:
219 dev, val = gl.qread()
220 if dev == DEVICE.LEFTMOUSE:
221 if val == 1:
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000222 info = format, x, y, qsize, rate
Jack Jansen3b253711992-12-14 12:25:21 +0000223 record(v, info, filename, audiofilename,\
Jack Jansen6bc8c7f1992-12-23 15:37:20 +0000224 mono, grey, greybits, monotreshold, \
225 fields, preallocspace)
Guido van Rossum180924d1992-08-20 11:46:28 +0000226 elif dev == DEVICE.REDRAW:
227 # Window resize (or move)
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000228 x, y = gl.getsize()
229 print x, 'x', y
230 v.SetSize(x, y)
231 v.BindGLWindow(win, SV.IN_REPLACE)
Guido van Rossum180924d1992-08-20 11:46:28 +0000232 elif dev in (DEVICE.ESCKEY, DEVICE.WINQUIT, DEVICE.WINSHUT):
233 # Quit
Guido van Rossum180924d1992-08-20 11:46:28 +0000234 v.CloseVideo()
235 gl.winclose(win)
236 break
237
238
239# Record until the mouse is released (or any other GL event)
240# XXX audio not yet supported
241
Jack Jansen6bc8c7f1992-12-23 15:37:20 +0000242def record(v, info, filename, audiofilename, mono, grey, greybits, \
243 monotreshold, fields, preallocspace):
Guido van Rossum180924d1992-08-20 11:46:28 +0000244 import thread
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000245 format, x, y, qsize, rate = info
246 fps = 59.64 # Fields per second
247 # XXX (Strange: need fps of Indigo monitor, not of PAL or NTSC!)
248 tpf = 1000.0 / fps # Time per field in msec
Jack Jansen3b253711992-12-14 12:25:21 +0000249 if filename:
250 vout = VFile.VoutFile().init(filename)
251 if mono:
252 vout.format = 'mono'
Jack Jansen6bc8c7f1992-12-23 15:37:20 +0000253 elif grey and greybits == 8:
Jack Jansen3b253711992-12-14 12:25:21 +0000254 vout.format = 'grey'
Jack Jansen6bc8c7f1992-12-23 15:37:20 +0000255 elif grey:
256 vout.format = 'grey'+`abs(greybits)`
Jack Jansen3b253711992-12-14 12:25:21 +0000257 else:
258 vout.format = 'rgb8'
259 vout.width = x
260 vout.height = y
Jack Jansen6bc8c7f1992-12-23 15:37:20 +0000261 if fields:
262 vout.packfactor = (1,-2)
Jack Jansen3b253711992-12-14 12:25:21 +0000263 vout.writeheader()
Jack Jansen6bc8c7f1992-12-23 15:37:20 +0000264 if preallocspace:
265 print 'Preallocating space...'
266 vout.prealloc(preallocspace)
267 print 'done.'
Jack Jansen3b253711992-12-14 12:25:21 +0000268 MAXSIZE = 20 # XXX should be a user option
269 import Queue
270 queue = Queue.Queue().init(MAXSIZE)
271 done = thread.allocate_lock()
272 done.acquire_lock()
Jack Jansen6bc8c7f1992-12-23 15:37:20 +0000273 convertor = None
274 if grey:
275 if greybits == 2:
276 convertor = imageop.grey2grey2
277 elif greybits == 4:
278 convertor = imageop.grey2grey4
279 elif greybits == -2:
280 convertor = imageop.dither2grey2
Jack Jansen3b253711992-12-14 12:25:21 +0000281 thread.start_new_thread(saveframes, \
Jack Jansen6bc8c7f1992-12-23 15:37:20 +0000282 (vout, queue, done, mono, monotreshold, convertor))
Jack Jansen3b253711992-12-14 12:25:21 +0000283 if audiofilename:
284 audiodone = thread.allocate_lock()
285 audiodone.acquire_lock()
286 audiostop = []
287 initaudio(audiofilename, audiostop, audiodone)
Guido van Rossum180924d1992-08-20 11:46:28 +0000288 gl.wintitle('(rec) ' + filename)
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000289 lastid = 0
Guido van Rossum180924d1992-08-20 11:46:28 +0000290 t0 = time.millitimer()
Jack Jansen3b253711992-12-14 12:25:21 +0000291 count = 0
Jack Jansen3b253711992-12-14 12:25:21 +0000292 ids = []
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000293 v.InitContinuousCapture(info)
Guido van Rossum180924d1992-08-20 11:46:28 +0000294 while not gl.qtest():
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000295 try:
296 cd, id = v.GetCaptureData()
Guido van Rossum42e07af1992-09-22 15:01:43 +0000297 except sv.error:
Jack Jansen6bc8c7f1992-12-23 15:37:20 +0000298 #time.millisleep(10) # XXX is this necessary?
299 sgi.nap(1) # XXX Try by Jack
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000300 continue
Jack Jansen3b253711992-12-14 12:25:21 +0000301 ids.append(id)
302
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000303 id = id + 2*rate
304## if id <> lastid + 2*rate:
305## print lastid, id
306 lastid = id
Jack Jansen3b253711992-12-14 12:25:21 +0000307 count = count+1
Jack Jansen6bc8c7f1992-12-23 15:37:20 +0000308 if fields:
309 data1, data2 = cd.GetFields()
310 cd.UnlockCaptureData()
311 if filename:
312 queue.put((data1, int(id*tpf)))
313 queue.put((data2, int((id+1)*tpf)))
314 else:
315 data = cd.InterleaveFields(1)
316 cd.UnlockCaptureData()
317 if filename:
318 queue.put((data, int(id*tpf)))
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000319 t1 = time.millitimer()
320 gl.wintitle('(busy) ' + filename)
321 print lastid, 'fields in', t1-t0, 'msec',
322 print '--', 0.1 * int(lastid * 10000.0 / (t1-t0)), 'fields/sec'
Guido van Rossum9533ebe1992-12-14 12:29:43 +0000323 print 'Captured',count*2, 'fields,',
324 print 0.1*int(count*20000.0/(t1-t0)), 'f/s',
325 if lastid:
326 print count*200.0/lastid, '%,',
327 print count*rate*200.0/lastid, '% of wanted rate',
328 print
Guido van Rossum852cc221993-02-15 17:33:36 +0000329 if ids:
330 print 'Ids:',
331 t0 = ids[0]
332 del ids[0]
333 for t1 in ids:
334 print t1-t0,
335 t0 = t1
336 print
Jack Jansen3b253711992-12-14 12:25:21 +0000337 if filename and audiofilename:
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000338 audiostop.append(None)
339 audiodone.acquire_lock()
340 v.EndContinuousCapture()
Jack Jansen3b253711992-12-14 12:25:21 +0000341 if filename:
342 queue.put(None) # Sentinel
343 done.acquire_lock()
Guido van Rossum180924d1992-08-20 11:46:28 +0000344 gl.wintitle('(done) ' + filename)
345
346
347# Thread to save the frames to the file
348
Jack Jansen6bc8c7f1992-12-23 15:37:20 +0000349def saveframes(vout, queue, done, mono, monotreshold, convertor):
Guido van Rossum180924d1992-08-20 11:46:28 +0000350 while 1:
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000351 x = queue.get()
352 if not x:
353 break
354 data, t = x
Jack Jansen6bc8c7f1992-12-23 15:37:20 +0000355 if convertor:
356 data = convertor(data, len(data), 1)
357 elif mono and monotreshold >= 0:
Jack Jansen3b253711992-12-14 12:25:21 +0000358 data = imageop.grey2mono(data, len(data), 1,\
359 monotreshold)
360 elif mono:
361 data = imageop.dither2mono(data, len(data), 1)
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000362 vout.writeframe(t, data, None)
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000363 sys.stderr.write('Done writing video\n')
Guido van Rossum180924d1992-08-20 11:46:28 +0000364 vout.close()
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000365 done.release_lock()
Guido van Rossum180924d1992-08-20 11:46:28 +0000366
367
Guido van Rossum8a861be1992-08-20 14:46:46 +0000368# Initialize audio recording
369
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000370AQSIZE = 8000 # XXX should be a user option
Guido van Rossum8a861be1992-08-20 14:46:46 +0000371
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000372def initaudio(filename, stop, done):
Guido van Rossum8a861be1992-08-20 14:46:46 +0000373 import thread, aiff
374 afile = aiff.Aiff().init(filename, 'w')
375 afile.nchannels = AL.MONO
376 afile.sampwidth = AL.SAMPLE_8
377 params = [AL.INPUT_RATE, 0]
378 al.getparams(AL.DEFAULT_DEVICE, params)
379 print 'audio sampling rate =', params[1]
380 afile.samprate = params[1]
381 c = al.newconfig()
382 c.setchannels(AL.MONO)
383 c.setqueuesize(AQSIZE)
384 c.setwidth(AL.SAMPLE_8)
385 aport = al.openport(filename, 'r', c)
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000386 thread.start_new_thread(audiorecord, (afile, aport, stop, done))
Guido van Rossum8a861be1992-08-20 14:46:46 +0000387
388
389# Thread to record audio samples
390
391# XXX should use writesampsraw for efficiency, but then destroy doesn't
392# XXX seem to set the #samples in the header correctly
393
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000394def audiorecord(afile, aport, stop, done):
395 while not stop:
Guido van Rossum8a861be1992-08-20 14:46:46 +0000396 data = aport.readsamps(AQSIZE/2)
397## afile.writesampsraw(data)
398 afile.writesamps(data)
399 del data
400 afile.destroy()
401 print 'Done writing audio'
Guido van Rossum62f6bc81992-09-03 16:56:04 +0000402 done.release_lock()
Guido van Rossum8a861be1992-08-20 14:46:46 +0000403
404
Guido van Rossum180924d1992-08-20 11:46:28 +0000405# Don't forget to call the main program
406
Guido van Rossume0be2b31992-09-01 14:45:57 +0000407try:
408 main()
409except KeyboardInterrupt:
410 print '[Interrupt]'