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