blob: c7e7fcc91b9794045758b9758d3e604c62f48b38 [file] [log] [blame]
Guido van Rossumb7e3cc11993-05-06 16:06:44 +00001#! /ufs/guido/bin/sgi/python
2
Guido van Rossum9f42f4f1993-05-10 15:07:20 +00003# Video bag of tricks: record video(+audio) in various formats and modes
Guido van Rossumb7e3cc11993-05-06 16:06:44 +00004
Guido van Rossumc5a14331993-05-07 11:20:07 +00005# XXX To do:
6# - audio
Guido van Rossumc5a14331993-05-07 11:20:07 +00007# - improve user interface
8# - help button?
9# - command line options to set initial settings
10# - save settings in a file
11# - ...?
Guido van Rossumbc6d3c31993-05-07 09:37:42 +000012
Guido van Rossumb7e3cc11993-05-06 16:06:44 +000013import sys
Guido van Rossum9f42f4f1993-05-10 15:07:20 +000014import time
Guido van Rossumb7e3cc11993-05-06 16:06:44 +000015import getopt
16import string
17import os
Guido van Rossumc5a14331993-05-07 11:20:07 +000018sts = os.system('makemap') # Must be before "import fl" to work
Guido van Rossumb7e3cc11993-05-06 16:06:44 +000019import sgi
20import gl
21import GL
22import DEVICE
23import fl
24import FL
25import flp
26import watchcursor
27import sv
28import SV
29import VFile
30import VGrabber
31import imageop
Guido van Rossum9f42f4f1993-05-10 15:07:20 +000032sys.path.append('/ufs/jack/src/av/vcr')
Guido van Rossumf6d80321993-06-10 13:40:51 +000033import VCR
Jack Jansen78991fd1993-07-23 11:59:25 +000034try:
35 import cl
36 import CL
37except ImportError:
38 cl = None
Guido van Rossumb7e3cc11993-05-06 16:06:44 +000039
40ARROW = 0
41WATCH = 1
42watchcursor.defwatch(WATCH)
43
44def main():
Guido van Rossumc5a14331993-05-07 11:20:07 +000045## fl.set_graphics_mode(0, 1)
Guido van Rossumb7e3cc11993-05-06 16:06:44 +000046 vb = VideoBagOfTricks().init()
47 while 1:
48 dummy = fl.do_forms()
49 [dummy]
50
51StopCapture = 'StopCapture'
52
Guido van Rossum9f42f4f1993-05-10 15:07:20 +000053VideoFormatLabels = ['Video off', 'rgb8', 'grey8', 'grey4', 'grey2', \
Jack Jansen78991fd1993-07-23 11:59:25 +000054 'grey2 dith', 'mono dith', 'mono thresh', 'rgb24', 'rgb24-jpeg', \
55 'compress']
Guido van Rossum9f42f4f1993-05-10 15:07:20 +000056VideoFormats = ['', 'rgb8', 'grey', 'grey4', 'grey2', \
Jack Jansen78991fd1993-07-23 11:59:25 +000057 'grey2', 'mono', 'mono', 'rgb', 'jpeg', 'compress']
Guido van Rossum9f42f4f1993-05-10 15:07:20 +000058
59VideoModeLabels = ['Continuous', 'Burst', 'Single frame', 'VCR sync']
60[VM_CONT, VM_BURST, VM_SINGLE, VM_VCR] = range(1, 5)
61
62AudioFormatLabels = ['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)
Guido van Rossumb7e3cc11993-05-06 16:06:44 +000065
Jack Jansen672754a1993-06-08 12:52:41 +000066VcrSpeedLabels = ['normal', '1/3', '1/5', '1/10', '1/30', 'single-step']
67VcrSpeeds = [None, 5, 4, 3, 2, 1, 0]
68
69RgbSizeLabels = ['full', 'quarter', 'sixteenth']
70
Jack Jansen78991fd1993-07-23 11:59:25 +000071# init file stuff:
72if os.environ.has_key('HOME'):
73 HOME=os.environ['HOME']
74else:
75 HOME='.'
76VB_INIT_FILE=HOME + '/.Vb_init'
77
78VB_INIT_KEYS=['vfile', 'vmode', 'mono_thresh', 'vformat', 'comp_scheme', \
79 'rgb24_size', 'afile', 'aformat']
80
Guido van Rossumb7e3cc11993-05-06 16:06:44 +000081class VideoBagOfTricks:
82
Guido van Rossum9f42f4f1993-05-10 15:07:20 +000083 # Init/close stuff
84
Guido van Rossumb7e3cc11993-05-06 16:06:44 +000085 def init(self):
Jack Jansen672754a1993-06-08 12:52:41 +000086 self.window = None
Guido van Rossumb7e3cc11993-05-06 16:06:44 +000087 formdef = flp.parse_form('VbForm', 'form')
88 flp.create_full_form(self, formdef)
89 self.setdefaults()
Jack Jansen78991fd1993-07-23 11:59:25 +000090 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()
100
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000101 self.openvideo()
102 self.makewindow()
103 self.bindvideo()
Jack Jansen78991fd1993-07-23 11:59:25 +0000104 if self.use_24:
105 self.optfullsizewindow()
Guido van Rossumc5a14331993-05-07 11:20:07 +0000106 self.showform()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000107 fl.set_event_call_back(self.do_event)
108 return self
109
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000110 def close(self):
111 self.close_video()
112 self.close_audio()
Jack Jansen78991fd1993-07-23 11:59:25 +0000113 self.savedefaults()
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000114 raise SystemExit, 0
115
Guido van Rossumc5a14331993-05-07 11:20:07 +0000116 def showform(self):
117 # Get position of video window
118 gl.winset(self.window)
119 x, y = gl.getorigin()
120 width, height = gl.getsize()
121 # Calculate position of form window
122 x1 = x + width + 10
123 x2 = x1 + int(self.form.w) - 1
124 y2 = y + height - 1
125 y1 = y2 - int(self.form.h) + 1
126 # Position and show form window
127 gl.prefposition(x1, x2, y1, y2)
Guido van Rossum43df8621993-06-11 15:48:39 +0000128 self.form.show_form(FL.PLACE_FREE, FL.TRUE, 'Vb Control')
Guido van Rossumc5a14331993-05-07 11:20:07 +0000129
Jack Jansen78991fd1993-07-23 11:59:25 +0000130 def getdefaultdefaults(self):
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000131 # Video defaults
132 self.vfile = 'film.video'
133 self.vmode = VM_CONT
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000134 self.mono_thresh = 128
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000135 self.vformat = 'rgb8'
Jack Jansen78991fd1993-07-23 11:59:25 +0000136 self.comp_scheme = 'Uncompressed'
137 self.rgb24_size = 1
138 # Missing: drop, rate, maxmem, nframes, rate, vcrspeed
139 # Audio defaults:
140 self.afile = 'film.aiff'
141 self.aformat = A_OFF
142
143 def getdefaults(self):
144 self.getdefaultdefaults()
145 # XXXX Read defaults file and override.
146 try:
147 fp = open(VB_INIT_FILE, 'r')
148 except IOError:
149 print 'Vb: no init file'
150 self.initcont = {}
151 return
152 data = fp.read(1000000)
153 try:
154 self.initcont = eval(data)
155 except:
156 print 'Vb: Ill-formatted init file'
157 self.initcont = {}
158 for k in self.initcont.keys():
159 if hasattr(self, k):
160 setattr(self, k, self.initcont[k])
161
162 def savedefaults(self):
163 newdb = {}
164 for k in VB_INIT_KEYS:
165 newdb[k] = getattr(self, k)
166 if newdb <> self.initcont:
167 try:
168 fp = open(VB_INIT_FILE, 'w')
169 except IOError:
170 print 'Vb: Cannot create', VB_INIT_FILE
171 return
172 fp.write(`newdb`)
173 fp.close()
174
175 def setdefaults(self):
176 self.getdefaults()
177 self.vcr = None
178 self.vout = None
179 self.capturing = 0
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000180 self.c_vformat.clear_choice()
181 for label in VideoFormatLabels:
182 self.c_vformat.addto_choice(label)
183 self.c_vformat.set_choice(1 + VideoFormats.index(self.vformat))
184 self.c_vmode.clear_choice()
185 for label in VideoModeLabels:
186 self.c_vmode.addto_choice(label)
187 self.c_vmode.set_choice(self.vmode)
188 self.get_vformat()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000189 self.b_drop.set_button(1)
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000190 self.in_rate.set_input('2')
191 self.in_maxmem.set_input('1.0')
192 self.in_nframes.set_input('0')
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000193 self.in_nframes_vcr.set_input('1')
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000194 self.in_rate_vcr.set_input('1')
Jack Jansen672754a1993-06-08 12:52:41 +0000195 self.c_vcrspeed.clear_choice()
196 for label in VcrSpeedLabels:
197 self.c_vcrspeed.addto_choice(label)
198 self.c_vcrspeed.set_choice(4)
199 self.c_rgb24_size.clear_choice()
200 for label in RgbSizeLabels:
201 self.c_rgb24_size.addto_choice(label)
Jack Jansen78991fd1993-07-23 11:59:25 +0000202 self.c_rgb24_size.set_choice(self.rgb24_size)
203 if cl:
204 algs = cl.QueryAlgorithms(CL.VIDEO)
205 self.all_comp_schemes = []
206 for i in range(0, len(algs), 2):
207 if algs[i+1] in (CL.COMPRESSOR, CL.CODEC):
208 self.all_comp_schemes.append(algs[i])
209 self.c_cformat.clear_choice()
210 for label in self.all_comp_schemes:
211 self.c_cformat.addto_choice(label)
212 i = self.all_comp_schemes.index(self.comp_scheme)
213 self.c_cformat.set_choice(i+1)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000214 # Audio defaults
215 self.aout = None
216 self.aport = None
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000217 self.c_aformat.clear_choice()
218 for label in AudioFormatLabels:
219 self.c_aformat.addto_choice(label)
220 self.c_aformat.set_choice(self.aformat)
221 self.get_aformat()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000222
223 def openvideo(self):
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000224 try:
225 self.video = sv.OpenVideo()
226 except sv.error, msg:
227 print 'Error opening video:', msg
228 self.video = None
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000229 param = [SV.BROADCAST, SV.PAL]
230 if self.video: self.video.GetParam(param)
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000231 if param[1] == SV.PAL:
232 x = SV.PAL_XMAX
233 y = SV.PAL_YMAX
234 elif param[1] == SV.NTSC:
235 x = SV.NTSC_XMAX
236 y = SV.NTSC_YMAX
237 else:
238 print 'Unknown video standard:', param[1]
239 sys.exit(1)
240 self.maxx, self.maxy = x, y
Guido van Rossum43df8621993-06-11 15:48:39 +0000241 self.curx = 256
242 self.cury = 256*3/4
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000243
244 def makewindow(self):
245 x, y = self.maxx, self.maxy
246 gl.foreground()
247 gl.maxsize(x, y)
248 gl.keepaspect(x, y)
249 gl.stepunit(8, 6)
Guido van Rossum43df8621993-06-11 15:48:39 +0000250 width = self.curx
251 height = self.cury
252 if width and height:
253 # Place the window at (150, 150) from top left
254 # (the video board likes this location...)
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000255 x1 = 150
Guido van Rossum43df8621993-06-11 15:48:39 +0000256 x2 = x1+width-1
257 SCRHEIGHT = 768
258 y2 = SCRHEIGHT-1-150
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000259 y1 = y2-height+1
260 gl.prefposition(x1, x2, y1, y2)
Guido van Rossum43df8621993-06-11 15:48:39 +0000261 self.window = gl.winopen('Vb video')
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000262 self.settitle()
263 if width:
264 gl.maxsize(x, y)
265 gl.keepaspect(x, y)
266 gl.stepunit(8, 6)
267 gl.winconstraints()
268 gl.qdevice(DEVICE.LEFTMOUSE)
269 gl.qdevice(DEVICE.WINQUIT)
270 gl.qdevice(DEVICE.WINSHUT)
271
Jack Jansen672754a1993-06-08 12:52:41 +0000272 def optfullsizewindow(self):
273 if not self.window:
274 return
275 gl.winset(self.window)
Guido van Rossum43df8621993-06-11 15:48:39 +0000276 if self.use_24:
277 x, y = self.maxx, self.maxy
278 else:
279 x, y = self.curx, self.cury
Guido van Rossum2055ee81993-06-11 14:13:13 +0000280 left, bottom = gl.getorigin()
281 width, height = gl.getsize()
282 bottom = bottom+height-y
283 gl.prefposition(left, left+x-1, bottom, bottom+y-1)
Jack Jansen672754a1993-06-08 12:52:41 +0000284 gl.winconstraints()
Guido van Rossum43df8621993-06-11 15:48:39 +0000285 if not self.use_24:
286 gl.keepaspect(x, y)
287 gl.stepunit(8, 6)
288 gl.maxsize(self.maxx, self.maxy)
289 gl.winconstraints()
Jack Jansen672754a1993-06-08 12:52:41 +0000290 self.bindvideo()
291
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000292 def bindvideo(self):
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000293 if not self.video: return
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000294 x, y = gl.getsize()
Guido van Rossum43df8621993-06-11 15:48:39 +0000295 if not self.use_24:
296 self.curx, self.cury = x, y
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000297 self.video.SetSize(x, y)
298 drop = self.b_drop.get_button()
299 if drop:
300 param = [SV.FIELDDROP, 1, SV.GENLOCK, SV.GENLOCK_OFF]
301 else:
302 param = [SV.FIELDDROP, 0, SV.GENLOCK, SV.GENLOCK_ON]
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000303 if self.rgb:
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000304 param = param+[SV.COLOR, SV.DEFAULT_COLOR, \
305 SV.DITHER, 1, \
306 SV.INPUT_BYPASS, 0]
307 else:
308 param = param+[SV.COLOR, SV.MONO, SV.DITHER, 0, \
309 SV.INPUT_BYPASS, 1]
310 self.video.BindGLWindow(self.window, SV.IN_REPLACE)
311 self.video.SetParam(param)
312
313 def rebindvideo(self):
314 gl.winset(self.window)
315 self.bindvideo()
316
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000317 def reset(self):
318 self.close_video()
319 self.close_audio()
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000320 if self.vcr:
321 try:
322 ok = self.vcr.still()
323 except VCR.error:
324 pass
325 self.vcr = None
326 self.b_capture.set_button(0)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000327
328 # Event handler (catches resize of video window)
329
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000330 def do_event(self, dev, val):
331 #print 'Event:', dev, val
332 if dev in (DEVICE.WINSHUT, DEVICE.WINQUIT):
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000333 self.close()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000334 if dev == DEVICE.REDRAW and val == self.window:
335 self.rebindvideo()
336 self.settitle()
337
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000338 # Video controls: format, mode, file
339
340 def cb_vformat(self, *args):
341 self.reset()
342 self.get_vformat()
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000343 if self.mono_use_thresh:
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000344 s = `self.mono_thresh`
345 s = fl.show_input('Please enter mono threshold', s)
346 if s:
347 try:
348 self.mono_thresh = string.atoi(s)
349 except string.atoi_error:
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000350 fl.show_message('Bad input, using', \
351 `self.mono_thresh`, '')
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000352 self.rebindvideo()
353
Jack Jansen78991fd1993-07-23 11:59:25 +0000354 def cb_cformat(self, *args):
355 i = self.c_cformat.get_choice()
356 self.comp_scheme = self.all_comp_schemes[i-1]
357
358
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000359 def cb_vmode(self, *args):
Guido van Rossumc17c84f1993-05-10 15:45:49 +0000360 if self.vcr:
361 self.vcr = None
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000362 self.vmode = self.c_vmode.get_choice()
363 self.form.freeze_form()
364 self.g_cont.hide_object()
365 self.g_burst.hide_object()
366 self.g_single.hide_object()
367 self.g_vcr.hide_object()
368 if self.vmode == VM_CONT:
369 self.g_cont.show_object()
370 elif self.vmode == VM_BURST:
371 self.g_burst.show_object()
372 elif self.vmode == VM_SINGLE:
373 self.g_single.show_object()
374 elif self.vmode == VM_VCR:
375 self.g_vcr.show_object()
376 self.form.unfreeze_form()
377
378 def cb_vfile(self, *args):
379 filename = self.vfile
380 hd, tl = os.path.split(filename)
381 filename = fl.file_selector('Video save file:', hd, '', tl)
382 if filename:
383 self.reset()
384 hd, tl = os.path.split(filename)
385 if hd == os.getcwd():
386 filename = tl
387 self.vfile = filename
388
389 # Video mode specific video controls
390
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000391 def cb_rate(self, *args):
392 pass
393
394 def cb_drop(self, *args):
395 self.rebindvideo()
396
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000397 def cb_maxmem(self, *args):
398 pass
399
400 def cb_nframes(self, *args):
401 pass
402
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000403 def cb_fps(self, *args):
404 pass
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000405
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000406 def cb_nframes_vcr(self, *args):
407 pass
408
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000409 def cb_rate_vcr(self, *args):
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000410 pass
411
Jack Jansen672754a1993-06-08 12:52:41 +0000412 def cb_vcrspeed(self, *args):
413 pass
414
415 def cb_rgb24_size(self, *args):
416 i = self.c_rgb24_size.get_choice()
417 if i:
418 self.rgb24_size = i
419
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000420 # Audio controls: format, file
421
422 def cb_aformat(self, *args):
423 self.get_aformat()
424
425 def cb_afile(self, *args):
426 filename = self.afile
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000427 hd, tl = os.path.split(filename)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000428 filename = fl.file_selector('Audio save file:', hd, '', tl)
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000429 if filename:
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000430 self.reset()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000431 hd, tl = os.path.split(filename)
432 if hd == os.getcwd():
433 filename = tl
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000434 self.afile = filename
435
436 # General controls: capture, reset, play, quit
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000437
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000438 def cb_capture(self, *args):
Guido van Rossumc5a14331993-05-07 11:20:07 +0000439 if self.capturing:
440 raise StopCapture
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000441 if not self.b_capture.get_button():
442 return
443 if not self.video or not self.vformat:
444 gl.ringbell()
445 return
446 if self.vmode == VM_CONT:
447 self.cont_capture()
448 elif self.vmode == VM_BURST:
449 self.burst_capture()
450 elif self.vmode == VM_SINGLE:
Jack Jansen672754a1993-06-08 12:52:41 +0000451 self.single_capture(None, None)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000452 elif self.vmode == VM_VCR:
453 self.vcr_capture()
454
455 def cb_reset(self, *args):
456 self.reset()
Guido van Rossumc5a14331993-05-07 11:20:07 +0000457
458 def cb_play(self, *args):
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000459 self.reset()
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000460 sts = os.system('Vplay -q ' + self.vfile + ' &')
Guido van Rossumc5a14331993-05-07 11:20:07 +0000461
462 def cb_quit(self, *args):
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000463 self.close()
464
465 # Capture routines
Guido van Rossumc5a14331993-05-07 11:20:07 +0000466
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000467 def burst_capture(self):
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000468 self.setwatch()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000469 gl.winset(self.window)
470 x, y = gl.getsize()
Jack Jansen672754a1993-06-08 12:52:41 +0000471 if self.use_24:
472 fl.show_message('Sorry, no 24 bit continuous capture yet', '', '')
473 return
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000474 vformat = SV.RGB8_FRAMES
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000475 nframes = self.getint(self.in_nframes, 0)
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000476 if nframes == 0:
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000477 maxmem = self.getint(self.in_maxmem, 1.0)
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000478 memsize = int(maxmem * 1024 * 1024)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000479 nframes = self.calcnframes()
480 info = (vformat, x, y, nframes, 1)
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000481 try:
482 info2, data, bitvec = self.video.CaptureBurst(info)
483 except sv.error, msg:
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000484 self.b_capture.set_button(0)
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000485 self.setarrow()
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000486 fl.show_message('Capture error:', str(msg), '')
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000487 return
Guido van Rossumc5a14331993-05-07 11:20:07 +0000488 if info <> info2: print info, '<>', info2
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000489 self.save_burst(info2, data, bitvec)
490 self.setarrow()
491
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000492 def calcnframes(self):
493 gl.winset(self.window)
494 x, y = gl.getsize()
495 pixels = x*y
496 pixels = pixels/2 # XXX always assume fields
497 if self.mono or self.grey:
498 n = memsize/pixels
499 else:
500 n = memsize/(4*pixels)
501 return max(1, n)
502
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000503 def save_burst(self, info, data, bitvec):
504 (vformat, x, y, nframes, rate) = info
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000505 self.open_if_closed()
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000506 fieldsize = x*y/2
507 nskipped = 0
508 realframeno = 0
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000509 tpf = 1000 / 50.0 # XXX
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000510 for frameno in range(0, nframes*2):
511 if frameno <> 0 and \
512 bitvec[frameno] == bitvec[frameno-1]:
513 nskipped = nskipped + 1
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000514 continue
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000515 #
516 # Save field.
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000517 # XXX Works only for fields and top-to-bottom
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000518 #
519 start = frameno*fieldsize
520 field = data[start:start+fieldsize]
521 realframeno = realframeno + 1
522 fn = int(realframeno*tpf)
523 if not self.write_frame(fn, field):
524 break
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000525
526 def cont_capture(self):
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000527 saved_label = self.b_capture.label
528 self.b_capture.label = 'Stop\n' + saved_label
529 self.open_if_closed()
530 self.init_cont()
531 fps = 59.64 # Fields per second
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000532 # XXX (fps of Indigo monitor, not of PAL or NTSC!)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000533 tpf = 1000.0 / fps # Time per field in msec
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000534 self.capturing = 1
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000535 self.start_audio()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000536 while 1:
537 try:
538 void = fl.check_forms()
539 except StopCapture:
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000540 break
541 try:
542 cd, id = self.video.GetCaptureData()
543 except sv.error:
544 sgi.nap(1)
545 continue
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000546 id = id + 2*self.rate
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000547 data = cd.InterleaveFields(1)
548 cd.UnlockCaptureData()
549 t = id*tpf
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000550 if not self.write_frame(t, data):
Guido van Rossume17c6c31993-05-06 16:27:25 +0000551 break
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000552 self.stop_audio()
Guido van Rossume17c6c31993-05-06 16:27:25 +0000553 self.capturing = 0
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000554 self.end_cont()
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000555 if self.aout:
556 # If recording audio, can't capture multiple sequences
557 self.reset()
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000558 self.b_capture.label = saved_label
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000559
Jack Jansen672754a1993-06-08 12:52:41 +0000560 def single_capture(self, stepfunc, timecode):
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000561 self.open_if_closed()
562 self.init_cont()
563 while 1:
564 try:
565 cd, id = self.video.GetCaptureData()
566 break
567 except sv.error:
568 pass
569 sgi.nap(1)
Jack Jansen672754a1993-06-08 12:52:41 +0000570 if stepfunc: # This might step the video
571 d=stepfunc() # to the next frame
572 if not self.use_24:
573 data = cd.InterleaveFields(1)
574 else:
575 x, y = self.vout.getsize()
Jack Jansen78991fd1993-07-23 11:59:25 +0000576 if self.use_compress:
577 if self.rgb24_size == 1:
578 data = cd.YUVtoYUV422DC(0)
579 elif self.rgb24_size == 2:
580 data = cd.YUVtoYUV422DC_quarter(1)
581 x = x/2
582 y = y/2
583 elif self.rgb24_size == 3:
584 data = cd.YUVtoYUV422DC_sixteenth(1)
585 x = x/4
586 y = y/4
Jack Jansen672754a1993-06-08 12:52:41 +0000587 else:
Jack Jansen78991fd1993-07-23 11:59:25 +0000588 data = cd.YUVtoRGB(1)
589 if self.maxx*self.maxy*4 <> len(data):
590 print 'maxx,maxy,exp,got=', self.maxx,
591 print self.maxy,self.maxx*self.maxy*4,
592 print len(data)
593 fl.showmessage('Wrong sized data')
594 return 0
595 if self.rgb24_size <> 1:
596 data = imageop.scale(data, 4, \
597 self.maxx, self.maxy, x, y)
Jack Jansen672754a1993-06-08 12:52:41 +0000598 if self.use_jpeg:
599 import jpeg
600 data = jpeg.compress(data, x, y, 4)
Jack Jansen78991fd1993-07-23 11:59:25 +0000601 if self.use_compress:
602 data = self.compressor.Compress(1, data)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000603 cd.UnlockCaptureData()
604 self.end_cont()
Jack Jansen672754a1993-06-08 12:52:41 +0000605 if timecode == None:
606 timecode = (self.nframes+1) * (1000/25)
607 return self.write_frame(timecode, data)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000608
609 def vcr_capture(self):
610 if not self.vcr:
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000611 try:
Guido van Rossum2055ee81993-06-11 14:13:13 +0000612 print 'Connecting to VCR ...'
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000613 self.vcr = VCR.VCR().init()
Guido van Rossum2055ee81993-06-11 14:13:13 +0000614 print 'Waiting for VCR to come online ...'
Jack Jansen78991fd1993-07-23 11:59:25 +0000615 self.vcr.initvcr()
Guido van Rossum2055ee81993-06-11 14:13:13 +0000616 print 'Preparing VCR ...'
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000617 if not (self.vcr.fmmode('dnr') and \
618 self.vcr.dmcontrol('digital slow')):
619 self.vcr_error('digital slow failed')
620 return
Guido van Rossum2055ee81993-06-11 14:13:13 +0000621 print 'VCR OK.'
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000622 except VCR.error, msg:
Guido van Rossumc17c84f1993-05-10 15:45:49 +0000623 self.vcr = None
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000624 self.vcr_error(msg)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000625 return
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000626 if not self.vcr.still():
627 self.vcr_error('still failed')
628 return
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000629 self.open_if_closed()
630 rate = self.getint(self.in_rate_vcr, 1)
631 rate = max(rate, 1)
Jack Jansen672754a1993-06-08 12:52:41 +0000632 vcrspeed = self.c_vcrspeed.get_choice()
633 vcrspeed = VcrSpeeds[vcrspeed]
634 if vcrspeed == 0:
635 stepfunc = self.vcr.step
636 else:
637 stepfunc = None
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000638 self.speed_factor = rate
Jack Jansen672754a1993-06-08 12:52:41 +0000639 addr = start_addr = self.vcr.sense()
640 if not self.single_capture(None, 0):
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000641 return
642 print 'captured %02d:%02d:%02d:%02d' % self.vcr.addr2tc(addr)
643 count = self.getint(self.in_nframes_vcr, 1) - 1
644 if count <= 0:
645 while rate > 0:
646 if not self.vcr.step():
647 self.vcr_error('step failed')
648 here = self.vcr.sense()
649 if here > addr:
650 rate = rate - (here - addr)
651 addr = here
652 return
Guido van Rossum2055ee81993-06-11 14:13:13 +0000653 if not self.vcr.fwdshuttle(vcrspeed):
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000654 self.vcr_error('fwd shuttle failed')
655 return
656 cycle = 0
657 while count > 0:
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000658 try:
659 here = self.vcr.sense()
660 except VCR.error, msg:
661 self.vcr_error(msg)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000662 break
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000663 if here <> addr:
664 if here <> addr+1:
665 print 'Missed', here-addr-1,
666 print 'frame' + 's'*(here-addr-1 <> 1)
667 cycle = (cycle+1) % rate
668 if cycle == 0:
Jack Jansen672754a1993-06-08 12:52:41 +0000669 tc = (here-start_addr)*40
670 if not self.single_capture(stepfunc, \
671 tc):
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000672 break
673 print 'captured %02d:%02d:%02d:%02d' \
674 % self.vcr.addr2tc(here)
675 count = count -1
676 addr = here
677 if self.vcr and not self.vcr.still():
678 self.vcr_error('still failed')
679
680 def vcr_error(self, msg):
681 self.reset()
682 fl.show_message('VCR error:', str(msg), '')
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000683
684 # Init/end continuous capture mode
685
686 def init_cont(self):
687 qsize = 1
688 if self.vmode == VM_CONT:
689 self.rate = self.getint(self.in_rate, 2)
690 else:
691 self.rate = 2
692 x, y = self.vout.getsize()
Jack Jansen672754a1993-06-08 12:52:41 +0000693 if self.use_24:
694 info = (SV.YUV411_FRAMES, x, y, qsize, self.rate)
695 else:
696 info = (SV.RGB8_FRAMES, x, y, qsize, self.rate)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000697 info2 = self.video.InitContinuousCapture(info)
698 if info2 <> info:
699 # XXX This is really only debug info
700 print 'Info mismatch: requested', info, 'got', info2
701
702 def end_cont(self):
703 self.video.EndContinuousCapture()
704
705 # Misc stuff
706
707 def settitle(self):
708 gl.winset(self.window)
709 x, y = gl.getsize()
Guido van Rossum43df8621993-06-11 15:48:39 +0000710 title = 'Vb ' + self.vfile + ' (%dx%d)' % (x, y)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000711 gl.wintitle(title)
712
713 def get_vformat(self):
714 i = self.c_vformat.get_choice()
715 label = VideoFormatLabels[i-1]
716 format = VideoFormats[i-1]
Jack Jansen78991fd1993-07-23 11:59:25 +0000717 if format == 'compress' and cl == None:
718 fl.show_message('Sorry, no compression library support')
719 format = ''
720 label = 'Video off'
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000721 self.vformat = format
722 if self.vformat == '':
723 self.form.freeze_form()
724 self.g_video.hide_object()
725 self.g_cont.hide_object()
726 self.g_burst.hide_object()
727 self.g_single.hide_object()
728 self.form.unfreeze_form()
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000729 else:
730 self.g_video.show_object()
731 if self.vmode == VM_CONT:
732 self.g_cont.show_object()
733 elif self.vmode == VM_BURST:
734 self.g_burst.show_object()
735 elif self.vmode == VM_SINGLE:
736 self.g_single.show_object()
Guido van Rossumc5a14331993-05-07 11:20:07 +0000737 #
Jack Jansen78991fd1993-07-23 11:59:25 +0000738 self.rgb = (format[:3] == 'rgb' or format == 'compress')
Guido van Rossumc5a14331993-05-07 11:20:07 +0000739 self.mono = (format == 'mono')
740 self.grey = (format[:4] == 'grey')
Jack Jansen78991fd1993-07-23 11:59:25 +0000741 self.use_24 = (format in ('rgb', 'jpeg', 'compress'))
742 if self.use_24:
Jack Jansen672754a1993-06-08 12:52:41 +0000743 self.g_rgb24.show_object()
744 else:
745 self.g_rgb24.hide_object()
746 self.use_jpeg = (format == 'jpeg')
Guido van Rossumc5a14331993-05-07 11:20:07 +0000747 self.mono_use_thresh = (label == 'mono thresh')
Jack Jansen78991fd1993-07-23 11:59:25 +0000748 self.use_compress = (format == 'compress')
749 if self.use_compress:
750 self.g_compress.show_object()
751 else:
752 self.g_compress.hide_object()
Guido van Rossumc5a14331993-05-07 11:20:07 +0000753 s = format[4:]
Jack Jansen78991fd1993-07-23 11:59:25 +0000754 if self.grey and s:
Guido van Rossumc5a14331993-05-07 11:20:07 +0000755 self.greybits = string.atoi(s)
756 else:
757 self.greybits = 8
758 if label == 'grey2 dith':
759 self.greybits = -2
760 #
761 convertor = None
762 if self.grey:
763 if self.greybits == 2:
764 convertor = imageop.grey2grey2
765 elif self.greybits == 4:
766 convertor = imageop.grey2grey4
767 elif self.greybits == -2:
768 convertor = imageop.dither2grey2
769 self.convertor = convertor
Jack Jansen672754a1993-06-08 12:52:41 +0000770 self.optfullsizewindow()
Guido van Rossumc5a14331993-05-07 11:20:07 +0000771
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000772 def get_aformat(self):
773 self.reset()
774 self.aformat = self.c_aformat.get_choice()
775 if self.aformat == A_OFF:
776 self.g_audio.hide_object()
777 else:
778 self.g_audio.show_object()
779
Jack Jansen78991fd1993-07-23 11:59:25 +0000780 def init_compressor(self, w, h):
781 self.compressor = None
782 scheme = cl.QuerySchemeFromName(CL.VIDEO, self.comp_scheme)
783 self.compressor = cl.OpenCompressor(scheme)
784 parambuf = [CL.IMAGE_WIDTH, w, \
785 CL.IMAGE_HEIGHT, h, \
786 CL.ORIGINAL_FORMAT, CL.YUV422DC]
787 self.compressor.SetParams(parambuf)
788 return self.compressor.Compress(0, '')
789
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000790 def open_if_closed(self):
791 if not self.vout:
792 self.open_video()
793 if not self.aout:
794 self.open_audio()
795
796 # File I/O handling
797
798 def open_video(self):
799 self.close_video()
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000800 gl.winset(self.window)
801 x, y = gl.getsize()
Jack Jansen672754a1993-06-08 12:52:41 +0000802 if self.use_24:
803 if self.rgb24_size == 2:
804 x, y = x/2, y/2
Jack Jansen78991fd1993-07-23 11:59:25 +0000805 elif self.rgb24_size == 3:
Jack Jansen672754a1993-06-08 12:52:41 +0000806 x, y = x/4, y/4
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000807 vout = VFile.VoutFile().init(self.vfile)
808 vout.setformat(self.vformat)
Jack Jansen78991fd1993-07-23 11:59:25 +0000809 if self.vformat == 'compress':
810 cheader = self.init_compressor(x, y)
811 vout.setcompressheader(cheader)
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000812 vout.setsize(x, y)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000813 if self.vmode == VM_BURST:
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000814 vout.setpf((1, -2))
815 vout.writeheader()
816 self.vout = vout
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000817 self.nframes = 0
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000818 self.speed_factor = 1
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000819 self.t_nframes.label = `self.nframes`
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000820
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000821 def write_frame(self, t, data):
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000822 t = t * self.speed_factor
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000823 if not self.vout:
824 gl.ringbell()
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000825 return 0
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000826 if self.convertor:
827 data = self.convertor(data, len(data), 1)
828 elif self.mono:
829 if self.mono_use_thresh:
830 data = imageop.grey2mono(data, \
831 len(data), 1,\
832 self.mono_thresh)
833 else:
834 data = imageop.dither2mono(data, \
835 len(data), 1)
836 try:
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000837 self.vout.writeframe(int(t), data, None)
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000838 except IOError, msg:
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000839 self.reset()
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000840 if msg == (0, 'Error 0'):
841 msg = 'disk full??'
842 fl.show_message('IOError', str(msg), '')
843 return 0
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000844 self.nframes = self.nframes + 1
845 self.t_nframes.label = `self.nframes`
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000846 return 1
847
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000848 def close_video(self):
849 if not self.vout:
850 return
851 self.nframes = 0
852 self.t_nframes.label = ''
Guido van Rossumc5a14331993-05-07 11:20:07 +0000853 try:
854 self.vout.close()
855 except IOError, msg:
856 if msg == (0, 'Error 0'):
857 msg = 'disk full??'
858 fl.show_message('IOError', str(msg), '')
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000859 self.vout = None
Jack Jansen78991fd1993-07-23 11:59:25 +0000860 self.compressor = None
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000861
862 # Watch cursor handling
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000863
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000864 def setwatch(self):
865 gl.winset(self.form.window)
866 gl.setcursor(WATCH, 0, 0)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000867 gl.winset(self.window)
868 gl.setcursor(WATCH, 0, 0)
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000869
870 def setarrow(self):
871 gl.winset(self.form.window)
872 gl.setcursor(ARROW, 0, 0)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000873 gl.winset(self.window)
874 gl.setcursor(ARROW, 0, 0)
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000875
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000876 # Numeric field handling
877
878 def getint(self, field, default):
879 try:
880 value = string.atoi(field.get_input())
881 except string.atoi_error:
882 value = default
883 field.set_input(`value`)
884 return value
885
886 def getfloat(self, field, default):
887 try:
888 value = float(eval(field.get_input()))
889 except:
890 value = float(default)
Guido van Rossumc17c84f1993-05-10 15:45:49 +0000891 field.set_input(`value`)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000892 return value
893
894 # Audio stuff
895
896 def open_audio(self):
897 if self.aformat == A_OFF:
898 return
899 import aifc
900 import al
901 import AL
902 import thread
903 self.close_audio()
904 params = [AL.INPUT_RATE, 0]
905 al.getparams(AL.DEFAULT_DEVICE, params)
906 rate = params[1]
907 self.aout = aifc.open(self.afile, 'w')
908 if self.aformat in (A_16_STEREO, A_8_STEREO):
909 nch = AL.STEREO
910 else:
911 nch = AL.MONO
912 if self.aformat in (A_16_STEREO, A_16_MONO):
913 width = AL.SAMPLE_16
914 else:
915 width = AL.SAMPLE_8
916 self.aout.setnchannels(nch)
917 self.aout.setsampwidth(width)
918 self.aout.setframerate(rate)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000919 c = al.newconfig()
920 c.setqueuesize(8000)
921 c.setchannels(nch)
922 c.setwidth(width)
923 self.aport = al.openport('Vb audio record', 'r', c)
924 self.audio_stop = 0
925 self.audio_ok = 0
926 self.audio_busy = 1
927 thread.start_new_thread(self.record_audio, ())
928
929 def start_audio(self):
930 if self.aformat == A_OFF:
931 return
932 self.audio_ok = 1
933
934 def record_audio(self, *args):
935 # This function runs in a separate thread
936 # Currently no semaphores are used
937 while not self.audio_stop:
938 data = self.aport.readsamps(4000)
939 if self.audio_ok:
Guido van Rossumf6d80321993-06-10 13:40:51 +0000940 self.aout.writeframes(data)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000941 data = None
942 self.audio_busy = 0
943
944 def stop_audio(self):
945 self.audio_ok = 0
946
947 def close_audio(self):
948 if self.aout:
949 self.audio_ok = 0
950 self.audio_stop = 1
951 while self.audio_busy:
952 time.sleep(0.1)
953 self.aout.close()
954 self.aout = None
955 if self.aport:
956 self.aport.closeport()
957 self.aport = None
958
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000959
960try:
961 main()
962except KeyboardInterrupt:
963 print '[Interrupt]'
964 sys.exit(1)