blob: ef4647a16610508cda227e55763006c5da3c7307 [file] [log] [blame]
Guido van Rossumf06ee5f1996-11-27 19:52:01 +00001#! /usr/bin/env python
Guido van Rossum349f2b51992-12-24 11:41:14 +00002
Guido van Rossum5e044b71993-02-25 14:20:13 +00003# Universal (non-interactive) CMIF video file copier.
Guido van Rossum349f2b51992-12-24 11:41:14 +00004
Guido van Rossum5e044b71993-02-25 14:20:13 +00005
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)
Jeremy Hyltona05e2932000-06-28 14:48:01 +000011# = drop frames that are less than n msec apart (to accommodate slow players)
Guido van Rossum5e044b71993-02-25 14:20:13 +000012# - 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 Rossum349f2b51992-12-24 11:41:14 +000017
18def usage():
Guido van Rossum5e044b71993-02-25 14:20:13 +000019 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 Rossumc97d2ed1993-02-25 14:50:27 +000030 print '-x xpf : new x packfactor (default unchanged)'
31 print '-y ypf : new y packfactor (default unchanged)'
Guido van Rossum5e044b71993-02-25 14:20:13 +000032 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 Rossum349f2b51992-12-24 11:41:14 +000039
Guido van Rossum5e044b71993-02-25 14:20:13 +000040
41import sys
42sys.path.append('/ufs/guido/src/video')
43
44import VFile
45import imgconv
46import imageop
47import getopt
48import string
49
50
51# Global options
52
53speed = 1.0
54mindelta = 0
55regen = None
56newpf = None
57newtype = None
58magnify = None
59newwidth = None
60newheight = None
61
62
63# Function to turn a string into a float
64
65atof_error = 'atof_error' # Exception if it fails
66
67def 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 Rossum349f2b51992-12-24 11:41:14 +000075
76def main():
Guido van Rossum5e044b71993-02-25 14:20:13 +000077 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 Rossum349f2b51992-12-24 11:41:14 +000087 usage()
Guido van Rossum5e044b71993-02-25 14:20:13 +000088 sys.exit(2)
89
90 xpf = ypf = None
Guido van Rossum349f2b51992-12-24 11:41:14 +000091
Guido van Rossum5e044b71993-02-25 14:20:13 +000092 # 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 Rossum349f2b51992-12-24 11:41:14 +0000113
Guido van Rossum5e044b71993-02-25 14:20:13 +0000114 if xpf or ypf:
Guido van Rossum5e044b71993-02-25 14:20:13 +0000115 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
148def process(infilename, outfilename):
Guido van Rossumc97d2ed1993-02-25 14:50:27 +0000149 global newwidth, newheight, newpf
Guido van Rossum5e044b71993-02-25 14:20:13 +0000150
151 try:
Guido van Rossum21a3ff91993-12-17 15:11:41 +0000152 vin = VFile.BasicVinFile(infilename)
Guido van Rossum5e044b71993-02-25 14:20:13 +0000153 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:
Guido van Rossum21a3ff91993-12-17 15:11:41 +0000164 vout = VFile.BasicVoutFile(outfilename)
Guido van Rossum5e044b71993-02-25 14:20:13 +0000165 except IOError, msg:
166 sys.stderr.write(outfilename + ': I/O error: ' + `msg` + '\n')
167 return 1
168
Guido van Rossum85f7bd51993-02-25 16:10:16 +0000169 print '=== input file ==='
Guido van Rossumc97d2ed1993-02-25 14:50:27 +0000170 vin.printinfo()
171
Guido van Rossum5e044b71993-02-25 14:20:13 +0000172 vout.setinfo(vin.getinfo())
173
174 scale = 0
175 flip = 0
Jack Jansen72d73641993-09-28 16:46:15 +0000176 decompress = 0
Guido van Rossum5e044b71993-02-25 14:20:13 +0000177
Jack Jansen72d73641993-09-28 16:46:15 +0000178 vinfmt = vin.format
179 if vinfmt == 'compress':
180 if not newtype or newtype == 'compress':
181 # compressed->compressed: copy compression header
182 vout.setcompressheader(vin.getcompressheader())
183 else:
184 # compressed->something else: go via rgb-24
185 decompress = 1
186 vinfmt = 'rgb'
187 elif newtype == 'compress':
188 # something else->compressed: not implemented
189 sys.stderr.write('Sorry, conversion to compressed not yet implemented\n')
190 return 1
Guido van Rossum5e044b71993-02-25 14:20:13 +0000191 if newtype:
192 vout.setformat(newtype)
193 try:
Jack Jansen72d73641993-09-28 16:46:15 +0000194 convert = imgconv.getconverter(vinfmt, vout.format)
Guido van Rossum5e044b71993-02-25 14:20:13 +0000195 except imgconv.error, msg:
196 sys.stderr.write(str(msg) + '\n')
197 return 1
198
199 if newpf:
Guido van Rossumc97d2ed1993-02-25 14:50:27 +0000200 xpf, ypf = newpf
201 if not xpf: xpf = vin.xpf
202 if not ypf: ypf = vout.ypf
203 newpf = (xpf, ypf)
Guido van Rossum5e044b71993-02-25 14:20:13 +0000204 vout.setpf(newpf)
Guido van Rossum5e044b71993-02-25 14:20:13 +0000205
206 if newwidth and newheight:
207 scale = 1
208
209 if vin.upside_down <> vout.upside_down or \
210 vin.mirror_image <> vout.mirror_image:
211 flip = 1
212
213 inwidth, inheight = vin.getsize()
214 inwidth = inwidth / vin.xpf
215 inheight = inheight / vin.ypf
216
217 if magnify:
218 newwidth = int(vout.width * magnify)
219 newheight = int(vout.height * magnify)
220 scale = 1
221
222 if scale:
223 vout.setsize(newwidth, newheight)
224 else:
225 newwidth, newheight = vout.getsize()
226
227 if vin.packfactor <> vout.packfactor:
228 scale = 1
229
230 if scale or flip:
231 if vout.bpp not in (8, 32):
232 sys.stderr.write('Can\'t scale or flip this type\n')
233 return 1
234
235 newwidth = newwidth / vout.xpf
236 newheight = newheight / vout.ypf
237
Guido van Rossum85f7bd51993-02-25 16:10:16 +0000238 print '=== output file ==='
Guido van Rossumc97d2ed1993-02-25 14:50:27 +0000239 vout.printinfo()
Guido van Rossum5e044b71993-02-25 14:20:13 +0000240 vout.writeheader()
241
242 told = 0
243 nin = 0
244 nout = 0
245 tin = 0
246 tout = 0
247
Guido van Rossum349f2b51992-12-24 11:41:14 +0000248 while 1:
Guido van Rossum5e044b71993-02-25 14:20:13 +0000249 try:
250 tin, data, cdata = vin.getnextframe()
251 except EOFError:
Guido van Rossum349f2b51992-12-24 11:41:14 +0000252 break
Jack Jansen72d73641993-09-28 16:46:15 +0000253 if decompress:
254 data = vin.decompress(data)
Guido van Rossum5e044b71993-02-25 14:20:13 +0000255 nin = nin + 1
256 if regen:
257 tout = nin * regen
Guido van Rossum349f2b51992-12-24 11:41:14 +0000258 else:
Guido van Rossum5e044b71993-02-25 14:20:13 +0000259 tout = tin
260 tout = int(tout / speed)
261 if tout - told < mindelta:
262 continue
263 told = tout
264 if newtype:
265 data = convert(data, inwidth, inheight)
Guido van Rossumc97d2ed1993-02-25 14:50:27 +0000266 if scale:
Guido van Rossum5e044b71993-02-25 14:20:13 +0000267 data = imageop.scale(data, vout.bpp/8, \
268 inwidth, inheight, newwidth, newheight)
Guido van Rossumc97d2ed1993-02-25 14:50:27 +0000269 if flip:
Guido van Rossum5e044b71993-02-25 14:20:13 +0000270 x0, y0 = 0, 0
Guido van Rossum85f7bd51993-02-25 16:10:16 +0000271 x1, y1 = newwidth-1, newheight-1
Guido van Rossum5e044b71993-02-25 14:20:13 +0000272 if vin.upside_down <> vout.upside_down:
273 y1, y0 = y0, y1
274 if vin.mirror_image <> vout.mirror_image:
275 x1, x0 = x0, x1
276 data = imageop.crop(data, vout.bpp/8, \
277 newwidth, newheight, x0, y0, x1, y1)
Guido van Rossum85f7bd51993-02-25 16:10:16 +0000278 print 'Writing frame', nout
Guido van Rossum5e044b71993-02-25 14:20:13 +0000279 vout.writeframe(tout, data, cdata)
280 nout = nout + 1
Guido van Rossum349f2b51992-12-24 11:41:14 +0000281
Guido van Rossum5e044b71993-02-25 14:20:13 +0000282 vout.close()
283 vin.close()
284
285
286# Don't forget to call the main program
287
288try:
289 main()
290except KeyboardInterrupt:
291 print '[Interrupt]'