summaryrefslogtreecommitdiffstats
path: root/Demo/sgi/video/VFile.py
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>1992-09-07 09:24:17 (GMT)
committerGuido van Rossum <guido@python.org>1992-09-07 09:24:17 (GMT)
commit4045c2fa5b8d4c22b51abbb28bbe15abe4cadced (patch)
tree49bb8256e95157e70b3431135980fb576fc381ce /Demo/sgi/video/VFile.py
parent32517f942713a320a6a0b1ca9aeb59b4e4ec0989 (diff)
downloadcpython-4045c2fa5b8d4c22b51abbb28bbe15abe4cadced.zip
cpython-4045c2fa5b8d4c22b51abbb28bbe15abe4cadced.tar.gz
cpython-4045c2fa5b8d4c22b51abbb28bbe15abe4cadced.tar.bz2
Almost completely rewritten for cleaner code.
Diffstat (limited to 'Demo/sgi/video/VFile.py')
-rwxr-xr-xDemo/sgi/video/VFile.py949
1 files changed, 578 insertions, 371 deletions
diff --git a/Demo/sgi/video/VFile.py b/Demo/sgi/video/VFile.py
index e43bd94..0f72306 100755
--- a/Demo/sgi/video/VFile.py
+++ b/Demo/sgi/video/VFile.py
@@ -1,91 +1,231 @@
-# VFile -- two classes for Video Files.
-# VinFile -- for video input.
-# VoutFile -- for video output.
+# Classes to read and write CMIF video files.
+# (For a description of the CMIF video format, see cmif-file.ms.)
+
+
+# Layers of functionality:
+#
+# VideoParams: maintain essential parameters of a video file
+# Displayer: display a frame in a window (with some extra parameters)
+# Grabber: grab a frame from a window
+# BasicVinFile: read a CMIF video file
+# BasicVoutFile: write a CMIF video file
+# VinFile: BasicVinFile + Displayer
+# VoutFile: BasicVoutFile + Displayer + Grabber
+
+
+# Imported modules
import sys
import gl
import GL
import colorsys
-Error = 'VFile.Error' # Exception
-# Missing from GL.py:
+# Exception raised for various occasions
+
+Error = 'VFile.Error' # file format errors
+CallError = 'VFile.CallError' # bad call
+
+
+# Constants returned by gl.getdisplaymode(), from <gl/get.h>
+
DMRGB = 0
+DMSINGLE = 1
+DMDOUBLE = 2
+DMRGBDOUBLE = 5
+
+
+# Max nr. of colormap entries to use
MAXMAP = 4096 - 256
-def conv_grey(l,x,y): return colorsys.yiq_to_rgb(l,0,0)
-def conv_yiq (y,i,q): return colorsys.yiq_to_rgb(y, (i-0.5)*1.2, q-0.5)
-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):
+
+# Parametrizations of colormap handling based on color system.
+# (These functions are used via eval with a constructed argument!)
+
+def conv_grey(l, x, y):
+ return colorsys.yiq_to_rgb(l, 0, 0)
+
+def conv_yiq(y, i, q):
+ return colorsys.yiq_to_rgb(y, (i-0.5)*1.2, q-0.5)
+
+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):
+
+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.
-#
-# It has the following methods:
-# init(filename)
-# initfp(fp, filename)
-# reopen()
-# rewind()
-# getnextframe()
-# skipnextframe()
-# (and many more)
-#
-# The following read-only data members provide public information:
-# version
-# filename
-# width, height
-# packfactor
-# c0bits, c1bits, c2bits, chrompack
-# offset
-# format
-#
-# These writable data members provide additional parametrization:
-# magnify
-# xorigin, yorigin
-# fallback
+# Choose one of the above based upon a color system name
+def choose_conversion(format):
+ try:
+ return eval('conv_' + format)
+ except:
+ raise Error, 'Unknown color system: ' + `format`
-# XXX it's a total mess now -- VFile is a new base class
-# XXX to support common functionality (e.g. showframe)
-class VFile:
+# Routines to grab data, per color system (only a few really supported).
+# (These functions are used via eval with a constructed argument!)
+
+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 rgb 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 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'
+ # 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)
+ 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'
+
+
+# Choose one of the above based upon a color system name
+
+def choose_grabber(format):
+ try:
+ return eval('grab_' + format)
+ except:
+ raise Error, 'Unknown color system: ' + `format`
+
+
+# Base class to manage video format parameters
+
+class VideoParams:
+
+ # Initialize an instance.
+ # Set all parameters to something decent
+ # (except width and height are set to zero)
+
+ def init(self):
+ # Essential parameters
+ self.format = 'grey' # color system used
+ # Choose from: 'rgb', 'rgb8', 'hsv', 'yiq', 'hls'
+ self.width = 0 # width of frame
+ self.height = 0 # height of frame
+ self.packfactor = 1 # expansion using rectzoom
+ # if packfactor == 0, data is one 32-bit word/pixel;
+ # otherwise, data is one byte/pixel
+ self.c0bits = 8 # bits in first color dimension
+ self.c1bits = 0 # bits in second color dimension
+ self.c2bits = 0 # bits in third color dimension
+ self.offset = 0 # colormap index offset (XXX ???)
+ self.chrompack = 0 # set if separate chrominance data
+ return self
+
+ # Set the frame width and height (e.g. from gl.getsize())
+
+ def setsize(self, size):
+ self.width, self.height = size
+
+ # Retrieve the frame width and height (e.g. for gl.prefsize())
+
+ def getsize(self):
+ return (self.width, self.height)
+
+ # Set all parameters.
+ # This does limited validity checking;
+ # if the check fails no parameters are changed
+
+ def setinfo(self, values):
+ (self.format, self.width, self.height, self.packfactor,\
+ self.c0bits, self.c1bits, self.c2bits, self.offset, \
+ self.chrompack) = values
+
+ # Retrieve all parameters in a format suitable for a subsequent
+ # call to setinfo()
- #
- # 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)
+ self.c0bits, self.c1bits, self.c2bits, self.offset, \
+ self.chrompack)
+
+ # Write the relevant bits to stdout
+
+ def printinfo(self):
+ print 'Format: ', self.format
+ print 'Size: ', self.width, 'x', self.height
+ print 'Pack: ', self.packfactor, '; chrom:', self.chrompack
+ print 'Bits: ', self.c0bits, self.c1bits, self.c2bits
+ print 'Offset: ', self.offset
+
+
+# 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()
+
+class Displayer(VideoParams):
+
+ # Initialize an instance.
+ # This does not need a current window
+
+ def init(self):
+ self = VideoParams.init(self)
+ # User-settable parameters
+ self.magnify = 1.0 # frame magnification factor
+ self.xorigin = 0 # x frame offset
+ self.yorigin = 0 # y frame offset (from bottom)
+ self.quiet = 0 # if set, don't print messages
+ self.fallback = 1 # allow fallback to grey
+ # Internal flags
+ self.colormapinited = 0 # must initialize window
+ self.skipchrom = 0 # don't skip chrominance data
+ return self
- # reopen() raises Error if the header is bad (which can only
- # happen if the file was written to since opened).
+ # setinfo() must reset some internal flags
- def reopen(self):
- self.fp.seek(0)
- x = self.initfp(self.fp, self.filename)
+ def setinfo(self, values):
+ VideoParams.setinfo(values)
+ self.colormapinited = 0
+ self.skipchrom = 0
- def setconvcolor(self):
- try:
- self.convcolor = eval('conv_'+self.format)
- except:
- raise Error, \
- self.filename + ': unknown colorsys ' + self.format
+ # Show one frame, initializing the window if necessary
def showframe(self, data, chromdata):
- w, h, pf = self.width, self.height, self.packfactor
if not self.colormapinited:
self.initcolormap()
+ w, h, pf = self.width, self.height, self.packfactor
factor = self.magnify
if pf: factor = factor * pf
if chromdata and not self.skipchrom:
@@ -102,50 +242,62 @@ class VFile:
if pf:
gl.writemask((1 << self.c0bits) - 1)
gl.pixmode(GL.PM_SIZE, 8)
- gl.rectzoom(factor, factor)
w = w/pf
h = h/pf
+ gl.rectzoom(factor, factor)
gl.lrectwrite(self.xorigin, self.yorigin, \
self.xorigin + w - 1, self.yorigin + h - 1, data)
+ # Initialize the window: set RGB or colormap mode as required,
+ # fill in the colormap, and clear the window
+
def initcolormap(self):
- self.colormapinited = 1
if self.format == 'rgb':
gl.RGBmode()
gl.gconfig()
- gl.RGBcolor(200, 200, 200)
+ self.colormapinited = 1
+ gl.RGBcolor(200, 200, 200) # XXX rather light grey
gl.clear()
return
gl.cmode()
gl.gconfig()
self.skipchrom = 0
+ if self.offset == 0:
+ self.mask = 0x7ff
+ else:
+ self.mask = 0xfff
if not self.quiet:
sys.stderr.write('Initializing color map...')
- self.initcmap()
+ self._initcmap()
+ self.colormapinited = 1
self.clear()
if not self.quiet:
sys.stderr.write(' Done.\n')
+ # Clear the window
+
def clear(self):
+ if not self.colormapinited: raise CallError
if self.offset == 0:
gl.color(0x800)
gl.clear()
- self.mask = 0x7ff
else:
- self.mask = 0xfff
gl.clear()
- def initcmap(self):
+ # Do the hard work for initializing the colormap
+
+ 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
if c0bits+c1bits+c2bits > maxbits:
if self.fallback and c0bits < maxbits:
- # Cannot display film in this mode, use mono
+ # Cannot display frames in this mode, use grey
self.skipchrom = 1
c1bits = c2bits = 0
- self.convcolor = conv_grey
+ convcolor = choose_conversion('grey')
else:
raise Error, 'Sorry, '+`maxbits`+ \
' bits max on this machine'
@@ -158,9 +310,10 @@ class VFile:
offset = self.offset
if maxbits <> 11:
offset = offset & ((1<<maxbits)-1)
- #for i in range(512, MAXMAP):
+ # XXX why is this here?
+ # for i in range(512, MAXMAP):
# gl.mapcolor(i, 0, 0, 0)
- #void = gl.qtest() # Should be gl.gflush()
+ # gl.gflush()
for c0 in range(maxc0):
c0v = c0/float(maxc0-1)
for c1 in range(maxc1):
@@ -174,366 +327,420 @@ class VFile:
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)
+ (c2 << (c0bits+c1bits))
if index < MAXMAP:
+ rv, gv, bv = \
+ convcolor(c0v, c1v, c2v)
+ r, g, b = int(rv*255.0), \
+ int(gv*255.0), \
+ int(bv*255.0)
gl.mapcolor(index, r, g, b)
- void = gl.gflush()
+ gl.gflush() # send the colormap changes to the X server
+
-
+# Class to grab frames from a window.
+# (This has fewer user-settable parameters than Displayer.)
+# It is the caller's responsibility to initialize the window and to
+# ensure that it is current when using grabframe()
-class VinFile(VFile):
+class Grabber(VideoParams):
- # init() and initfp() raise Error if the header is bad.
- # init() raises whatever open() raises if the file can't be opened.
+ # XXX The init() method of VideoParams is just fine, for now
+
+ # Grab a frame.
+ # Return (data, chromdata) just like getnextframe().
+
+ def grabframe(self):
+ grabber = choose_grabber(self.format)
+ return grabber(self.width, self.height, self.packfactor)
+
+
+# Read a CMIF video file header.
+# Return (version, values) where version is 0.0, 1.0, 2.0 or 3.0,
+# and values is ready for setinfo().
+# Raise Error if there is an error in the info
+
+def readfileheader(fp, filename):
+ #
+ # Get identifying header
+ #
+ line = fp.readline(20)
+ if line == 'CMIF video 0.0\n':
+ version = 0.0
+ elif line == 'CMIF video 1.0\n':
+ version = 1.0
+ elif line == 'CMIF video 2.0\n':
+ version = 2.0
+ elif line == 'CMIF video 3.0\n':
+ version = 3.0
+ else:
+ # XXX Could be version 0.0 without identifying header
+ raise Error, \
+ filename + ': Unrecognized file header: ' + `line`[:20]
+ #
+ # Get color encoding info
+ #
+ if version <= 1.0:
+ format = 'grey'
+ c0bits, c1bits, c2bits = 8, 0, 0
+ chrompack = 0
+ offset = 0
+ elif version == 2.0:
+ line = fp.readline()
+ try:
+ c0bits, c1bits, c2bits, chrompack = eval(line[:-1])
+ except:
+ raise Error, filename + ': Bad 2.0 color info'
+ if c1bits or c2bits:
+ format = 'yiq'
+ else:
+ format = 'grey'
+ offset = 0
+ elif version == 3.0:
+ line = fp.readline()
+ try:
+ format, rest = eval(line[:-1])
+ except:
+ raise Error, filename + ': Bad 3.0 color info'
+ if format == 'rgb':
+ c0bits = c1bits = c2bits = 0
+ chrompack = 0
+ offset = 0
+ elif format == 'grey':
+ c0bits = rest
+ c1bits = c2bits = 0
+ chrompack = 0
+ offset = 0
+ else:
+ try:
+ c0bits, c1bits, c2bits, chrompack, offset = rest
+ except:
+ raise Error, filename + ': Bad 3.0 color info'
+ #
+ # Get frame geometry info
+ #
+ line = fp.readline()
+ try:
+ x = eval(line[:-1])
+ except:
+ 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'
+ elif len(x) == 2 and version <= 1.0:
+ width, height = x
+ packfactor = 2
+ else:
+ raise Error, filename + ': Bad (w,h,pf) info'
+ #
+ # Return (version, values)
+ #
+ values = (format, width, height, packfactor, \
+ c0bits, c1bits, c2bits, offset, chrompack)
+ return (version, values)
+
+
+# Read a *frame* header -- separate functions per version.
+# Return (timecode, datasize, chromdatasize).
+# Raise EOFError if end of data is reached.
+# Raise Error if data is bad.
+
+def readv0frameheader(fp):
+ line = fp.readline()
+ if not line or line == '\n': raise EOFError
+ try:
+ t = eval(line[:-1])
+ except:
+ raise Error, 'Bad 0.0 frame header'
+ return (t, 0, 0)
+
+def readv1frameheader(fp):
+ line = fp.readline()
+ if not line or line == '\n': raise EOFError
+ try:
+ t, datasize = eval(line[:-1])
+ except:
+ raise Error, 'Bad 1.0 frame header'
+ return (t, datasize, 0)
+
+def readv2frameheader(fp):
+ line = fp.readline()
+ if not line or line == '\n': raise EOFError
+ try:
+ t, datasize = eval(line[:-1])
+ except:
+ raise Error, 'Bad 2.0 frame header'
+ return (t, datasize, 0)
+
+def readv3frameheader(fp):
+ line = fp.readline()
+ if not line or line == '\n': raise EOFError
+ try:
+ t, datasize, chromdatasize = x = eval(line[:-1])
+ except:
+ raise Error, 'Bad 3.0 frame header'
+ return x
+
+
+# Write a CMIF video file header (always version 3.0)
+
+def writefileheader(fp, values):
+ (format, width, height, packfactor, \
+ c0bits, c1bits, c2bits, offset, chrompack) = values
+ #
+ # Write identifying header
+ #
+ fp.write('CMIF video 3.0\n')
+ #
+ # Write color encoding info
+ #
+ if format == 'rgb':
+ data = ('rgb', 0)
+ elif format == 'grey':
+ data = ('grey', c0bits)
+ else:
+ data = (format, (c0bits, c1bits, c2bits, chrompack, offset))
+ fp.write(`data`+'\n')
+ #
+ # Write frame geometry info
+ #
+ if format == 'rgb':
+ packfactor = 0
+ elif packfactor == 0:
+ packfactor = 1
+ data = (width, height, packfactor)
+ fp.write(`data`+'\n')
+
+
+# Basic class for reading CMIF video files
+
+class BasicVinFile(VideoParams):
def init(self, filename):
if filename == '-':
- return self.initfp(sys.stdin, filename)
- return self.initfp(open(filename, 'r'), filename)
+ fp = sys.stdin
+ else:
+ fp = open(filename, 'r')
+ return self.initfp(fp, filename)
def initfp(self, fp, filename):
- self.colormapinited = 0
- self.magnify = 1.0
- self.xorigin = self.yorigin = 0
- self.fallback = 1
- self.skipchrom = 0
+ self = VideoParams.init(self)
self.fp = fp
self.filename = filename
- self.quiet = 0
- #
- line = self.fp.readline()
- if line == 'CMIF video 1.0\n':
- self.version = 1.0
- elif line == 'CMIF video 2.0\n':
- self.version = 2.0
- elif line == 'CMIF video 3.0\n':
- self.version = 3.0
- else:
- raise Error, self.filename + ': bad video format'
- #
- if self.version < 2.0:
- self.c0bits, self.c1bits, self.c2bits = 8, 0, 0
- self.chrompack = 0
- self.offset = 0
- self.format = 'grey'
+ self.version, values = readfileheader(fp, filename)
+ VideoParams.setinfo(self, values)
+ if self.version == 0.0:
+ w, h, pf = self.width, self.height, self.packfactor
+ if pf == 0:
+ self._datasize = w*h*4
+ else:
+ self._datasize = (w/pf) * (h/pf)
+ self._readframeheader = self._readv0frameheader
+ elif self.version == 1.0:
+ self._readframeheader = readv1frameheader
elif self.version == 2.0:
- line = self.fp.readline()
- try:
- self.c0bits, self.c1bits, self.c2bits, \
- self.chrompack = eval(line[:-1])
- if self.c1bits or self.c2bits:
- self.format = 'yiq'
- else:
- self.format = 'grey'
- self.offset = 0
- except:
- raise Error, \
- self.filename + ': bad 2.0 color info'
+ self._readframeheader = readv2frameheader
elif self.version == 3.0:
- line = self.fp.readline()
- try:
- self.format, rest = eval(line[:-1])
- if self.format == 'rgb':
- 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
- self.c1bits = self.c2bits = \
- self.chrompack = 0
- else:
- self.c0bits,self.c1bits,self.c2bits,\
- self.chrompack,self.offset = rest
- except:
- raise Error, \
- self.filename + ': bad 3.0 color info'
-
- self.setconvcolor()
- #
- line = self.fp.readline()
+ self._readframeheader = readv3frameheader
+ else:
+ raise Error, \
+ filename + ': Bad version: ' + `self.version`
+ self.framecount = 0
+ self.atframeheader = 1
try:
- x = eval(line[:-1])
- if self.version > 1.0 or len(x) == 3:
- self.width, self.height, self.packfactor = x
- if self.packfactor == 0:
- self.format = 'rgb'
- else:
- sef.width, self.height = x
- self.packfactor = 2
- except:
- raise Error, self.filename + ': bad (w,h,pf) info'
- self.frameno = 0
- self.framecache = []
- self.hascache = 0
- #
+ self.startpos = self.fp.tell()
+ self.canseek = 1
+ except IOError:
+ self.startpos = -1
+ self.canseek = 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'
+ def _readv0frameheader(self, fp):
+ t, ds, cs = readv0frameheader(fp)
+ ds = self._datasize
+ return (t, ds, cs)
def close(self):
self.fp.close()
- self.fp = None
+ del self.fp
+ del self._readframeheader
+
+ def setinfo(self, values):
+ raise CallError # Can't change info of input file!
+
+ def setsize(self, size):
+ raise CallError # Can't change info of input file!
def rewind(self):
- if self.hascache:
- self.frameno = 0
- else:
- self.reopen()
+ if not self.canseek:
+ raise Error, self.filename + ': can\'t seek'
+ self.fp.seek(self.startpos)
+ self.framecount = 0
+ self.atframeheader = 1
- def position(self):
- if self.frameno >= len(self.framecache):
- raise EOFError
- self.fp.seek(self.framecache[self.frameno][0])
+ def warmcache(self):
+ pass
- # getnextframe() raises EOFError (built-in) if there is no next frame,
- # or if the next frame is broken.
- # So to getnextframeheader(), getnextframedata() and skipnextframe().
+ def printinfo(self):
+ print 'File: ', self.filename
+ print 'Version: ', self.version
+ VideoParams.printinfo(self)
def getnextframe(self):
- time, size, chromsize = self.getnextframeheader()
- data, chromdata = self.getnextframedata(size, chromsize)
- 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:
- chromdata = self.fp.read(chromsize)
- if len(chromdata) <> chromsize: raise EOFError
- else:
- chromdata = None
- #
- return data, chromdata
+ t, ds, cs = self.getnextframeheader()
+ data, cdata = self.getnextframedata(ds, cs)
+ return (t, data, cdata)
def skipnextframe(self):
- time, size, chromsize = self.getnextframeheader()
- self.skipnextframedata(size, chromsize)
- 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
- except:
- # Assume it's a pipe -- read the data to discard it
- dummy = self.fp.read(size + chromsize)
+ t, ds, cs = self.getnextframeheader()
+ self.skipnextframedata(ds, cs)
+ return t
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
+ if not self.atframeheader: raise CallError
+ self.atframeheader = 0
try:
- x = eval(line[:-1])
- if type(x) in (type(0), type(0.0)):
- time = x
- if pf == 0:
- size = w * h * 4
- else:
- size = (w/pf) * (h/pf)
- elif len(x) == 2:
- time, size = x
- cp = self.chrompack
- if cp:
- cw = (w + cp - 1) / cp
- ch = (h + cp - 1) / cp
- chromsize = 2 * cw * ch
- else:
- chromsize = 0
- else:
- 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):
- time, data, chromdata = self.getnextframe()
- self.showframe(data, chromdata)
- return time
-
-#
-# 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'
+ return self._readframeheader(self.fp)
+ except Error, msg:
+ # Patch up the error message
+ raise Error, self.filename + ': ' + msg
+
+ def getnextframedata(self, ds, cs):
+ if self.atframeheader: raise CallError
+ if ds:
+ data = self.fp.read(ds)
+ if len(data) < ds: raise EOFError
+ else:
+ data = ''
+ if cs:
+ cdata = self.fp.read(cs)
+ if len(cdata) < cs: raise EOFerror
+ else:
+ cdata = ''
+ self.atframeheader = 1
+ self.framecount = self.framecount + 1
+ return (data, cdata)
+
+ def skipnextframedata(self, ds, cs):
+ 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
+ # ended up beyond the end of the file
+ if self.canseek:
+ self.fp.seek(ds + cs, 1) # Relative seek
+ else:
+ dummy = self.fp.read(ds + cs)
+ del dummy
+ self.atframeheader = 1
+ self.framecount = self.framecount + 1
-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'
+class BasicVoutFile(VideoParams):
-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(VFile):
def init(self, filename):
if filename == '-':
- return self.initfp(sys.stdout, filename)
+ fp = sys.stdout
else:
- return self.initfp(open(filename,'w'), filename)
-
+ fp = open(filename, 'w')
+ return self.initfp(fp, filename)
+
def initfp(self, fp, filename):
+ self = VideoParams.init(self)
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.filename = filename
+ self.version = 3.0 # In case anyone inquires
self.headerwritten = 0
- self.quiet = 0
- self.magnify = 1
- self.setconvcolor()
- self.xorigin = self.yorigin = 0
return self
+ def flush(self):
+ self.fp.flush()
+
def close(self):
self.fp.close()
- x = self.initfp(None, None)
+ del self.fp
def setinfo(self, values):
- self.format, self.width, self.height, self.packfactor,\
- self.c0bits, self.c1bits, self.c2bits, self.offset, \
- self.chrompack = values
- self.setconvcolor()
+ if self.headerwritten: raise CallError
+ VideoParams.setinfo(self, values)
def writeheader(self):
+ if self.headerwritten: raise CallError
+ writefileheader(self.fp, self.getinfo())
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', self.c0bits)
- 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)
+ self.atheader = 1
+ self.framecount = 0
+
+ def rewind(self):
+ self.fp.seek(0)
+ self.headerwritten = 0
+ self.atheader = 1
+ self.framecount = 0
+
+ def printinfo(self):
+ print 'File: ', self.filename
+ VideoParams.printinfo(self)
+
+ def writeframe(self, t, data, cdata):
+ if data: ds = len(data)
+ else: ds = 0
+ if cdata: cs = len(cdata)
+ else: cs = 0
+ self.writeframeheader(t, ds, cs)
+ self.writeframedata(data, cdata)
+
+ 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')
+ self.atheader = 0
+
+ def writeframedata(self, data, cdata):
+ if not self.headerwritten or self.atheader: raise CallError
+ if data: self.fp.write(data)
+ if cdata: self.fp.write(cdata)
+ self.atheader = 1
+ self.framecount = self.framecount + 1
+
+
+# Classes that combine files with displayers and/or grabbers:
+
+class VinFile(BasicVinFile, Displayer):
+
+ def initfp(self, fp, filename):
+ self = Displayer.init(self)
+ return BasicVinFile.initfp(self, fp, filename)
+
+ def shownextframe(self):
+ t, data, cdata = self.getnextframe()
+ self.showframe(data, cdata)
+ return t
+
+
+class VoutFile(BasicVoutFile, Displayer, Grabber):
+
+ def initfp(self, fp, filename):
+ self = Displayer.init(self)
+## self = Grabber.init(self) # XXX not needed
+ return BasicVoutFile.initfp(self, fp, filename)
+
+
+# Simple test program (VinFile only)
- def grabframe(self):
- return self._grabber(self.width, self.height, self.packfactor)
-
def test():
- import sys, time
- filename = 'film.video'
+ import time
if sys.argv[1:]: filename = sys.argv[1]
+ else: filename = 'film.video'
vin = VinFile().init(filename)
- print 'File: ', filename
- print 'Version: ', vin.version
- print 'Size: ', vin.width, 'x', vin.height
- print 'Pack: ', vin.packfactor, '; chrom:', vin.chrompack
- print 'Bits: ', vin.c0bits, vin.c1bits, vin.c2bits
- print 'Format: ', vin.format
- print 'Offset: ', vin.offset
+ vin.printinfo()
gl.foreground()
- gl.prefsize(vin.width, vin.height)
+ gl.prefsize(vin.getsize())
wid = gl.winopen(filename)
vin.initcolormap()
t0 = time.millitimer()
while 1:
- try:
- t, data, chromdata = vin.getnextframe()
- except EOFError:
- break
- dt = t + t0 - time.millitimer()
- if dt > 0:
- time.millisleep(dt)
- vin.showframe(data, chromdata)
- print 'Done.'
+ try: t = vin.shownextframe()
+ except EOFError: break
+ dt = t0 + t - time.millitimer()
+ if dt > 0: time.millisleep(dt)
time.sleep(2)
-