blob: 0a0ced1b6c47fb8ba3e97d885ad6dfa390f5677a [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 Rossumb7e3cc11993-05-06 16:06:44 +000033
34ARROW = 0
35WATCH = 1
36watchcursor.defwatch(WATCH)
37
38def main():
Guido van Rossumc5a14331993-05-07 11:20:07 +000039## fl.set_graphics_mode(0, 1)
Guido van Rossumb7e3cc11993-05-06 16:06:44 +000040 vb = VideoBagOfTricks().init()
41 while 1:
42 dummy = fl.do_forms()
43 [dummy]
44
45StopCapture = 'StopCapture'
46
Guido van Rossum9f42f4f1993-05-10 15:07:20 +000047VideoFormatLabels = ['Video off', 'rgb8', 'grey8', 'grey4', 'grey2', \
Guido van Rossumbc6d3c31993-05-07 09:37:42 +000048 'grey2 dith', 'mono dith', 'mono thresh']
Guido van Rossum9f42f4f1993-05-10 15:07:20 +000049VideoFormats = ['', 'rgb8', 'grey', 'grey4', 'grey2', \
50 'grey2', 'mono', 'mono']
51
52VideoModeLabels = ['Continuous', 'Burst', 'Single frame', 'VCR sync']
53[VM_CONT, VM_BURST, VM_SINGLE, VM_VCR] = range(1, 5)
54
55AudioFormatLabels = ['Audio off', \
56 '16 bit mono', '16 bit stereo', '8 bit mono', '8 bit stereo']
57[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 +000058
59class VideoBagOfTricks:
60
Guido van Rossum9f42f4f1993-05-10 15:07:20 +000061 # Init/close stuff
62
Guido van Rossumb7e3cc11993-05-06 16:06:44 +000063 def init(self):
64 formdef = flp.parse_form('VbForm', 'form')
65 flp.create_full_form(self, formdef)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +000066 self.g_cont.hide_object()
Guido van Rossumc5a14331993-05-07 11:20:07 +000067 self.g_burst.hide_object()
Guido van Rossum9f42f4f1993-05-10 15:07:20 +000068 self.g_single.hide_object()
69 self.g_vcr.hide_object()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +000070 self.setdefaults()
71 self.openvideo()
72 self.makewindow()
73 self.bindvideo()
Guido van Rossumc5a14331993-05-07 11:20:07 +000074 self.showform()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +000075 fl.set_event_call_back(self.do_event)
76 return self
77
Guido van Rossum9f42f4f1993-05-10 15:07:20 +000078 def close(self):
79 self.close_video()
80 self.close_audio()
81 raise SystemExit, 0
82
Guido van Rossumc5a14331993-05-07 11:20:07 +000083 def showform(self):
84 # Get position of video window
85 gl.winset(self.window)
86 x, y = gl.getorigin()
87 width, height = gl.getsize()
88 # Calculate position of form window
89 x1 = x + width + 10
90 x2 = x1 + int(self.form.w) - 1
91 y2 = y + height - 1
92 y1 = y2 - int(self.form.h) + 1
93 # Position and show form window
94 gl.prefposition(x1, x2, y1, y2)
95 self.form.show_form(FL.PLACE_FREE, FL.TRUE, \
96 'Video Bag Of Tricks')
97
Guido van Rossumb7e3cc11993-05-06 16:06:44 +000098 def setdefaults(self):
Guido van Rossum9f42f4f1993-05-10 15:07:20 +000099 self.vcr = None
100 self.vout = None
101 self.capturing = 0
102 # Video defaults
103 self.vfile = 'film.video'
104 self.vmode = VM_CONT
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000105 self.mono_thresh = 128
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000106 self.vformat = 'rgb8'
107 self.c_vformat.clear_choice()
108 for label in VideoFormatLabels:
109 self.c_vformat.addto_choice(label)
110 self.c_vformat.set_choice(1 + VideoFormats.index(self.vformat))
111 self.c_vmode.clear_choice()
112 for label in VideoModeLabels:
113 self.c_vmode.addto_choice(label)
114 self.c_vmode.set_choice(self.vmode)
115 self.get_vformat()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000116 self.b_drop.set_button(1)
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000117 self.in_rate.set_input('2')
118 self.in_maxmem.set_input('1.0')
119 self.in_nframes.set_input('0')
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000120 self.in_nframes_vcr.set_input('1')
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000121 self.in_rate_vcr.set_input('1')
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000122 # Audio defaults
123 self.aout = None
124 self.aport = None
125 self.afile = 'film.aiff'
126 self.aformat = A_OFF
127 self.c_aformat.clear_choice()
128 for label in AudioFormatLabels:
129 self.c_aformat.addto_choice(label)
130 self.c_aformat.set_choice(self.aformat)
131 self.get_aformat()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000132
133 def openvideo(self):
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000134 try:
135 self.video = sv.OpenVideo()
136 except sv.error, msg:
137 print 'Error opening video:', msg
138 self.video = None
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000139 param = [SV.BROADCAST, SV.PAL]
140 if self.video: self.video.GetParam(param)
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000141 if param[1] == SV.PAL:
142 x = SV.PAL_XMAX
143 y = SV.PAL_YMAX
144 elif param[1] == SV.NTSC:
145 x = SV.NTSC_XMAX
146 y = SV.NTSC_YMAX
147 else:
148 print 'Unknown video standard:', param[1]
149 sys.exit(1)
150 self.maxx, self.maxy = x, y
151
152 def makewindow(self):
153 x, y = self.maxx, self.maxy
154 gl.foreground()
155 gl.maxsize(x, y)
156 gl.keepaspect(x, y)
157 gl.stepunit(8, 6)
158 width = 256 # XXX
159 if width:
160 height = width*3/4
161 x1 = 150
162 x2 = x1 + width-1
163 y2 = 768-150
164 y1 = y2-height+1
165 gl.prefposition(x1, x2, y1, y2)
166 self.window = gl.winopen('Vb: initializing')
167 self.settitle()
168 if width:
169 gl.maxsize(x, y)
170 gl.keepaspect(x, y)
171 gl.stepunit(8, 6)
172 gl.winconstraints()
173 gl.qdevice(DEVICE.LEFTMOUSE)
174 gl.qdevice(DEVICE.WINQUIT)
175 gl.qdevice(DEVICE.WINSHUT)
176
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000177 def bindvideo(self):
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000178 if not self.video: return
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000179 x, y = gl.getsize()
180 self.video.SetSize(x, y)
181 drop = self.b_drop.get_button()
182 if drop:
183 param = [SV.FIELDDROP, 1, SV.GENLOCK, SV.GENLOCK_OFF]
184 else:
185 param = [SV.FIELDDROP, 0, SV.GENLOCK, SV.GENLOCK_ON]
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000186 if self.rgb:
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000187 param = param+[SV.COLOR, SV.DEFAULT_COLOR, \
188 SV.DITHER, 1, \
189 SV.INPUT_BYPASS, 0]
190 else:
191 param = param+[SV.COLOR, SV.MONO, SV.DITHER, 0, \
192 SV.INPUT_BYPASS, 1]
193 self.video.BindGLWindow(self.window, SV.IN_REPLACE)
194 self.video.SetParam(param)
195
196 def rebindvideo(self):
197 gl.winset(self.window)
198 self.bindvideo()
199
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000200 def reset(self):
201 self.close_video()
202 self.close_audio()
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000203 if self.vcr:
204 try:
205 ok = self.vcr.still()
206 except VCR.error:
207 pass
208 self.vcr = None
209 self.b_capture.set_button(0)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000210
211 # Event handler (catches resize of video window)
212
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000213 def do_event(self, dev, val):
214 #print 'Event:', dev, val
215 if dev in (DEVICE.WINSHUT, DEVICE.WINQUIT):
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000216 self.close()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000217 if dev == DEVICE.REDRAW and val == self.window:
218 self.rebindvideo()
219 self.settitle()
220
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000221 # Video controls: format, mode, file
222
223 def cb_vformat(self, *args):
224 self.reset()
225 self.get_vformat()
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000226 if self.mono_use_thresh:
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000227 s = `self.mono_thresh`
228 s = fl.show_input('Please enter mono threshold', s)
229 if s:
230 try:
231 self.mono_thresh = string.atoi(s)
232 except string.atoi_error:
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000233 fl.show_message('Bad input, using', \
234 `self.mono_thresh`, '')
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000235 self.rebindvideo()
236
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000237 def cb_vmode(self, *args):
Guido van Rossumc17c84f1993-05-10 15:45:49 +0000238 if self.vcr:
239 self.vcr = None
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000240 self.vmode = self.c_vmode.get_choice()
241 self.form.freeze_form()
242 self.g_cont.hide_object()
243 self.g_burst.hide_object()
244 self.g_single.hide_object()
245 self.g_vcr.hide_object()
246 if self.vmode == VM_CONT:
247 self.g_cont.show_object()
248 elif self.vmode == VM_BURST:
249 self.g_burst.show_object()
250 elif self.vmode == VM_SINGLE:
251 self.g_single.show_object()
252 elif self.vmode == VM_VCR:
253 self.g_vcr.show_object()
254 self.form.unfreeze_form()
255
256 def cb_vfile(self, *args):
257 filename = self.vfile
258 hd, tl = os.path.split(filename)
259 filename = fl.file_selector('Video save file:', hd, '', tl)
260 if filename:
261 self.reset()
262 hd, tl = os.path.split(filename)
263 if hd == os.getcwd():
264 filename = tl
265 self.vfile = filename
266
267 # Video mode specific video controls
268
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000269 def cb_rate(self, *args):
270 pass
271
272 def cb_drop(self, *args):
273 self.rebindvideo()
274
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000275 def cb_maxmem(self, *args):
276 pass
277
278 def cb_nframes(self, *args):
279 pass
280
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000281 def cb_fps(self, *args):
282 pass
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000283
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000284 def cb_nframes_vcr(self, *args):
285 pass
286
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000287 def cb_rate_vcr(self, *args):
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000288 pass
289
290 # Audio controls: format, file
291
292 def cb_aformat(self, *args):
293 self.get_aformat()
294
295 def cb_afile(self, *args):
296 filename = self.afile
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000297 hd, tl = os.path.split(filename)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000298 filename = fl.file_selector('Audio save file:', hd, '', tl)
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000299 if filename:
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000300 self.reset()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000301 hd, tl = os.path.split(filename)
302 if hd == os.getcwd():
303 filename = tl
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000304 self.afile = filename
305
306 # General controls: capture, reset, play, quit
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000307
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000308 def cb_capture(self, *args):
Guido van Rossumc5a14331993-05-07 11:20:07 +0000309 if self.capturing:
310 raise StopCapture
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000311 if not self.b_capture.get_button():
312 return
313 if not self.video or not self.vformat:
314 gl.ringbell()
315 return
316 if self.vmode == VM_CONT:
317 self.cont_capture()
318 elif self.vmode == VM_BURST:
319 self.burst_capture()
320 elif self.vmode == VM_SINGLE:
321 self.single_capture()
322 elif self.vmode == VM_VCR:
323 self.vcr_capture()
324
325 def cb_reset(self, *args):
326 self.reset()
Guido van Rossumc5a14331993-05-07 11:20:07 +0000327
328 def cb_play(self, *args):
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000329 self.reset()
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000330 sts = os.system('Vplay -q ' + self.vfile + ' &')
Guido van Rossumc5a14331993-05-07 11:20:07 +0000331
332 def cb_quit(self, *args):
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000333 self.close()
334
335 # Capture routines
Guido van Rossumc5a14331993-05-07 11:20:07 +0000336
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000337 def burst_capture(self):
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000338 self.setwatch()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000339 gl.winset(self.window)
340 x, y = gl.getsize()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000341 vformat = SV.RGB8_FRAMES
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000342 nframes = self.getint(self.in_nframes, 0)
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000343 if nframes == 0:
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000344 maxmem = self.getint(self.in_maxmem, 1.0)
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000345 memsize = int(maxmem * 1024 * 1024)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000346 nframes = self.calcnframes()
347 info = (vformat, x, y, nframes, 1)
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000348 try:
349 info2, data, bitvec = self.video.CaptureBurst(info)
350 except sv.error, msg:
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000351 self.b_capture.set_button(0)
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000352 self.setarrow()
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000353 fl.show_message('Capture error:', str(msg), '')
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000354 return
Guido van Rossumc5a14331993-05-07 11:20:07 +0000355 if info <> info2: print info, '<>', info2
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000356 self.save_burst(info2, data, bitvec)
357 self.setarrow()
358
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000359 def calcnframes(self):
360 gl.winset(self.window)
361 x, y = gl.getsize()
362 pixels = x*y
363 pixels = pixels/2 # XXX always assume fields
364 if self.mono or self.grey:
365 n = memsize/pixels
366 else:
367 n = memsize/(4*pixels)
368 return max(1, n)
369
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000370 def save_burst(self, info, data, bitvec):
371 (vformat, x, y, nframes, rate) = info
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000372 self.open_if_closed()
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000373 fieldsize = x*y/2
374 nskipped = 0
375 realframeno = 0
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000376 tpf = 1000 / 50.0 # XXX
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000377 for frameno in range(0, nframes*2):
378 if frameno <> 0 and \
379 bitvec[frameno] == bitvec[frameno-1]:
380 nskipped = nskipped + 1
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000381 continue
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000382 #
383 # Save field.
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000384 # XXX Works only for fields and top-to-bottom
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000385 #
386 start = frameno*fieldsize
387 field = data[start:start+fieldsize]
388 realframeno = realframeno + 1
389 fn = int(realframeno*tpf)
390 if not self.write_frame(fn, field):
391 break
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000392
393 def cont_capture(self):
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000394 saved_label = self.b_capture.label
395 self.b_capture.label = 'Stop\n' + saved_label
396 self.open_if_closed()
397 self.init_cont()
398 fps = 59.64 # Fields per second
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000399 # XXX (fps of Indigo monitor, not of PAL or NTSC!)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000400 tpf = 1000.0 / fps # Time per field in msec
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000401 self.capturing = 1
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000402 self.start_audio()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000403 while 1:
404 try:
405 void = fl.check_forms()
406 except StopCapture:
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000407 break
408 try:
409 cd, id = self.video.GetCaptureData()
410 except sv.error:
411 sgi.nap(1)
412 continue
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000413 id = id + 2*self.rate
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000414 data = cd.InterleaveFields(1)
415 cd.UnlockCaptureData()
416 t = id*tpf
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000417 if not self.write_frame(t, data):
Guido van Rossume17c6c31993-05-06 16:27:25 +0000418 break
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000419 self.stop_audio()
Guido van Rossume17c6c31993-05-06 16:27:25 +0000420 self.capturing = 0
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000421 self.end_cont()
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000422 if self.aout:
423 # If recording audio, can't capture multiple sequences
424 self.reset()
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000425 self.b_capture.label = saved_label
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000426
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000427 def single_capture(self):
428 self.open_if_closed()
429 self.init_cont()
430 while 1:
431 try:
432 cd, id = self.video.GetCaptureData()
433 break
434 except sv.error:
435 pass
436 sgi.nap(1)
437 data = cd.InterleaveFields(1)
438 cd.UnlockCaptureData()
439 self.end_cont()
440 t = (self.nframes+1) * (1000/25)
441 return self.write_frame(t, data)
442
443 def vcr_capture(self):
444 if not self.vcr:
445 import VCR
446 try:
447 self.vcr = VCR.VCR().init()
Guido van Rossumc17c84f1993-05-10 15:45:49 +0000448 self.vcr.wait()
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000449 if not (self.vcr.fmmode('dnr') and \
450 self.vcr.dmcontrol('digital slow')):
451 self.vcr_error('digital slow failed')
452 return
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000453 except VCR.error, msg:
Guido van Rossumc17c84f1993-05-10 15:45:49 +0000454 self.vcr = None
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000455 self.vcr_error(msg)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000456 return
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000457 if not self.vcr.still():
458 self.vcr_error('still failed')
459 return
460 # XXX for some reason calling where() too often hangs the VCR,
461 # XXX so we insert sleep(0.1) before every sense() call.
462 self.open_if_closed()
463 rate = self.getint(self.in_rate_vcr, 1)
464 rate = max(rate, 1)
465 self.speed_factor = rate
466 addr = self.vcr.sense()
467 if not self.single_capture():
468 return
469 print 'captured %02d:%02d:%02d:%02d' % self.vcr.addr2tc(addr)
470 count = self.getint(self.in_nframes_vcr, 1) - 1
471 if count <= 0:
472 while rate > 0:
473 if not self.vcr.step():
474 self.vcr_error('step failed')
475 here = self.vcr.sense()
476 if here > addr:
477 rate = rate - (here - addr)
478 addr = here
479 return
480 if not self.vcr.fwdshuttle(2): # one tenth speed
481 self.vcr_error('fwd shuttle failed')
482 return
483 cycle = 0
484 while count > 0:
485 time.sleep(0.1)
486 try:
487 here = self.vcr.sense()
488 except VCR.error, msg:
489 self.vcr_error(msg)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000490 break
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000491 if here <> addr:
492 if here <> addr+1:
493 print 'Missed', here-addr-1,
494 print 'frame' + 's'*(here-addr-1 <> 1)
495 cycle = (cycle+1) % rate
496 if cycle == 0:
497 if not self.single_capture():
498 break
499 print 'captured %02d:%02d:%02d:%02d' \
500 % self.vcr.addr2tc(here)
501 count = count -1
502 addr = here
503 if self.vcr and not self.vcr.still():
504 self.vcr_error('still failed')
505
506 def vcr_error(self, msg):
507 self.reset()
508 fl.show_message('VCR error:', str(msg), '')
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000509
510 # Init/end continuous capture mode
511
512 def init_cont(self):
513 qsize = 1
514 if self.vmode == VM_CONT:
515 self.rate = self.getint(self.in_rate, 2)
516 else:
517 self.rate = 2
518 x, y = self.vout.getsize()
519 info = (SV.RGB8_FRAMES, x, y, qsize, self.rate)
520 info2 = self.video.InitContinuousCapture(info)
521 if info2 <> info:
522 # XXX This is really only debug info
523 print 'Info mismatch: requested', info, 'got', info2
524
525 def end_cont(self):
526 self.video.EndContinuousCapture()
527
528 # Misc stuff
529
530 def settitle(self):
531 gl.winset(self.window)
532 x, y = gl.getsize()
533 title = 'Vb:' + self.vfile + ' (%dx%d)' % (x, y)
534 gl.wintitle(title)
535
536 def get_vformat(self):
537 i = self.c_vformat.get_choice()
538 label = VideoFormatLabels[i-1]
539 format = VideoFormats[i-1]
540 self.vformat = format
541 if self.vformat == '':
542 self.form.freeze_form()
543 self.g_video.hide_object()
544 self.g_cont.hide_object()
545 self.g_burst.hide_object()
546 self.g_single.hide_object()
547 self.form.unfreeze_form()
548 return
549 else:
550 self.g_video.show_object()
551 if self.vmode == VM_CONT:
552 self.g_cont.show_object()
553 elif self.vmode == VM_BURST:
554 self.g_burst.show_object()
555 elif self.vmode == VM_SINGLE:
556 self.g_single.show_object()
Guido van Rossumc5a14331993-05-07 11:20:07 +0000557 #
558 self.rgb = (format[:3] == 'rgb')
559 self.mono = (format == 'mono')
560 self.grey = (format[:4] == 'grey')
561 self.mono_use_thresh = (label == 'mono thresh')
562 s = format[4:]
563 if s:
564 self.greybits = string.atoi(s)
565 else:
566 self.greybits = 8
567 if label == 'grey2 dith':
568 self.greybits = -2
569 #
570 convertor = None
571 if self.grey:
572 if self.greybits == 2:
573 convertor = imageop.grey2grey2
574 elif self.greybits == 4:
575 convertor = imageop.grey2grey4
576 elif self.greybits == -2:
577 convertor = imageop.dither2grey2
578 self.convertor = convertor
579
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000580 def get_aformat(self):
581 self.reset()
582 self.aformat = self.c_aformat.get_choice()
583 if self.aformat == A_OFF:
584 self.g_audio.hide_object()
585 else:
586 self.g_audio.show_object()
587
588 def open_if_closed(self):
589 if not self.vout:
590 self.open_video()
591 if not self.aout:
592 self.open_audio()
593
594 # File I/O handling
595
596 def open_video(self):
597 self.close_video()
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000598 gl.winset(self.window)
599 x, y = gl.getsize()
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000600 vout = VFile.VoutFile().init(self.vfile)
601 vout.setformat(self.vformat)
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000602 vout.setsize(x, y)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000603 if self.vmode == VM_BURST:
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000604 vout.setpf((1, -2))
605 vout.writeheader()
606 self.vout = vout
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000607 self.nframes = 0
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000608 self.speed_factor = 1
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000609 self.t_nframes.label = `self.nframes`
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000610
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000611 def write_frame(self, t, data):
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000612 t = t * self.speed_factor
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000613 if not self.vout:
614 gl.ringbell()
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000615 return 0
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000616 if self.convertor:
617 data = self.convertor(data, len(data), 1)
618 elif self.mono:
619 if self.mono_use_thresh:
620 data = imageop.grey2mono(data, \
621 len(data), 1,\
622 self.mono_thresh)
623 else:
624 data = imageop.dither2mono(data, \
625 len(data), 1)
626 try:
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000627 self.vout.writeframe(int(t), data, None)
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000628 except IOError, msg:
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000629 self.reset()
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000630 if msg == (0, 'Error 0'):
631 msg = 'disk full??'
632 fl.show_message('IOError', str(msg), '')
633 return 0
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000634 self.nframes = self.nframes + 1
635 self.t_nframes.label = `self.nframes`
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000636 return 1
637
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000638 def close_video(self):
639 if not self.vout:
640 return
641 self.nframes = 0
642 self.t_nframes.label = ''
Guido van Rossumc5a14331993-05-07 11:20:07 +0000643 try:
644 self.vout.close()
645 except IOError, msg:
646 if msg == (0, 'Error 0'):
647 msg = 'disk full??'
648 fl.show_message('IOError', str(msg), '')
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000649 self.vout = None
650
651 # Watch cursor handling
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000652
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000653 def setwatch(self):
654 gl.winset(self.form.window)
655 gl.setcursor(WATCH, 0, 0)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000656 gl.winset(self.window)
657 gl.setcursor(WATCH, 0, 0)
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000658
659 def setarrow(self):
660 gl.winset(self.form.window)
661 gl.setcursor(ARROW, 0, 0)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000662 gl.winset(self.window)
663 gl.setcursor(ARROW, 0, 0)
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000664
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000665 # Numeric field handling
666
667 def getint(self, field, default):
668 try:
669 value = string.atoi(field.get_input())
670 except string.atoi_error:
671 value = default
672 field.set_input(`value`)
673 return value
674
675 def getfloat(self, field, default):
676 try:
677 value = float(eval(field.get_input()))
678 except:
679 value = float(default)
Guido van Rossumc17c84f1993-05-10 15:45:49 +0000680 field.set_input(`value`)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000681 return value
682
683 # Audio stuff
684
685 def open_audio(self):
686 if self.aformat == A_OFF:
687 return
688 import aifc
689 import al
690 import AL
691 import thread
692 self.close_audio()
693 params = [AL.INPUT_RATE, 0]
694 al.getparams(AL.DEFAULT_DEVICE, params)
695 rate = params[1]
696 self.aout = aifc.open(self.afile, 'w')
697 if self.aformat in (A_16_STEREO, A_8_STEREO):
698 nch = AL.STEREO
699 else:
700 nch = AL.MONO
701 if self.aformat in (A_16_STEREO, A_16_MONO):
702 width = AL.SAMPLE_16
703 else:
704 width = AL.SAMPLE_8
705 self.aout.setnchannels(nch)
706 self.aout.setsampwidth(width)
707 self.aout.setframerate(rate)
708 self.aout.writeframes('')
709 c = al.newconfig()
710 c.setqueuesize(8000)
711 c.setchannels(nch)
712 c.setwidth(width)
713 self.aport = al.openport('Vb audio record', 'r', c)
714 self.audio_stop = 0
715 self.audio_ok = 0
716 self.audio_busy = 1
717 thread.start_new_thread(self.record_audio, ())
718
719 def start_audio(self):
720 if self.aformat == A_OFF:
721 return
722 self.audio_ok = 1
723
724 def record_audio(self, *args):
725 # This function runs in a separate thread
726 # Currently no semaphores are used
727 while not self.audio_stop:
728 data = self.aport.readsamps(4000)
729 if self.audio_ok:
730 self.aout.writeframesraw(data)
731 data = None
732 self.audio_busy = 0
733
734 def stop_audio(self):
735 self.audio_ok = 0
736
737 def close_audio(self):
738 if self.aout:
739 self.audio_ok = 0
740 self.audio_stop = 1
741 while self.audio_busy:
742 time.sleep(0.1)
743 self.aout.close()
744 self.aout = None
745 if self.aport:
746 self.aport.closeport()
747 self.aport = None
748
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000749
750try:
751 main()
752except KeyboardInterrupt:
753 print '[Interrupt]'
754 sys.exit(1)