blob: 92b3e061030d0577c988060dfb3e8b82f2b6062d [file] [log] [blame]
Guido van Rossumb7e3cc11993-05-06 16:06:44 +00001#! /ufs/guido/bin/sgi/python
2
3# Video bag-of-tricks
4
Guido van Rossumc5a14331993-05-07 11:20:07 +00005# XXX To do:
6# - audio
7# - single frame recording
8# - improve user interface
9# - help button?
10# - command line options to set initial settings
11# - save settings in a file
12# - ...?
Guido van Rossumbc6d3c31993-05-07 09:37:42 +000013
Guido van Rossumb7e3cc11993-05-06 16:06:44 +000014import sys
15import 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
32
33ARROW = 0
34WATCH = 1
35watchcursor.defwatch(WATCH)
36
37def main():
Guido van Rossumc5a14331993-05-07 11:20:07 +000038## fl.set_graphics_mode(0, 1)
Guido van Rossumb7e3cc11993-05-06 16:06:44 +000039 vb = VideoBagOfTricks().init()
40 while 1:
41 dummy = fl.do_forms()
42 [dummy]
43
44StopCapture = 'StopCapture'
45
Guido van Rossumbc6d3c31993-05-07 09:37:42 +000046Labels = ['rgb8', 'grey8', 'grey4', 'grey2', \
47 'grey2 dith', 'mono dith', 'mono thresh']
48Formats = ['rgb8', 'grey', 'grey4', 'grey2', \
49 'grey2', 'mono', 'mono']
Guido van Rossumb7e3cc11993-05-06 16:06:44 +000050
51class VideoBagOfTricks:
52
53 def init(self):
54 formdef = flp.parse_form('VbForm', 'form')
55 flp.create_full_form(self, formdef)
Guido van Rossume17c6c31993-05-06 16:27:25 +000056 self.g_stop.hide_object()
Guido van Rossumc5a14331993-05-07 11:20:07 +000057 self.g_burst.hide_object()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +000058 self.setdefaults()
59 self.openvideo()
60 self.makewindow()
61 self.bindvideo()
62 self.capturing = 0
Guido van Rossumc5a14331993-05-07 11:20:07 +000063 self.showform()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +000064 fl.set_event_call_back(self.do_event)
65 return self
66
Guido van Rossumc5a14331993-05-07 11:20:07 +000067 def showform(self):
68 # Get position of video window
69 gl.winset(self.window)
70 x, y = gl.getorigin()
71 width, height = gl.getsize()
72 # Calculate position of form window
73 x1 = x + width + 10
74 x2 = x1 + int(self.form.w) - 1
75 y2 = y + height - 1
76 y1 = y2 - int(self.form.h) + 1
77 # Position and show form window
78 gl.prefposition(x1, x2, y1, y2)
79 self.form.show_form(FL.PLACE_FREE, FL.TRUE, \
80 'Video Bag Of Tricks')
81
Guido van Rossumb7e3cc11993-05-06 16:06:44 +000082 def setdefaults(self):
Guido van Rossumbc6d3c31993-05-07 09:37:42 +000083 self.mono_thresh = 128
Guido van Rossumb7e3cc11993-05-06 16:06:44 +000084 self.format = 'rgb8'
85 self.c_format.clear_choice()
Guido van Rossumbc6d3c31993-05-07 09:37:42 +000086 for label in Labels:
Guido van Rossumb7e3cc11993-05-06 16:06:44 +000087 self.c_format.addto_choice(label)
Guido van Rossumbc6d3c31993-05-07 09:37:42 +000088 self.get_format()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +000089 self.b_drop.set_button(1)
90 self.b_burst.set_button(0)
91 self.in_rate.set_input('2')
92 self.in_maxmem.set_input('1.0')
93 self.in_nframes.set_input('0')
94 self.in_file.set_input('film.video')
95
96 def openvideo(self):
Guido van Rossumbc6d3c31993-05-07 09:37:42 +000097 try:
98 self.video = sv.OpenVideo()
99 except sv.error, msg:
100 print 'Error opening video:', msg
101 self.video = None
102 #sys.exit(1)
103 param = [SV.BROADCAST, SV.PAL]
104 if self.video: self.video.GetParam(param)
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000105 if param[1] == SV.PAL:
106 x = SV.PAL_XMAX
107 y = SV.PAL_YMAX
108 elif param[1] == SV.NTSC:
109 x = SV.NTSC_XMAX
110 y = SV.NTSC_YMAX
111 else:
112 print 'Unknown video standard:', param[1]
113 sys.exit(1)
114 self.maxx, self.maxy = x, y
115
116 def makewindow(self):
117 x, y = self.maxx, self.maxy
118 gl.foreground()
119 gl.maxsize(x, y)
120 gl.keepaspect(x, y)
121 gl.stepunit(8, 6)
122 width = 256 # XXX
123 if width:
124 height = width*3/4
125 x1 = 150
126 x2 = x1 + width-1
127 y2 = 768-150
128 y1 = y2-height+1
129 gl.prefposition(x1, x2, y1, y2)
130 self.window = gl.winopen('Vb: initializing')
131 self.settitle()
132 if width:
133 gl.maxsize(x, y)
134 gl.keepaspect(x, y)
135 gl.stepunit(8, 6)
136 gl.winconstraints()
137 gl.qdevice(DEVICE.LEFTMOUSE)
138 gl.qdevice(DEVICE.WINQUIT)
139 gl.qdevice(DEVICE.WINSHUT)
140
141 def settitle(self):
142 gl.winset(self.window)
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000143 x, y = gl.getsize()
144 title = 'Vb:' + self.in_file.get_input() + ' (%dx%d)' % (x, y)
145 gl.wintitle(title)
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000146
147 def bindvideo(self):
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000148 if not self.video: return
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000149 x, y = gl.getsize()
150 self.video.SetSize(x, y)
151 drop = self.b_drop.get_button()
152 if drop:
153 param = [SV.FIELDDROP, 1, SV.GENLOCK, SV.GENLOCK_OFF]
154 else:
155 param = [SV.FIELDDROP, 0, SV.GENLOCK, SV.GENLOCK_ON]
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000156 if self.rgb:
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000157 param = param+[SV.COLOR, SV.DEFAULT_COLOR, \
158 SV.DITHER, 1, \
159 SV.INPUT_BYPASS, 0]
160 else:
161 param = param+[SV.COLOR, SV.MONO, SV.DITHER, 0, \
162 SV.INPUT_BYPASS, 1]
163 self.video.BindGLWindow(self.window, SV.IN_REPLACE)
164 self.video.SetParam(param)
165
166 def rebindvideo(self):
167 gl.winset(self.window)
168 self.bindvideo()
169
170 def do_event(self, dev, val):
171 #print 'Event:', dev, val
172 if dev in (DEVICE.WINSHUT, DEVICE.WINQUIT):
173 self.cb_quit()
174 if dev == DEVICE.REDRAW and val == self.window:
175 self.rebindvideo()
176 self.settitle()
177
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000178 def cb_format(self, *args):
179 self.get_format()
180 if self.mono_use_thresh:
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000181 s = `self.mono_thresh`
182 s = fl.show_input('Please enter mono threshold', s)
183 if s:
184 try:
185 self.mono_thresh = string.atoi(s)
186 except string.atoi_error:
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000187 fl.show_message('Bad input, using', \
188 `self.mono_thresh`, '')
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000189 self.rebindvideo()
190
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000191 def cb_rate(self, *args):
192 pass
193
194 def cb_drop(self, *args):
195 self.rebindvideo()
196
197 def cb_burst(self, *args):
Guido van Rossumc5a14331993-05-07 11:20:07 +0000198 if self.b_burst.get_button():
199 self.in_rate.set_input('1')
200 self.b_drop.set_button(1)
201## self.g_stop.hide_object()
202 self.g_burst.show_object()
203 else:
204 self.in_rate.set_input('2')
205 self.b_drop.set_button(0)
206## self.g_stop.show_object()
207 self.g_burst.hide_object()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000208
209 def cb_maxmem(self, *args):
210 pass
211
212 def cb_nframes(self, *args):
213 pass
214
215 def cb_file(self, *args):
216 filename = self.in_file.get_input()
217 if filename == '':
218 filename = 'film.video'
219 self.in_file.set_input(filename)
220 self.settitle()
221
222 def cb_open(self, *args):
223 filename = self.in_file.get_input()
224 hd, tl = os.path.split(filename)
225 filename = fl.file_selector('Select file:', hd, '', tl)
226 if filename:
227 hd, tl = os.path.split(filename)
228 if hd == os.getcwd():
229 filename = tl
230 self.in_file.set_input(filename)
231 self.cb_file()
232
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000233 def cb_capture(self, *args):
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000234 if not self.video:
235 gl.ringbell()
236 return
237 if self.b_burst.get_button():
238 self.burst_capture()
239 else:
240 self.cont_capture()
241
Guido van Rossumc5a14331993-05-07 11:20:07 +0000242 def cb_stop(self, *args):
243 if self.capturing:
244 raise StopCapture
245 gl.ringbell()
246
247 def cb_play(self, *args):
248 filename = self.in_file.get_input()
249 sts = os.system('Vplay -q ' + filename + ' &')
250
251 def cb_quit(self, *args):
252 raise SystemExit, 0
253
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000254 def burst_capture(self):
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000255 self.setwatch()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000256 gl.winset(self.window)
257 x, y = gl.getsize()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000258 vformat = SV.RGB8_FRAMES
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000259 try:
260 nframes = string.atoi(self.in_nframes.get_input())
261 except string.atoi_error:
262 nframes = 0
263 if nframes == 0:
264 try:
265 maxmem = \
266 float(eval(self.in_maxmem.get_input()))
267 except:
268 maxmem = 1.0
269 memsize = int(maxmem * 1024 * 1024)
270 nframes = calcnframes(x, y, \
271 self.mono or self.grey, memsize)
272 print 'nframes =', nframes
273 rate = string.atoi(self.in_rate.get_input())
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000274 info = (vformat, x, y, nframes, rate)
275 try:
276 info2, data, bitvec = self.video.CaptureBurst(info)
277 except sv.error, msg:
278 fl.show_message('Capture error:', str(msg), '')
279 self.setarrow()
280 return
Guido van Rossumc5a14331993-05-07 11:20:07 +0000281 if info <> info2: print info, '<>', info2
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000282 self.save_burst(info2, data, bitvec)
283 self.setarrow()
284
285 def save_burst(self, info, data, bitvec):
286 (vformat, x, y, nframes, rate) = info
287 self.open_file()
288 fieldsize = x*y/2
289 nskipped = 0
290 realframeno = 0
291 tpf = 1000 / 50.0 #XXXX
292 # Trying to find the pattern in frame skipping
293 okstretch = 0
294 skipstretch = 0
295 for frameno in range(0, nframes*2):
296 if frameno <> 0 and \
297 bitvec[frameno] == bitvec[frameno-1]:
298 nskipped = nskipped + 1
299 if okstretch:
300 #print okstretch, 'ok',
301 okstretch = 0
302 skipstretch = skipstretch + 1
303 continue
304 if skipstretch:
305 #print skipstretch, 'skipped'
306 skipstretch = 0
307 okstretch = okstretch + 1
308 #
309 # Save field.
310 # XXXX Works only for fields and top-to-bottom
311 #
312 start = frameno*fieldsize
313 field = data[start:start+fieldsize]
314 realframeno = realframeno + 1
315 fn = int(realframeno*tpf)
316 if not self.write_frame(fn, field):
317 break
318 #print okstretch, 'ok',
319 #print skipstretch, 'skipped'
320 #print 'Skipped', nskipped, 'duplicate frames'
321 self.close_file()
322
323 def cont_capture(self):
324 self.setwatch()
325 self.g_main.hide_object()
326 self.open_file()
327 vformat = SV.RGB8_FRAMES
328 qsize = 1 # XXX Should be an option?
329 try:
330 rate = string.atoi(self.in_rate.get_input())
331 except string.atoi_error:
332 rate = 2
333 x, y = self.vout.getsize()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000334 info = (vformat, x, y, qsize, rate)
335 ids = []
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000336 fps = 59.64 # Fields per second
337 # XXX (fps of Indigo monitor, not of PAL or NTSC!)
338 tpf = 1000.0 / fps # Time per field in msec
339 info2 = self.video.InitContinuousCapture(info)
340 if info2 <> info:
341 print 'Info mismatch: requested', info, 'got', info2
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000342 self.capturing = 1
Guido van Rossume17c6c31993-05-06 16:27:25 +0000343 self.g_stop.show_object()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000344 self.setarrow()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000345 while 1:
346 try:
347 void = fl.check_forms()
348 except StopCapture:
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000349 break
350 try:
351 cd, id = self.video.GetCaptureData()
352 except sv.error:
353 sgi.nap(1)
354 continue
355 ids.append(id)
356 id = id + 2*rate
357 data = cd.InterleaveFields(1)
358 cd.UnlockCaptureData()
359 t = id*tpf
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000360 if not self.write_frame(t, data):
Guido van Rossume17c6c31993-05-06 16:27:25 +0000361 break
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000362 self.setwatch()
Guido van Rossume17c6c31993-05-06 16:27:25 +0000363 self.g_stop.hide_object()
364 self.capturing = 0
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000365 self.video.EndContinuousCapture()
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000366 self.close_file()
Guido van Rossume17c6c31993-05-06 16:27:25 +0000367 self.g_main.show_object()
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000368 self.setarrow()
369
Guido van Rossumc5a14331993-05-07 11:20:07 +0000370 def get_format(self):
371 i = self.c_format.get_choice()
372 label = Labels[i-1]
373 format = Formats[i-1]
374 self.format = format
375 #
376 self.rgb = (format[:3] == 'rgb')
377 self.mono = (format == 'mono')
378 self.grey = (format[:4] == 'grey')
379 self.mono_use_thresh = (label == 'mono thresh')
380 s = format[4:]
381 if s:
382 self.greybits = string.atoi(s)
383 else:
384 self.greybits = 8
385 if label == 'grey2 dith':
386 self.greybits = -2
387 #
388 convertor = None
389 if self.grey:
390 if self.greybits == 2:
391 convertor = imageop.grey2grey2
392 elif self.greybits == 4:
393 convertor = imageop.grey2grey4
394 elif self.greybits == -2:
395 convertor = imageop.dither2grey2
396 self.convertor = convertor
397
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000398 def open_file(self):
399 gl.winset(self.window)
400 x, y = gl.getsize()
401 self.cb_file() # Make sure filename is OK
402 filename = self.in_file.get_input()
403 vout = VFile.VoutFile().init(filename)
404 vout.setformat(self.format)
405 vout.setsize(x, y)
406 if self.b_burst.get_button():
407 vout.setpf((1, -2))
408 vout.writeheader()
409 self.vout = vout
410
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000411 def write_frame(self, t, data):
412 if self.convertor:
413 data = self.convertor(data, len(data), 1)
414 elif self.mono:
415 if self.mono_use_thresh:
416 data = imageop.grey2mono(data, \
417 len(data), 1,\
418 self.mono_thresh)
419 else:
420 data = imageop.dither2mono(data, \
421 len(data), 1)
422 try:
423 self.vout.writeframe(t, data, None)
424 except IOError, msg:
425 if msg == (0, 'Error 0'):
426 msg = 'disk full??'
427 fl.show_message('IOError', str(msg), '')
428 return 0
429 return 1
430
Guido van Rossumc5a14331993-05-07 11:20:07 +0000431 def close_file(self):
432 try:
433 self.vout.close()
434 except IOError, msg:
435 if msg == (0, 'Error 0'):
436 msg = 'disk full??'
437 fl.show_message('IOError', str(msg), '')
438 del self.vout
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000439
Guido van Rossumbc6d3c31993-05-07 09:37:42 +0000440 def setwatch(self):
441 gl.winset(self.form.window)
442 gl.setcursor(WATCH, 0, 0)
443
444 def setarrow(self):
445 gl.winset(self.form.window)
446 gl.setcursor(ARROW, 0, 0)
447
448def calcnframes(x, y, grey, memsize):
449 pixels = x*y
450 pixels = pixels/2 # XXX always assume fields
451 if grey: n = memsize/pixels
452 else: n = memsize/(4*pixels)
453 return max(1, n)
Guido van Rossumb7e3cc11993-05-06 16:06:44 +0000454
455try:
456 main()
457except KeyboardInterrupt:
458 print '[Interrupt]'
459 sys.exit(1)