summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xDemo/sgi/video/VFile.py246
1 files changed, 217 insertions, 29 deletions
diff --git a/Demo/sgi/video/VFile.py b/Demo/sgi/video/VFile.py
index 0f72306374..e5aea41888 100755
--- a/Demo/sgi/video/VFile.py
+++ b/Demo/sgi/video/VFile.py
@@ -11,6 +11,9 @@
# BasicVoutFile: write a CMIF video file
# VinFile: BasicVinFile + Displayer
# VoutFile: BasicVoutFile + Displayer + Grabber
+#
+# XXX Future extension:
+# BasicVinoutFile: supports overwriting of individual frames
# Imported modules
@@ -25,6 +28,7 @@ import colorsys
Error = 'VFile.Error' # file format errors
CallError = 'VFile.CallError' # bad call
+AssertError = 'VFile.AssertError' # internal malfunction
# Constants returned by gl.getdisplaymode(), from <gl/get.h>
@@ -75,6 +79,61 @@ def choose_conversion(format):
raise Error, 'Unknown color system: ' + `format`
+# Inverses of the above
+
+def inv_grey(r, g, b):
+ y, i, q = colorsys.rgb_to_yiq(r, g, b)
+ return y, 0, 0
+
+def inv_yiq(r, g, b):
+ y, i, q = colorsys.rgb_to_yiq(r, g, b)
+ return y, i/1.2 + 0.5, q + 0.5
+
+def inv_hls(r, g, b):
+ h, l, s = colorsys.rgb_to_hls(r, g, b)
+ return l, h, s
+
+def inv_hsv(r, g, b):
+ h, s, v = colorsys.rgb_to_hsv(r, g, b)
+ return v, h, s
+
+def inv_rgb(r, g, b):
+ raise Error, 'Attempt to invert RGB colormap'
+
+def inv_rgb8(r, g, b):
+ r = int(r*7.0)
+ g = int(g*7.0)
+ b = int(b*7.0)
+ rgb = ((r&7) << 5) | ((b&3) << 3) | (g&7)
+ return rgb / 255.0, 0, 0
+
+
+# Choose one of the above based upon a color system name
+
+def choose_inverse(format):
+ try:
+ return eval('inv_' + format)
+ except:
+ raise Error, 'Unknown color system: ' + `format`
+
+
+# Predicate to see whether this is an entry level (non-XS) Indigo.
+# If so we can lrectwrite 8-bit wide pixels into a window in RGB mode
+
+def is_entry_indigo():
+ # XXX hack, hack. We should call gl.gversion() but that doesn't
+ # exist in earlier Python versions. Therefore we check the number
+ # of bitplanes *and* the size of the monitor.
+ xmax = gl.getgdesc(GL.GD_XPMAX)
+ if xmax <> 1024: return 0
+ ymax = gl.getgdesc(GL.GD_YPMAX)
+ if ymax != 768: return 0
+ 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)
+ return (r, g, b) == (3, 3, 2)
+
+
# Routines to grab data, per color system (only a few really supported).
# (These functions are used via eval with a constructed argument!)
@@ -90,14 +149,10 @@ def grab_rgb8(w, h, pf):
raise Error, 'Sorry, can only grab rgb8 in single-buf rgbmode'
if pf <> 1 and pf <> 0:
raise Error, 'Sorry, can only grab rgb8 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'
+ if not is_entry_indigo():
+ raise Error, 'Sorry, can only grab rgb8 on entry level Indigo'
# XXX Dirty Dirty here.
# XXX Set buffer to cmap mode, grab image and set it back.
- # XXX (Shouldn't be necessary???)
gl.cmode()
gl.gconfig()
gl.pixmode(GL.PM_SIZE, 8)
@@ -193,7 +248,7 @@ class VideoParams:
# Class to display video frames in a window.
# It is the caller's responsibility to ensure that the correct window
-# is current when using showframe(), initcolormap() and clear()
+# is current when using showframe(), initcolormap(), clear() and clearto()
class Displayer(VideoParams):
@@ -211,6 +266,8 @@ class Displayer(VideoParams):
# Internal flags
self.colormapinited = 0 # must initialize window
self.skipchrom = 0 # don't skip chrominance data
+ self.color0 = None # magic, used by clearto()
+ self.fixcolor0 = 0 # don't need to fix color0
return self
# setinfo() must reset some internal flags
@@ -219,12 +276,17 @@ class Displayer(VideoParams):
VideoParams.setinfo(values)
self.colormapinited = 0
self.skipchrom = 0
+ self.color0 = None
+ self.fixcolor0 = 0
# Show one frame, initializing the window if necessary
def showframe(self, data, chromdata):
if not self.colormapinited:
self.initcolormap()
+ if self.fixcolor0:
+ gl.mapcolor(self.color0)
+ self.fixcolor0 = 0
w, h, pf = self.width, self.height, self.packfactor
factor = self.magnify
if pf: factor = factor * pf
@@ -247,18 +309,28 @@ class Displayer(VideoParams):
gl.rectzoom(factor, factor)
gl.lrectwrite(self.xorigin, self.yorigin, \
self.xorigin + w - 1, self.yorigin + h - 1, data)
+ gl.gflush()
# Initialize the window: set RGB or colormap mode as required,
# fill in the colormap, and clear the window
def initcolormap(self):
+ self.colormapinited = 1
+ self.color0 = None
+ self.fixcolor0 = 0
if self.format == 'rgb':
gl.RGBmode()
gl.gconfig()
- self.colormapinited = 1
gl.RGBcolor(200, 200, 200) # XXX rather light grey
gl.clear()
return
+ if self.format == 'rgb8' and is_entry_indigo():
+ gl.RGBmode()
+ gl.gconfig()
+ gl.RGBcolor(200, 200, 200) # XXX rather light grey
+ gl.clear()
+ gl.pixmode(GL.PM_SIZE, 8)
+ return
gl.cmode()
gl.gconfig()
self.skipchrom = 0
@@ -269,29 +341,51 @@ class Displayer(VideoParams):
if not self.quiet:
sys.stderr.write('Initializing color map...')
self._initcmap()
- self.colormapinited = 1
- self.clear()
+ gl.clear()
if not self.quiet:
sys.stderr.write(' Done.\n')
- # Clear the window
+ # Clear the window to a default color
def clear(self):
if not self.colormapinited: raise CallError
- if self.offset == 0:
- gl.color(0x800)
- gl.clear()
- else:
+ if gl.getdisplaymode() in (DMRGB, DMRGBDOUBLE):
+ gl.RGBcolor(200, 200, 200) # XXX rather light grey
gl.clear()
+ return
+ gl.writemask(0xffffffff)
+ gl.clear()
+
+ # Clear the window to a given RGB color.
+ # This may steal the first color index used; the next call to
+ # showframe() will restore the intended mapping for that index
- # Do the hard work for initializing the colormap
+ def clearto(self, r, g, b):
+ if not self.colormapinited: raise CallError
+ if gl.getdisplaymode() in (DMRGB, DMRGBDOUBLE):
+ gl.RGBcolor(r, g, b)
+ gl.clear()
+ return
+ index = self.color0[0]
+ self.fixcolor0 = 1
+ gl.mapcolor(index, r, g, b)
+ gl.writemask(0xffffffff)
+ gl.clear()
+ gl.gflush()
+
+ # Do the hard work for initializing the colormap (internal).
+ # This also sets the current color to the first color index
+ # used -- the caller should never change this since it is used
+ # by clear() and clearto()
def _initcmap(self):
convcolor = choose_conversion(self.format)
maxbits = gl.getgdesc(GL.GD_BITS_NORM_SNG_CMODE)
if maxbits > 11:
maxbits = 11
- c0bits, c1bits, c2bits = self.c0bits, self.c1bits, self.c2bits
+ c0bits = self.c0bits
+ c1bits = self.c1bits
+ c2bits = self.c2bits
if c0bits+c1bits+c2bits > maxbits:
if self.fallback and c0bits < maxbits:
# Cannot display frames in this mode, use grey
@@ -310,10 +404,8 @@ class Displayer(VideoParams):
offset = self.offset
if maxbits <> 11:
offset = offset & ((1<<maxbits)-1)
- # XXX why is this here?
- # for i in range(512, MAXMAP):
- # gl.mapcolor(i, 0, 0, 0)
- # gl.gflush()
+ self.color0 = None
+ self.fixcolor0 = 0
for c0 in range(maxc0):
c0v = c0/float(maxc0-1)
for c1 in range(maxc1):
@@ -335,6 +427,11 @@ class Displayer(VideoParams):
int(gv*255.0), \
int(bv*255.0)
gl.mapcolor(index, r, g, b)
+ if self.color0 == None:
+ self.color0 = \
+ index, r, g, b
+ # Permanently make the first color index current
+ gl.color(self.color0[0])
gl.gflush() # send the colormap changes to the X server
@@ -379,6 +476,7 @@ def readfileheader(fp, filename):
filename + ': Unrecognized file header: ' + `line`[:20]
#
# Get color encoding info
+ # (The format may change to 'rgb' later when packfactor == 0)
#
if version <= 1.0:
format = 'grey'
@@ -412,6 +510,7 @@ def readfileheader(fp, filename):
chrompack = 0
offset = 0
else:
+ # XXX ought to check that the format is valid
try:
c0bits, c1bits, c2bits, chrompack, offset = rest
except:
@@ -424,10 +523,13 @@ def readfileheader(fp, filename):
x = eval(line[:-1])
except:
raise Error, filename + ': Bad (w,h,pf) info'
+ if type(x) <> type(()):
+ raise Error, filename + ': Bad (w,h,pf) info'
if len(x) == 3:
width, height, packfactor = x
if packfactor == 0 and version < 3.0:
format = 'rgb'
+ c0bits = 0
elif len(x) == 2 and version <= 1.0:
width, height = x
packfactor = 2
@@ -548,6 +650,8 @@ class BasicVinFile(VideoParams):
filename + ': Bad version: ' + `self.version`
self.framecount = 0
self.atframeheader = 1
+ self.eofseen = 0
+ self.errorseen = 0
try:
self.startpos = self.fp.tell()
self.canseek = 1
@@ -578,9 +682,11 @@ class BasicVinFile(VideoParams):
self.fp.seek(self.startpos)
self.framecount = 0
self.atframeheader = 1
+ self.eofseen = 0
+ self.errorseen = 0
def warmcache(self):
- pass
+ print '[BasicVinFile.warmcache() not implemented]'
def printinfo(self):
print 'File: ', self.filename
@@ -598,24 +704,36 @@ class BasicVinFile(VideoParams):
return t
def getnextframeheader(self):
+ if self.eofseen: raise EOFError
+ if self.errorseen: raise CallError
if not self.atframeheader: raise CallError
self.atframeheader = 0
try:
return self._readframeheader(self.fp)
except Error, msg:
+ self.errorseen = 1
# Patch up the error message
raise Error, self.filename + ': ' + msg
+ except EOFError:
+ self.eofseen = 1
+ raise EOFError
def getnextframedata(self, ds, cs):
+ if self.eofseen: raise EOFError
+ if self.errorseen: raise CallError
if self.atframeheader: raise CallError
if ds:
data = self.fp.read(ds)
- if len(data) < ds: raise EOFError
+ if len(data) < ds:
+ self.eofseen = 1
+ raise EOFError
else:
data = ''
if cs:
cdata = self.fp.read(cs)
- if len(cdata) < cs: raise EOFerror
+ if len(cdata) < cs:
+ self.eofseen = 1
+ raise EOFError
else:
cdata = ''
self.atframeheader = 1
@@ -623,6 +741,8 @@ class BasicVinFile(VideoParams):
return (data, cdata)
def skipnextframedata(self, ds, cs):
+ if self.eofseen: raise EOFError
+ if self.errorseen: raise CallError
if self.atframeheader: raise CallError
# Note that this won't raise EOFError for a partial frame
# since there is no easy way to tell whether a seek
@@ -636,6 +756,70 @@ class BasicVinFile(VideoParams):
self.framecount = self.framecount + 1
+# Derived class implementing random access
+
+class RandomVinFile(BasicVinFile):
+
+ def initfp(self, fp, filename):
+ self = BasicVinFile.initfp(self, fp, filename)
+ self.index = []
+ return self
+
+ def warmcache(self):
+ if len(self.index) == 0:
+ self.rewind()
+ while 1:
+ try: dummy = self.skipnextframe()
+ except EOFError: break
+ else:
+ print '[RandomVinFile.warmcache(): too late]'
+ self.rewind()
+
+ def getnextframeheader(self):
+ if self.framecount < len(self.index):
+ return self._getindexframeheader(self.framecount)
+ if self.framecount > len(self.index):
+ raise AssertError, \
+ 'managed to bypass index?!?'
+ rv = BasicVinFile.getnextframeheader(self)
+ if self.canseek:
+ pos = self.fp.tell()
+ self.index.append(rv, pos)
+ return rv
+
+ def getrandomframe(self, i):
+ t, ds, cs = self.getrandomframeheader(i)
+ data, cdata = self.getnextframedata()
+ return t, ds, cs
+
+ def getrandomframeheader(self, i):
+ if i < 0: raise ValueError, 'negative frame index'
+ if not self.canseek:
+ raise Error, self.filename + ': can\'t seek'
+ if i < len(self.index):
+ return self._getindexframeheader(i)
+ if len(self.index) > 0:
+ rv = self.getrandomframeheader(len(self.index)-1)
+ else:
+ self.rewind()
+ rv = self.getnextframeheader()
+ while i > self.framecount:
+ self.skipnextframedata()
+ rv = self.getnextframeheader()
+ return rv
+
+ def _getindexframeheader(self, i):
+ (rv, pos) = self.index[i]
+ self.fp.seek(pos)
+ self.framecount = i
+ self.atframeheader = 0
+ self.eofseen = 0
+ self.errorseen = 0
+ return rv
+
+
+# Basic class for writing CMIF video files
+
class BasicVoutFile(VideoParams):
def init(self, filename):
@@ -649,7 +833,7 @@ class BasicVoutFile(VideoParams):
self = VideoParams.init(self)
self.fp = fp
self.filename = filename
- self.version = 3.0 # In case anyone inquires
+ self.version = 3.0 # In case anyone inquries
self.headerwritten = 0
return self
@@ -692,7 +876,10 @@ class BasicVoutFile(VideoParams):
def writeframeheader(self, t, ds, cs):
if not self.headerwritten: self.writeheader()
if not self.atheader: raise CallError
- self.fp.write(`(t, ds, cs)` + '\n')
+ data = `(t, ds, cs)`
+ n = len(data)
+ if n < 63: data = data + ' '*(63-n)
+ self.fp.write(data + '\n')
self.atheader = 0
def writeframedata(self, data, cdata):
@@ -705,11 +892,11 @@ class BasicVoutFile(VideoParams):
# Classes that combine files with displayers and/or grabbers:
-class VinFile(BasicVinFile, Displayer):
+class VinFile(RandomVinFile, Displayer):
def initfp(self, fp, filename):
self = Displayer.init(self)
- return BasicVinFile.initfp(self, fp, filename)
+ return RandomVinFile.initfp(self, fp, filename)
def shownextframe(self):
t, data, cdata = self.getnextframe()
@@ -739,8 +926,9 @@ def test():
vin.initcolormap()
t0 = time.millitimer()
while 1:
- try: t = vin.shownextframe()
+ try: t, data, cdata = vin.getnextframe()
except EOFError: break
dt = t0 + t - time.millitimer()
if dt > 0: time.millisleep(dt)
+ vin.showframe(data, cdata)
time.sleep(2)