Commit 00bb1a74 authored by Guido van Rossum's avatar Guido van Rossum

Added class VoutFile.

Added rgb8 support.
Added cache of frame offsets to VinFile.
Misc hacks to grab rgb8 data.
parent 66686bf5
......@@ -9,6 +9,9 @@ import colorsys
Error = 'VFile.Error' # Exception
# Missing from GL.py:
DMRGB = 0
MAXMAP = 4096 - 256
def conv_grey(l,x,y): return colorsys.yiq_to_rgb(l,0,0)
......@@ -17,6 +20,12 @@ def conv_hls (l,h,s): return colorsys.hls_to_rgb(h,l,s)
def conv_hsv (v,h,s): return colorsys.hsv_to_rgb(h,s,v)
def conv_rgb (r,g,b):
raise Error, 'Attempt to make RGB colormap'
def conv_rgb8(rgb,d1,d2):
rgb = int(rgb*255.0)
r = (rgb >> 5) & 0x07
g = (rgb ) & 0x07
b = (rgb >> 3) & 0x03
return (r/7.0, g/7.0, b/3.0)
# Class VinFile represents a video file used for input.
#
......@@ -39,6 +48,7 @@ def conv_rgb (r,g,b):
# These writable data members provide additional parametrization:
# magnify
# xorigin, yorigin
# fallback
class VinFile():
......@@ -54,6 +64,8 @@ class VinFile():
self.colormapinited = 0
self.magnify = 1.0
self.xorigin = self.yorigin = 0
self.fallback = 1
self.skipchrom = 0
self.fp = fp
self.filename = filename
#
......@@ -90,7 +102,11 @@ class VinFile():
try:
self.format, rest = eval(line[:-1])
if self.format == 'rgb':
pass
self.offset = 0
self.c0bits = 0
self.c1bits = 0
self.c2bits = 0
self.chrompack = 0
elif self.format == 'grey':
self.offset = 0
self.c0bits = rest
......@@ -121,9 +137,34 @@ class VinFile():
self.packfactor = 2
except:
raise Error, self.filename + ': bad (w,h,pf) info'
self.frameno = 0
self.framecache = []
self.hascache = 0
#
return self
def warmcache(self):
if self.hascache: return
n = 0
try:
while 1:
void = self.skipnextframe()
n = n + 1
except EOFError:
pass
if not self.hascache:
raise Error, 'Cannot warm cache'
#
# getinfo returns all info pertaining to a film. The returned tuple
# can be passed to VoutFile.setinfo()
#
def getinfo(self):
return (self.format, self.width, self.height, self.packfactor,\
self.c0bits, self.c1bits, self.c2bits, self.offset, \
self.chrompack)
# rewind() raises Error if the header is bad (which can only
# happen if the file was written to since opened).
......@@ -131,6 +172,11 @@ class VinFile():
self.fp.seek(0)
x = self.initfp(self.fp, self.filename)
def position(self):
if self.frameno >= len(self.framecache):
raise EOFError
self.fp.seek(self.framecache[self.frameno][0])
# getnextframe() raises EOFError (built-in) if there is no next frame,
# or if the next frame is broken.
# So to getnextframeheader(), getnextframedata() and skipnextframe().
......@@ -141,6 +187,9 @@ class VinFile():
return time, data, chromdata
def getnextframedata(self, (size, chromsize)):
if self.hascache:
self.position()
self.frameno = self.frameno + 1
data = self.fp.read(size)
if len(data) <> size: raise EOFError
if chromsize:
......@@ -157,6 +206,9 @@ class VinFile():
return time
def skipnextframedata(self, (size, chromsize)):
if self.hascache:
self.frameno = self.frameno + 1
return
# Note that this won't raise EOFError for a partial frame.
try:
self.fp.seek(size + chromsize, 1) # Relative seek
......@@ -165,8 +217,13 @@ class VinFile():
dummy = self.fp.read(size + chromsize)
def getnextframeheader(self):
if self.hascache:
if self.frameno >= len(self.framecache):
raise EOFError
return self.framecache[self.frameno][1]
line = self.fp.readline()
if not line:
self.hascache = 1
raise EOFError
#
w, h, pf = self.width, self.height, self.packfactor
......@@ -191,6 +248,8 @@ class VinFile():
time, size, chromsize = x
except:
raise Error, self.filename + ': bad frame header'
cdata = (self.fp.tell(), (time, size, chromsize))
self.framecache.append(cdata)
return time, size, chromsize
def shownextframe(self):
......@@ -204,7 +263,7 @@ class VinFile():
self.initcolormap()
factor = self.magnify
if pf: factor = factor * pf
if chromdata:
if chromdata and not self.skipchrom:
cp = self.chrompack
cw = (w+cp-1)/cp
ch = (h+cp-1)/cp
......@@ -232,49 +291,188 @@ class VinFile():
return
gl.cmode()
gl.gconfig()
self.skipchrom = 0
sys.stderr.write('Initializing color map...')
initcmap(self.convcolor, self.c0bits, self.c1bits, \
self.c2bits, self.chrompack, self.offset)
self.initcmap()
sys.stderr.write(' Done.\n')
if self.offset == 0:
gl.color(0x800)
gl.clear()
self.mask = 0x7ff
else:
self.mask = 0xfff
gl.clear()
def initcmap(convcolor, c0bits, c1bits, c2bits, chrompack, offset):
if c0bits+c1bits+c2bits > 11:
raise Error, 'Sorry, 11 bits max'
maxc0 = 1 << c0bits
maxc1 = 1 << c1bits
maxc2 = 1 << c2bits
if offset == 0:
offset = 2048
for i in range(offset, MAXMAP):
gl.mapcolor(i, 0, 255, 0)
for c0 in range(maxc0):
c0v = c0/float(maxc0-1)
for c1 in range(maxc1):
if maxc1 == 1:
c1v = 0
def initcmap(self):
maxbits = gl.getgdesc(GL.GD_BITS_NORM_SNG_CMODE)
if maxbits > 11:
maxbits = 11
c0bits, c1bits, c2bits = self.c0bits, self.c1bits, self.c2bits
if c0bits+c1bits+c2bits > maxbits:
if self.fallback and c0bits < maxbits:
# Cannot display film in this mode, use mono
self.skipchrom = 1
c1bits = c2bits = 0
self.convcolor = conv_grey
else:
c1v = c1/float(maxc1-1)
for c2 in range(maxc2):
if maxc2 == 1:
c2v = 0
raise Error, 'Sorry, '+`maxbits`+ \
' bits max on this machine'
maxc0 = 1 << c0bits
maxc1 = 1 << c1bits
maxc2 = 1 << c2bits
if self.offset == 0 and maxbits == 11:
offset = 2048
else:
offset = self.offset
if maxbits <> 11:
offset = offset & ((1<<maxbits)-1)
#for i in range(512, MAXMAP):
# gl.mapcolor(i, 0, 0, 0)
#void = gl.qtest() # Should be gl.gflush()
for c0 in range(maxc0):
c0v = c0/float(maxc0-1)
for c1 in range(maxc1):
if maxc1 == 1:
c1v = 0
else:
c2v = c2/float(maxc2-1)
index = offset + c0 + \
(c1<<c0bits) + (c2 << (c0bits+c1bits))
rv, gv, bv = convcolor(c0v, c1v, c2v)
r, g, b = \
int(rv*255.0), int(gv*255.0), int(bv*255.0)
if index < MAXMAP:
gl.mapcolor(index, r, g, b)
c1v = c1/float(maxc1-1)
for c2 in range(maxc2):
if maxc2 == 1:
c2v = 0
else:
c2v = c2/float(maxc2-1)
index = offset + c0 + (c1<<c0bits) + \
(c2 << (c0bits+c1bits))
rv, gv, bv = self.convcolor( \
c0v, c1v, c2v)
r, g, b = int(rv*255.0), \
int(gv*255.0), int(bv*255.0)
if index < MAXMAP:
gl.mapcolor(index, r, g, b)
void = gl.gflush()
#
# A set of routines to grab images from windows
#
def grab_rgb(w, h, pf):
if gl.getdisplaymode() <> DMRGB:
raise Error, 'Sorry, can only grab rgb in single-buf rgbmode'
if pf <> 1 and pf <> 0:
raise Error, 'Sorry, only grab with packfactor=1'
return gl.lrectread(0, 0, w-1, h-1), None
def grab_rgb8(w, h, pf):
if gl.getdisplaymode() <> DMRGB:
raise Error, 'Sorry, can only grab rgb in single-buf rgbmode'
if pf <> 1 and pf <> 0:
raise Error, 'Sorry, can only grab with packfactor=1'
r = gl.getgdesc(GL.GD_BITS_NORM_SNG_RED)
g = gl.getgdesc(GL.GD_BITS_NORM_SNG_GREEN)
b = gl.getgdesc(GL.GD_BITS_NORM_SNG_BLUE)
if (r,g,b) <> (3,3,2):
raise Error, 'Sorry, can only grab rgb8 on 8-bit Indigo'
# Dirty Dirty here. Set buffer to cmap mode, grab image and set it back
gl.cmode()
gl.gconfig()
gl.pixmode(GL.PM_SIZE, 8)
data = gl.lrectread(0, 0, w-1, h-1)
data = data[:w*h] # BUG FIX for python lrectread
gl.RGBmode()
gl.gconfig()
gl.pixmode(GL.PM_SIZE, 32)
return data, None
def grab_grey(w, h, pf):
raise Error, 'Sorry, grabbing grey not implemented'
def grab_yiq(w, h, pf):
raise Error, 'Sorry, grabbing yiq not implemented'
def grab_hls(w, h, pf):
raise Error, 'Sorry, grabbing hls not implemented'
def grab_hsv(w, h, pf):
raise Error, 'Sorry, grabbing hsv not implemented'
#
# The class VoutFile is not as well-designed (and tested) as VinFile.
# Notably it will accept almost any garbage and write it to the video
# output file
#
class VoutFile():
def init(self, filename):
if filename == '-':
return self.initfp(sys.stdout, filename)
else:
return self.initfp(open(filename,'w'), filename)
def initfp(self, fp, filename):
self.fp = fp
self.format = 'grey'
self.width = self.height = 0
self.packfactor = 1
self.c0bits = 8
self.c1bits = self.c2bits = 0
self.offset = 0
self.chrompack = 0
self.headerwritten = 0
return self
def close(self):
self.fp.close()
self.initfp(None, None)
def setinfo(self, values):
self.format, self.width, self.height, self.packfactor,\
self.c0bits, self.c1bits, self.c2bits, self.offset, \
self.chrompack = values
def writeheader(self):
self.headerwritten = 1
if self.format == 'rgb':
self.packfactor = 0
elif self.packfactor == 0:
self.packfactor = 1
self.fp.write('CMIF video 3.0\n')
if self.format == 'rgb':
data = ('rgb', 0)
elif self.format == 'grey':
data = ('grey', 0)
else:
data = (self.format, (self.c0bits, self.c1bits, \
self.c2bits, self.chrompack, self.offset))
self.fp.write(`data`+'\n')
data = (self.width, self.height, self.packfactor)
self.fp.write(`data`+'\n')
try:
self._grabber = eval('grab_' + self.format)
except:
raise Error, 'unknown colorsys: ' + self.format
def writeframeheader(self, data):
if not self.headerwritten:
raise Error, 'Writing frame data before header'
# XXXX Should we sanity check here?
self.fp.write(`data`+'\n')
def writeframedata(self, data, chromdata):
# XXXX Check sizes here
self.fp.write(data)
if chromdata:
self.fp.write(chromdata)
def writeframe(self, time, data, chromdata):
if chromdata:
clen = len(chromdata)
else:
clen = 0
self.writeframeheader((time, len(data), clen))
self.writeframedata(data, chromdata)
def grabframe(self):
return self._grabber(self.width, self.height, self.packfactor)
def test():
import sys, time
filename = 'film.video'
......@@ -303,3 +501,4 @@ def test():
vin.showframe(data, chromdata)
print 'Done.'
time.sleep(2)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment