blob: 176c0e5a0c0dcbf5b853fea9316b53f279a249f0 [file] [log] [blame]
Guido van Rossumf06ee5f1996-11-27 19:52:01 +00001#! /usr/bin/env python
Guido van Rossum82534fd1992-08-18 17:01:02 +00002
3# Play CMIF movie files
4
5
Guido van Rossume755aa51992-08-21 12:34:55 +00006# Help function
7
8def help():
9 print 'Usage: Vplay [options] [file] ...'
10 print
11 print 'Options:'
12 print '-M magnify : magnify the image by the given factor'
13 print '-d : write some debug stuff on stderr'
14 print '-l : loop, playing the movie over and over again'
Guido van Rossum605909d1993-12-28 21:28:31 +000015 print '-m delta : drop frames closer than delta seconds (default 0.)'
Guido van Rossume1783321992-09-07 09:35:23 +000016 print '-n : don\'t wait after each file'
Guido van Rossume755aa51992-08-21 12:34:55 +000017 print '-q : quiet, no informative messages'
Guido van Rossum605909d1993-12-28 21:28:31 +000018 print '-r delta : regenerate input time base delta seconds apart'
Guido van Rossume755aa51992-08-21 12:34:55 +000019 print '-s speed : speed change factor (default 1.0)'
20 print '-t : use a 2nd thread for read-ahead'
21 print '-x left : window offset from left of screen'
22 print '-y top : window offset from top of screen'
Jack Jansen772eca61993-01-27 11:42:21 +000023 print '-w width : window width'
24 print '-h height : window height'
25 print '-b color : background color (white,black or (r,g,b))'
Guido van Rossume755aa51992-08-21 12:34:55 +000026 print 'file ... : file(s) to play; default film.video'
27 print
28 print 'User interface:'
29 print 'Press the left mouse button to stop or restart the movie.'
30 print 'Press ESC or use the window manager Close or Quit command'
31 print 'to close the window and play the next file (if any).'
Guido van Rossum82534fd1992-08-18 17:01:02 +000032
33
Guido van Rossume755aa51992-08-21 12:34:55 +000034# Imported modules
Guido van Rossum82534fd1992-08-18 17:01:02 +000035
Guido van Rossum843d1531992-08-18 14:16:12 +000036import sys
Guido van Rossume755aa51992-08-21 12:34:55 +000037sys.path.append('/ufs/guido/src/video') # Increase chance of finding VFile
Guido van Rossum843d1531992-08-18 14:16:12 +000038import VFile
39import time
40import gl, GL
Guido van Rossume755aa51992-08-21 12:34:55 +000041from DEVICE import REDRAW, ESCKEY, LEFTMOUSE, WINSHUT, WINQUIT
Guido van Rossum82534fd1992-08-18 17:01:02 +000042import getopt
43import string
44
45
46# Global options
47
Guido van Rossume755aa51992-08-21 12:34:55 +000048debug = 0
Guido van Rossum82534fd1992-08-18 17:01:02 +000049looping = 0
Guido van Rossume755aa51992-08-21 12:34:55 +000050magnify = 1
Guido van Rossum78aab861992-08-20 11:52:42 +000051mindelta = 0
Guido van Rossume755aa51992-08-21 12:34:55 +000052nowait = 0
Guido van Rossum78aab861992-08-20 11:52:42 +000053quiet = 0
54regen = None
Guido van Rossume755aa51992-08-21 12:34:55 +000055speed = 1.0
56threading = 0
57xoff = yoff = None
Jack Jansen772eca61993-01-27 11:42:21 +000058xwsiz = ywsiz = None
59bgcolor = None
Guido van Rossum82534fd1992-08-18 17:01:02 +000060
61
62# Main program -- mostly command line parsing
Guido van Rossum843d1531992-08-18 14:16:12 +000063
64def main():
Guido van Rossume755aa51992-08-21 12:34:55 +000065 global debug, looping, magnify, mindelta, nowait, quiet, regen, speed
Jack Jansen772eca61993-01-27 11:42:21 +000066 global threading, xoff, yoff, xwsiz, ywsiz, bgcolor
Guido van Rossume755aa51992-08-21 12:34:55 +000067
68 # Parse command line
69 try:
Jack Jansen772eca61993-01-27 11:42:21 +000070 opts, args = getopt.getopt(sys.argv[1:], \
71 'M:dlm:nqr:s:tx:y:w:h:b:')
Guido van Rossume755aa51992-08-21 12:34:55 +000072 except getopt.error, msg:
73 sys.stdout = sys.stderr
74 print 'Error:', msg, '\n'
75 help()
76 sys.exit(2)
77
78 # Interpret options
79 try:
80 for opt, arg in opts:
Guido van Rossume0be2b31992-09-01 14:45:57 +000081 if opt == '-M': magnify = float(eval(arg))
Guido van Rossume755aa51992-08-21 12:34:55 +000082 if opt == '-d': debug = debug + 1
83 if opt == '-l': looping = 1
Guido van Rossum605909d1993-12-28 21:28:31 +000084 if opt == '-m': mindelta = float(eval(arg))
Guido van Rossume755aa51992-08-21 12:34:55 +000085 if opt == '-n': nowait = 1
86 if opt == '-q': quiet = 1
Guido van Rossum605909d1993-12-28 21:28:31 +000087 if opt == '-r': regen = float(eval(arg))
Guido van Rossume755aa51992-08-21 12:34:55 +000088 if opt == '-s':
89 try:
90 speed = float(eval(arg))
91 except:
92 sys.stdout = sys.stderr
93 print 'Option -s needs float argument'
94 sys.exit(2)
95 if opt == '-t':
96 try:
97 import thread
98 threading = 1
99 except ImportError:
100 print 'Sorry, this version of Python',
101 print 'does not support threads:',
102 print '-t ignored'
103 if opt == '-x': xoff = string.atoi(arg)
104 if opt == '-y': yoff = string.atoi(arg)
Jack Jansen772eca61993-01-27 11:42:21 +0000105 if opt == '-w': xwsiz = string.atoi(arg)
106 if opt == '-h': ywsiz = string.atoi(arg)
107 if opt == '-b':
108 if arg == 'black':
109 bgcolor = (0,0,0)
110 elif arg == 'white':
111 bgcolor = (255,255,255)
112 else:
113 try:
114 bgcolor = eval(arg)
115 xxr, xxg, xxb = bgcolor
116 except:
117 print '-b needs (r,g,b) tuple'
118 sys.exit(2)
Guido van Rossume755aa51992-08-21 12:34:55 +0000119 except string.atoi_error:
120 sys.stdout = sys.stderr
Guido van Rossum42e9be41992-12-24 11:38:29 +0000121 print 'Option', opt, 'requires integer argument'
Guido van Rossume755aa51992-08-21 12:34:55 +0000122 sys.exit(2)
123
124 # Check validity of certain options combinations
125 if nowait and looping:
126 print 'Warning: -n and -l are mutually exclusive; -n ignored'
127 nowait = 0
128 if xoff <> None and yoff == None:
129 print 'Warning: -x without -y ignored'
130 if xoff == None and yoff <> None:
131 print 'Warning: -y without -x ignored'
132
133 # Process all files
134 if not args: args = ['film.video']
135 sts = 0
Guido van Rossum82534fd1992-08-18 17:01:02 +0000136 for filename in args:
Guido van Rossume755aa51992-08-21 12:34:55 +0000137 sts = (process(filename) or sts)
138
139 # Exit with proper exit status
140 sys.exit(sts)
Guido van Rossum82534fd1992-08-18 17:01:02 +0000141
142
Guido van Rossum78aab861992-08-20 11:52:42 +0000143# Process one movie file
Guido van Rossum843d1531992-08-18 14:16:12 +0000144
145def process(filename):
Guido van Rossum78aab861992-08-20 11:52:42 +0000146 try:
Guido van Rossum21a3ff91993-12-17 15:11:41 +0000147 vin = VFile.VinFile(filename)
Guido van Rossum78aab861992-08-20 11:52:42 +0000148 except IOError, msg:
149 sys.stderr.write(filename + ': I/O error: ' + `msg` + '\n')
Guido van Rossume755aa51992-08-21 12:34:55 +0000150 return 1
Guido van Rossum78aab861992-08-20 11:52:42 +0000151 except VFile.Error, msg:
152 sys.stderr.write(msg + '\n')
Guido van Rossume755aa51992-08-21 12:34:55 +0000153 return 1
Guido van Rossum78aab861992-08-20 11:52:42 +0000154 except EOFError:
155 sys.stderr.write(filename + ': EOF in video header\n')
Guido van Rossume755aa51992-08-21 12:34:55 +0000156 return 1
Guido van Rossum78aab861992-08-20 11:52:42 +0000157
158 if not quiet:
Guido van Rossume1783321992-09-07 09:35:23 +0000159 vin.printinfo()
Guido van Rossum843d1531992-08-18 14:16:12 +0000160
161 gl.foreground()
Guido van Rossume755aa51992-08-21 12:34:55 +0000162
Guido van Rossume0be2b31992-09-01 14:45:57 +0000163 width, height = int(vin.width * magnify), int(vin.height * magnify)
Jack Jansen772eca61993-01-27 11:42:21 +0000164 xborder = yborder = 0
165 if xwsiz:
166 vin.xorigin = (xwsiz - width)/2
167 width = xwsiz
168 if ywsiz:
169 vin.yorigin = (ywsiz - height)/2
170 height = ywsiz
Guido van Rossume755aa51992-08-21 12:34:55 +0000171 if xoff <> None and yoff <> None:
172 scrheight = gl.getgdesc(GL.GD_YPMAX)
173 gl.prefposition(xoff, xoff+width-1, \
174 scrheight-yoff-height, scrheight-yoff-1)
175 else:
176 gl.prefsize(width, height)
177
Guido van Rossum78aab861992-08-20 11:52:42 +0000178 win = gl.winopen(filename)
Guido van Rossume755aa51992-08-21 12:34:55 +0000179 gl.clear()
180
181 if quiet: vin.quiet = 1
Guido van Rossum843d1531992-08-18 14:16:12 +0000182 vin.initcolormap()
183
Jack Jansen772eca61993-01-27 11:42:21 +0000184 if bgcolor:
185 r, g, b = bgcolor
186 vin.clearto(r,g,b)
187
Guido van Rossum843d1531992-08-18 14:16:12 +0000188 gl.qdevice(ESCKEY)
189 gl.qdevice(WINSHUT)
190 gl.qdevice(WINQUIT)
Guido van Rossume755aa51992-08-21 12:34:55 +0000191 gl.qdevice(LEFTMOUSE)
Guido van Rossum843d1531992-08-18 14:16:12 +0000192
Guido van Rossume755aa51992-08-21 12:34:55 +0000193 stop = 0
Guido van Rossum78aab861992-08-20 11:52:42 +0000194
195 while not stop:
Guido van Rossume755aa51992-08-21 12:34:55 +0000196 gl.wintitle(filename)
197 stop = (playonce(vin) or nowait)
198 gl.wintitle('(done) ' + filename)
199 if not looping:
200 while not stop:
201 dev, val = gl.qread()
Guido van Rossum2de9b681992-09-07 15:11:30 +0000202 if dev == REDRAW:
Jack Jansen772eca61993-01-27 11:42:21 +0000203 if bgcolor:
204 r,g,b = bgcolor
205 vin.clearto(r,g,b)
206 else:
207 vin.clear()
Guido van Rossume755aa51992-08-21 12:34:55 +0000208 if dev == LEFTMOUSE and val == 1:
209 break # Continue outer loop
210 if dev == ESCKEY and val == 1 or \
211 dev in (WINSHUT, WINQUIT):
212 stop = 1
Guido van Rossum78aab861992-08-20 11:52:42 +0000213
Guido van Rossume755aa51992-08-21 12:34:55 +0000214 # Set xoff, yoff for the next window from the current window
215 global xoff, yoff
216 xoff, yoff = gl.getorigin()
217 width, height = gl.getsize()
218 scrheight = gl.getgdesc(GL.GD_YPMAX)
219 yoff = scrheight - yoff - height
Guido van Rossum78aab861992-08-20 11:52:42 +0000220 gl.winclose(win)
221
Guido van Rossume755aa51992-08-21 12:34:55 +0000222 return 0
223
Guido van Rossum78aab861992-08-20 11:52:42 +0000224
225# Play a movie once; return 1 if user wants to stop, 0 if not
226
227def playonce(vin):
Guido van Rossume755aa51992-08-21 12:34:55 +0000228 vin.rewind()
Guido van Rossum78aab861992-08-20 11:52:42 +0000229 vin.colormapinited = 1
230 vin.magnify = magnify
231
Guido van Rossume755aa51992-08-21 12:34:55 +0000232 if threading:
Guido van Rossum9ee7e151992-08-25 12:29:30 +0000233 MAXSIZE = 20 # Don't read ahead too much
Guido van Rossume755aa51992-08-21 12:34:55 +0000234 import thread
Guido van Rossum9ee7e151992-08-25 12:29:30 +0000235 import Queue
Guido van Rossum21a3ff91993-12-17 15:11:41 +0000236 queue = Queue.Queue(MAXSIZE)
Guido van Rossume755aa51992-08-21 12:34:55 +0000237 stop = []
238 thread.start_new_thread(read_ahead, (vin, queue, stop))
239 # Get the read-ahead thread going
Guido van Rossum9ee7e151992-08-25 12:29:30 +0000240 while queue.qsize() < MAXSIZE/2 and not stop:
Guido van Rossum605909d1993-12-28 21:28:31 +0000241 time.sleep(0.100)
Guido van Rossume755aa51992-08-21 12:34:55 +0000242
Guido van Rossum78aab861992-08-20 11:52:42 +0000243 tin = 0
Guido van Rossume1783321992-09-07 09:35:23 +0000244 toffset = 0
245 oldtin = 0
Guido van Rossum78aab861992-08-20 11:52:42 +0000246 told = 0
247 nin = 0
248 nout = 0
Guido van Rossume755aa51992-08-21 12:34:55 +0000249 nlate = 0
Guido van Rossum78aab861992-08-20 11:52:42 +0000250 nskipped = 0
Guido van Rossume755aa51992-08-21 12:34:55 +0000251 data = None
Guido van Rossum78aab861992-08-20 11:52:42 +0000252
Guido van Rossum605909d1993-12-28 21:28:31 +0000253 tlast = t0 = time.time()
Guido van Rossum78aab861992-08-20 11:52:42 +0000254
255 while 1:
Guido van Rossum78aab861992-08-20 11:52:42 +0000256 if gl.qtest():
Guido van Rossum843d1531992-08-18 14:16:12 +0000257 dev, val = gl.qread()
Guido van Rossume755aa51992-08-21 12:34:55 +0000258 if dev == ESCKEY and val == 1 or \
259 dev in (WINSHUT, WINQUIT) or \
260 dev == LEFTMOUSE and val == 1:
261 if debug: sys.stderr.write('\n')
262 if threading:
263 stop.append(None)
Guido van Rossum9ee7e151992-08-25 12:29:30 +0000264 while 1:
265 item = queue.get()
266 if item == None: break
Guido van Rossume755aa51992-08-21 12:34:55 +0000267 return (dev != LEFTMOUSE)
Guido van Rossum843d1531992-08-18 14:16:12 +0000268 if dev == REDRAW:
269 gl.reshapeviewport()
Guido van Rossume755aa51992-08-21 12:34:55 +0000270 if data: vin.showframe(data, cdata)
271 if threading:
Guido van Rossum9ee7e151992-08-25 12:29:30 +0000272 if debug and queue.empty(): sys.stderr.write('.')
273 item = queue.get()
274 if item == None: break
275 tin, data, cdata = item
Guido van Rossume755aa51992-08-21 12:34:55 +0000276 else:
277 try:
278 tin, size, csize = vin.getnextframeheader()
279 except EOFError:
280 break
Guido van Rossum605909d1993-12-28 21:28:31 +0000281 tin = tin*0.001
Guido van Rossume755aa51992-08-21 12:34:55 +0000282 nin = nin+1
Guido van Rossume1783321992-09-07 09:35:23 +0000283 if tin+toffset < oldtin:
284 print 'Fix reversed time:', oldtin, 'to', tin
285 toffset = oldtin - tin
286 tin = tin + toffset
287 oldtin = tin
Guido van Rossume755aa51992-08-21 12:34:55 +0000288 if regen: tout = nin * regen
289 else: tout = tin
Guido van Rossum605909d1993-12-28 21:28:31 +0000290 tout = tout / speed
Guido van Rossume755aa51992-08-21 12:34:55 +0000291 if tout - told < mindelta:
292 nskipped = nskipped + 1
Guido van Rossume1783321992-09-07 09:35:23 +0000293 if not threading:
294 vin.skipnextframedata(size, csize)
Guido van Rossume755aa51992-08-21 12:34:55 +0000295 else:
296 if not threading:
297 try:
298 data, cdata = \
299 vin.getnextframedata(size, csize)
300 except EOFError:
301 if not quiet:
302 print '[incomplete last frame]'
303 break
Guido van Rossum605909d1993-12-28 21:28:31 +0000304 now = time.time()
Guido van Rossume755aa51992-08-21 12:34:55 +0000305 dt = (tout-told) - (now-tlast)
306 told = tout
Guido van Rossum605909d1993-12-28 21:28:31 +0000307 if debug: sys.stderr.write(`round(dt, 3)` + ' ')
Guido van Rossume755aa51992-08-21 12:34:55 +0000308 if dt < 0: nlate = nlate + 1
309 if dt > 0:
Guido van Rossum605909d1993-12-28 21:28:31 +0000310 time.sleep(dt)
311 now = time.time()
Guido van Rossume755aa51992-08-21 12:34:55 +0000312 tlast = now
313 vin.showframe(data, cdata)
314 nout = nout + 1
Guido van Rossum78aab861992-08-20 11:52:42 +0000315
Guido van Rossum605909d1993-12-28 21:28:31 +0000316 t1 = time.time()
Guido van Rossum78aab861992-08-20 11:52:42 +0000317
Guido van Rossume755aa51992-08-21 12:34:55 +0000318 if debug: sys.stderr.write('\n')
319
320 if quiet: return 0
Guido van Rossum78aab861992-08-20 11:52:42 +0000321
Guido van Rossum605909d1993-12-28 21:28:31 +0000322 print 'Recorded:', nin, 'frames in', round(tin, 3), 'sec.',
323 if tin: print '-- average', round(nin/tin, 1), 'frames/sec',
Guido van Rossum78aab861992-08-20 11:52:42 +0000324 print
325
Guido van Rossume755aa51992-08-21 12:34:55 +0000326 if nskipped: print 'Skipped', nskipped, 'frames'
Guido van Rossum78aab861992-08-20 11:52:42 +0000327
328 tout = t1-t0
329 print 'Played:', nout,
Guido van Rossum605909d1993-12-28 21:28:31 +0000330 print 'frames in', round(tout, 3), 'sec.',
331 if tout: print '-- average', round(nout/tout, 1), 'frames/sec',
Guido van Rossum78aab861992-08-20 11:52:42 +0000332 print
333
Guido van Rossume755aa51992-08-21 12:34:55 +0000334 if nlate: print 'There were', nlate, 'late frames'
Guido van Rossum78aab861992-08-20 11:52:42 +0000335
336 return 0
Guido van Rossum843d1531992-08-18 14:16:12 +0000337
Guido van Rossum82534fd1992-08-18 17:01:02 +0000338
Guido van Rossume755aa51992-08-21 12:34:55 +0000339# Read-ahead thread
340
341def read_ahead(vin, queue, stop):
342 try:
Guido van Rossum9ee7e151992-08-25 12:29:30 +0000343 while not stop: queue.put(vin.getnextframe())
Guido van Rossume755aa51992-08-21 12:34:55 +0000344 except EOFError:
Guido van Rossum9ee7e151992-08-25 12:29:30 +0000345 pass
346 queue.put(None)
Guido van Rossume755aa51992-08-21 12:34:55 +0000347 stop.append(None)
348
349
Guido van Rossum82534fd1992-08-18 17:01:02 +0000350# Don't forget to call the main program
351
Guido van Rossume755aa51992-08-21 12:34:55 +0000352try:
353 main()
354except KeyboardInterrupt:
355 print '[Interrupt]'