2 #! /ufs/guido/bin/sgi/python-405
4 # Capture a CMIF movie using the Indigo video library and board
6 # 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
12 # Usage and help functions (keep this up-to-date if you change the program!)
15 print 'Usage: Vrec [options] [moviefile [audiofile]]'
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', \
22 print '-w width : initial window width', \
23 '(default 256, use 0 for 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 thresholded 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', \
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.'
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.'
50 sys
.path
.append('/ufs/guido/src/video')
66 format
= SV
.RGB8_FRAMES
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'
95 qsize
= string
.atoi(arg
)
97 rate
= string
.atoi(arg
)
100 '-r rate must be >= 2\n')
103 width
= string
.atoi(arg
)
110 greybits
= string
.atoi(arg
)
111 if not greybits
in (2, 4, 8):
113 'Only 2, 4 or 8 bit greyscale supported\n')
122 monotreshold
= string
.atoi(arg
)
126 preallocspace
= string
.atoi(arg
)
127 except string
.atoi_error
:
128 sys
.stdout
= sys
.stderr
129 print 'Option', opt
, 'requires integer argument'
132 # Check excess arguments
133 # If norecord is on, refuse filename arguments
136 sys
.stdout
= sys
.stderr
137 print 'With -n, no filename arguments are used\n'
141 sys
.stdout
= sys
.stderr
142 print 'Too many filename arguments\n'
146 # Process file arguments
150 filename
= 'film.video'
152 if args
[1:] and not audio
:
153 sys
.stderr
.write('-a turned on by appearance of 2nd file\n')
158 audiofilename
= args
[1]
160 audiofilename
= 'film.aiff'
165 filename
= audiofilename
= ''
169 # Determine maximum window size based on signal standard
170 param
= [SV
.BROADCAST
, 0]
172 if param
[1] == SV
.PAL
:
175 elif param
[1] == SV
.NTSC
:
179 print 'Unknown video standard', param
[1]
192 gl
.prefposition(x1
, x2
, y1
, y2
)
193 win
= gl
.winopen(filename
)
205 param
= [SV
.FIELDDROP
, 1, SV
.GENLOCK
, SV
.GENLOCK_OFF
]
207 param
= [SV
.FIELDDROP
, 0, SV
.GENLOCK
, SV
.GENLOCK_ON
]
209 param
= param
+[SV
.COLOR
, SV
.MONO
, SV
.DITHER
, 0, \
212 param
= param
+[SV
.COLOR
, SV
.DEFAULT_COLOR
, SV
.INPUT_BYPASS
, 0]
214 v
.BindGLWindow(win
, SV
.IN_REPLACE
)
217 gl
.qdevice(DEVICE
.LEFTMOUSE
)
218 gl
.qdevice(DEVICE
.WINQUIT
)
219 gl
.qdevice(DEVICE
.WINSHUT
)
220 gl
.qdevice(DEVICE
.ESCKEY
)
225 dev
, val
= gl
.qread()
226 if dev
== DEVICE
.LEFTMOUSE
:
228 info
= format
, x
, y
, qsize
, rate
229 record(v
, info
, filename
, audiofilename
,\
230 mono
, grey
, greybits
, monotreshold
, \
231 fields
, preallocspace
)
232 elif dev
== DEVICE
.REDRAW
:
233 # Window resize (or move)
237 v
.BindGLWindow(win
, SV
.IN_REPLACE
)
238 elif dev
in (DEVICE
.ESCKEY
, DEVICE
.WINQUIT
, DEVICE
.WINSHUT
):
245 # Record until the mouse is released (or any other GL event)
246 # XXX audio not yet supported
248 def record(v
, info
, filename
, audiofilename
, mono
, grey
, greybits
, \
249 monotreshold
, fields
, preallocspace
):
251 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
256 vout
= VFile
.VoutFile(filename
)
259 elif grey
and greybits
== 8:
262 format
= 'grey'+`
abs(greybits
)`
265 vout
.setformat(format
)
271 print 'Preallocating space...'
272 vout
.prealloc(preallocspace
)
274 MAXSIZE
= 20 # XXX should be a user option
276 queue
= Queue
.Queue(MAXSIZE
)
277 done
= thread
.allocate_lock()
282 convertor
= imageop
.grey2grey2
284 convertor
= imageop
.grey2grey4
286 convertor
= imageop
.dither2grey2
287 thread
.start_new_thread(saveframes
, \
288 (vout
, queue
, done
, mono
, monotreshold
, convertor
))
290 audiodone
= thread
.allocate_lock()
291 audiodone
.acquire_lock()
293 initaudio(audiofilename
, audiostop
, audiodone
)
294 gl
.wintitle('(rec) ' + filename
)
299 v
.InitContinuousCapture(info
)
300 while not gl
.qtest():
302 cd
, id = v
.GetCaptureData()
304 #time.sleep(0.010) # XXX is this necessary?
305 sgi
.nap(1) # XXX Try by Jack
310 ## if id <> lastid + 2*rate:
315 data1
, data2
= cd
.GetFields()
316 cd
.UnlockCaptureData()
318 queue
.put((data1
, int(id*tpf
)))
319 queue
.put((data2
, int((id+1)*tpf
)))
321 data
= cd
.InterleaveFields(1)
322 cd
.UnlockCaptureData()
324 queue
.put((data
, int(id*tpf
)))
326 gl
.wintitle('(busy) ' + filename
)
327 print lastid
, 'fields in', round(t1
-t0
, 3), 'sec',
328 print '--', round(lastid
/(t1
-t0
), 1), 'fields/sec'
329 print 'Captured',count
*2, 'fields,',
330 print round(count
*2/(t1
-t0
), 1), 'f/s',
333 print round(count
*200.0/lastid
), '%, or',
334 print round(count
*rate
*200.0/lastid
), '% of wanted rate )',
344 if filename
and audiofilename
:
345 audiostop
.append(None)
346 audiodone
.acquire_lock()
347 v
.EndContinuousCapture()
349 queue
.put(None) # Sentinel
351 gl
.wintitle('(done) ' + filename
)
354 # Thread to save the frames to the file
356 def saveframes(vout
, queue
, done
, mono
, monotreshold
, convertor
):
363 data
= convertor(data
, len(data
), 1)
364 elif mono
and monotreshold
>= 0:
365 data
= imageop
.grey2mono(data
, len(data
), 1,\
368 data
= imageop
.dither2mono(data
, len(data
), 1)
369 vout
.writeframe(t
, data
, None)
370 sys
.stderr
.write('Done writing video\n')
375 # Initialize audio recording
377 AQSIZE
= 8000 # XXX should be a user option
379 def initaudio(filename
, stop
, done
):
381 afile
= aifc
.open(filename
, 'w')
382 afile
.setnchannels(AL
.MONO
)
383 afile
.setsampwidth(AL
.SAMPLE_8
)
384 params
= [AL
.INPUT_RATE
, 0]
385 al
.getparams(AL
.DEFAULT_DEVICE
, params
)
386 print 'audio sampling rate =', params
[1]
387 afile
.setframerate(params
[1])
389 c
.setchannels(AL
.MONO
)
390 c
.setqueuesize(AQSIZE
)
391 c
.setwidth(AL
.SAMPLE_8
)
392 aport
= al
.openport(filename
, 'r', c
)
393 thread
.start_new_thread(audiorecord
, (afile
, aport
, stop
, done
))
396 # Thread to record audio samples
398 def audiorecord(afile
, aport
, stop
, done
):
400 data
= aport
.readsamps(AQSIZE
/2)
401 afile
.writesampsraw(data
)
404 print 'Done writing audio'
408 # Don't forget to call the main program
412 except KeyboardInterrupt: