Apparently the code to forestall Tk eating events was too aggressive (Tk user input...
[python/dscho.git] / Demo / sgi / video / Vb.py
blobe1b06d683666c7b510df639a9ea52d3ae6c21bb6
1 #! /usr/bin/env python
3 # Video bag of tricks: record video(+audio) in various formats and modes
5 # XXX To do:
6 # - audio
7 # - improve user interface
8 # - help button?
9 # - command line options to set initial settings
10 # - save settings in a file
11 # - ...?
13 import sys
14 import time
15 import getopt
16 import string
17 import os
18 sts = os.system('makemap') # Must be before "import fl" to work
19 import sgi
20 import gl
21 import GL
22 import DEVICE
23 import fl
24 import FL
25 import flp
26 import watchcursor
27 import sv
28 import SV
29 import VFile
30 import VGrabber
31 import imageop
32 sys.path.append('/ufs/jack/src/av/vcr')
33 import VCR
34 try:
35 import cl
36 except ImportError:
37 cl = None
39 ARROW = 0
40 WATCH = 1
41 watchcursor.defwatch(WATCH)
43 def main():
44 ## fl.set_graphics_mode(0, 1)
45 vb = VideoBagOfTricks()
46 while 1:
47 dummy = fl.do_forms()
48 [dummy]
50 StopCapture = 'StopCapture'
52 VideoFormatLabels = ['Video off', 'rgb8', 'grey8', 'grey4', 'grey2', \
53 'grey2 dith', 'mono dith', 'mono thresh', 'rgb24', 'rgb24-jpeg', \
54 'compress']
55 VideoFormats = ['', 'rgb8', 'grey', 'grey4', 'grey2', \
56 'grey2', 'mono', 'mono', 'rgb', 'jpeg', 'compress']
58 VideoModeLabels = ['Continuous', 'Burst', 'Single frame', 'VCR sync']
59 [VM_CONT, VM_BURST, VM_SINGLE, VM_VCR] = range(1, 5)
61 AudioFormatLabels = ['Audio off', \
62 '16 bit mono', '16 bit stereo', '8 bit mono', '8 bit stereo']
63 [A_OFF, A_16_MONO, A_16_STEREO, A_8_MONO, A_8_STEREO] = range(1, 6)
65 VcrSpeedLabels = ['normal', '1/3', '1/5', '1/10', '1/30', 'single-step']
66 VcrSpeeds = [None, 5, 4, 3, 2, 1, 0]
68 RgbSizeLabels = ['full', 'quarter', 'sixteenth']
70 # init file stuff:
71 if os.environ.has_key('HOME'):
72 HOME=os.environ['HOME']
73 else:
74 HOME='.'
75 VB_INIT_FILE=HOME + '/.Vb_init'
77 VB_INIT_KEYS=['vfile', 'vmode', 'mono_thresh', 'vformat', 'comp_scheme', \
78 'rgb24_size', 'afile', 'aformat']
80 class VideoBagOfTricks:
82 # Init/close stuff
84 def __init__(self):
85 self.window = None
86 formdef = flp.parse_form('VbForm', 'form')
87 flp.create_full_form(self, formdef)
88 self.setdefaults()
89 if self.vmode <> VM_CONT:
90 self.g_cont.hide_object()
91 if self.vmode <> VM_BURST:
92 self.g_burst.hide_object()
93 if self.vmode <> VM_SINGLE:
94 self.g_single.hide_object()
95 if self.vmode <> VM_VCR:
96 self.g_vcr.hide_object()
97 if self.vformat <> 'compress':
98 self.g_compress.hide_object()
100 self.openvideo()
101 self.makewindow()
102 self.bindvideo()
103 if self.use_24:
104 self.optfullsizewindow()
105 self.showform()
106 fl.set_event_call_back(self.do_event)
108 def close(self):
109 self.close_video()
110 self.close_audio()
111 self.savedefaults()
112 raise SystemExit, 0
114 def showform(self):
115 # Get position of video window
116 gl.winset(self.window)
117 x, y = gl.getorigin()
118 width, height = gl.getsize()
119 # Calculate position of form window
120 x1 = x + width + 10
121 x2 = x1 + int(self.form.w) - 1
122 y2 = y + height - 1
123 y1 = y2 - int(self.form.h) + 1
124 # Position and show form window
125 gl.prefposition(x1, x2, y1, y2)
126 self.form.show_form(FL.PLACE_FREE, FL.TRUE, 'Vb Control')
128 def getdefaultdefaults(self):
129 # Video defaults
130 self.vfile = 'film.video'
131 self.vmode = VM_CONT
132 self.mono_thresh = 128
133 self.vformat = 'rgb8'
134 self.comp_scheme = 'Uncompressed'
135 self.rgb24_size = 1
136 # Missing: drop, rate, maxmem, nframes, rate, vcrspeed
137 # Audio defaults:
138 self.afile = 'film.aiff'
139 self.aformat = A_OFF
141 def getdefaults(self):
142 self.getdefaultdefaults()
143 # XXXX Read defaults file and override.
144 try:
145 fp = open(VB_INIT_FILE, 'r')
146 except IOError:
147 print 'Vb: no init file'
148 self.initcont = {}
149 return
150 data = fp.read(1000000)
151 try:
152 self.initcont = eval(data)
153 except:
154 print 'Vb: Ill-formatted init file'
155 self.initcont = {}
156 for k in self.initcont.keys():
157 if hasattr(self, k):
158 setattr(self, k, self.initcont[k])
160 def savedefaults(self):
161 newdb = {}
162 for k in VB_INIT_KEYS:
163 newdb[k] = getattr(self, k)
164 if newdb <> self.initcont:
165 try:
166 fp = open(VB_INIT_FILE, 'w')
167 except IOError:
168 print 'Vb: Cannot create', VB_INIT_FILE
169 return
170 fp.write(`newdb`)
171 fp.close()
173 def setdefaults(self):
174 self.getdefaults()
175 self.vcr = None
176 self.vout = None
177 self.capturing = 0
178 self.c_vformat.clear_choice()
179 for label in VideoFormatLabels:
180 self.c_vformat.addto_choice(label)
181 self.c_vformat.set_choice(1 + VideoFormats.index(self.vformat))
182 self.c_vmode.clear_choice()
183 for label in VideoModeLabels:
184 self.c_vmode.addto_choice(label)
185 self.c_vmode.set_choice(self.vmode)
186 self.get_vformat()
187 self.b_drop.set_button(1)
188 self.in_rate.set_input('2')
189 self.in_maxmem.set_input('1.0')
190 self.in_nframes.set_input('0')
191 self.in_nframes_vcr.set_input('1')
192 self.in_rate_vcr.set_input('1')
193 self.c_vcrspeed.clear_choice()
194 for label in VcrSpeedLabels:
195 self.c_vcrspeed.addto_choice(label)
196 self.c_vcrspeed.set_choice(4)
197 self.c_rgb24_size.clear_choice()
198 for label in RgbSizeLabels:
199 self.c_rgb24_size.addto_choice(label)
200 self.c_rgb24_size.set_choice(self.rgb24_size)
201 if cl:
202 algs = cl.QueryAlgorithms(cl.VIDEO)
203 self.all_comp_schemes = []
204 for i in range(0, len(algs), 2):
205 if algs[i+1] in (cl.COMPRESSOR, cl.CODEC):
206 self.all_comp_schemes.append(algs[i])
207 self.c_cformat.clear_choice()
208 for label in self.all_comp_schemes:
209 self.c_cformat.addto_choice(label)
210 i = self.all_comp_schemes.index(self.comp_scheme)
211 self.c_cformat.set_choice(i+1)
212 # Audio defaults
213 self.aout = None
214 self.aport = None
215 self.c_aformat.clear_choice()
216 for label in AudioFormatLabels:
217 self.c_aformat.addto_choice(label)
218 self.c_aformat.set_choice(self.aformat)
219 self.get_aformat()
221 def openvideo(self):
222 try:
223 self.video = sv.OpenVideo()
224 except sv.error, msg:
225 print 'Error opening video:', msg
226 self.video = None
227 param = [SV.BROADCAST, SV.PAL]
228 if self.video: self.video.GetParam(param)
229 if param[1] == SV.PAL:
230 x = SV.PAL_XMAX
231 y = SV.PAL_YMAX
232 elif param[1] == SV.NTSC:
233 x = SV.NTSC_XMAX
234 y = SV.NTSC_YMAX
235 else:
236 print 'Unknown video standard:', param[1]
237 sys.exit(1)
238 self.maxx, self.maxy = x, y
239 self.curx = 256
240 self.cury = 256*3/4
242 def makewindow(self):
243 x, y = self.maxx, self.maxy
244 gl.foreground()
245 gl.maxsize(x, y)
246 gl.keepaspect(x, y)
247 gl.stepunit(8, 6)
248 width = self.curx
249 height = self.cury
250 if width and height:
251 # Place the window at (150, 150) from top left
252 # (the video board likes this location...)
253 x1 = 150
254 x2 = x1+width-1
255 SCRHEIGHT = 768
256 y2 = SCRHEIGHT-1-150
257 y1 = y2-height+1
258 gl.prefposition(x1, x2, y1, y2)
259 self.window = gl.winopen('Vb video')
260 self.settitle()
261 if width:
262 gl.maxsize(x, y)
263 gl.keepaspect(x, y)
264 gl.stepunit(8, 6)
265 gl.winconstraints()
266 gl.qdevice(DEVICE.LEFTMOUSE)
267 gl.qdevice(DEVICE.WINQUIT)
268 gl.qdevice(DEVICE.WINSHUT)
270 def optfullsizewindow(self):
271 if not self.window:
272 return
273 gl.winset(self.window)
274 if self.use_24:
275 x, y = self.maxx, self.maxy
276 else:
277 x, y = self.curx, self.cury
278 left, bottom = gl.getorigin()
279 width, height = gl.getsize()
280 bottom = bottom+height-y
281 gl.prefposition(left, left+x-1, bottom, bottom+y-1)
282 gl.winconstraints()
283 if not self.use_24:
284 gl.keepaspect(x, y)
285 gl.stepunit(8, 6)
286 gl.maxsize(self.maxx, self.maxy)
287 gl.winconstraints()
288 self.bindvideo()
290 def bindvideo(self):
291 if not self.video: return
292 x, y = gl.getsize()
293 if not self.use_24:
294 self.curx, self.cury = x, y
295 self.video.SetSize(x, y)
296 drop = self.b_drop.get_button()
297 if drop:
298 param = [SV.FIELDDROP, 1, SV.GENLOCK, SV.GENLOCK_OFF]
299 else:
300 param = [SV.FIELDDROP, 0, SV.GENLOCK, SV.GENLOCK_ON]
301 if self.rgb:
302 param = param+[SV.COLOR, SV.DEFAULT_COLOR, \
303 SV.DITHER, 1, \
304 SV.INPUT_BYPASS, 0]
305 else:
306 param = param+[SV.COLOR, SV.MONO, SV.DITHER, 0, \
307 SV.INPUT_BYPASS, 1]
308 self.video.BindGLWindow(self.window, SV.IN_REPLACE)
309 self.video.SetParam(param)
311 def rebindvideo(self):
312 gl.winset(self.window)
313 self.bindvideo()
315 def reset(self):
316 self.close_video()
317 self.close_audio()
318 if self.vcr:
319 try:
320 ok = self.vcr.still()
321 except VCR.error:
322 pass
323 self.vcr = None
324 self.b_capture.set_button(0)
326 # Event handler (catches resize of video window)
328 def do_event(self, dev, val):
329 #print 'Event:', dev, val
330 if dev in (DEVICE.WINSHUT, DEVICE.WINQUIT):
331 self.close()
332 if dev == DEVICE.REDRAW and val == self.window:
333 self.rebindvideo()
334 self.settitle()
336 # Video controls: format, mode, file
338 def cb_vformat(self, *args):
339 self.reset()
340 self.get_vformat()
341 if self.mono_use_thresh:
342 s = `self.mono_thresh`
343 s = fl.show_input('Please enter mono threshold', s)
344 if s:
345 try:
346 self.mono_thresh = string.atoi(s)
347 except string.atoi_error:
348 fl.show_message('Bad input, using', \
349 `self.mono_thresh`, '')
350 self.rebindvideo()
352 def cb_cformat(self, *args):
353 i = self.c_cformat.get_choice()
354 self.comp_scheme = self.all_comp_schemes[i-1]
357 def cb_vmode(self, *args):
358 if self.vcr:
359 self.vcr = None
360 self.vmode = self.c_vmode.get_choice()
361 self.form.freeze_form()
362 self.g_cont.hide_object()
363 self.g_burst.hide_object()
364 self.g_single.hide_object()
365 self.g_vcr.hide_object()
366 if self.vmode == VM_CONT:
367 self.g_cont.show_object()
368 elif self.vmode == VM_BURST:
369 self.g_burst.show_object()
370 elif self.vmode == VM_SINGLE:
371 self.g_single.show_object()
372 elif self.vmode == VM_VCR:
373 self.g_vcr.show_object()
374 self.form.unfreeze_form()
376 def cb_vfile(self, *args):
377 filename = self.vfile
378 hd, tl = os.path.split(filename)
379 filename = fl.file_selector('Video save file:', hd, '', tl)
380 if filename:
381 self.reset()
382 hd, tl = os.path.split(filename)
383 if hd == os.getcwd():
384 filename = tl
385 self.vfile = filename
387 # Video mode specific video controls
389 def cb_rate(self, *args):
390 pass
392 def cb_drop(self, *args):
393 self.rebindvideo()
395 def cb_maxmem(self, *args):
396 pass
398 def cb_nframes(self, *args):
399 pass
401 def cb_fps(self, *args):
402 pass
404 def cb_nframes_vcr(self, *args):
405 pass
407 def cb_rate_vcr(self, *args):
408 pass
410 def cb_vcrspeed(self, *args):
411 pass
413 def cb_rgb24_size(self, *args):
414 i = self.c_rgb24_size.get_choice()
415 if i:
416 self.rgb24_size = i
418 # Audio controls: format, file
420 def cb_aformat(self, *args):
421 self.get_aformat()
423 def cb_afile(self, *args):
424 filename = self.afile
425 hd, tl = os.path.split(filename)
426 filename = fl.file_selector('Audio save file:', hd, '', tl)
427 if filename:
428 self.reset()
429 hd, tl = os.path.split(filename)
430 if hd == os.getcwd():
431 filename = tl
432 self.afile = filename
434 # General controls: capture, reset, play, quit
436 def cb_capture(self, *args):
437 if self.capturing:
438 raise StopCapture
439 if not self.b_capture.get_button():
440 return
441 if not self.video or not self.vformat:
442 gl.ringbell()
443 return
444 if self.vmode == VM_CONT:
445 self.cont_capture()
446 elif self.vmode == VM_BURST:
447 self.burst_capture()
448 elif self.vmode == VM_SINGLE:
449 self.single_capture(None, None)
450 elif self.vmode == VM_VCR:
451 self.vcr_capture()
453 def cb_reset(self, *args):
454 self.reset()
456 def cb_play(self, *args):
457 self.reset()
458 sts = os.system('Vplay -q ' + self.vfile + ' &')
460 def cb_quit(self, *args):
461 self.close()
463 # Capture routines
465 def burst_capture(self):
466 self.setwatch()
467 gl.winset(self.window)
468 x, y = gl.getsize()
469 if self.use_24:
470 fl.show_message('Sorry, no 24 bit continuous capture yet', '', '')
471 return
472 vformat = SV.RGB8_FRAMES
473 nframes = self.getint(self.in_nframes, 0)
474 if nframes == 0:
475 maxmem = self.getint(self.in_maxmem, 1.0)
476 memsize = int(maxmem * 1024 * 1024)
477 nframes = self.calcnframes(memsize)
478 info = (vformat, x, y, nframes, 1)
479 try:
480 info2, data, bitvec = self.video.CaptureBurst(info)
481 except sv.error, msg:
482 self.b_capture.set_button(0)
483 self.setarrow()
484 fl.show_message('Capture error:', str(msg), '')
485 return
486 if info <> info2: print info, '<>', info2
487 self.save_burst(info2, data, bitvec)
488 self.setarrow()
490 def calcnframes(self, memsize):
491 gl.winset(self.window)
492 x, y = gl.getsize()
493 pixels = x*y
494 pixels = pixels/2 # XXX always assume fields
495 if self.mono or self.grey:
496 n = memsize/pixels
497 else:
498 n = memsize/(4*pixels)
499 return max(1, n)
501 def save_burst(self, info, data, bitvec):
502 (vformat, x, y, nframes, rate) = info
503 self.open_if_closed()
504 fieldsize = x*y/2
505 nskipped = 0
506 realframeno = 0
507 tpf = 1000 / 50.0 # XXX
508 for frameno in range(0, nframes*2):
509 if frameno <> 0 and \
510 bitvec[frameno] == bitvec[frameno-1]:
511 nskipped = nskipped + 1
512 continue
514 # Save field.
515 # XXX Works only for fields and top-to-bottom
517 start = frameno*fieldsize
518 field = data[start:start+fieldsize]
519 realframeno = realframeno + 1
520 fn = int(realframeno*tpf)
521 if not self.write_frame(fn, field):
522 break
524 def cont_capture(self):
525 saved_label = self.b_capture.label
526 self.b_capture.label = 'Stop\n' + saved_label
527 self.open_if_closed()
528 self.init_cont()
529 fps = 59.64 # Fields per second
530 # XXX (fps of Indigo monitor, not of PAL or NTSC!)
531 tpf = 1000.0 / fps # Time per field in msec
532 self.capturing = 1
533 self.start_audio()
534 while 1:
535 try:
536 void = fl.check_forms()
537 except StopCapture:
538 break
539 try:
540 cd, id = self.video.GetCaptureData()
541 except sv.error:
542 sgi.nap(1)
543 continue
544 id = id + 2*self.rate
545 data = cd.InterleaveFields(1)
546 cd.UnlockCaptureData()
547 t = id*tpf
548 if not self.write_frame(t, data):
549 break
550 self.stop_audio()
551 self.capturing = 0
552 self.end_cont()
553 if self.aout:
554 # If recording audio, can't capture multiple sequences
555 self.reset()
556 self.b_capture.label = saved_label
558 def single_capture(self, stepfunc, timecode):
559 self.open_if_closed()
560 self.init_cont()
561 while 1:
562 try:
563 cd, id = self.video.GetCaptureData()
564 break
565 except sv.error:
566 pass
567 sgi.nap(1)
568 if stepfunc: # This might step the video
569 d=stepfunc() # to the next frame
570 if not self.use_24:
571 data = cd.InterleaveFields(1)
572 else:
573 x, y = self.vout.getsize()
574 if self.use_compress:
575 if self.rgb24_size == 1:
576 data = cd.YUVtoYUV422DC(0)
577 elif self.rgb24_size == 2:
578 data = cd.YUVtoYUV422DC_quarter(1)
579 x = x/2
580 y = y/2
581 elif self.rgb24_size == 3:
582 data = cd.YUVtoYUV422DC_sixteenth(1)
583 x = x/4
584 y = y/4
585 else:
586 data = cd.YUVtoRGB(1)
587 if self.maxx*self.maxy*4 <> len(data):
588 print 'maxx,maxy,exp,got=', self.maxx,
589 print self.maxy,self.maxx*self.maxy*4,
590 print len(data)
591 fl.showmessage('Wrong sized data')
592 return 0
593 if self.rgb24_size <> 1:
594 data = imageop.scale(data, 4, \
595 self.maxx, self.maxy, x, y)
596 if self.use_jpeg:
597 import jpeg
598 data = jpeg.compress(data, x, y, 4)
599 if self.use_compress:
600 data = self.compressor.Compress(1, data)
601 cd.UnlockCaptureData()
602 self.end_cont()
603 if timecode == None:
604 timecode = (self.nframes+1) * (1000/25)
605 return self.write_frame(timecode, data)
607 def vcr_capture(self):
608 if not self.vcr:
609 try:
610 print 'Connecting to VCR ...'
611 self.vcr = VCR.VCR()
612 print 'Waiting for VCR to come online ...'
613 self.vcr.initvcr()
614 print 'Preparing VCR ...'
615 if not (self.vcr.fmmode('dnr') and \
616 self.vcr.dmcontrol('digital slow')):
617 self.vcr_error('digital slow failed')
618 return
619 print 'VCR OK.'
620 except VCR.error, msg:
621 self.vcr = None
622 self.vcr_error(msg)
623 return
624 if not self.vcr.still():
625 self.vcr_error('still failed')
626 return
627 self.open_if_closed()
628 rate = self.getint(self.in_rate_vcr, 1)
629 rate = max(rate, 1)
630 vcrspeed = self.c_vcrspeed.get_choice()
631 vcrspeed = VcrSpeeds[vcrspeed]
632 if vcrspeed == 0:
633 stepfunc = self.vcr.step
634 else:
635 stepfunc = None
636 self.speed_factor = rate
637 addr = start_addr = self.vcr.sense()
638 if not self.single_capture(None, 0):
639 return
640 print 'captured %02d:%02d:%02d:%02d' % self.vcr.addr2tc(addr)
641 count = self.getint(self.in_nframes_vcr, 1) - 1
642 if count <= 0:
643 while rate > 0:
644 if not self.vcr.step():
645 self.vcr_error('step failed')
646 here = self.vcr.sense()
647 if here > addr:
648 rate = rate - (here - addr)
649 addr = here
650 return
651 if not self.vcr.fwdshuttle(vcrspeed):
652 self.vcr_error('fwd shuttle failed')
653 return
654 cycle = 0
655 while count > 0:
656 try:
657 here = self.vcr.sense()
658 except VCR.error, msg:
659 self.vcr_error(msg)
660 break
661 if here <> addr:
662 if here <> addr+1:
663 print 'Missed', here-addr-1,
664 print 'frame' + 's'*(here-addr-1 <> 1)
665 cycle = (cycle+1) % rate
666 if cycle == 0:
667 tc = (here-start_addr)*40
668 if not self.single_capture(stepfunc, \
669 tc):
670 break
671 print 'captured %02d:%02d:%02d:%02d' \
672 % self.vcr.addr2tc(here)
673 count = count -1
674 addr = here
675 if self.vcr and not self.vcr.still():
676 self.vcr_error('still failed')
678 def vcr_error(self, msg):
679 self.reset()
680 fl.show_message('VCR error:', str(msg), '')
682 # Init/end continuous capture mode
684 def init_cont(self):
685 qsize = 1
686 if self.vmode == VM_CONT:
687 self.rate = self.getint(self.in_rate, 2)
688 else:
689 self.rate = 2
690 x, y = self.vout.getsize()
691 if self.use_24:
692 info = (SV.YUV411_FRAMES, x, y, qsize, self.rate)
693 else:
694 info = (SV.RGB8_FRAMES, x, y, qsize, self.rate)
695 info2 = self.video.InitContinuousCapture(info)
696 if info2 <> info:
697 # XXX This is really only debug info
698 print 'Info mismatch: requested', info, 'got', info2
700 def end_cont(self):
701 self.video.EndContinuousCapture()
703 # Misc stuff
705 def settitle(self):
706 gl.winset(self.window)
707 x, y = gl.getsize()
708 title = 'Vb ' + self.vfile + ' (%dx%d)' % (x, y)
709 gl.wintitle(title)
711 def get_vformat(self):
712 i = self.c_vformat.get_choice()
713 label = VideoFormatLabels[i-1]
714 format = VideoFormats[i-1]
715 if format == 'compress' and cl == None:
716 fl.show_message('Sorry, no compression library support')
717 format = ''
718 label = 'Video off'
719 self.vformat = format
720 if self.vformat == '':
721 self.form.freeze_form()
722 self.g_video.hide_object()
723 self.g_cont.hide_object()
724 self.g_burst.hide_object()
725 self.g_single.hide_object()
726 self.form.unfreeze_form()
727 else:
728 self.g_video.show_object()
729 if self.vmode == VM_CONT:
730 self.g_cont.show_object()
731 elif self.vmode == VM_BURST:
732 self.g_burst.show_object()
733 elif self.vmode == VM_SINGLE:
734 self.g_single.show_object()
736 self.rgb = (format[:3] == 'rgb' or format == 'compress')
737 self.mono = (format == 'mono')
738 self.grey = (format[:4] == 'grey')
739 self.use_24 = (format in ('rgb', 'jpeg', 'compress'))
740 if self.use_24:
741 self.g_rgb24.show_object()
742 else:
743 self.g_rgb24.hide_object()
744 self.use_jpeg = (format == 'jpeg')
745 self.mono_use_thresh = (label == 'mono thresh')
746 self.use_compress = (format == 'compress')
747 if self.use_compress:
748 self.g_compress.show_object()
749 else:
750 self.g_compress.hide_object()
751 s = format[4:]
752 if self.grey and s:
753 self.greybits = string.atoi(s)
754 else:
755 self.greybits = 8
756 if label == 'grey2 dith':
757 self.greybits = -2
759 convertor = None
760 if self.grey:
761 if self.greybits == 2:
762 convertor = imageop.grey2grey2
763 elif self.greybits == 4:
764 convertor = imageop.grey2grey4
765 elif self.greybits == -2:
766 convertor = imageop.dither2grey2
767 self.convertor = convertor
768 self.optfullsizewindow()
770 def get_aformat(self):
771 self.reset()
772 self.aformat = self.c_aformat.get_choice()
773 if self.aformat == A_OFF:
774 self.g_audio.hide_object()
775 else:
776 self.g_audio.show_object()
778 def init_compressor(self, w, h):
779 self.compressor = None
780 scheme = cl.QuerySchemeFromName(cl.VIDEO, self.comp_scheme)
781 self.compressor = cl.OpenCompressor(scheme)
782 parambuf = [cl.IMAGE_WIDTH, w, \
783 cl.IMAGE_HEIGHT, h, \
784 cl.ORIGINAL_FORMAT, cl.YUV422DC]
785 self.compressor.SetParams(parambuf)
786 return self.compressor.Compress(0, '')
788 def open_if_closed(self):
789 if not self.vout:
790 self.open_video()
791 if not self.aout:
792 self.open_audio()
794 # File I/O handling
796 def open_video(self):
797 self.close_video()
798 gl.winset(self.window)
799 x, y = gl.getsize()
800 if self.use_24:
801 if self.rgb24_size == 2:
802 x, y = x/2, y/2
803 elif self.rgb24_size == 3:
804 x, y = x/4, y/4
805 vout = VFile.VoutFile(self.vfile)
806 vout.setformat(self.vformat)
807 if self.vformat == 'compress':
808 cheader = self.init_compressor(x, y)
809 vout.setcompressheader(cheader)
810 vout.setsize(x, y)
811 if self.vmode == VM_BURST:
812 vout.setpf((1, -2))
813 vout.writeheader()
814 self.vout = vout
815 self.nframes = 0
816 self.speed_factor = 1
817 self.t_nframes.label = `self.nframes`
819 def write_frame(self, t, data):
820 t = t * self.speed_factor
821 if not self.vout:
822 gl.ringbell()
823 return 0
824 if self.convertor:
825 data = self.convertor(data, len(data), 1)
826 elif self.mono:
827 if self.mono_use_thresh:
828 data = imageop.grey2mono(data, \
829 len(data), 1,\
830 self.mono_thresh)
831 else:
832 data = imageop.dither2mono(data, \
833 len(data), 1)
834 try:
835 self.vout.writeframe(int(t), data, None)
836 except IOError, msg:
837 self.reset()
838 if msg == (0, 'Error 0'):
839 msg = 'disk full??'
840 fl.show_message('IOError', str(msg), '')
841 return 0
842 self.nframes = self.nframes + 1
843 self.t_nframes.label = `self.nframes`
844 return 1
846 def close_video(self):
847 if not self.vout:
848 return
849 self.nframes = 0
850 self.t_nframes.label = ''
851 try:
852 self.vout.close()
853 except IOError, msg:
854 if msg == (0, 'Error 0'):
855 msg = 'disk full??'
856 fl.show_message('IOError', str(msg), '')
857 self.vout = None
858 self.compressor = None
860 # Watch cursor handling
862 def setwatch(self):
863 gl.winset(self.form.window)
864 gl.setcursor(WATCH, 0, 0)
865 gl.winset(self.window)
866 gl.setcursor(WATCH, 0, 0)
868 def setarrow(self):
869 gl.winset(self.form.window)
870 gl.setcursor(ARROW, 0, 0)
871 gl.winset(self.window)
872 gl.setcursor(ARROW, 0, 0)
874 # Numeric field handling
876 def getint(self, field, default):
877 try:
878 value = string.atoi(field.get_input())
879 except string.atoi_error:
880 value = default
881 field.set_input(`value`)
882 return value
884 def getfloat(self, field, default):
885 try:
886 value = float(eval(field.get_input()))
887 except:
888 value = float(default)
889 field.set_input(`value`)
890 return value
892 # Audio stuff
894 def open_audio(self):
895 if self.aformat == A_OFF:
896 return
897 import aifc
898 import al
899 import AL
900 import thread
901 self.close_audio()
902 params = [AL.INPUT_RATE, 0]
903 al.getparams(AL.DEFAULT_DEVICE, params)
904 rate = params[1]
905 self.aout = aifc.open(self.afile, 'w')
906 if self.aformat in (A_16_STEREO, A_8_STEREO):
907 nch = AL.STEREO
908 else:
909 nch = AL.MONO
910 if self.aformat in (A_16_STEREO, A_16_MONO):
911 width = AL.SAMPLE_16
912 else:
913 width = AL.SAMPLE_8
914 self.aout.setnchannels(nch)
915 self.aout.setsampwidth(width)
916 self.aout.setframerate(rate)
917 c = al.newconfig()
918 c.setqueuesize(8000)
919 c.setchannels(nch)
920 c.setwidth(width)
921 self.aport = al.openport('Vb audio record', 'r', c)
922 self.audio_stop = 0
923 self.audio_ok = 0
924 self.audio_busy = 1
925 thread.start_new_thread(self.record_audio, ())
927 def start_audio(self):
928 if self.aformat == A_OFF:
929 return
930 self.audio_ok = 1
932 def record_audio(self, *args):
933 # This function runs in a separate thread
934 # Currently no semaphores are used
935 while not self.audio_stop:
936 data = self.aport.readsamps(4000)
937 if self.audio_ok:
938 self.aout.writeframes(data)
939 data = None
940 self.audio_busy = 0
942 def stop_audio(self):
943 self.audio_ok = 0
945 def close_audio(self):
946 if self.aout:
947 self.audio_ok = 0
948 self.audio_stop = 1
949 while self.audio_busy:
950 time.sleep(0.1)
951 self.aout.close()
952 self.aout = None
953 if self.aport:
954 self.aport.closeport()
955 self.aport = None
958 try:
959 main()
960 except KeyboardInterrupt:
961 print '[Interrupt]'
962 sys.exit(1)