- Separated grabbing (which isn't used much!) from VFile.

- Renamed old Vcopy.py to OldVcopy.py, some cosmetic changes to it (is
  it still needed?)
- Added new Vcopy.py which does everything that Vtime.py does but also
  format conversions, image scaling, and packfactors.
- VFile: make packfactor always a tuple; introduce set and get methods
  for pf, format, and calculate some derived values.
- Added new module GET.py to std library, use it instead of defining
  DM* in VFile.
- Get rid of C programs (new Python programs can do all that they do
  and they probably don't understand the current file format anyway).
This commit is contained in:
Guido van Rossum 1993-02-25 14:20:13 +00:00
parent b616ebe4e4
commit 5e044b7009
5 changed files with 479 additions and 307 deletions

View File

@ -59,9 +59,9 @@ Vtime.py Copy a video file, manipulating the time codes (e.g.
faster/slower, or regenerate time codes, or drop faster/slower, or regenerate time codes, or drop
frames too close apart) frames too close apart)
Vcopy.py selectively write frames from one movie file to another Vcopy.py Universal video file copying tool. Can manipulate the
usage: Vcopy [-t type] [-m treshold] [-a] infile outfile time codes, change the type, size, and packfactor.
commands: 'n' gets next frame; 'w' writes current frame Subsumes Vtime.py.
Vmkjpeg.py compress an rgb or grey video file to jpeg[grey] format Vmkjpeg.py compress an rgb or grey video file to jpeg[grey] format

View File

@ -6,11 +6,10 @@
# #
# VideoParams: maintain essential parameters of a video file # VideoParams: maintain essential parameters of a video file
# Displayer: display a frame in a window (with some extra parameters) # Displayer: display a frame in a window (with some extra parameters)
# Grabber: grab a frame from a window
# BasicVinFile: read a CMIF video file # BasicVinFile: read a CMIF video file
# BasicVoutFile: write a CMIF video file # BasicVoutFile: write a CMIF video file
# VinFile: BasicVinFile + Displayer # VinFile: BasicVinFile + Displayer
# VoutFile: BasicVoutFile + Displayer + Grabber # VoutFile: BasicVoutFile + Displayer
# #
# XXX Future extension: # XXX Future extension:
# BasicVinoutFile: supports overwriting of individual frames # BasicVinoutFile: supports overwriting of individual frames
@ -21,6 +20,7 @@
import sys import sys
import gl import gl
import GL import GL
import GET
import colorsys import colorsys
import imageop import imageop
@ -32,14 +32,6 @@ CallError = 'VFile.CallError' # bad call
AssertError = 'VFile.AssertError' # internal malfunction AssertError = 'VFile.AssertError' # internal malfunction
# Constants returned by gl.getdisplaymode(), from <gl/get.h>
DMRGB = 0
DMSINGLE = 1
DMDOUBLE = 2
DMRGBDOUBLE = 5
# Max nr. of colormap entries to use # Max nr. of colormap entries to use
MAXMAP = 4096 - 256 MAXMAP = 4096 - 256
@ -151,9 +143,9 @@ def is_entry_indigo():
b = gl.getgdesc(GL.GD_BITS_NORM_SNG_BLUE) b = gl.getgdesc(GL.GD_BITS_NORM_SNG_BLUE)
return (r, g, b) == (3, 3, 2) return (r, g, b) == (3, 3, 2)
#
# Predicate function to see whether this machine supports pixmode(PM_SIZE) # Predicate to see whether this machine supports pixmode(PM_SIZE) with
# with values 1 or 4. # values 1 or 4.
# #
# XXX Temporarily disabled, since it is unclear which machines support # XXX Temporarily disabled, since it is unclear which machines support
# XXX which pixelsizes. # XXX which pixelsizes.
@ -161,66 +153,24 @@ def is_entry_indigo():
# XXX The XS appears to support 4 bit pixels, but (looking at osview) it # XXX The XS appears to support 4 bit pixels, but (looking at osview) it
# XXX seems as if the conversion is done by the kernel (unpacking ourselves # XXX seems as if the conversion is done by the kernel (unpacking ourselves
# XXX is faster than using PM_SIZE=4) # XXX is faster than using PM_SIZE=4)
#
def support_packed_pixels(): def support_packed_pixels():
return 0 # To be architecture-dependent return 0 # To be architecture-dependent
# 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'
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.
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'
def grab_jpeg(w, h, pf):
# XXX Ought to grab rgb and compress it
raise Error, 'sorry, grabbing jpeg not implemented'
def grab_jpeggrey(w, h, pf):
raise Error, 'sorry, grabbing jpeggrey not implemented'
# Choose one of the above based upon a color system name # Tables listing bits per pixel for some formats
def choose_grabber(format): bitsperpixel = { \
try: 'rgb': 32, \
return eval('grab_' + format) 'rgb8': 8, \
except: 'grey': 8, \
raise Error, 'Unknown color system: ' + `format` 'grey4': 4, \
'grey2': 2, \
'mono': 1, \
}
bppafterdecomp = {'jpeg': 32, 'jpeggrey': 8}
# Base class to manage video format parameters # Base class to manage video format parameters
@ -233,39 +183,102 @@ class VideoParams:
def init(self): def init(self):
# Essential parameters # Essential parameters
self.frozen = 0 # if set, can't change parameters
self.format = 'grey' # color system used self.format = 'grey' # color system used
# Choose from: grey, rgb, rgb8, hsv, yiq, hls, jpeg, jpeggrey, # Choose from: grey, rgb, rgb8, hsv, yiq, hls, jpeg, jpeggrey,
# mono, grey2, grey4 # mono, grey2, grey4
self.width = 0 # width of frame self.width = 0 # width of frame
self.height = 0 # height of frame self.height = 0 # height of frame
self.packfactor = 1 # expansion using rectzoom self.packfactor = 1, 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.c0bits = 8 # bits in first color dimension
self.c1bits = 0 # bits in second color dimension self.c1bits = 0 # bits in second color dimension
self.c2bits = 0 # bits in third color dimension self.c2bits = 0 # bits in third color dimension
self.offset = 0 # colormap index offset (XXX ???) self.offset = 0 # colormap index offset (XXX ???)
self.chrompack = 0 # set if separate chrominance data self.chrompack = 0 # set if separate chrominance data
self.setderived()
return self return self
# Freeze the parameters (disallow changes)
def freeze(self):
self.frozen = 1
# Unfreeze the parameters (allow changes)
def unfreeze(self):
self.frozen = 0
# Set some values derived from the standard info values
def setderived(self):
if self.frozen: raise AssertError
if bitsperpixel.has_key(self.format):
self.bpp = bitsperpixel[self.format]
else:
self.bpp = 0
xpf, ypf = self.packfactor
self.xpf = abs(xpf)
self.ypf = abs(ypf)
self.mirror_image = (xpf < 0)
self.upside_down = (ypf < 0)
self.realwidth = self.width / self.xpf
self.realheight = self.height / self.ypf
# Set the frame width and height (e.g. from gl.getsize()) # Set the frame width and height (e.g. from gl.getsize())
def setsize(self, width, height): def setsize(self, width, height):
if self.frozen: raise CallError
width = (width/self.xpf)*self.xpf
height = (height/self.ypf)*self.ypf
self.width, self.height = width, height self.width, self.height = width, height
self.setderived()
# Retrieve the frame width and height (e.g. for gl.prefsize()) # Retrieve the frame width and height (e.g. for gl.prefsize())
def getsize(self): def getsize(self):
return (self.width, self.height) return (self.width, self.height)
# Set all parameters. # Set the format
# This does limited validity checking;
# if the check fails no parameters are changed def setformat(self, format):
if self.frozen: raise CallError
if format <> self.format:
self.format = format
self.setderived()
# Get the format
def getformat(self):
return self.format
# Set the packfactor
def setpf(self, pf):
if self.frozen: raise CallError
## if type(pf) is type(0):
## if pf == 0:
## pf = (1, 1)
## else:
## pf = (pf, pf)
if type(pf) is not type(()) or len(pf) <> 2: raise CallError
self.packfactor = pf
self.setderived()
# Get the packfactor
def getpf(self):
return self.packfactor
# Set all parameters
def setinfo(self, values): def setinfo(self, values):
(self.format, self.width, self.height, self.packfactor,\ if self.frozen: raise CallError
self.c0bits, self.c1bits, self.c2bits, self.offset, \ self.setformat(values[0])
self.chrompack) = values self.setpf(values[3])
self.setsize(values[1], values[2])
(self.c0bits, self.c1bits, self.c2bits, \
self.offset, self.chrompack) = values[4:]
self.setderived()
# Retrieve all parameters in a format suitable for a subsequent # Retrieve all parameters in a format suitable for a subsequent
# call to setinfo() # call to setinfo()
@ -281,27 +294,17 @@ class VideoParams:
print 'Format: ', self.format print 'Format: ', self.format
print 'Size: ', self.width, 'x', self.height print 'Size: ', self.width, 'x', self.height
print 'Pack: ', self.packfactor, '; chrom:', self.chrompack print 'Pack: ', self.packfactor, '; chrom:', self.chrompack
print 'Bpp: ', self.bpp
print 'Bits: ', self.c0bits, self.c1bits, self.c2bits print 'Bits: ', self.c0bits, self.c1bits, self.c2bits
print 'Offset: ', self.offset print 'Offset: ', self.offset
# Calculate data size, if possible # Calculate data size, if possible
# (Not counting frame header or cdata size)
def calcframesize(self): def calcframesize(self):
if self.format == 'rgb': if not self.bpp: raise CallError
return self.width*self.height*4 size = self.width/self.xpf * self.height/self.ypf
if self.format in ('jpeg', 'jpeggrey'): size = (size * self.bpp + 7) / 8
raise CallError
if type(self.packfactor) == type(()):
xpf, ypf = self.packfactor
else:
xpf = ypf = self.packfactor
if ypf < 0: ypf = -ypf
size = (self.width/xpf)*(self.height/ypf)
if self.format == 'grey4':
size = (size+1)/2
elif self.format == 'grey2':
size = (size+3)/4
elif self.format == 'mono':
size = (size+7)/8
return size return size
@ -346,33 +349,16 @@ class Displayer(VideoParams):
(0,0,self.width,self.height)) (0,0,self.width,self.height))
def showpartframe(self, data, chromdata, (x,y,w,h)): def showpartframe(self, data, chromdata, (x,y,w,h)):
pf = self.packfactor pmsize = self.bpp
pmsize = 8 xpf, ypf = self.xpf, self.ypf
if pf: if self.upside_down:
if type(pf) == type(()): gl.pixmode(GL.PM_TTOB, 1)
xpf, ypf = pf if self.mirror_image:
else: gp.pixmode(GL.PM_RTOL, 1)
xpf = ypf = pf
if ypf < 0:
gl.pixmode(GL.PM_TTOB, 1)
ypf = -ypf
if xpf < 0:
gl.pixmode(GL.PM_RTOL, 1)
xpf = -xpf
else:
xpf = ypf = 1
if self.format in ('jpeg', 'jpeggrey'): if self.format in ('jpeg', 'jpeggrey'):
import jpeg import jpeg
data, width, height, bytes = jpeg.decompress(data) data, width, height, bytes = jpeg.decompress(data)
if self.format == 'jpeg': pmsize = bytes*8
b = 4
xp = yp = 1
else:
b = 1
xp = xpf
yp = ypf
if (width, height, bytes) <> (w/xp, h/yp, b):
raise Error, 'jpeg data has wrong size'
elif self.format in ('mono', 'grey4'): elif self.format in ('mono', 'grey4'):
if self.mustunpack: if self.mustunpack:
if self.format == 'mono': if self.format == 'mono':
@ -381,24 +367,18 @@ class Displayer(VideoParams):
elif self.format == 'grey4': elif self.format == 'grey4':
data = imageop.grey42grey(data, \ data = imageop.grey42grey(data, \
w/xpf, h/ypf) w/xpf, h/ypf)
else: pmsize = 8
# We don't need to unpack, the hardware
# can do it.
if self.format == 'mono':
pmsize = 1
else:
pmsize = 4
elif self.format == 'grey2': elif self.format == 'grey2':
data = imageop.grey22grey(data, w/xpf, h/ypf) data = imageop.grey22grey(data, w/xpf, h/ypf)
pmsize = 8
if not self.colormapinited: if not self.colormapinited:
self.initcolormap() self.initcolormap()
if self.fixcolor0: if self.fixcolor0:
gl.mapcolor(self.color0) gl.mapcolor(self.color0)
self.fixcolor0 = 0 self.fixcolor0 = 0
xfactor = yfactor = self.magnify xfactor = yfactor = self.magnify
if pf: xfactor = xfactor * xpf
xfactor = xfactor * xpf yfactor = yfactor * ypf
yfactor = yfactor * ypf
if chromdata and not self.skipchrom: if chromdata and not self.skipchrom:
cp = self.chrompack cp = self.chrompack
cx = int(x*xfactor*cp) + self.xorigin cx = int(x*xfactor*cp) + self.xorigin
@ -411,13 +391,13 @@ class Displayer(VideoParams):
gl.lrectwrite(cx, cy, cx + cw - 1, cy + ch - 1, \ gl.lrectwrite(cx, cy, cx + cw - 1, cy + ch - 1, \
chromdata) chromdata)
# #
if pf: if pmsize < 32:
gl.writemask((1 << self.c0bits) - 1) gl.writemask((1 << self.c0bits) - 1)
gl.pixmode(GL.PM_SIZE, pmsize) gl.pixmode(GL.PM_SIZE, pmsize)
w = w/xpf w = w/xpf
h = h/ypf h = h/ypf
x = x/xpf x = x/xpf
y = y/ypf y = y/ypf
gl.rectzoom(xfactor, yfactor) gl.rectzoom(xfactor, yfactor)
x = int(x*xfactor)+self.xorigin x = int(x*xfactor)+self.xorigin
y = int(y*yfactor)+self.yorigin y = int(y*yfactor)+self.yorigin
@ -464,7 +444,7 @@ class Displayer(VideoParams):
def clear(self): def clear(self):
if not self.colormapinited: raise CallError if not self.colormapinited: raise CallError
if gl.getdisplaymode() in (DMRGB, DMRGBDOUBLE): if gl.getdisplaymode() in (GET.DMRGB, GET.DMRGBDOUBLE):
gl.RGBcolor(200, 200, 200) # XXX rather light grey gl.RGBcolor(200, 200, 200) # XXX rather light grey
gl.clear() gl.clear()
return return
@ -477,7 +457,7 @@ class Displayer(VideoParams):
def clearto(self, r, g, b): def clearto(self, r, g, b):
if not self.colormapinited: raise CallError if not self.colormapinited: raise CallError
if gl.getdisplaymode() in (DMRGB, DMRGBDOUBLE): if gl.getdisplaymode() in (GET.DMRGB, GET.DMRGBDOUBLE):
gl.RGBcolor(r, g, b) gl.RGBcolor(r, g, b)
gl.clear() gl.clear()
return return
@ -553,23 +533,6 @@ class Displayer(VideoParams):
gl.gflush() # send the colormap changes to the X server 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 Grabber(VideoParams):
# 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. # Read a CMIF video file header.
# Return (version, values) where version is 0.0, 1.0, 2.0 or 3.[01], # Return (version, values) where version is 0.0, 1.0, 2.0 or 3.[01],
# and values is ready for setinfo(). # and values is ready for setinfo().
@ -620,8 +583,6 @@ def readfileheader(fp, filename):
format, rest = eval(line[:-1]) format, rest = eval(line[:-1])
except: except:
raise Error, filename + ': Bad 3.[01] color info' raise Error, filename + ': Bad 3.[01] color info'
if format == 'xrgb8':
format = 'rgb8' # rgb8 upside-down, for X
if format in ('rgb', 'jpeg'): if format in ('rgb', 'jpeg'):
c0bits = c1bits = c2bits = 0 c0bits = c1bits = c2bits = 0
chrompack = 0 chrompack = 0
@ -637,6 +598,11 @@ def readfileheader(fp, filename):
c0bits, c1bits, c2bits, chrompack, offset = rest c0bits, c1bits, c2bits, chrompack, offset = rest
except: except:
raise Error, filename + ': Bad 3.[01] color info' raise Error, filename + ': Bad 3.[01] color info'
if format == 'xrgb8':
format = 'rgb8' # rgb8 upside-down, for X
upside_down = 1
else:
upside_down = 0
# #
# Get frame geometry info # Get frame geometry info
# #
@ -657,15 +623,18 @@ def readfileheader(fp, filename):
packfactor = 2 packfactor = 2
else: else:
raise Error, filename + ': Bad (w,h,pf) info' raise Error, filename + ': Bad (w,h,pf) info'
if type(packfactor) == type(()): if type(packfactor) is type(0):
if packfactor == 0: packfactor = 1
xpf = ypf = packfactor
else:
xpf, ypf = packfactor xpf, ypf = packfactor
xpf = abs(xpf) if upside_down:
ypf = abs(ypf) ypf = -ypf
width = (width/xpf) * xpf packfactor = (xpf, ypf)
height = (height/ypf) * ypf xpf = abs(xpf)
elif packfactor > 1: ypf = abs(ypf)
width = (width / packfactor) * packfactor width = (width/xpf) * xpf
height = (height / packfactor) * packfactor height = (height/ypf) * ypf
# #
# Return (version, values) # Return (version, values)
# #
@ -762,7 +731,8 @@ class BasicVinFile(VideoParams):
self.fp = fp self.fp = fp
self.filename = filename self.filename = filename
self.version, values = readfileheader(fp, filename) self.version, values = readfileheader(fp, filename)
VideoParams.setinfo(self, values) self.setinfo(values)
self.freeze()
if self.version == 0.0: if self.version == 0.0:
w, h, pf = self.width, self.height, self.packfactor w, h, pf = self.width, self.height, self.packfactor
if pf == 0: if pf == 0:
@ -801,12 +771,6 @@ class BasicVinFile(VideoParams):
del self.fp del self.fp
del self._readframeheader del self._readframeheader
def setinfo(self, values):
raise CallError # Can't change info of input file!
def setsize(self, width, height):
raise CallError # Can't change info of input file!
def rewind(self): def rewind(self):
if not self.canseek: if not self.canseek:
raise Error, self.filename + ': can\'t seek' raise Error, self.filename + ': can\'t seek'
@ -1022,8 +986,7 @@ class BasicVoutFile(VideoParams):
self = VideoParams.init(self) self = VideoParams.init(self)
self.fp = fp self.fp = fp
self.filename = filename self.filename = filename
self.version = 3.0 # In case anyone inquries self.version = 3.1 # In case anyone inquries
self.headerwritten = 0
return self return self
def flush(self): def flush(self):
@ -1034,27 +997,23 @@ class BasicVoutFile(VideoParams):
del self.fp del self.fp
def prealloc(self, nframes): def prealloc(self, nframes):
if not self.headerwritten: raise CallError if not self.frozen: raise CallError
data = '\xff' * self.calcframesize() data = '\xff' * (self.calcframesize() + 64)
pos = self.fp.tell() pos = self.fp.tell()
for i in range(nframes): for i in range(nframes):
self.fp.write(data) self.fp.write(data)
self.fp.seek(pos) self.fp.seek(pos)
def setinfo(self, values):
if self.headerwritten: raise CallError
VideoParams.setinfo(self, values)
def writeheader(self): def writeheader(self):
if self.headerwritten: raise CallError if self.frozen: raise CallError
writefileheader(self.fp, self.getinfo()) writefileheader(self.fp, self.getinfo())
self.headerwritten = 1 self.freeze()
self.atheader = 1 self.atheader = 1
self.framecount = 0 self.framecount = 0
def rewind(self): def rewind(self):
self.fp.seek(0) self.fp.seek(0)
self.headerwritten = 0 self.unfreeze()
self.atheader = 1 self.atheader = 1
self.framecount = 0 self.framecount = 0
@ -1071,7 +1030,7 @@ class BasicVoutFile(VideoParams):
self.writeframedata(data, cdata) self.writeframedata(data, cdata)
def writeframeheader(self, t, ds, cs): def writeframeheader(self, t, ds, cs):
if not self.headerwritten: self.writeheader() if not self.frozen: self.writeheader()
if not self.atheader: raise CallError if not self.atheader: raise CallError
data = `(t, ds, cs)` data = `(t, ds, cs)`
n = len(data) n = len(data)
@ -1080,14 +1039,14 @@ class BasicVoutFile(VideoParams):
self.atheader = 0 self.atheader = 0
def writeframedata(self, data, cdata): def writeframedata(self, data, cdata):
if not self.headerwritten or self.atheader: raise CallError if not self.frozen or self.atheader: raise CallError
if data: self.fp.write(data) if data: self.fp.write(data)
if cdata: self.fp.write(cdata) if cdata: self.fp.write(cdata)
self.atheader = 1 self.atheader = 1
self.framecount = self.framecount + 1 self.framecount = self.framecount + 1
# Classes that combine files with displayers and/or grabbers: # Classes that combine files with displayers:
class VinFile(RandomVinFile, Displayer): class VinFile(RandomVinFile, Displayer):
@ -1101,7 +1060,7 @@ class VinFile(RandomVinFile, Displayer):
return t return t
class VoutFile(BasicVoutFile, Displayer, Grabber): class VoutFile(BasicVoutFile, Displayer):
def initfp(self, fp, filename): def initfp(self, fp, filename):
self = Displayer.init(self) self = Displayer.init(self)

