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 ...@@ -9,6 +9,9 @@ import colorsys
Error = 'VFile.Error' # Exception Error = 'VFile.Error' # Exception
# Missing from GL.py:
DMRGB = 0
MAXMAP = 4096 - 256 MAXMAP = 4096 - 256
def conv_grey(l,x,y): return colorsys.yiq_to_rgb(l,0,0) 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) ...@@ -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_hsv (v,h,s): return colorsys.hsv_to_rgb(h,s,v)
def conv_rgb (r,g,b): def conv_rgb (r,g,b):
raise Error, 'Attempt to make RGB colormap' 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. # Class VinFile represents a video file used for input.
# #
...@@ -39,6 +48,7 @@ def conv_rgb (r,g,b): ...@@ -39,6 +48,7 @@ def conv_rgb (r,g,b):
# These writable data members provide additional parametrization: # These writable data members provide additional parametrization:
# magnify # magnify
# xorigin, yorigin # xorigin, yorigin
# fallback
class VinFile(): class VinFile():
...@@ -54,6 +64,8 @@ class VinFile(): ...@@ -54,6 +64,8 @@ class VinFile():
self.colormapinited = 0 self.colormapinited = 0
self.magnify = 1.0 self.magnify = 1.0
self.xorigin = self.yorigin = 0 self.xorigin = self.yorigin = 0
self.fallback = 1
self.skipchrom = 0
self.fp = fp self.fp = fp
self.filename = filename self.filename = filename
# #
...@@ -90,7 +102,11 @@ class VinFile(): ...@@ -90,7 +102,11 @@ class VinFile():
try: try:
self.format, rest = eval(line[:-1]) self.format, rest = eval(line[:-1])
if self.format == 'rgb': if self.format == 'rgb':
pass self.offset = 0
self.c0bits = 0
self.c1bits = 0
self.c2bits = 0
self.chrompack = 0
elif self.format == 'grey': elif self.format == 'grey':
self.offset = 0 self.offset = 0
self.c0bits = rest self.c0bits = rest
...@@ -121,9 +137,34 @@ class VinFile(): ...@@ -121,9 +137,34 @@ class VinFile():
self.packfactor = 2 self.packfactor = 2
except: except:
raise Error, self.filename + ': bad (w,h,pf) info' raise Error, self.filename + ': bad (w,h,pf) info'
self.frameno = 0
self.framecache = []
self.hascache = 0
# #
return self 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 # rewind() raises Error if the header is bad (which can only
# happen if the file was written to since opened). # happen if the file was written to since opened).
...@@ -131,6 +172,11 @@ class VinFile(): ...@@ -131,6 +172,11 @@ class VinFile():
self.fp.seek(0) self.fp.seek(0)
x = self.initfp(self.fp, self.filename) 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, # getnextframe() raises EOFError (built-in) if there is no next frame,
# or if the next frame is broken. # or if the next frame is broken.
# So to getnextframeheader(), getnextframedata() and skipnextframe(). # So to getnextframeheader(), getnextframedata() and skipnextframe().
...@@ -141,6 +187,9 @@ class VinFile(): ...@@ -141,6 +187,9 @@ class VinFile():
return time, data, chromdata return time, data, chromdata
def getnextframedata(self, (size, chromsize)): def getnextframedata(self, (size, chromsize)):
if self.hascache:
self.position()
self.frameno = self.frameno + 1
data = self.fp.read(size) data = self.fp.read(size)
if len(data) <> size: raise EOFError if len(data) <> size: raise EOFError
if chromsize: if chromsize:
...@@ -157,6 +206,9 @@ class VinFile(): ...@@ -157,6 +206,9 @@ class VinFile():
return time return time
def skipnextframedata(self, (size, chromsize)): 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. # Note that this won't raise EOFError for a partial frame.
try: try:
self.fp.seek(size + chromsize, 1) # Relative seek self.fp.seek(size + chromsize, 1) # Relative seek
...@@ -165,8 +217,13 @@ class VinFile(): ...@@ -165,8 +217,13 @@ class VinFile():
dummy = self.fp.read(size + chromsize) dummy = self.fp.read(size + chromsize)
def getnextframeheader(self): def getnextframeheader(self):
if self.hascache:
if self.frameno >= len(self.framecache):
raise EOFError
return self.framecache[self.frameno][1]
line = self.fp.readline() line = self.fp.readline()
if not line: if not line:
self.hascache = 1
raise EOFError raise EOFError
# #
w, h, pf = self.width, self.height, self.packfactor w, h, pf = self.width, self.height, self.packfactor
...@@ -191,6 +248,8 @@ class VinFile(): ...@@ -191,6 +248,8 @@ class VinFile():
time, size, chromsize = x time, size, chromsize = x
except: except:
raise Error, self.filename + ': bad frame header' raise Error, self.filename + ': bad frame header'
cdata = (self.fp.tell(), (time, size, chromsize))
self.framecache.append(cdata)
return time, size, chromsize return time, size, chromsize
def shownextframe(self): def shownextframe(self):
...@@ -204,7 +263,7 @@ class VinFile(): ...@@ -204,7 +263,7 @@ class VinFile():
self.initcolormap() self.initcolormap()
factor = self.magnify factor = self.magnify
if pf: factor = factor * pf if pf: factor = factor * pf
if chromdata: if chromdata and not self.skipchrom:
cp = self.chrompack cp = self.chrompack
cw = (w+cp-1)/cp cw = (w+cp-1)/cp
ch = (h+cp-1)/cp ch = (h+cp-1)/cp
...@@ -232,28 +291,45 @@ class VinFile(): ...@@ -232,28 +291,45 @@ class VinFile():
return return
gl.cmode() gl.cmode()
gl.gconfig() gl.gconfig()
self.skipchrom = 0
sys.stderr.write('Initializing color map...') sys.stderr.write('Initializing color map...')
initcmap(self.convcolor, self.c0bits, self.c1bits, \ self.initcmap()
self.c2bits, self.chrompack, self.offset)
sys.stderr.write(' Done.\n') sys.stderr.write(' Done.\n')
if self.offset == 0: if self.offset == 0:
gl.color(0x800) gl.color(0x800)
gl.clear()
self.mask = 0x7ff self.mask = 0x7ff
else: else:
self.mask = 0xfff self.mask = 0xfff
gl.clear() gl.clear()
def initcmap(convcolor, c0bits, c1bits, c2bits, chrompack, offset): def initcmap(self):
if c0bits+c1bits+c2bits > 11: maxbits = gl.getgdesc(GL.GD_BITS_NORM_SNG_CMODE)
raise Error, 'Sorry, 11 bits max' 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:
raise Error, 'Sorry, '+`maxbits`+ \
' bits max on this machine'
maxc0 = 1 << c0bits maxc0 = 1 << c0bits
maxc1 = 1 << c1bits maxc1 = 1 << c1bits
maxc2 = 1 << c2bits maxc2 = 1 << c2bits
if offset == 0: if self.offset == 0 and maxbits == 11:
offset = 2048 offset = 2048
for i in range(offset, MAXMAP): else:
gl.mapcolor(i, 0, 255, 0) 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): for c0 in range(maxc0):
c0v = c0/float(maxc0-1) c0v = c0/float(maxc0-1)
for c1 in range(maxc1): for c1 in range(maxc1):
...@@ -266,14 +342,136 @@ def initcmap(convcolor, c0bits, c1bits, c2bits, chrompack, offset): ...@@ -266,14 +342,136 @@ def initcmap(convcolor, c0bits, c1bits, c2bits, chrompack, offset):
c2v = 0 c2v = 0
else: else:
c2v = c2/float(maxc2-1) c2v = c2/float(maxc2-1)
index = offset + c0 + \ index = offset + c0 + (c1<<c0bits) + \
(c1<<c0bits) + (c2 << (c0bits+c1bits)) (c2 << (c0bits+c1bits))
rv, gv, bv = convcolor(c0v, c1v, c2v) rv, gv, bv = self.convcolor( \
r, g, b = \ c0v, c1v, c2v)
int(rv*255.0), int(gv*255.0), int(bv*255.0) r, g, b = int(rv*255.0), \
int(gv*255.0), int(bv*255.0)
if index < MAXMAP: if index < MAXMAP:
gl.mapcolor(index, r, g, b) 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(): def test():
import sys, time import sys, time
...@@ -303,3 +501,4 @@ def test(): ...@@ -303,3 +501,4 @@ def test():
vin.showframe(data, chromdata) vin.showframe(data, chromdata)
print 'Done.' print 'Done.'
time.sleep(2) 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