Kaydet (Commit) 2080b347 authored tarafından 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.
üst 444db07d
...@@ -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,49 +291,188 @@ class VinFile(): ...@@ -232,49 +291,188 @@ 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:
maxc0 = 1 << c0bits maxbits = 11
maxc1 = 1 << c1bits c0bits, c1bits, c2bits = self.c0bits, self.c1bits, self.c2bits
maxc2 = 1 << c2bits if c0bits+c1bits+c2bits > maxbits:
if offset == 0: if self.fallback and c0bits < maxbits:
offset = 2048 # Cannot display film in this mode, use mono
for i in range(offset, MAXMAP): self.skipchrom = 1
gl.mapcolor(i, 0, 255, 0) c1bits = c2bits = 0
for c0 in range(maxc0): self.convcolor = conv_grey
c0v = c0/float(maxc0-1)
for c1 in range(maxc1):
if maxc1 == 1:
c1v = 0
else: else:
c1v = c1/float(maxc1-1) raise Error, 'Sorry, '+`maxbits`+ \
for c2 in range(maxc2): ' bits max on this machine'
if maxc2 == 1: maxc0 = 1 << c0bits
c2v = 0 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: else:
c2v = c2/float(maxc2-1) c1v = c1/float(maxc1-1)
index = offset + c0 + \ for c2 in range(maxc2):
(c1<<c0bits) + (c2 << (c0bits+c1bits)) if maxc2 == 1:
rv, gv, bv = convcolor(c0v, c1v, c2v) c2v = 0
r, g, b = \ else:
int(rv*255.0), int(gv*255.0), int(bv*255.0) c2v = c2/float(maxc2-1)
if index < MAXMAP: index = offset + c0 + (c1<<c0bits) + \
gl.mapcolor(index, r, g, b) (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(): def test():
import sys, time import sys, time
filename = 'film.video' filename = 'film.video'
...@@ -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