Guido van Rossum | 5e044b7 | 1993-02-25 14:20:13 +0000 | [diff] [blame] | 1 | #! /ufs/guido/bin/sgi/python |
Guido van Rossum | 349f2b5 | 1992-12-24 11:41:14 +0000 | [diff] [blame] | 2 | |
Guido van Rossum | 5e044b7 | 1993-02-25 14:20:13 +0000 | [diff] [blame] | 3 | # Universal (non-interactive) CMIF video file copier. |
Guido van Rossum | 349f2b5 | 1992-12-24 11:41:14 +0000 | [diff] [blame] | 4 | |
Guido van Rossum | 5e044b7 | 1993-02-25 14:20:13 +0000 | [diff] [blame] | 5 | |
| 6 | # Possibilities: |
| 7 | # |
| 8 | # - Manipulate the time base: |
| 9 | # = resample at a fixed rate |
| 10 | # = divide the time codes by a speed factor (to make it go faster/slower) |
| 11 | # = drop frames that are less than n msec apart (to accomodate slow players) |
| 12 | # - Convert to a different format |
| 13 | # - Magnify (scale) the image |
| 14 | |
| 15 | |
| 16 | # Usage function (keep this up-to-date if you change the program!) |
Guido van Rossum | 349f2b5 | 1992-12-24 11:41:14 +0000 | [diff] [blame] | 17 | |
| 18 | def usage(): |
Guido van Rossum | 5e044b7 | 1993-02-25 14:20:13 +0000 | [diff] [blame] | 19 | print 'Usage: Vcopy [options] [infile [outfile]]' |
| 20 | print |
| 21 | print 'Options:' |
| 22 | print |
| 23 | print '-t type : new image type (default unchanged)' |
| 24 | print |
| 25 | print '-M magnify : image magnification factor (default unchanged)' |
| 26 | print '-w width : output image width (default height*4/3 if -h used)' |
| 27 | print '-h height : output image height (default width*3/4 if -w used)' |
| 28 | print |
| 29 | print '-p pf : new x and y packfactor (default unchanged)' |
Guido van Rossum | c97d2ed | 1993-02-25 14:50:27 +0000 | [diff] [blame^] | 30 | print '-x xpf : new x packfactor (default unchanged)' |
| 31 | print '-y ypf : new y packfactor (default unchanged)' |
Guido van Rossum | 5e044b7 | 1993-02-25 14:20:13 +0000 | [diff] [blame] | 32 | print |
| 33 | print '-m delta : drop frames closer than delta msec (default 0)' |
| 34 | print '-r delta : regenerate input time base delta msec apart' |
| 35 | print '-s speed : speed change factor (default unchanged)' |
| 36 | print |
| 37 | print 'infile : input file (default film.video)' |
| 38 | print 'outfile : output file (default out.video)' |
Guido van Rossum | 349f2b5 | 1992-12-24 11:41:14 +0000 | [diff] [blame] | 39 | |
Guido van Rossum | 5e044b7 | 1993-02-25 14:20:13 +0000 | [diff] [blame] | 40 | |
| 41 | import sys |
| 42 | sys.path.append('/ufs/guido/src/video') |
| 43 | |
| 44 | import VFile |
| 45 | import imgconv |
| 46 | import imageop |
| 47 | import getopt |
| 48 | import string |
| 49 | |
| 50 | |
| 51 | # Global options |
| 52 | |
| 53 | speed = 1.0 |
| 54 | mindelta = 0 |
| 55 | regen = None |
| 56 | newpf = None |
| 57 | newtype = None |
| 58 | magnify = None |
| 59 | newwidth = None |
| 60 | newheight = None |
| 61 | |
| 62 | |
| 63 | # Function to turn a string into a float |
| 64 | |
| 65 | atof_error = 'atof_error' # Exception if it fails |
| 66 | |
| 67 | def atof(s): |
| 68 | try: |
| 69 | return float(eval(s)) |
| 70 | except: |
| 71 | raise atof_error |
| 72 | |
| 73 | |
| 74 | # Main program -- mostly command line parsing |
Guido van Rossum | 349f2b5 | 1992-12-24 11:41:14 +0000 | [diff] [blame] | 75 | |
| 76 | def main(): |
Guido van Rossum | 5e044b7 | 1993-02-25 14:20:13 +0000 | [diff] [blame] | 77 | global speed, mindelta, regen, newpf, newtype, \ |
| 78 | magnify, newwidth, newheight |
| 79 | |
| 80 | # Parse command line |
| 81 | try: |
| 82 | opts, args = getopt.getopt(sys.argv[1:], \ |
| 83 | 'M:h:m:p:r:s:t:w:x:y:') |
| 84 | except getopt.error, msg: |
| 85 | sys.stdout = sys.stderr |
| 86 | print 'Error:', msg, '\n' |
Guido van Rossum | 349f2b5 | 1992-12-24 11:41:14 +0000 | [diff] [blame] | 87 | usage() |
Guido van Rossum | 5e044b7 | 1993-02-25 14:20:13 +0000 | [diff] [blame] | 88 | sys.exit(2) |
| 89 | |
| 90 | xpf = ypf = None |
Guido van Rossum | 349f2b5 | 1992-12-24 11:41:14 +0000 | [diff] [blame] | 91 | |
Guido van Rossum | 5e044b7 | 1993-02-25 14:20:13 +0000 | [diff] [blame] | 92 | # Interpret options |
| 93 | try: |
| 94 | for opt, arg in opts: |
| 95 | if opt == '-M': magnify = atof(arg) |
| 96 | if opt == '-h': height = string.atoi(arg) |
| 97 | if opt == '-m': mindelta = string.atoi(arg) |
| 98 | if opt == '-p': xpf = ypf = string.atoi(arg) |
| 99 | if opt == '-r': regen = string.atoi(arg) |
| 100 | if opt == '-s': speed = atof(arg) |
| 101 | if opt == '-t': newtype = arg |
| 102 | if opt == '-w': newwidth = string.atoi(arg) |
| 103 | if opt == '-x': xpf = string.atoi(arg) |
| 104 | if opt == '-y': ypf = string.atoi(arg) |
| 105 | except string.atoi_error: |
| 106 | sys.stdout = sys.stderr |
| 107 | print 'Option', opt, 'requires integer argument' |
| 108 | sys.exit(2) |
| 109 | except atof_error: |
| 110 | sys.stdout = sys.stderr |
| 111 | print 'Option', opt, 'requires float argument' |
| 112 | sys.exit(2) |
Guido van Rossum | 349f2b5 | 1992-12-24 11:41:14 +0000 | [diff] [blame] | 113 | |
Guido van Rossum | 5e044b7 | 1993-02-25 14:20:13 +0000 | [diff] [blame] | 114 | if xpf or ypf: |
Guido van Rossum | 5e044b7 | 1993-02-25 14:20:13 +0000 | [diff] [blame] | 115 | newpf = (xpf, ypf) |
| 116 | |
| 117 | if newwidth or newheight: |
| 118 | if magnify: |
| 119 | sys.stdout = sys.stderr |
| 120 | print 'Options -w or -h are incompatible with -M' |
| 121 | sys.exit(2) |
| 122 | if not newheight: |
| 123 | newheight = newwidth * 3 / 4 |
| 124 | elif not newwidth: |
| 125 | newwidth = newheight * 4 / 3 |
| 126 | |
| 127 | # Check filename arguments |
| 128 | if len(args) < 1: |
| 129 | args.append('film.video') |
| 130 | if len(args) < 2: |
| 131 | args.append('out.video') |
| 132 | if len(args) > 2: |
| 133 | usage() |
| 134 | sys.exit(2) |
| 135 | if args[0] == args[1]: |
| 136 | sys.stderr.write('Input file can\'t be output file\n') |
| 137 | sys.exit(2) |
| 138 | |
| 139 | # Do the right thing |
| 140 | sts = process(args[0], args[1]) |
| 141 | |
| 142 | # Exit |
| 143 | sys.exit(sts) |
| 144 | |
| 145 | |
| 146 | # Copy one file to another |
| 147 | |
| 148 | def process(infilename, outfilename): |
Guido van Rossum | c97d2ed | 1993-02-25 14:50:27 +0000 | [diff] [blame^] | 149 | global newwidth, newheight, newpf |
Guido van Rossum | 5e044b7 | 1993-02-25 14:20:13 +0000 | [diff] [blame] | 150 | |
| 151 | try: |
| 152 | vin = VFile.BasicVinFile().init(infilename) |
| 153 | except IOError, msg: |
| 154 | sys.stderr.write(infilename + ': I/O error: ' + `msg` + '\n') |
| 155 | return 1 |
| 156 | except VFile.Error, msg: |
| 157 | sys.stderr.write(msg + '\n') |
| 158 | return 1 |
| 159 | except EOFError: |
| 160 | sys.stderr.write(infilename + ': EOF in video file\n') |
| 161 | return 1 |
| 162 | |
| 163 | try: |
| 164 | vout = VFile.BasicVoutFile().init(outfilename) |
| 165 | except IOError, msg: |
| 166 | sys.stderr.write(outfilename + ': I/O error: ' + `msg` + '\n') |
| 167 | return 1 |
| 168 | |
Guido van Rossum | c97d2ed | 1993-02-25 14:50:27 +0000 | [diff] [blame^] | 169 | vin.printinfo() |
| 170 | |
Guido van Rossum | 5e044b7 | 1993-02-25 14:20:13 +0000 | [diff] [blame] | 171 | vout.setinfo(vin.getinfo()) |
| 172 | |
| 173 | scale = 0 |
| 174 | flip = 0 |
| 175 | |
| 176 | if newtype: |
| 177 | vout.setformat(newtype) |
| 178 | try: |
| 179 | convert = imgconv.getconverter(vin.format, vout.format) |
| 180 | except imgconv.error, msg: |
| 181 | sys.stderr.write(str(msg) + '\n') |
| 182 | return 1 |
| 183 | |
| 184 | if newpf: |
Guido van Rossum | c97d2ed | 1993-02-25 14:50:27 +0000 | [diff] [blame^] | 185 | xpf, ypf = newpf |
| 186 | if not xpf: xpf = vin.xpf |
| 187 | if not ypf: ypf = vout.ypf |
| 188 | newpf = (xpf, ypf) |
Guido van Rossum | 5e044b7 | 1993-02-25 14:20:13 +0000 | [diff] [blame] | 189 | vout.setpf(newpf) |
| 190 | scale = 1 |
| 191 | |
| 192 | if newwidth and newheight: |
| 193 | scale = 1 |
| 194 | |
| 195 | if vin.upside_down <> vout.upside_down or \ |
| 196 | vin.mirror_image <> vout.mirror_image: |
| 197 | flip = 1 |
| 198 | |
| 199 | inwidth, inheight = vin.getsize() |
| 200 | inwidth = inwidth / vin.xpf |
| 201 | inheight = inheight / vin.ypf |
| 202 | |
| 203 | if magnify: |
| 204 | newwidth = int(vout.width * magnify) |
| 205 | newheight = int(vout.height * magnify) |
| 206 | scale = 1 |
| 207 | |
| 208 | if scale: |
| 209 | vout.setsize(newwidth, newheight) |
| 210 | else: |
| 211 | newwidth, newheight = vout.getsize() |
| 212 | |
| 213 | if vin.packfactor <> vout.packfactor: |
| 214 | scale = 1 |
| 215 | |
| 216 | if scale or flip: |
| 217 | if vout.bpp not in (8, 32): |
| 218 | sys.stderr.write('Can\'t scale or flip this type\n') |
| 219 | return 1 |
| 220 | |
| 221 | newwidth = newwidth / vout.xpf |
| 222 | newheight = newheight / vout.ypf |
| 223 | |
Guido van Rossum | c97d2ed | 1993-02-25 14:50:27 +0000 | [diff] [blame^] | 224 | vout.printinfo() |
Guido van Rossum | 5e044b7 | 1993-02-25 14:20:13 +0000 | [diff] [blame] | 225 | vout.writeheader() |
| 226 | |
| 227 | told = 0 |
| 228 | nin = 0 |
| 229 | nout = 0 |
| 230 | tin = 0 |
| 231 | tout = 0 |
| 232 | |
Guido van Rossum | 349f2b5 | 1992-12-24 11:41:14 +0000 | [diff] [blame] | 233 | while 1: |
Guido van Rossum | 5e044b7 | 1993-02-25 14:20:13 +0000 | [diff] [blame] | 234 | try: |
| 235 | tin, data, cdata = vin.getnextframe() |
| 236 | except EOFError: |
Guido van Rossum | 349f2b5 | 1992-12-24 11:41:14 +0000 | [diff] [blame] | 237 | break |
Guido van Rossum | 5e044b7 | 1993-02-25 14:20:13 +0000 | [diff] [blame] | 238 | nin = nin + 1 |
| 239 | if regen: |
| 240 | tout = nin * regen |
Guido van Rossum | 349f2b5 | 1992-12-24 11:41:14 +0000 | [diff] [blame] | 241 | else: |
Guido van Rossum | 5e044b7 | 1993-02-25 14:20:13 +0000 | [diff] [blame] | 242 | tout = tin |
| 243 | tout = int(tout / speed) |
| 244 | if tout - told < mindelta: |
| 245 | continue |
| 246 | told = tout |
| 247 | if newtype: |
| 248 | data = convert(data, inwidth, inheight) |
Guido van Rossum | c97d2ed | 1993-02-25 14:50:27 +0000 | [diff] [blame^] | 249 | if scale: |
Guido van Rossum | 5e044b7 | 1993-02-25 14:20:13 +0000 | [diff] [blame] | 250 | data = imageop.scale(data, vout.bpp/8, \ |
| 251 | inwidth, inheight, newwidth, newheight) |
Guido van Rossum | c97d2ed | 1993-02-25 14:50:27 +0000 | [diff] [blame^] | 252 | if flip: |
Guido van Rossum | 5e044b7 | 1993-02-25 14:20:13 +0000 | [diff] [blame] | 253 | x0, y0 = 0, 0 |
| 254 | x1, y1 = newwidth-1, neheight-1 |
| 255 | if vin.upside_down <> vout.upside_down: |
| 256 | y1, y0 = y0, y1 |
| 257 | if vin.mirror_image <> vout.mirror_image: |
| 258 | x1, x0 = x0, x1 |
| 259 | data = imageop.crop(data, vout.bpp/8, \ |
| 260 | newwidth, newheight, x0, y0, x1, y1) |
| 261 | vout.writeframe(tout, data, cdata) |
| 262 | nout = nout + 1 |
Guido van Rossum | 349f2b5 | 1992-12-24 11:41:14 +0000 | [diff] [blame] | 263 | |
Guido van Rossum | 5e044b7 | 1993-02-25 14:20:13 +0000 | [diff] [blame] | 264 | vout.close() |
| 265 | vin.close() |
| 266 | |
| 267 | |
| 268 | # Don't forget to call the main program |
| 269 | |
| 270 | try: |
| 271 | main() |
| 272 | except KeyboardInterrupt: |
| 273 | print '[Interrupt]' |