#! /ufs/guido/bin/sgi/python # Universal (non-interactive) CMIF video file copier. # Possibilities: # # - Manipulate the time base: # = resample at a fixed rate # = divide the time codes by a speed factor (to make it go faster/slower) # = drop frames that are less than n msec apart (to accomodate slow players) # - Convert to a different format # - Magnify (scale) the image # Usage function (keep this up-to-date if you change the program!) def usage(): print 'Usage: Vcopy [options] [infile [outfile]]' print print 'Options:' print print '-t type : new image type (default unchanged)' print print '-M magnify : image magnification factor (default unchanged)' print '-w width : output image width (default height*4/3 if -h used)' print '-h height : output image height (default width*3/4 if -w used)' print print '-p pf : new x and y packfactor (default unchanged)' print '-x xpf : new x packfactor (default unchanged)' print '-y ypf : new y packfactor (default unchanged)' print print '-m delta : drop frames closer than delta msec (default 0)' print '-r delta : regenerate input time base delta msec apart' print '-s speed : speed change factor (default unchanged)' print print 'infile : input file (default film.video)' print 'outfile : output file (default out.video)' import sys sys.path.append('/ufs/guido/src/video') import VFile import imgconv import imageop import getopt import string # Global options speed = 1.0 mindelta = 0 regen = None newpf = None newtype = None magnify = None newwidth = None newheight = None # Function to turn a string into a float atof_error = 'atof_error' # Exception if it fails def atof(s): try: return float(eval(s)) except: raise atof_error # Main program -- mostly command line parsing def main(): global speed, mindelta, regen, newpf, newtype, \ magnify, newwidth, newheight # Parse command line try: opts, args = getopt.getopt(sys.argv[1:], \ 'M:h:m:p:r:s:t:w:x:y:') except getopt.error, msg: sys.stdout = sys.stderr print 'Error:', msg, '\n' usage() sys.exit(2) xpf = ypf = None # Interpret options try: for opt, arg in opts: if opt == '-M': magnify = atof(arg) if opt == '-h': height = string.atoi(arg) if opt == '-m': mindelta = string.atoi(arg) if opt == '-p': xpf = ypf = string.atoi(arg) if opt == '-r': regen = string.atoi(arg) if opt == '-s': speed = atof(arg) if opt == '-t': newtype = arg if opt == '-w': newwidth = string.atoi(arg) if opt == '-x': xpf = string.atoi(arg) if opt == '-y': ypf = string.atoi(arg) except string.atoi_error: sys.stdout = sys.stderr print 'Option', opt, 'requires integer argument' sys.exit(2) except atof_error: sys.stdout = sys.stderr print 'Option', opt, 'requires float argument' sys.exit(2) if xpf or ypf: newpf = (xpf, ypf) if newwidth or newheight: if magnify: sys.stdout = sys.stderr print 'Options -w or -h are incompatible with -M' sys.exit(2) if not newheight: newheight = newwidth * 3 / 4 elif not newwidth: newwidth = newheight * 4 / 3 # Check filename arguments if len(args) < 1: args.append('film.video') if len(args) < 2: args.append('out.video') if len(args) > 2: usage() sys.exit(2) if args[0] == args[1]: sys.stderr.write('Input file can\'t be output file\n') sys.exit(2) # Do the right thing sts = process(args[0], args[1]) # Exit sys.exit(sts) # Copy one file to another def process(infilename, outfilename): global newwidth, newheight, newpf try: vin = VFile.BasicVinFile().init(infilename) except IOError, msg: sys.stderr.write(infilename + ': I/O error: ' + `msg` + '\n') return 1 except VFile.Error, msg: sys.stderr.write(msg + '\n') return 1 except EOFError: sys.stderr.write(infilename + ': EOF in video file\n') return 1 try: vout = VFile.BasicVoutFile().init(outfilename) except IOError, msg: sys.stderr.write(outfilename + ': I/O error: ' + `msg` + '\n') return 1 print '=== input file ===' vin.printinfo() vout.setinfo(vin.getinfo()) scale = 0 flip = 0 if newtype: vout.setformat(newtype) try: convert = imgconv.getconverter(vin.format, vout.format) except imgconv.error, msg: sys.stderr.write(str(msg) + '\n') return 1 if newpf: xpf, ypf = newpf if not xpf: xpf = vin.xpf if not ypf: ypf = vout.ypf newpf = (xpf, ypf) vout.setpf(newpf) if newwidth and newheight: scale = 1 if vin.upside_down <> vout.upside_down or \ vin.mirror_image <> vout.mirror_image: flip = 1 inwidth, inheight = vin.getsize() inwidth = inwidth / vin.xpf inheight = inheight / vin.ypf if magnify: newwidth = int(vout.width * magnify) newheight = int(vout.height * magnify) scale = 1 if scale: vout.setsize(newwidth, newheight) else: newwidth, newheight = vout.getsize() if vin.packfactor <> vout.packfactor: scale = 1 if scale or flip: if vout.bpp not in (8, 32): sys.stderr.write('Can\'t scale or flip this type\n') return 1 newwidth = newwidth / vout.xpf newheight = newheight / vout.ypf print '=== output file ===' vout.printinfo() vout.writeheader() told = 0 nin = 0 nout = 0 tin = 0 tout = 0 while 1: try: tin, data, cdata = vin.getnextframe() except EOFError: break nin = nin + 1 if regen: tout = nin * regen else: tout = tin tout = int(tout / speed) if tout - told < mindelta: continue told = tout if newtype: data = convert(data, inwidth, inheight) if scale: data = imageop.scale(data, vout.bpp/8, \ inwidth, inheight, newwidth, newheight) if flip: x0, y0 = 0, 0 x1, y1 = newwidth-1, newheight-1 if vin.upside_down <> vout.upside_down: y1, y0 = y0, y1 if vin.mirror_image <> vout.mirror_image: x1, x0 = x0, x1 data = imageop.crop(data, vout.bpp/8, \ newwidth, newheight, x0, y0, x1, y1) print 'Writing frame', nout vout.writeframe(tout, data, cdata) nout = nout + 1 vout.close() vin.close() # Don't forget to call the main program try: main() except KeyboardInterrupt: print '[Interrupt]'