78
Demo/sgi/video/VGrabber.py Executable file
View File

@ -0,0 +1,78 @@
# 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()
import gl, GL
import VFile
import GET
from VFile import Error
class VGrabber(VFile.VideoParams):
# 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)
# Choose one of the grabber functions below based upon a color system name
def choose_grabber(format):
try:
return eval('grab_' + format)
except:
raise Error, 'Unknown color system: ' + `format`
# 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() <> GET.DMRGB:
raise Error, 'Sorry, can only grab rgb in single-buf rgbmode'
if pf <> (1, 1):
raise Error, 'Sorry, only grab rgb with packfactor (1,1)'
return gl.lrectread(0, 0, w-1, h-1), None
def grab_rgb8(w, h, pf):
if gl.getdisplaymode() <> GET.DMRGB:
raise Error, 'Sorry, can only grab rgb8 in single-buf rgbmode'
if pf <> (1, 1):
raise Error, 'Sorry, can only grab rgb8 with packfactor (1,1)'
if not VFile.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.
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'
def grab_jpeg(w, h, pf):
# XXX Ought to grab rgb and compress it
raise Error, 'sorry, grabbing jpeg not implemented'
def grab_jpeggrey(w, h, pf):
raise Error, 'sorry, grabbing jpeggrey not implemented'

