Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 1 | #! /ufs/guido/bin/sgi/python |
Guido van Rossum | 82534fd | 1992-08-18 17:01:02 +0000 | [diff] [blame] | 2 | |
| 3 | # Play CMIF movie files |
| 4 | |
| 5 | |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 6 | # Help function |
| 7 | |
| 8 | def 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' |
| 15 | print '-m delta : drop frames closer than delta msec (default 0)' |
Guido van Rossum | e178332 | 1992-09-07 09:35:23 +0000 | [diff] [blame] | 16 | print '-n : don\'t wait after each file' |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 17 | print '-q : quiet, no informative messages' |
| 18 | print '-r delta : regenerate input time base delta msec apart' |
| 19 | 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' |
| 23 | print 'file ... : file(s) to play; default film.video' |
| 24 | print |
| 25 | print 'User interface:' |
| 26 | print 'Press the left mouse button to stop or restart the movie.' |
| 27 | print 'Press ESC or use the window manager Close or Quit command' |
| 28 | print 'to close the window and play the next file (if any).' |
Guido van Rossum | 82534fd | 1992-08-18 17:01:02 +0000 | [diff] [blame] | 29 | |
| 30 | |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 31 | # Imported modules |
Guido van Rossum | 82534fd | 1992-08-18 17:01:02 +0000 | [diff] [blame] | 32 | |
Guido van Rossum | 843d153 | 1992-08-18 14:16:12 +0000 | [diff] [blame] | 33 | import sys |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 34 | sys.path.append('/ufs/guido/src/video') # Increase chance of finding VFile |
Guido van Rossum | 843d153 | 1992-08-18 14:16:12 +0000 | [diff] [blame] | 35 | import VFile |
| 36 | import time |
| 37 | import gl, GL |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 38 | from DEVICE import REDRAW, ESCKEY, LEFTMOUSE, WINSHUT, WINQUIT |
Guido van Rossum | 82534fd | 1992-08-18 17:01:02 +0000 | [diff] [blame] | 39 | import getopt |
| 40 | import string |
| 41 | |
| 42 | |
| 43 | # Global options |
| 44 | |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 45 | debug = 0 |
Guido van Rossum | 82534fd | 1992-08-18 17:01:02 +0000 | [diff] [blame] | 46 | looping = 0 |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 47 | magnify = 1 |
Guido van Rossum | 78aab86 | 1992-08-20 11:52:42 +0000 | [diff] [blame] | 48 | mindelta = 0 |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 49 | nowait = 0 |
Guido van Rossum | 78aab86 | 1992-08-20 11:52:42 +0000 | [diff] [blame] | 50 | quiet = 0 |
| 51 | regen = None |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 52 | speed = 1.0 |
| 53 | threading = 0 |
| 54 | xoff = yoff = None |
Guido van Rossum | 82534fd | 1992-08-18 17:01:02 +0000 | [diff] [blame] | 55 | |
| 56 | |
| 57 | # Main program -- mostly command line parsing |
Guido van Rossum | 843d153 | 1992-08-18 14:16:12 +0000 | [diff] [blame] | 58 | |
| 59 | def main(): |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 60 | global debug, looping, magnify, mindelta, nowait, quiet, regen, speed |
| 61 | global threading, xoff, yoff |
| 62 | |
| 63 | # Parse command line |
| 64 | try: |
| 65 | opts, args = getopt.getopt(sys.argv[1:], 'M:dlm:nqr:s:tx:y:') |
| 66 | except getopt.error, msg: |
| 67 | sys.stdout = sys.stderr |
| 68 | print 'Error:', msg, '\n' |
| 69 | help() |
| 70 | sys.exit(2) |
| 71 | |
| 72 | # Interpret options |
| 73 | try: |
| 74 | for opt, arg in opts: |
Guido van Rossum | e0be2b3 | 1992-09-01 14:45:57 +0000 | [diff] [blame] | 75 | if opt == '-M': magnify = float(eval(arg)) |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 76 | if opt == '-d': debug = debug + 1 |
| 77 | if opt == '-l': looping = 1 |
| 78 | if opt == '-m': mindelta = string.atoi(arg) |
| 79 | if opt == '-n': nowait = 1 |
| 80 | if opt == '-q': quiet = 1 |
| 81 | if opt == '-r': regen = string.atoi(arg) |
| 82 | if opt == '-s': |
| 83 | try: |
| 84 | speed = float(eval(arg)) |
| 85 | except: |
| 86 | sys.stdout = sys.stderr |
| 87 | print 'Option -s needs float argument' |
| 88 | sys.exit(2) |
| 89 | if opt == '-t': |
| 90 | try: |
| 91 | import thread |
| 92 | threading = 1 |
| 93 | except ImportError: |
| 94 | print 'Sorry, this version of Python', |
| 95 | print 'does not support threads:', |
| 96 | print '-t ignored' |
| 97 | if opt == '-x': xoff = string.atoi(arg) |
| 98 | if opt == '-y': yoff = string.atoi(arg) |
| 99 | except string.atoi_error: |
| 100 | sys.stdout = sys.stderr |
Guido van Rossum | 42e9be4 | 1992-12-24 11:38:29 +0000 | [diff] [blame] | 101 | print 'Option', opt, 'requires integer argument' |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 102 | sys.exit(2) |
| 103 | |
| 104 | # Check validity of certain options combinations |
| 105 | if nowait and looping: |
| 106 | print 'Warning: -n and -l are mutually exclusive; -n ignored' |
| 107 | nowait = 0 |
| 108 | if xoff <> None and yoff == None: |
| 109 | print 'Warning: -x without -y ignored' |
| 110 | if xoff == None and yoff <> None: |
| 111 | print 'Warning: -y without -x ignored' |
| 112 | |
| 113 | # Process all files |
| 114 | if not args: args = ['film.video'] |
| 115 | sts = 0 |
Guido van Rossum | 82534fd | 1992-08-18 17:01:02 +0000 | [diff] [blame] | 116 | for filename in args: |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 117 | sts = (process(filename) or sts) |
| 118 | |
| 119 | # Exit with proper exit status |
| 120 | sys.exit(sts) |
Guido van Rossum | 82534fd | 1992-08-18 17:01:02 +0000 | [diff] [blame] | 121 | |
| 122 | |
Guido van Rossum | 78aab86 | 1992-08-20 11:52:42 +0000 | [diff] [blame] | 123 | # Process one movie file |
Guido van Rossum | 843d153 | 1992-08-18 14:16:12 +0000 | [diff] [blame] | 124 | |
| 125 | def process(filename): |
Guido van Rossum | 78aab86 | 1992-08-20 11:52:42 +0000 | [diff] [blame] | 126 | try: |
| 127 | vin = VFile.VinFile().init(filename) |
| 128 | except IOError, msg: |
| 129 | sys.stderr.write(filename + ': I/O error: ' + `msg` + '\n') |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 130 | return 1 |
Guido van Rossum | 78aab86 | 1992-08-20 11:52:42 +0000 | [diff] [blame] | 131 | except VFile.Error, msg: |
| 132 | sys.stderr.write(msg + '\n') |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 133 | return 1 |
Guido van Rossum | 78aab86 | 1992-08-20 11:52:42 +0000 | [diff] [blame] | 134 | except EOFError: |
| 135 | sys.stderr.write(filename + ': EOF in video header\n') |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 136 | return 1 |
Guido van Rossum | 78aab86 | 1992-08-20 11:52:42 +0000 | [diff] [blame] | 137 | |
| 138 | if not quiet: |
Guido van Rossum | e178332 | 1992-09-07 09:35:23 +0000 | [diff] [blame] | 139 | vin.printinfo() |
Guido van Rossum | 843d153 | 1992-08-18 14:16:12 +0000 | [diff] [blame] | 140 | |
| 141 | gl.foreground() |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 142 | |
Guido van Rossum | e0be2b3 | 1992-09-01 14:45:57 +0000 | [diff] [blame] | 143 | width, height = int(vin.width * magnify), int(vin.height * magnify) |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 144 | if xoff <> None and yoff <> None: |
| 145 | scrheight = gl.getgdesc(GL.GD_YPMAX) |
| 146 | gl.prefposition(xoff, xoff+width-1, \ |
| 147 | scrheight-yoff-height, scrheight-yoff-1) |
| 148 | else: |
| 149 | gl.prefsize(width, height) |
| 150 | |
Guido van Rossum | 78aab86 | 1992-08-20 11:52:42 +0000 | [diff] [blame] | 151 | win = gl.winopen(filename) |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 152 | gl.clear() |
| 153 | |
| 154 | if quiet: vin.quiet = 1 |
Guido van Rossum | 843d153 | 1992-08-18 14:16:12 +0000 | [diff] [blame] | 155 | vin.initcolormap() |
| 156 | |
| 157 | gl.qdevice(ESCKEY) |
| 158 | gl.qdevice(WINSHUT) |
| 159 | gl.qdevice(WINQUIT) |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 160 | gl.qdevice(LEFTMOUSE) |
Guido van Rossum | 843d153 | 1992-08-18 14:16:12 +0000 | [diff] [blame] | 161 | |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 162 | stop = 0 |
Guido van Rossum | 78aab86 | 1992-08-20 11:52:42 +0000 | [diff] [blame] | 163 | |
| 164 | while not stop: |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 165 | gl.wintitle(filename) |
| 166 | stop = (playonce(vin) or nowait) |
| 167 | gl.wintitle('(done) ' + filename) |
| 168 | if not looping: |
| 169 | while not stop: |
| 170 | dev, val = gl.qread() |
Guido van Rossum | 2de9b68 | 1992-09-07 15:11:30 +0000 | [diff] [blame] | 171 | if dev == REDRAW: |
| 172 | vin.clear() |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 173 | if dev == LEFTMOUSE and val == 1: |
| 174 | break # Continue outer loop |
| 175 | if dev == ESCKEY and val == 1 or \ |
| 176 | dev in (WINSHUT, WINQUIT): |
| 177 | stop = 1 |
Guido van Rossum | 78aab86 | 1992-08-20 11:52:42 +0000 | [diff] [blame] | 178 | |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 179 | # Set xoff, yoff for the next window from the current window |
| 180 | global xoff, yoff |
| 181 | xoff, yoff = gl.getorigin() |
| 182 | width, height = gl.getsize() |
| 183 | scrheight = gl.getgdesc(GL.GD_YPMAX) |
| 184 | yoff = scrheight - yoff - height |
Guido van Rossum | 78aab86 | 1992-08-20 11:52:42 +0000 | [diff] [blame] | 185 | gl.winclose(win) |
| 186 | |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 187 | return 0 |
| 188 | |
Guido van Rossum | 78aab86 | 1992-08-20 11:52:42 +0000 | [diff] [blame] | 189 | |
| 190 | # Play a movie once; return 1 if user wants to stop, 0 if not |
| 191 | |
| 192 | def playonce(vin): |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 193 | vin.rewind() |
Guido van Rossum | 78aab86 | 1992-08-20 11:52:42 +0000 | [diff] [blame] | 194 | vin.colormapinited = 1 |
| 195 | vin.magnify = magnify |
| 196 | |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 197 | if threading: |
Guido van Rossum | 9ee7e15 | 1992-08-25 12:29:30 +0000 | [diff] [blame] | 198 | MAXSIZE = 20 # Don't read ahead too much |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 199 | import thread |
Guido van Rossum | 9ee7e15 | 1992-08-25 12:29:30 +0000 | [diff] [blame] | 200 | import Queue |
| 201 | queue = Queue.Queue().init(MAXSIZE) |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 202 | stop = [] |
| 203 | thread.start_new_thread(read_ahead, (vin, queue, stop)) |
| 204 | # Get the read-ahead thread going |
Guido van Rossum | 9ee7e15 | 1992-08-25 12:29:30 +0000 | [diff] [blame] | 205 | while queue.qsize() < MAXSIZE/2 and not stop: |
| 206 | time.millisleep(100) |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 207 | |
Guido van Rossum | 78aab86 | 1992-08-20 11:52:42 +0000 | [diff] [blame] | 208 | tin = 0 |
Guido van Rossum | e178332 | 1992-09-07 09:35:23 +0000 | [diff] [blame] | 209 | toffset = 0 |
| 210 | oldtin = 0 |
Guido van Rossum | 78aab86 | 1992-08-20 11:52:42 +0000 | [diff] [blame] | 211 | told = 0 |
| 212 | nin = 0 |
| 213 | nout = 0 |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 214 | nlate = 0 |
Guido van Rossum | 78aab86 | 1992-08-20 11:52:42 +0000 | [diff] [blame] | 215 | nskipped = 0 |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 216 | data = None |
Guido van Rossum | 78aab86 | 1992-08-20 11:52:42 +0000 | [diff] [blame] | 217 | |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 218 | tlast = t0 = time.millitimer() |
Guido van Rossum | 78aab86 | 1992-08-20 11:52:42 +0000 | [diff] [blame] | 219 | |
| 220 | while 1: |
Guido van Rossum | 78aab86 | 1992-08-20 11:52:42 +0000 | [diff] [blame] | 221 | if gl.qtest(): |
Guido van Rossum | 843d153 | 1992-08-18 14:16:12 +0000 | [diff] [blame] | 222 | dev, val = gl.qread() |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 223 | if dev == ESCKEY and val == 1 or \ |
| 224 | dev in (WINSHUT, WINQUIT) or \ |
| 225 | dev == LEFTMOUSE and val == 1: |
| 226 | if debug: sys.stderr.write('\n') |
| 227 | if threading: |
| 228 | stop.append(None) |
Guido van Rossum | 9ee7e15 | 1992-08-25 12:29:30 +0000 | [diff] [blame] | 229 | while 1: |
| 230 | item = queue.get() |
| 231 | if item == None: break |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 232 | return (dev != LEFTMOUSE) |
Guido van Rossum | 843d153 | 1992-08-18 14:16:12 +0000 | [diff] [blame] | 233 | if dev == REDRAW: |
| 234 | gl.reshapeviewport() |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 235 | if data: vin.showframe(data, cdata) |
| 236 | if threading: |
Guido van Rossum | 9ee7e15 | 1992-08-25 12:29:30 +0000 | [diff] [blame] | 237 | if debug and queue.empty(): sys.stderr.write('.') |
| 238 | item = queue.get() |
| 239 | if item == None: break |
| 240 | tin, data, cdata = item |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 241 | else: |
| 242 | try: |
| 243 | tin, size, csize = vin.getnextframeheader() |
| 244 | except EOFError: |
| 245 | break |
| 246 | nin = nin+1 |
Guido van Rossum | e178332 | 1992-09-07 09:35:23 +0000 | [diff] [blame] | 247 | if tin+toffset < oldtin: |
| 248 | print 'Fix reversed time:', oldtin, 'to', tin |
| 249 | toffset = oldtin - tin |
| 250 | tin = tin + toffset |
| 251 | oldtin = tin |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 252 | if regen: tout = nin * regen |
| 253 | else: tout = tin |
| 254 | tout = int(tout / speed) |
| 255 | if tout - told < mindelta: |
| 256 | nskipped = nskipped + 1 |
Guido van Rossum | e178332 | 1992-09-07 09:35:23 +0000 | [diff] [blame] | 257 | if not threading: |
| 258 | vin.skipnextframedata(size, csize) |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 259 | else: |
| 260 | if not threading: |
| 261 | try: |
| 262 | data, cdata = \ |
| 263 | vin.getnextframedata(size, csize) |
| 264 | except EOFError: |
| 265 | if not quiet: |
| 266 | print '[incomplete last frame]' |
| 267 | break |
| 268 | now = time.millitimer() |
| 269 | dt = (tout-told) - (now-tlast) |
| 270 | told = tout |
| 271 | if debug: sys.stderr.write(`dt/10` + ' ') |
| 272 | if dt < 0: nlate = nlate + 1 |
| 273 | if dt > 0: |
| 274 | time.millisleep(dt) |
| 275 | now = now + dt |
| 276 | tlast = now |
| 277 | vin.showframe(data, cdata) |
| 278 | nout = nout + 1 |
Guido van Rossum | 78aab86 | 1992-08-20 11:52:42 +0000 | [diff] [blame] | 279 | |
| 280 | t1 = time.millitimer() |
| 281 | |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 282 | if debug: sys.stderr.write('\n') |
| 283 | |
| 284 | if quiet: return 0 |
Guido van Rossum | 78aab86 | 1992-08-20 11:52:42 +0000 | [diff] [blame] | 285 | |
| 286 | print 'Recorded:', nin, 'frames in', tin*0.001, 'sec.', |
| 287 | if tin: print '-- average', int(nin*10000.0/tin)*0.1, 'frames/sec', |
| 288 | print |
| 289 | |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 290 | if nskipped: print 'Skipped', nskipped, 'frames' |
Guido van Rossum | 78aab86 | 1992-08-20 11:52:42 +0000 | [diff] [blame] | 291 | |
| 292 | tout = t1-t0 |
| 293 | print 'Played:', nout, |
| 294 | print 'frames in', tout*0.001, 'sec.', |
| 295 | if tout: print '-- average', int(nout*10000.0/tout)*0.1, 'frames/sec', |
| 296 | print |
| 297 | |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 298 | if nlate: print 'There were', nlate, 'late frames' |
Guido van Rossum | 78aab86 | 1992-08-20 11:52:42 +0000 | [diff] [blame] | 299 | |
| 300 | return 0 |
Guido van Rossum | 843d153 | 1992-08-18 14:16:12 +0000 | [diff] [blame] | 301 | |
Guido van Rossum | 82534fd | 1992-08-18 17:01:02 +0000 | [diff] [blame] | 302 | |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 303 | # Read-ahead thread |
| 304 | |
| 305 | def read_ahead(vin, queue, stop): |
| 306 | try: |
Guido van Rossum | 9ee7e15 | 1992-08-25 12:29:30 +0000 | [diff] [blame] | 307 | while not stop: queue.put(vin.getnextframe()) |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 308 | except EOFError: |
Guido van Rossum | 9ee7e15 | 1992-08-25 12:29:30 +0000 | [diff] [blame] | 309 | pass |
| 310 | queue.put(None) |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 311 | stop.append(None) |
| 312 | |
| 313 | |
Guido van Rossum | 82534fd | 1992-08-18 17:01:02 +0000 | [diff] [blame] | 314 | # Don't forget to call the main program |
| 315 | |
Guido van Rossum | e755aa5 | 1992-08-21 12:34:55 +0000 | [diff] [blame] | 316 | try: |
| 317 | main() |
| 318 | except KeyboardInterrupt: |
| 319 | print '[Interrupt]' |