blob: a0a578d20f5cae6e7c8f006b34135ccd4b6309e3 [file] [log] [blame]
Guido van Rossum094a9de1991-12-03 16:50:00 +00001# VFile -- two classes for Video Files.
2# VinFile -- for video input.
3# VoutFile -- for video output.
4
5import sys
6import gl
7import GL
Guido van Rossum444339d1991-12-03 16:52:40 +00008import colorsys
Guido van Rossum094a9de1991-12-03 16:50:00 +00009
10Error = 'VFile.Error' # Exception
11
Guido van Rossum444339d1991-12-03 16:52:40 +000012def conv_grey(l,x,y): return colorsys.yiq_to_rgb(l,0,0)
13def conv_yiq (y,i,q): return colorsys.yiq_to_rgb(y, (i-0.5)*1.2, q-0.5)
14def conv_hls (l,h,s): return colorsys.hls_to_rgb(h,l,s)
15def conv_hsv (v,h,s): return colorsys.hsv_to_rgb(h,s,v)
16def conv_rgb (r,g,b):
17 raise Error, 'Attempt to make RGB colormap'
Guido van Rossum094a9de1991-12-03 16:50:00 +000018
19# Class VinFile represents a video file used for input.
20#
21# It has the following methods:
22# init(filename)
23# initfp(fp, filename)
24# rewind()
25# getframe()
26# skipframe()
27#
28# The following read-only data members provide public information:
29# version
30# filename
31# width, height
32# packfactor
Guido van Rossum444339d1991-12-03 16:52:40 +000033# c0bits, c1bits, c2bits, chrompack
34# offset
35# format
Guido van Rossum094a9de1991-12-03 16:50:00 +000036#
37# These writable data members provide additional parametrization:
38# xorigin, yorigin
39
40class VinFile():
41
42 # init() and initfp() raise Error if the header is bad.
43 # init() raises whatever open() raises if the file can't be opened.
44
45 def init(self, filename):
46 if filename = '-':
47 return self.initfp(sys.stdin, filename)
48 return self.initfp(open(filename, 'r'), filename)
49
50 def initfp(self, (fp, filename)):
51 self.colormapinited = 0
52 self.magnify = 1.0
53 self.xorigin = self.yorigin = 0
54 self.fp = fp
55 self.filename = filename
56 #
57 line = self.fp.readline()
58 if line = 'CMIF video 1.0\n':
59 self.version = 1.0
60 elif line = 'CMIF video 2.0\n':
61 self.version = 2.0
Guido van Rossum444339d1991-12-03 16:52:40 +000062 elif line = 'CMIF video 3.0\n':
63 self.version = 3.0
Guido van Rossum094a9de1991-12-03 16:50:00 +000064 else:
65 raise Error, self.filename + ': bad video format'
66 #
67 if self.version < 2.0:
Guido van Rossum444339d1991-12-03 16:52:40 +000068 self.c0bits, self.c1bits, self.c2bits = 8, 0, 0
Guido van Rossum094a9de1991-12-03 16:50:00 +000069 self.chrompack = 0
Guido van Rossum444339d1991-12-03 16:52:40 +000070 self.offset = 0
71 self.format = 'grey'
72 elif self.version = 2.0:
Guido van Rossum094a9de1991-12-03 16:50:00 +000073 line = self.fp.readline()
74 try:
Guido van Rossum444339d1991-12-03 16:52:40 +000075 self.c0bits, self.c1bits, self.c2bits, \
Guido van Rossum094a9de1991-12-03 16:50:00 +000076 self.chrompack = eval(line[:-1])
Guido van Rossum444339d1991-12-03 16:52:40 +000077 if self.c1bits or self.c2bits:
78 self.format = 'yiq'
79 else:
80 self.format = 'grey'
81 self.offset = 0
Guido van Rossum094a9de1991-12-03 16:50:00 +000082 except:
Guido van Rossum444339d1991-12-03 16:52:40 +000083 raise Error, self.filename + ': bad 2.0 color info'
84 elif self.version = 3.0:
85 line = self.fp.readline()
86 try:
87 self.format, rest = eval(line[:-1])
88 if self.format = 'rgb':
89 pass
90 elif self.format = 'grey':
91 self.offset = 0
92 self.c0bits = rest
93 self.c1bits = self.c2bits = \
94 self.chrompack = 0
95 else:
96 self.c0bits,self.c1bits,self.c2bits,\
97 self.chrompack,self.offset = rest
98 except:
99 raise Error, self.filename + ': bad 3.0 color info'
100
101 try:
102 self.convcolor = eval('conv_'+self.format)
103 except:
104 raise Error, self.filename + ': unknown colorsys ' + self.format
Guido van Rossum094a9de1991-12-03 16:50:00 +0000105 #
106 line = self.fp.readline()
107 try:
108 x = eval(line[:-1])
109 if self.version > 1.0 or len(x) = 3:
110 self.width, self.height, self.packfactor = x
Guido van Rossum444339d1991-12-03 16:52:40 +0000111 if self.packfactor = 0:
112 self.format = 'rgb'
Guido van Rossum094a9de1991-12-03 16:50:00 +0000113 else:
114 sef.width, self.height = x
115 self.packfactor = 2
116 except:
117 raise Error, self.filename + ': bad (w,h,pf) info'
118 #
119 return self
120
121 # rewind() raises Error if the header is bad (which can only
122 # happen if the file was written to since opened).
123
124 def rewind(self):
125 self.fp.seek(0)
126 x = self.initfp(self.fp, self.filename)
127
128 # getnextframe() raises EOFError (built-in) if there is no next frame,
129 # or if the next frame is broken.
130 # So to getnextframeheader(), getnextframedata() and skipnextframe().
131
132 def getnextframe(self):
133 time, size, chromsize = self.getnextframeheader()
134 data, chromdata = self.getnextframedata(size, chromsize)
135 return time, data, chromdata
136
137 def getnextframedata(self, (size, chromsize)):
138 data = self.fp.read(size)
139 if len(data) <> size: raise EOFError
140 if chromsize:
141 chromdata = self.fp.read(chromsize)
142 if len(chromdata) <> chromsize: raise EOFError
143 else:
144 chromdata = None
145 #
146 return data, chromdata
147
148 def skipnextframe(self):
149 time, size, chromsize = self.getnextframeheader()
150 self.skipnextframedata(size, chromsize)
151 return time
152
153 def skipnextframedata(self, (size, chromsize)):
154 # Note that this won't raise EOFError for a partial frame.
155 try:
Guido van Rossum444339d1991-12-03 16:52:40 +0000156 self.fp.seek(size + chromsize, 1) # Relatc1ve seek
Guido van Rossum094a9de1991-12-03 16:50:00 +0000157 except:
158 # Assume it's a pipe -- read the data to discard it
159 dummy = self.fp.read(size)
160 dummy = self.fp.read(chromsize)
161
162 def getnextframeheader(self):
163 line = self.fp.readline()
164 if not line:
165 raise EOFError
166 #
167 w, h, pf = self.width, self.height, self.packfactor
168 try:
169 x = eval(line[:-1])
170 if type(x) in (type(0), type(0.0)):
171 time = x
172 if pf = 0:
173 size = w * h * 4
174 else:
175 size = (w/pf) * (h/pf)
176 elif len(x) = 2:
177 time, size = x
178 cp = self.chrompack
179 if cp:
180 cw = (w + cp - 1) / cp
181 ch = (h + cp - 1) / cp
182 chromsize = 2 * cw * ch
183 else:
184 chromsize = 0
185 else:
186 time, size, chromsize = x
187 except:
188 raise Error, self.filename + ': bad frame header'
189 return time, size, chromsize
190
191 def shownextframe(self):
192 time, data, chromdata = self.getnextframe()
193 self.showframe(data, chromdata)
194 return time
195
196 def showframe(self, (data, chromdata)):
197 w, h, pf = self.width, self.height, self.packfactor
Guido van Rossum444339d1991-12-03 16:52:40 +0000198 if not self.colormapinited:
199 self.initcolormap()
Guido van Rossum094a9de1991-12-03 16:50:00 +0000200 factor = self.magnify
201 if pf: factor = factor * pf
202 if chromdata:
203 cp = self.chrompack
204 cw = (w+cp-1)/cp
205 ch = (h+cp-1)/cp
206 gl.rectzoom(factor*cp, factor*cp)
207 gl.pixmode(GL.PM_SIZE, 16)
Guido van Rossum444339d1991-12-03 16:52:40 +0000208 gl.writemask(self.mask - ((1 << self.c0bits) - 1))
Guido van Rossum094a9de1991-12-03 16:50:00 +0000209 gl.lrectwrite(self.xorigin, self.yorigin, \
210 self.xorigin + cw - 1, self.yorigin + ch - 1, \
211 chromdata)
212 #
213 if pf:
Guido van Rossum444339d1991-12-03 16:52:40 +0000214 gl.writemask((1 << self.c0bits) - 1)
Guido van Rossum094a9de1991-12-03 16:50:00 +0000215 gl.pixmode(GL.PM_SIZE, 8)
216 gl.rectzoom(factor, factor)
217 w = w/pf
218 h = h/pf
219 gl.lrectwrite(self.xorigin, self.yorigin, \
220 self.xorigin + w - 1, self.yorigin + h - 1, data)
221
222 def initcolormap(self):
Guido van Rossum094a9de1991-12-03 16:50:00 +0000223 self.colormapinited = 1
Guido van Rossum444339d1991-12-03 16:52:40 +0000224 if self.format = 'rgb':
225 gl.RGBmode()
226 gl.gconfig()
227 return
228 initcmap(self.convcolor, self.c0bits, self.c1bits, self.c2bits, self.chrompack, self.offset)
229 if self.offset == 0:
230 gl.color(0x800)
231 self.mask = 0x7ff
232 else:
233 self.mask = 0xfff
234 gl.clear()
Guido van Rossum094a9de1991-12-03 16:50:00 +0000235
236
Guido van Rossum444339d1991-12-03 16:52:40 +0000237def initcmap(convcolor, c0bits, c1bits, c2bits, chrompack, offset):
238 if c0bits+c1bits+c2bits > 11:
Guido van Rossum094a9de1991-12-03 16:50:00 +0000239 raise Error, 'Sorry, 11 bits max'
240 import colorsys
Guido van Rossum444339d1991-12-03 16:52:40 +0000241 maxc0 = 1 << c0bits
242 maxc1 = 1 << c1bits
243 maxc2 = 1 << c2bits
244 if offset = 0:
245 offset = 2048
246 rng = (offset, 4192-256)
247 for i in range(rng):
Guido van Rossum094a9de1991-12-03 16:50:00 +0000248 gl.mapcolor(i, 0, 255, 0)
Guido van Rossum444339d1991-12-03 16:52:40 +0000249 for c0 in range(maxc0):
250 c0v = c0/float(maxc0-1)
251 for c1 in range(maxc1):
252 if maxc1 = 1:
253 c1v = 0
Guido van Rossum094a9de1991-12-03 16:50:00 +0000254 else:
Guido van Rossum444339d1991-12-03 16:52:40 +0000255 c1v = c1/float(maxc1-1)
256 for c2 in range(maxc2):
257 if maxc2 = 1:
258 c2v = 0
Guido van Rossum094a9de1991-12-03 16:50:00 +0000259 else:
Guido van Rossum444339d1991-12-03 16:52:40 +0000260 c2v = c2/float(maxc2-1)
261 index = offset + c0 + \
262 (c1 << c0bits) + (c2 << (c0bits+c1bits))
263 rv, gv, bv = convcolor(c0v, c1v, c2v)
Guido van Rossum094a9de1991-12-03 16:50:00 +0000264 r, g, b = \
265 int(rv*255.0), int(gv*255.0), int(bv*255.0)
266 if index < 4096 - 256:
267 gl.mapcolor(index, r, g, b)
268
269
270def test():
271 import sys
272 filename = 'film.video'
273 if sys.argv[1:]: filename = sys.argv[1]
274 vin = VinFile().init(filename)
Guido van Rossum444339d1991-12-03 16:52:40 +0000275 print 'Version: ', vin.version
276 print 'Size: ', vin.width, 'x', vin.height
277 print 'Pack: ', vin.packfactor, vin.chrompack
278 print 'Bits: ', vin.c0bits, vin.c1bits, vin.c2bits
279 print 'Format: ', vin.format
280 print 'Offset: ', vin.offset
Guido van Rossum094a9de1991-12-03 16:50:00 +0000281 gl.foreground()
282 gl.prefsize(vin.width, vin.height)
283 wid = gl.winopen('VFile.test: ' + filename)
284 try:
285 while 1:
286 t = vin.shownextframe()
287 except EOFError:
288 pass
Guido van Rossum444339d1991-12-03 16:52:40 +0000289 import time
290 time.sleep(5)