View File

@ -1,134 +1,269 @@
# Copy a video file, interactively, frame-by-frame. #! /ufs/guido/bin/sgi/python
import sys # Universal (non-interactive) CMIF video file copier.
import getopt
from gl import *
from DEVICE import *
import VFile
import string
import imageop
def report(time, iframe):
print 'Frame', iframe, ': t =', time # Possibilities:
#
# - Manipulate the time base:
# = resample at a fixed rate
# = divide the time codes by a speed factor (to make it go faster/slower)
# = drop frames that are less than n msec apart (to accomodate slow players)
# - Convert to a different format
# - Magnify (scale) the image
# Usage function (keep this up-to-date if you change the program!)
def usage(): def usage():
sys.stderr.write('usage: Vcopy [-t type] [-m treshold] [-a] infile outfile\n') print 'Usage: Vcopy [options] [infile [outfile]]'
sys.stderr.write('-t Convert to other type\n') print
sys.stderr.write('-a Automatic\n') print 'Options:'
sys.stderr.write('-m Convert grey to mono with treshold\n') print
sys.stderr.write('-d Convert grey to mono with dithering\n') print '-t type : new image type (default unchanged)'
sys.exit(2) print
print '-M magnify : image magnification factor (default unchanged)'
print '-w width : output image width (default height*4/3 if -h used)'
print '-h height : output image height (default width*3/4 if -w used)'
print
print '-p pf : new x and y packfactor (default unchanged)'
print '-x xpf : new x packfactor (default 1 if -y used)'
print '-y ypf : new y packfactor (default 1 if -x used)'
print
print '-m delta : drop frames closer than delta msec (default 0)'
print '-r delta : regenerate input time base delta msec apart'
print '-s speed : speed change factor (default unchanged)'
print
print 'infile : input file (default film.video)'
print 'outfile : output file (default out.video)'
def help():
print 'Command summary:' import sys
print 'n get next image from input' sys.path.append('/ufs/guido/src/video')
print 'w write current image to output'
import VFile
import imgconv
import imageop
import getopt
import string
# Global options
speed = 1.0
mindelta = 0
regen = None
newpf = None
newtype = None
magnify = None
newwidth = None
newheight = None
# Function to turn a string into a float
atof_error = 'atof_error' # Exception if it fails
def atof(s):
try:
return float(eval(s))
except:
raise atof_error
# Main program -- mostly command line parsing
def main(): def main():
foreground() global speed, mindelta, regen, newpf, newtype, \
opts, args = getopt.getopt(sys.argv[1:], 't:am:d') magnify, newwidth, newheight
if len(args) <> 2:
# Parse command line
try:
opts, args = getopt.getopt(sys.argv[1:], \
'M:h:m:p:r:s:t:w:x:y:')
except getopt.error, msg:
sys.stdout = sys.stderr
print 'Error:', msg, '\n'
usage() usage()
[ifile, ofile] = args sys.exit(2)
print 'open film ', ifile
ifilm = VFile.VinFile().init(ifile) xpf = ypf = None
print 'open output ', ofile
ofilm = VFile.VoutFile().init(ofile)
ofilm.setinfo(ifilm.getinfo()) # Interpret options
try:
for opt, arg in opts:
if opt == '-M': magnify = atof(arg)
if opt == '-h': height = string.atoi(arg)
if opt == '-m': mindelta = string.atoi(arg)
if opt == '-p': xpf = ypf = string.atoi(arg)
if opt == '-r': regen = string.atoi(arg)
if opt == '-s': speed = atof(arg)
if opt == '-t': newtype = arg
if opt == '-w': newwidth = string.atoi(arg)
if opt == '-x': xpf = string.atoi(arg)
if opt == '-y': ypf = string.atoi(arg)
except string.atoi_error:
sys.stdout = sys.stderr
print 'Option', opt, 'requires integer argument'
sys.exit(2)
except atof_error:
sys.stdout = sys.stderr
print 'Option', opt, 'requires float argument'
sys.exit(2)
if xpf or ypf:
if not xpf: xpf = 1
if not ypf: ypf = 1
newpf = (xpf, ypf)
if newwidth or newheight:
if magnify:
sys.stdout = sys.stderr
print 'Options -w or -h are incompatible with -M'
sys.exit(2)
if not newheight:
newheight = newwidth * 3 / 4
elif not newwidth:
newwidth = newheight * 4 / 3
# Check filename arguments
if len(args) < 1:
args.append('film.video')
if len(args) < 2:
args.append('out.video')
if len(args) > 2:
usage()
sys.exit(2)
if args[0] == args[1]:
sys.stderr.write('Input file can\'t be output file\n')
sys.exit(2)
# Do the right thing
sts = process(args[0], args[1])
# Exit
sys.exit(sts)
# Copy one file to another
def process(infilename, outfilename):
global newwidth, newheight
try:
vin = VFile.BasicVinFile().init(infilename)
except IOError, msg:
sys.stderr.write(infilename + ': I/O error: ' + `msg` + '\n')
return 1
except VFile.Error, msg:
sys.stderr.write(msg + '\n')
return 1
except EOFError:
sys.stderr.write(infilename + ': EOF in video file\n')
return 1
try:
vout = VFile.BasicVoutFile().init(outfilename)
except IOError, msg:
sys.stderr.write(outfilename + ': I/O error: ' + `msg` + '\n')
return 1
vout.setinfo(vin.getinfo())
scale = 0
flip = 0
if newtype:
vout.setformat(newtype)
try:
convert = imgconv.getconverter(vin.format, vout.format)
except imgconv.error, msg:
sys.stderr.write(str(msg) + '\n')
return 1
if newpf:
vout.setpf(newpf)
scale = 1
if newwidth and newheight:
scale = 1
if vin.upside_down <> vout.upside_down or \
vin.mirror_image <> vout.mirror_image:
flip = 1
inwidth, inheight = vin.getsize()
inwidth = inwidth / vin.xpf
inheight = inheight / vin.ypf
if magnify:
newwidth = int(vout.width * magnify)
newheight = int(vout.height * magnify)
scale = 1
if scale:
vout.setsize(newwidth, newheight)
else:
newwidth, newheight = vout.getsize()
if vin.packfactor <> vout.packfactor:
scale = 1
if scale or flip:
if vout.bpp not in (8, 32):
sys.stderr.write('Can\'t scale or flip this type\n')
return 1
newwidth = newwidth / vout.xpf
newheight = newheight / vout.ypf
vout.writeheader()
told = 0
nin = 0
nout = 0
tin = 0
tout = 0
use_grabber = 0
continuous = 0
tomono = 0
tomonodither = 0
for o, a in opts:
if o == '-t':
ofilm.format = a
use_grabber = 1
if o == '-a':
continuous = 1
if o == '-m':
if ifilm.format <> 'grey':
print '-m only supported for greyscale'
sys.exit(1)
tomono = 1
treshold = string.atoi(a)
ofilm.format = 'mono'
if o == '-d':
if ifilm.format <> 'grey':
print '-m only supported for greyscale'
sys.exit(1)
tomonodither = 1
ofilm.format = 'mono'
ofilm.writeheader()
#
prefsize(ifilm.width, ifilm.height)
w = winopen(ifile)
qdevice(KEYBD)
qdevice(ESCKEY)
qdevice(WINQUIT)
qdevice(WINSHUT)
print 'qdevice calls done'
#
help()
#
time, data, cdata = ifilm.getnextframe()
ifilm.showframe(data, cdata)
iframe = 1
report(time, iframe)
#
while 1: while 1:
if continuous: try:
dev = KEYBD tin, data, cdata = vin.getnextframe()
else: except EOFError:
dev, val = qread()
if dev in (ESCKEY, WINQUIT, WINSHUT):
break break
if dev == REDRAW: nin = nin + 1
reshapeviewport() if regen:
elif dev == KEYBD: tout = nin * regen
if continuous:
c = '0'
else:
c = chr(val)
#XXX Debug
if c == 'R':
c3i(255,0,0)
clear()
if c == 'G':
c3i(0,255,0)
clear()
if c == 'B':
c3i(0,0,255)
clear()
if c == 'w' or continuous:
if use_grabber:
data, cdata = ofilm.grabframe()
if tomono:
data = imageop.grey2mono(data, \
ifilm.width, ifilm.height, \
treshold)
if tomonodither:
data = imageop.dither2mono(data, \
ifilm.width, ifilm.height)
ofilm.writeframe(time, data, cdata)
print 'Frame', iframe, 'written.'
if c == 'n' or continuous:
try:
time,data,cdata = ifilm.getnextframe()
ifilm.showframe(data, cdata)
iframe = iframe+1
report(time, iframe)
except EOFError:
print 'EOF'
if continuous:
break
ringbell()
elif dev == INPUTCHANGE:
pass
else: else:
print '(dev, val) =', (dev, val) tout = tin
ofilm.close() tout = int(tout / speed)
if tout - told < mindelta:
continue
told = tout
if newtype:
data = convert(data, inwidth, inheight)
if newwidth and newheight:
data = imageop.scale(data, vout.bpp/8, \
inwidth, inheight, newwidth, newheight)
if vin.upside_down <> vout.upside_down or \
vin.mirror_image <> vout.mirror_image:
x0, y0 = 0, 0
x1, y1 = newwidth-1, neheight-1
if vin.upside_down <> vout.upside_down:
y1, y0 = y0, y1
if vin.mirror_image <> vout.mirror_image:
x1, x0 = x0, x1
data = imageop.crop(data, vout.bpp/8, \
newwidth, newheight, x0, y0, x1, y1)
vout.writeframe(tout, data, cdata)
nout = nout + 1
main() vout.close()
vin.close()
# Don't forget to call the main program
try:
main()
except KeyboardInterrupt:
print '[Interrupt]'

View File

@ -22,7 +22,7 @@ def rgb2jpeg(img, x, y):
def jpeggrey2grey(img, width, height): def jpeggrey2grey(img, width, height):
import jpeg import jpeg
data, width, height, bytesperpixel = jpeg.decompress(img) data, width, height, bytesperpixel = jpeg.decompress(img)
if bytesperpixel <> 1: raise RuntimeError, 'not grayscale jpeg' if bytesperpixel <> 1: raise RuntimeError, 'not greyscale jpeg'
return data return data
def jpeg2rgb(img, width, height): def jpeg2rgb(img, width, height):