blob: 57e76ae3d877126c6e71196474e4a366f38458cb [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
Guido van Rossumb7e3cc11993-05-06 16:06:44 +000034
35ARROW = 0
36WATCH = 1
37watchcursor.defwatch(WATCH)
38
39def main():
Guido van Rossumc5a14331993-05-07 11:20:07 +000040## fl.set_graphics_mode(0, 1)
Guido van Rossumb7e3cc11993-05-06 16:06:44 +000041 vb = VideoBagOfTricks().init()
42 while 1:
43 dummy = fl.do_forms()
44 [dummy]
45
46StopCapture = 'StopCapture'
47
Guido van Rossum9f42f4f1993-05-10 15:07:20 +000048VideoFormatLabels = ['Video off', 'rgb8', 'grey8', 'grey4', 'grey2', \
Jack Jansen672754a1993-06-08 12:52:41 +000049 'grey2 dith', 'mono dith', 'mono thresh', 'rgb24', 'rgb24-jpeg']
Guido van Rossum9f42f4f1993-05-10 15:07:20 +000050VideoFormats = ['', 'rgb8', 'grey', 'grey4', 'grey2', \
Jack Jansen672754a1993-06-08 12:52:41 +000051 'grey2', 'mono', 'mono', 'rgb', 'jpeg']
Guido van Rossum9f42f4f1993-05-10 15:07:20 +000052
53VideoModeLabels = ['Continuous', 'Burst', 'Single frame', 'VCR sync']
54[VM_CONT, VM_BURST, VM_SINGLE, VM_VCR] = range(1, 5)
55
56AudioFormatLabels = ['Audio off', \
57 '16 bit mono', '16 bit stereo', '8 bit mono', '8 bit stereo']
58[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 +000059
Jack Jansen672754a1993-06-08 12:52:41 +000060VcrSpeedLabels = ['normal', '1/3', '1/5', '1/10', '1/30', 'single-step']
61VcrSpeeds = [None, 5, 4, 3, 2, 1, 0]
62
63RgbSizeLabels = ['full', 'quarter', 'sixteenth']
64
Guido van Rossumb7e3cc11993-05-06 16:06:44 +000065class VideoBagOfTricks:
66
Guido van Rossum9f42f4f1993-05-10 15:07:20 +000067 # Init/close stuff
68
Guido van Rossumb7e3cc11993-05-06 16:06:44 +000069 def init(self):
Jack Jansen672754a1993-06-08 12:52:41 +000070 self.window = None
Guido van Rossumb7e3cc11993-05-06 16:06:44 +000071 formdef = flp.parse_form('VbForm', 'form')
72 flp.create_full_form(self, formdef)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +000073 self.g_cont.hide_object()
Guido van Rossumc5a14331993-05-07 11:20:07 +000074 self.g_burst.hide_object()
Guido van Rossum9f42f4f1993-05-10 15:07:20 +000075 self.g_single.hide_object()
76 self.g_vcr.hide_object()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +000077 self.setdefaults()
78 self.openvideo()
79 self.makewindow()
80 self.bindvideo()
Guido van Rossumc5a14331993-05-07 11:20:07 +000081 self.showform()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +000082 fl.set_event_call_back(self.do_event)
83 return self
84
Guido van Rossum9f42f4f1993-05-10 15:07:20 +000085 def close(self):
86 self.close_video()
87 self.close_audio()
88 raise SystemExit, 0
89
Guido van Rossumc5a14331993-05-07 11:20:07 +000090 def showform(self):
91 # Get position of video window
92 gl.winset(self.window)
93 x, y = gl.getorigin()
94 width, height = gl.getsize()
95 # Calculate position of form window
96 x1 = x + width + 10
97 x2 = x1 + int(self.form.w) - 1
98 y2 = y + height - 1
99 y1 = y2 - int(self.form.h) + 1
100 # Position and show form window
101 gl.prefposition(x1, x2, y1, y2)
Guido van Rossum43df8621993-06-11 15:48:39 +0000102 self.form.show_form(FL.PLACE_FREE, FL.TRUE, 'Vb Control')
Guido van Rossumc5a14331993-05-07 11:20:07 +0000103
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000104 def setdefaults(self):
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000105 self.vcr = None
106 self.vout = None
107 self.capturing = 0
108 # Video defaults
109 self.vfile = 'film.video'
110 self.vmode = VM_CONT
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000111 self.mono_thresh = 128
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000112 self.vformat = 'rgb8'
113 self.c_vformat.clear_choice()
114 for label in VideoFormatLabels:
115 self.c_vformat.addto_choice(label)
116 self.c_vformat.set_choice(1 + VideoFormats.index(self.vformat))
117 self.c_vmode.clear_choice()
118 for label in VideoModeLabels:
119 self.c_vmode.addto_choice(label)
120 self.c_vmode.set_choice(self.vmode)
121 self.get_vformat()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000122 self.b_drop.set_button(1)
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000123 self.in_rate.set_input('2')
124 self.in_maxmem.set_input('1.0')
125 self.in_nframes.set_input('0')
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000126 self.in_nframes_vcr.set_input('1')
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000127 self.in_rate_vcr.set_input('1')
Jack Jansen672754a1993-06-08 12:52:41 +0000128 self.c_vcrspeed.clear_choice()
129 for label in VcrSpeedLabels:
130 self.c_vcrspeed.addto_choice(label)
131 self.c_vcrspeed.set_choice(4)
132 self.c_rgb24_size.clear_choice()
133 for label in RgbSizeLabels:
134 self.c_rgb24_size.addto_choice(label)
135 self.c_rgb24_size.set_choice(1)
136 self.rgb24_size = 1
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000137 # Audio defaults
138 self.aout = None
139 self.aport = None
140 self.afile = 'film.aiff'
141 self.aformat = A_OFF
142 self.c_aformat.clear_choice()
143 for label in AudioFormatLabels:
144 self.c_aformat.addto_choice(label)
145 self.c_aformat.set_choice(self.aformat)
146 self.get_aformat()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000147
148 def openvideo(self):
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000149 try:
150 self.video = sv.OpenVideo()
151 except sv.error, msg:
152 print 'Error opening video:', msg
153 self.video = None
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000154 param = [SV.BROADCAST, SV.PAL]
155 if self.video: self.video.GetParam(param)
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000156 if param[1] == SV.PAL:
157 x = SV.PAL_XMAX
158 y = SV.PAL_YMAX
159 elif param[1] == SV.NTSC:
160 x = SV.NTSC_XMAX
161 y = SV.NTSC_YMAX
162 else:
163 print 'Unknown video standard:', param[1]
164 sys.exit(1)
165 self.maxx, self.maxy = x, y
Guido van Rossum43df8621993-06-11 15:48:39 +0000166 self.curx = 256
167 self.cury = 256*3/4
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000168
169 def makewindow(self):
170 x, y = self.maxx, self.maxy
171 gl.foreground()
172 gl.maxsize(x, y)
173 gl.keepaspect(x, y)
174 gl.stepunit(8, 6)
Guido van Rossum43df8621993-06-11 15:48:39 +0000175 width = self.curx
176 height = self.cury
177 if width and height:
178 # Place the window at (150, 150) from top left
179 # (the video board likes this location...)
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000180 x1 = 150
Guido van Rossum43df8621993-06-11 15:48:39 +0000181 x2 = x1+width-1
182 SCRHEIGHT = 768
183 y2 = SCRHEIGHT-1-150
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000184 y1 = y2-height+1
185 gl.prefposition(x1, x2, y1, y2)
Guido van Rossum43df8621993-06-11 15:48:39 +0000186 self.window = gl.winopen('Vb video')
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000187 self.settitle()
188 if width:
189 gl.maxsize(x, y)
190 gl.keepaspect(x, y)
191 gl.stepunit(8, 6)
192 gl.winconstraints()
193 gl.qdevice(DEVICE.LEFTMOUSE)
194 gl.qdevice(DEVICE.WINQUIT)
195 gl.qdevice(DEVICE.WINSHUT)
196
Jack Jansen672754a1993-06-08 12:52:41 +0000197 def optfullsizewindow(self):
198 if not self.window:
199 return
200 gl.winset(self.window)
Guido van Rossum43df8621993-06-11 15:48:39 +0000201 if self.use_24:
202 x, y = self.maxx, self.maxy
203 else:
204 x, y = self.curx, self.cury
Guido van Rossum2055ee81993-06-11 14:13:13 +0000205 left, bottom = gl.getorigin()
206 width, height = gl.getsize()
207 bottom = bottom+height-y
208 gl.prefposition(left, left+x-1, bottom, bottom+y-1)
Jack Jansen672754a1993-06-08 12:52:41 +0000209 gl.winconstraints()
Guido van Rossum43df8621993-06-11 15:48:39 +0000210 if not self.use_24:
211 gl.keepaspect(x, y)
212 gl.stepunit(8, 6)
213 gl.maxsize(self.maxx, self.maxy)
214 gl.winconstraints()
Jack Jansen672754a1993-06-08 12:52:41 +0000215 self.bindvideo()
216
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000217 def bindvideo(self):
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000218 if not self.video: return
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000219 x, y = gl.getsize()
Guido van Rossum43df8621993-06-11 15:48:39 +0000220 if not self.use_24:
221 self.curx, self.cury = x, y
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000222 self.video.SetSize(x, y)
223 drop = self.b_drop.get_button()
224 if drop:
225 param = [SV.FIELDDROP, 1, SV.GENLOCK, SV.GENLOCK_OFF]
226 else:
227 param = [SV.FIELDDROP, 0, SV.GENLOCK, SV.GENLOCK_ON]
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000228 if self.rgb:
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000229 param = param+[SV.COLOR, SV.DEFAULT_COLOR, \
230 SV.DITHER, 1, \
231 SV.INPUT_BYPASS, 0]
232 else:
233 param = param+[SV.COLOR, SV.MONO, SV.DITHER, 0, \
234 SV.INPUT_BYPASS, 1]
235 self.video.BindGLWindow(self.window, SV.IN_REPLACE)
236 self.video.SetParam(param)
237
238 def rebindvideo(self):
239 gl.winset(self.window)
240 self.bindvideo()
241
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000242 def reset(self):
243 self.close_video()
244 self.close_audio()
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000245 if self.vcr:
246 try:
247 ok = self.vcr.still()
248 except VCR.error:
249 pass
250 self.vcr = None
251 self.b_capture.set_button(0)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000252
253 # Event handler (catches resize of video window)
254
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000255 def do_event(self, dev, val):
256 #print 'Event:', dev, val
257 if dev in (DEVICE.WINSHUT, DEVICE.WINQUIT):
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000258 self.close()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000259 if dev == DEVICE.REDRAW and val == self.window:
260 self.rebindvideo()
261 self.settitle()
262
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000263 # Video controls: format, mode, file
264
265 def cb_vformat(self, *args):
266 self.reset()
267 self.get_vformat()
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000268 if self.mono_use_thresh:
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000269 s = `self.mono_thresh`
270 s = fl.show_input('Please enter mono threshold', s)
271 if s:
272 try:
273 self.mono_thresh = string.atoi(s)
274 except string.atoi_error:
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000275 fl.show_message('Bad input, using', \
276 `self.mono_thresh`, '')
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000277 self.rebindvideo()
278
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000279 def cb_vmode(self, *args):
Guido van Rossumc17c84f1993-05-10 15:45:49 +0000280 if self.vcr:
281 self.vcr = None
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000282 self.vmode = self.c_vmode.get_choice()
283 self.form.freeze_form()
284 self.g_cont.hide_object()
285 self.g_burst.hide_object()
286 self.g_single.hide_object()
287 self.g_vcr.hide_object()
288 if self.vmode == VM_CONT:
289 self.g_cont.show_object()
290 elif self.vmode == VM_BURST:
291 self.g_burst.show_object()
292 elif self.vmode == VM_SINGLE:
293 self.g_single.show_object()
294 elif self.vmode == VM_VCR:
295 self.g_vcr.show_object()
296 self.form.unfreeze_form()
297
298 def cb_vfile(self, *args):
299 filename = self.vfile
300 hd, tl = os.path.split(filename)
301 filename = fl.file_selector('Video save file:', hd, '', tl)
302 if filename:
303 self.reset()
304 hd, tl = os.path.split(filename)
305 if hd == os.getcwd():
306 filename = tl
307 self.vfile = filename
308
309 # Video mode specific video controls
310
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000311 def cb_rate(self, *args):
312 pass
313
314 def cb_drop(self, *args):
315 self.rebindvideo()
316
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000317 def cb_maxmem(self, *args):
318 pass
319
320 def cb_nframes(self, *args):
321 pass
322
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000323 def cb_fps(self, *args):
324 pass
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000325
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000326 def cb_nframes_vcr(self, *args):
327 pass
328
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000329 def cb_rate_vcr(self, *args):
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000330 pass
331
Jack Jansen672754a1993-06-08 12:52:41 +0000332 def cb_vcrspeed(self, *args):
333 pass
334
335 def cb_rgb24_size(self, *args):
336 i = self.c_rgb24_size.get_choice()
337 if i:
338 self.rgb24_size = i
339
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000340 # Audio controls: format, file
341
342 def cb_aformat(self, *args):
343 self.get_aformat()
344
345 def cb_afile(self, *args):
346 filename = self.afile
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000347 hd, tl = os.path.split(filename)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000348 filename = fl.file_selector('Audio save file:', hd, '', tl)
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000349 if filename:
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000350 self.reset()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000351 hd, tl = os.path.split(filename)
352 if hd == os.getcwd():
353 filename = tl
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000354 self.afile = filename
355
356 # General controls: capture, reset, play, quit
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000357
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000358 def cb_capture(self, *args):
Guido van Rossumc5a14331993-05-07 11:20:07 +0000359 if self.capturing:
360 raise StopCapture
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000361 if not self.b_capture.get_button():
362 return
363 if not self.video or not self.vformat:
364 gl.ringbell()
365 return
366 if self.vmode == VM_CONT:
367 self.cont_capture()
368 elif self.vmode == VM_BURST:
369 self.burst_capture()
370 elif self.vmode == VM_SINGLE:
Jack Jansen672754a1993-06-08 12:52:41 +0000371 self.single_capture(None, None)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000372 elif self.vmode == VM_VCR:
373 self.vcr_capture()
374
375 def cb_reset(self, *args):
376 self.reset()
Guido van Rossumc5a14331993-05-07 11:20:07 +0000377
378 def cb_play(self, *args):
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000379 self.reset()
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000380 sts = os.system('Vplay -q ' + self.vfile + ' &')
Guido van Rossumc5a14331993-05-07 11:20:07 +0000381
382 def cb_quit(self, *args):
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000383 self.close()
384
385 # Capture routines
Guido van Rossumc5a14331993-05-07 11:20:07 +0000386
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000387 def burst_capture(self):
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000388 self.setwatch()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000389 gl.winset(self.window)
390 x, y = gl.getsize()
Jack Jansen672754a1993-06-08 12:52:41 +0000391 if self.use_24:
392 fl.show_message('Sorry, no 24 bit continuous capture yet', '', '')
393 return
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000394 vformat = SV.RGB8_FRAMES
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000395 nframes = self.getint(self.in_nframes, 0)
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000396 if nframes == 0:
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000397 maxmem = self.getint(self.in_maxmem, 1.0)
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000398 memsize = int(maxmem * 1024 * 1024)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000399 nframes = self.calcnframes()
400 info = (vformat, x, y, nframes, 1)
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000401 try:
402 info2, data, bitvec = self.video.CaptureBurst(info)
403 except sv.error, msg:
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000404 self.b_capture.set_button(0)
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000405 self.setarrow()
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000406 fl.show_message('Capture error:', str(msg), '')
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000407 return
Guido van Rossumc5a14331993-05-07 11:20:07 +0000408 if info <> info2: print info, '<>', info2
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000409 self.save_burst(info2, data, bitvec)
410 self.setarrow()
411
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000412 def calcnframes(self):
413 gl.winset(self.window)
414 x, y = gl.getsize()
415 pixels = x*y
416 pixels = pixels/2 # XXX always assume fields
417 if self.mono or self.grey:
418 n = memsize/pixels
419 else:
420 n = memsize/(4*pixels)
421 return max(1, n)
422
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000423 def save_burst(self, info, data, bitvec):
424 (vformat, x, y, nframes, rate) = info
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000425 self.open_if_closed()
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000426 fieldsize = x*y/2
427 nskipped = 0
428 realframeno = 0
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000429 tpf = 1000 / 50.0 # XXX
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000430 for frameno in range(0, nframes*2):
431 if frameno <> 0 and \
432 bitvec[frameno] == bitvec[frameno-1]:
433 nskipped = nskipped + 1
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000434 continue
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000435 #
436 # Save field.
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000437 # XXX Works only for fields and top-to-bottom
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000438 #
439 start = frameno*fieldsize
440 field = data[start:start+fieldsize]
441 realframeno = realframeno + 1
442 fn = int(realframeno*tpf)
443 if not self.write_frame(fn, field):
444 break
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000445
446 def cont_capture(self):
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000447 saved_label = self.b_capture.label
448 self.b_capture.label = 'Stop\n' + saved_label
449 self.open_if_closed()
450 self.init_cont()
451 fps = 59.64 # Fields per second
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000452 # XXX (fps of Indigo monitor, not of PAL or NTSC!)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000453 tpf = 1000.0 / fps # Time per field in msec
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000454 self.capturing = 1
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000455 self.start_audio()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000456 while 1:
457 try:
458 void = fl.check_forms()
459 except StopCapture:
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000460 break
461 try:
462 cd, id = self.video.GetCaptureData()
463 except sv.error:
464 sgi.nap(1)
465 continue
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000466 id = id + 2*self.rate
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000467 data = cd.InterleaveFields(1)
468 cd.UnlockCaptureData()
469 t = id*tpf
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000470 if not self.write_frame(t, data):
Guido van Rossume17c6c31993-05-06 16:27:25 +0000471 break
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000472 self.stop_audio()
Guido van Rossume17c6c31993-05-06 16:27:25 +0000473 self.capturing = 0
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000474 self.end_cont()
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000475 if self.aout:
476 # If recording audio, can't capture multiple sequences
477 self.reset()
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000478 self.b_capture.label = saved_label
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000479
Jack Jansen672754a1993-06-08 12:52:41 +0000480 def single_capture(self, stepfunc, timecode):
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000481 self.open_if_closed()
482 self.init_cont()
483 while 1:
484 try:
485 cd, id = self.video.GetCaptureData()
486 break
487 except sv.error:
488 pass
489 sgi.nap(1)
Jack Jansen672754a1993-06-08 12:52:41 +0000490 if stepfunc: # This might step the video
491 d=stepfunc() # to the next frame
492 if not self.use_24:
493 data = cd.InterleaveFields(1)
494 else:
495 x, y = self.vout.getsize()
496 if self.rgb24_size == 1:
497 data = cd.YUVtoRGB(1)
498 elif self.rgb24_size == 2:
499 data = cd.YUVtoRGB_quarter(1)
500 x = x/2
501 y = y/2
502 elif self.rgb24_size == 3:
503 data = cd.YUVtoRGB_sixteenth(1)
504 x = x/4
505 y = y/4
506 else:
507 raise 'Kaboo! Kaboo!'
508 if self.use_jpeg:
509 import jpeg
510 data = jpeg.compress(data, x, y, 4)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000511 cd.UnlockCaptureData()
512 self.end_cont()
Jack Jansen672754a1993-06-08 12:52:41 +0000513 if timecode == None:
514 timecode = (self.nframes+1) * (1000/25)
515 return self.write_frame(timecode, data)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000516
517 def vcr_capture(self):
518 if not self.vcr:
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000519 try:
Guido van Rossum2055ee81993-06-11 14:13:13 +0000520 print 'Connecting to VCR ...'
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000521 self.vcr = VCR.VCR().init()
Guido van Rossum2055ee81993-06-11 14:13:13 +0000522 print 'Waiting for VCR to come online ...'
Guido van Rossumc17c84f1993-05-10 15:45:49 +0000523 self.vcr.wait()
Guido van Rossum2055ee81993-06-11 14:13:13 +0000524 print 'Preparing VCR ...'
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000525 if not (self.vcr.fmmode('dnr') and \
526 self.vcr.dmcontrol('digital slow')):
527 self.vcr_error('digital slow failed')
528 return
Guido van Rossum2055ee81993-06-11 14:13:13 +0000529 print 'VCR OK.'
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000530 except VCR.error, msg:
Guido van Rossumc17c84f1993-05-10 15:45:49 +0000531 self.vcr = None
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000532 self.vcr_error(msg)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000533 return
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000534 if not self.vcr.still():
535 self.vcr_error('still failed')
536 return
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000537 self.open_if_closed()
538 rate = self.getint(self.in_rate_vcr, 1)
539 rate = max(rate, 1)
Jack Jansen672754a1993-06-08 12:52:41 +0000540 vcrspeed = self.c_vcrspeed.get_choice()
541 vcrspeed = VcrSpeeds[vcrspeed]
542 if vcrspeed == 0:
543 stepfunc = self.vcr.step
544 else:
545 stepfunc = None
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000546 self.speed_factor = rate
Jack Jansen672754a1993-06-08 12:52:41 +0000547 addr = start_addr = self.vcr.sense()
548 if not self.single_capture(None, 0):
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000549 return
550 print 'captured %02d:%02d:%02d:%02d' % self.vcr.addr2tc(addr)
551 count = self.getint(self.in_nframes_vcr, 1) - 1
552 if count <= 0:
553 while rate > 0:
554 if not self.vcr.step():
555 self.vcr_error('step failed')
556 here = self.vcr.sense()
557 if here > addr:
558 rate = rate - (here - addr)
559 addr = here
560 return
Guido van Rossum2055ee81993-06-11 14:13:13 +0000561 if not self.vcr.fwdshuttle(vcrspeed):
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000562 self.vcr_error('fwd shuttle failed')
563 return
564 cycle = 0
565 while count > 0:
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000566 try:
567 here = self.vcr.sense()
568 except VCR.error, msg:
569 self.vcr_error(msg)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000570 break
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000571 if here <> addr:
572 if here <> addr+1:
573 print 'Missed', here-addr-1,
574 print 'frame' + 's'*(here-addr-1 <> 1)
575 cycle = (cycle+1) % rate
576 if cycle == 0:
Jack Jansen672754a1993-06-08 12:52:41 +0000577 tc = (here-start_addr)*40
578 if not self.single_capture(stepfunc, \
579 tc):
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000580 break
581 print 'captured %02d:%02d:%02d:%02d' \
582 % self.vcr.addr2tc(here)
583 count = count -1
584 addr = here
585 if self.vcr and not self.vcr.still():
586 self.vcr_error('still failed')
587
588 def vcr_error(self, msg):
589 self.reset()
590 fl.show_message('VCR error:', str(msg), '')
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000591
592 # Init/end continuous capture mode
593
594 def init_cont(self):
595 qsize = 1
596 if self.vmode == VM_CONT:
597 self.rate = self.getint(self.in_rate, 2)
598 else:
599 self.rate = 2
600 x, y = self.vout.getsize()
Jack Jansen672754a1993-06-08 12:52:41 +0000601 if self.use_24:
602 info = (SV.YUV411_FRAMES, x, y, qsize, self.rate)
603 else:
604 info = (SV.RGB8_FRAMES, x, y, qsize, self.rate)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000605 info2 = self.video.InitContinuousCapture(info)
606 if info2 <> info:
607 # XXX This is really only debug info
608 print 'Info mismatch: requested', info, 'got', info2
609
610 def end_cont(self):
611 self.video.EndContinuousCapture()
612
613 # Misc stuff
614
615 def settitle(self):
616 gl.winset(self.window)
617 x, y = gl.getsize()
Guido van Rossum43df8621993-06-11 15:48:39 +0000618 title = 'Vb ' + self.vfile + ' (%dx%d)' % (x, y)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000619 gl.wintitle(title)
620
621 def get_vformat(self):
622 i = self.c_vformat.get_choice()
623 label = VideoFormatLabels[i-1]
624 format = VideoFormats[i-1]
625 self.vformat = format
626 if self.vformat == '':
627 self.form.freeze_form()
628 self.g_video.hide_object()
629 self.g_cont.hide_object()
630 self.g_burst.hide_object()
631 self.g_single.hide_object()
632 self.form.unfreeze_form()
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000633 else:
634 self.g_video.show_object()
635 if self.vmode == VM_CONT:
636 self.g_cont.show_object()
637 elif self.vmode == VM_BURST:
638 self.g_burst.show_object()
639 elif self.vmode == VM_SINGLE:
640 self.g_single.show_object()
Guido van Rossumc5a14331993-05-07 11:20:07 +0000641 #
642 self.rgb = (format[:3] == 'rgb')
643 self.mono = (format == 'mono')
644 self.grey = (format[:4] == 'grey')
Jack Jansen672754a1993-06-08 12:52:41 +0000645 self.use_24 = (format in ('rgb', 'jpeg'))
Guido van Rossum43df8621993-06-11 15:48:39 +0000646 if self.use_24 and 0: ### quarter/sixteenth decoding not impl.
Jack Jansen672754a1993-06-08 12:52:41 +0000647 self.g_rgb24.show_object()
648 else:
649 self.g_rgb24.hide_object()
650 self.use_jpeg = (format == 'jpeg')
Guido van Rossumc5a14331993-05-07 11:20:07 +0000651 self.mono_use_thresh = (label == 'mono thresh')
652 s = format[4:]
653 if s:
654 self.greybits = string.atoi(s)
655 else:
656 self.greybits = 8
657 if label == 'grey2 dith':
658 self.greybits = -2
659 #
660 convertor = None
661 if self.grey:
662 if self.greybits == 2:
663 convertor = imageop.grey2grey2
664 elif self.greybits == 4:
665 convertor = imageop.grey2grey4
666 elif self.greybits == -2:
667 convertor = imageop.dither2grey2
668 self.convertor = convertor
Jack Jansen672754a1993-06-08 12:52:41 +0000669 self.optfullsizewindow()
Guido van Rossumc5a14331993-05-07 11:20:07 +0000670
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000671 def get_aformat(self):
672 self.reset()
673 self.aformat = self.c_aformat.get_choice()
674 if self.aformat == A_OFF:
675 self.g_audio.hide_object()
676 else:
677 self.g_audio.show_object()
678
679 def open_if_closed(self):
680 if not self.vout:
681 self.open_video()
682 if not self.aout:
683 self.open_audio()
684
685 # File I/O handling
686
687 def open_video(self):
688 self.close_video()
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000689 gl.winset(self.window)
690 x, y = gl.getsize()
Jack Jansen672754a1993-06-08 12:52:41 +0000691 if self.use_24:
692 if self.rgb24_size == 2:
693 x, y = x/2, y/2
694 elif self.rgb24_size == 4:
695 x, y = x/4, y/4
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000696 vout = VFile.VoutFile().init(self.vfile)
697 vout.setformat(self.vformat)
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000698 vout.setsize(x, y)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000699 if self.vmode == VM_BURST:
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000700 vout.setpf((1, -2))
701 vout.writeheader()
702 self.vout = vout
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000703 self.nframes = 0
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000704 self.speed_factor = 1
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000705 self.t_nframes.label = `self.nframes`
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000706
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000707 def write_frame(self, t, data):
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000708 t = t * self.speed_factor
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000709 if not self.vout:
710 gl.ringbell()
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000711 return 0
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000712 if self.convertor:
713 data = self.convertor(data, len(data), 1)
714 elif self.mono:
715 if self.mono_use_thresh:
716 data = imageop.grey2mono(data, \
717 len(data), 1,\
718 self.mono_thresh)
719 else:
720 data = imageop.dither2mono(data, \
721 len(data), 1)
722 try:
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000723 self.vout.writeframe(int(t), data, None)
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000724 except IOError, msg:
Guido van Rossumad4fcd41993-05-11 18:36:54 +0000725 self.reset()
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000726 if msg == (0, 'Error 0'):
727 msg = 'disk full??'
728 fl.show_message('IOError', str(msg), '')
729 return 0
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000730 self.nframes = self.nframes + 1
731 self.t_nframes.label = `self.nframes`
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000732 return 1
733
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000734 def close_video(self):
735 if not self.vout:
736 return
737 self.nframes = 0
738 self.t_nframes.label = ''
Guido van Rossumc5a14331993-05-07 11:20:07 +0000739 try:
740 self.vout.close()
741 except IOError, msg:
742 if msg == (0, 'Error 0'):
743 msg = 'disk full??'
744 fl.show_message('IOError', str(msg), '')
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000745 self.vout = None
746
747 # Watch cursor handling
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000748
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000749 def setwatch(self):
750 gl.winset(self.form.window)
751 gl.setcursor(WATCH, 0, 0)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000752 gl.winset(self.window)
753 gl.setcursor(WATCH, 0, 0)
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000754
755 def setarrow(self):
756 gl.winset(self.form.window)
757 gl.setcursor(ARROW, 0, 0)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000758 gl.winset(self.window)
759 gl.setcursor(ARROW, 0, 0)
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000760
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000761 # Numeric field handling
762
763 def getint(self, field, default):
764 try:
765 value = string.atoi(field.get_input())
766 except string.atoi_error:
767 value = default
768 field.set_input(`value`)
769 return value
770
771 def getfloat(self, field, default):
772 try:
773 value = float(eval(field.get_input()))
774 except:
775 value = float(default)
Guido van Rossumc17c84f1993-05-10 15:45:49 +0000776 field.set_input(`value`)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000777 return value
778
779 # Audio stuff
780
781 def open_audio(self):
782 if self.aformat == A_OFF:
783 return
784 import aifc
785 import al
786 import AL
787 import thread
788 self.close_audio()
789 params = [AL.INPUT_RATE, 0]
790 al.getparams(AL.DEFAULT_DEVICE, params)
791 rate = params[1]
792 self.aout = aifc.open(self.afile, 'w')
793 if self.aformat in (A_16_STEREO, A_8_STEREO):
794 nch = AL.STEREO
795 else:
796 nch = AL.MONO
797 if self.aformat in (A_16_STEREO, A_16_MONO):
798 width = AL.SAMPLE_16
799 else:
800 width = AL.SAMPLE_8
801 self.aout.setnchannels(nch)
802 self.aout.setsampwidth(width)
803 self.aout.setframerate(rate)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000804 c = al.newconfig()
805 c.setqueuesize(8000)
806 c.setchannels(nch)
807 c.setwidth(width)
808 self.aport = al.openport('Vb audio record', 'r', c)
809 self.audio_stop = 0
810 self.audio_ok = 0
811 self.audio_busy = 1
812 thread.start_new_thread(self.record_audio, ())
813
814 def start_audio(self):
815 if self.aformat == A_OFF:
816 return
817 self.audio_ok = 1
818
819 def record_audio(self, *args):
820 # This function runs in a separate thread
821 # Currently no semaphores are used
822 while not self.audio_stop:
823 data = self.aport.readsamps(4000)
824 if self.audio_ok:
Guido van Rossumf6d80321993-06-10 13:40:51 +0000825 self.aout.writeframes(data)
Guido van Rossum9f42f4f1993-05-10 15:07:20 +0000826 data = None
827 self.audio_busy = 0
828
829 def stop_audio(self):
830 self.audio_ok = 0
831
832 def close_audio(self):
833 if self.aout:
834 self.audio_ok = 0
835 self.audio_stop = 1
836 while self.audio_busy:
837 time.sleep(0.1)
838 self.aout.close()
839 self.aout = None
840 if self.aport:
841 self.aport.closeport()
842 self.aport = None
843
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000844
845try:
846 main()
847except KeyboardInterrupt:
848 print '[Interrupt]'
849 sys.exit(1)