- 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:
parent
b616ebe4e4
commit
5e044b7009
@ -59,9 +59,9 @@ Vtime.py Copy a video file, manipulating the time codes (e.g.
|
||||
faster/slower, or regenerate time codes, or drop
|
||||
frames too close apart)
|
||||
|
||||
Vcopy.py selectively write frames from one movie file to another
|
||||
usage: Vcopy [-t type] [-m treshold] [-a] infile outfile
|
||||
commands: 'n' gets next frame; 'w' writes current frame
|
||||
Vcopy.py Universal video file copying tool. Can manipulate the
|
||||
time codes, change the type, size, and packfactor.
|
||||
Subsumes Vtime.py.
|
||||
|
||||
Vmkjpeg.py compress an rgb or grey video file to jpeg[grey] format
|
||||
|
||||
|
@ -6,11 +6,10 @@
|
||||
#
|
||||
# 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
|
||||
# VoutFile: BasicVoutFile + Displayer
|
||||
#
|
||||
# XXX Future extension:
|
||||
# BasicVinoutFile: supports overwriting of individual frames
|
||||
@ -21,6 +20,7 @@
|
||||
import sys
|
||||
import gl
|
||||
import GL
|
||||
import GET
|
||||
import colorsys
|
||||
import imageop
|
||||
|
||||
@ -32,14 +32,6 @@ CallError = 'VFile.CallError' # bad call
|
||||
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
|
||||
|
||||
MAXMAP = 4096 - 256
|
||||
@ -151,9 +143,9 @@ def is_entry_indigo():
|
||||
b = gl.getgdesc(GL.GD_BITS_NORM_SNG_BLUE)
|
||||
return (r, g, b) == (3, 3, 2)
|
||||
|
||||
#
|
||||
# Predicate function to see whether this machine supports pixmode(PM_SIZE)
|
||||
# with values 1 or 4.
|
||||
|
||||
# Predicate to see whether this machine supports pixmode(PM_SIZE) with
|
||||
# values 1 or 4.
|
||||
#
|
||||
# XXX Temporarily disabled, since it is unclear which machines support
|
||||
# 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 seems as if the conversion is done by the kernel (unpacking ourselves
|
||||
# XXX is faster than using PM_SIZE=4)
|
||||
#
|
||||
|
||||
def support_packed_pixels():
|
||||
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):
|
||||
try:
|
||||
return eval('grab_' + format)
|
||||
except:
|
||||
raise Error, 'Unknown color system: ' + `format`
|
||||
bitsperpixel = { \
|
||||
'rgb': 32, \
|
||||
'rgb8': 8, \
|
||||
'grey': 8, \
|
||||
'grey4': 4, \
|
||||
'grey2': 2, \
|
||||
'mono': 1, \
|
||||
}
|
||||
|
||||
bppafterdecomp = {'jpeg': 32, 'jpeggrey': 8}
|
||||
|
||||
|
||||
# Base class to manage video format parameters
|
||||
@ -233,39 +183,102 @@ class VideoParams:
|
||||
|
||||
def init(self):
|
||||
# Essential parameters
|
||||
self.frozen = 0 # if set, can't change parameters
|
||||
self.format = 'grey' # color system used
|
||||
# Choose from: grey, rgb, rgb8, hsv, yiq, hls, jpeg, jpeggrey,
|
||||
# mono, grey2, grey4
|
||||
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.packfactor = 1, 1 # expansion using rectzoom
|
||||
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
|
||||
self.setderived()
|
||||
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())
|
||||
|
||||
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.setderived()
|
||||
|
||||
# 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
|
||||
# Set the format
|
||||
|
||||
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):
|
||||
(self.format, self.width, self.height, self.packfactor,\
|
||||
self.c0bits, self.c1bits, self.c2bits, self.offset, \
|
||||
self.chrompack) = values
|
||||
if self.frozen: raise CallError
|
||||
self.setformat(values[0])
|
||||
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
|
||||
# call to setinfo()
|
||||
@ -281,27 +294,17 @@ class VideoParams:
|
||||
print 'Format: ', self.format
|
||||
print 'Size: ', self.width, 'x', self.height
|
||||
print 'Pack: ', self.packfactor, '; chrom:', self.chrompack
|
||||
print 'Bpp: ', self.bpp
|
||||
print 'Bits: ', self.c0bits, self.c1bits, self.c2bits
|
||||
print 'Offset: ', self.offset
|
||||
|
||||
# Calculate data size, if possible
|
||||
# (Not counting frame header or cdata size)
|
||||
|
||||
def calcframesize(self):
|
||||
if self.format == 'rgb':
|
||||
return self.width*self.height*4
|
||||
if self.format in ('jpeg', 'jpeggrey'):
|
||||
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
|
||||
if not self.bpp: raise CallError
|
||||
size = self.width/self.xpf * self.height/self.ypf
|
||||
size = (size * self.bpp + 7) / 8
|
||||
return size
|
||||
|
||||
|
||||
@ -346,33 +349,16 @@ class Displayer(VideoParams):
|
||||
(0,0,self.width,self.height))
|
||||
|
||||
def showpartframe(self, data, chromdata, (x,y,w,h)):
|
||||
pf = self.packfactor
|
||||
pmsize = 8
|
||||
if pf:
|
||||
if type(pf) == type(()):
|
||||
xpf, ypf = pf
|
||||
else:
|
||||
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
|
||||
pmsize = self.bpp
|
||||
xpf, ypf = self.xpf, self.ypf
|
||||
if self.upside_down:
|
||||
gl.pixmode(GL.PM_TTOB, 1)
|
||||
if self.mirror_image:
|
||||
gp.pixmode(GL.PM_RTOL, 1)
|
||||
if self.format in ('jpeg', 'jpeggrey'):
|
||||
import jpeg
|
||||
data, width, height, bytes = jpeg.decompress(data)
|
||||
if self.format == 'jpeg':
|
||||
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'
|
||||
pmsize = bytes*8
|
||||
elif self.format in ('mono', 'grey4'):
|
||||
if self.mustunpack:
|
||||
if self.format == 'mono':
|
||||
@ -381,24 +367,18 @@ class Displayer(VideoParams):
|
||||
elif self.format == 'grey4':
|
||||
data = imageop.grey42grey(data, \
|
||||
w/xpf, h/ypf)
|
||||
else:
|
||||
# We don't need to unpack, the hardware
|
||||
# can do it.
|
||||
if self.format == 'mono':
|
||||
pmsize = 1
|
||||
else:
|
||||
pmsize = 4
|
||||
pmsize = 8
|
||||
elif self.format == 'grey2':
|
||||
data = imageop.grey22grey(data, w/xpf, h/ypf)
|
||||
pmsize = 8
|
||||
if not self.colormapinited:
|
||||
self.initcolormap()
|
||||
if self.fixcolor0:
|
||||
gl.mapcolor(self.color0)
|
||||
self.fixcolor0 = 0
|
||||
xfactor = yfactor = self.magnify
|
||||
if pf:
|
||||
xfactor = xfactor * xpf
|
||||
yfactor = yfactor * ypf
|
||||
xfactor = xfactor * xpf
|
||||
yfactor = yfactor * ypf
|
||||
if chromdata and not self.skipchrom:
|
||||
cp = self.chrompack
|
||||
cx = int(x*xfactor*cp) + self.xorigin
|
||||
@ -411,13 +391,13 @@ class Displayer(VideoParams):
|
||||
gl.lrectwrite(cx, cy, cx + cw - 1, cy + ch - 1, \
|
||||
chromdata)
|
||||
#
|
||||
if pf:
|
||||
if pmsize < 32:
|
||||
gl.writemask((1 << self.c0bits) - 1)
|
||||
gl.pixmode(GL.PM_SIZE, pmsize)
|
||||
w = w/xpf
|
||||
h = h/ypf
|
||||
x = x/xpf
|
||||
y = y/ypf
|
||||
gl.pixmode(GL.PM_SIZE, pmsize)
|
||||
w = w/xpf
|
||||
h = h/ypf
|
||||
x = x/xpf
|
||||
y = y/ypf
|
||||
gl.rectzoom(xfactor, yfactor)
|
||||
x = int(x*xfactor)+self.xorigin
|
||||
y = int(y*yfactor)+self.yorigin
|
||||
@ -464,7 +444,7 @@ class Displayer(VideoParams):
|
||||
|
||||
def clear(self):
|
||||
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.clear()
|
||||
return
|
||||
@ -477,7 +457,7 @@ class Displayer(VideoParams):
|
||||
|
||||
def clearto(self, r, g, b):
|
||||
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.clear()
|
||||
return
|
||||
@ -553,23 +533,6 @@ class Displayer(VideoParams):
|
||||
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.
|
||||
# Return (version, values) where version is 0.0, 1.0, 2.0 or 3.[01],
|
||||
# and values is ready for setinfo().
|
||||
@ -620,8 +583,6 @@ def readfileheader(fp, filename):
|
||||
format, rest = eval(line[:-1])
|
||||
except:
|
||||
raise Error, filename + ': Bad 3.[01] color info'
|
||||
if format == 'xrgb8':
|
||||
format = 'rgb8' # rgb8 upside-down, for X
|
||||
if format in ('rgb', 'jpeg'):
|
||||
c0bits = c1bits = c2bits = 0
|
||||
chrompack = 0
|
||||
@ -637,6 +598,11 @@ def readfileheader(fp, filename):
|
||||
c0bits, c1bits, c2bits, chrompack, offset = rest
|
||||
except:
|
||||
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
|
||||
#
|
||||
@ -657,15 +623,18 @@ def readfileheader(fp, filename):
|
||||
packfactor = 2
|
||||
else:
|
||||
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 = abs(xpf)
|
||||
ypf = abs(ypf)
|
||||
width = (width/xpf) * xpf
|
||||
height = (height/ypf) * ypf
|
||||
elif packfactor > 1:
|
||||
width = (width / packfactor) * packfactor
|
||||
height = (height / packfactor) * packfactor
|
||||
if upside_down:
|
||||
ypf = -ypf
|
||||
packfactor = (xpf, ypf)
|
||||
xpf = abs(xpf)
|
||||
ypf = abs(ypf)
|
||||
width = (width/xpf) * xpf
|
||||
height = (height/ypf) * ypf
|
||||
#
|
||||
# Return (version, values)
|
||||
#
|
||||
@ -762,7 +731,8 @@ class BasicVinFile(VideoParams):
|
||||
self.fp = fp
|
||||
self.filename = filename
|
||||
self.version, values = readfileheader(fp, filename)
|
||||
VideoParams.setinfo(self, values)
|
||||
self.setinfo(values)
|
||||
self.freeze()
|
||||
if self.version == 0.0:
|
||||
w, h, pf = self.width, self.height, self.packfactor
|
||||
if pf == 0:
|
||||
@ -801,12 +771,6 @@ class BasicVinFile(VideoParams):
|
||||
del self.fp
|
||||
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):
|
||||
if not self.canseek:
|
||||
raise Error, self.filename + ': can\'t seek'
|
||||
@ -1022,8 +986,7 @@ class BasicVoutFile(VideoParams):
|
||||
self = VideoParams.init(self)
|
||||
self.fp = fp
|
||||
self.filename = filename
|
||||
self.version = 3.0 # In case anyone inquries
|
||||
self.headerwritten = 0
|
||||
self.version = 3.1 # In case anyone inquries
|
||||
return self
|
||||
|
||||
def flush(self):
|
||||
@ -1034,27 +997,23 @@ class BasicVoutFile(VideoParams):
|
||||
del self.fp
|
||||
|
||||
def prealloc(self, nframes):
|
||||
if not self.headerwritten: raise CallError
|
||||
data = '\xff' * self.calcframesize()
|
||||
if not self.frozen: raise CallError
|
||||
data = '\xff' * (self.calcframesize() + 64)
|
||||
pos = self.fp.tell()
|
||||
for i in range(nframes):
|
||||
self.fp.write(data)
|
||||
self.fp.seek(pos)
|
||||
|
||||
def setinfo(self, values):
|
||||
if self.headerwritten: raise CallError
|
||||
VideoParams.setinfo(self, values)
|
||||
|
||||
def writeheader(self):
|
||||
if self.headerwritten: raise CallError
|
||||
if self.frozen: raise CallError
|
||||
writefileheader(self.fp, self.getinfo())
|
||||
self.headerwritten = 1
|
||||
self.freeze()
|
||||
self.atheader = 1
|
||||
self.framecount = 0
|
||||
|
||||
def rewind(self):
|
||||
self.fp.seek(0)
|
||||
self.headerwritten = 0
|
||||
self.unfreeze()
|
||||
self.atheader = 1
|
||||
self.framecount = 0
|
||||
|
||||
@ -1071,7 +1030,7 @@ class BasicVoutFile(VideoParams):
|
||||
self.writeframedata(data, cdata)
|
||||
|
||||
def writeframeheader(self, t, ds, cs):
|
||||
if not self.headerwritten: self.writeheader()
|
||||
if not self.frozen: self.writeheader()
|
||||
if not self.atheader: raise CallError
|
||||
data = `(t, ds, cs)`
|
||||
n = len(data)
|
||||
@ -1080,14 +1039,14 @@ class BasicVoutFile(VideoParams):
|
||||
self.atheader = 0
|
||||
|
||||
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 cdata: self.fp.write(cdata)
|
||||
self.atheader = 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):
|
||||
|
||||
@ -1101,7 +1060,7 @@ class VinFile(RandomVinFile, Displayer):
|
||||
return t
|
||||
|
||||
|
||||
class VoutFile(BasicVoutFile, Displayer, Grabber):
|
||||
class VoutFile(BasicVoutFile, Displayer):
|
||||
|
||||
def initfp(self, fp, filename):
|
||||
self = Displayer.init(self)
|
||||
|
78
Demo/sgi/video/VGrabber.py
Executable file
78
Demo/sgi/video/VGrabber.py
Executable 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'
|
@ -1,134 +1,269 @@
|
||||
# Copy a video file, interactively, frame-by-frame.
|
||||
#! /ufs/guido/bin/sgi/python
|
||||
|
||||
import sys
|
||||
import getopt
|
||||
from gl import *
|
||||
from DEVICE import *
|
||||
import VFile
|
||||
import string
|
||||
import imageop
|
||||
# Universal (non-interactive) CMIF video file copier.
|
||||
|
||||
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():
|
||||
sys.stderr.write('usage: Vcopy [-t type] [-m treshold] [-a] infile outfile\n')
|
||||
sys.stderr.write('-t Convert to other type\n')
|
||||
sys.stderr.write('-a Automatic\n')
|
||||
sys.stderr.write('-m Convert grey to mono with treshold\n')
|
||||
sys.stderr.write('-d Convert grey to mono with dithering\n')
|
||||
sys.exit(2)
|
||||
print 'Usage: Vcopy [options] [infile [outfile]]'
|
||||
print
|
||||
print 'Options:'
|
||||
print
|
||||
print '-t type : new image type (default unchanged)'
|
||||
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:'
|
||||
print 'n get next image from input'
|
||||
print 'w write current image to output'
|
||||
|
||||
import sys
|
||||
sys.path.append('/ufs/guido/src/video')
|
||||
|
||||
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():
|
||||
foreground()
|
||||
opts, args = getopt.getopt(sys.argv[1:], 't:am:d')
|
||||
if len(args) <> 2:
|
||||
global speed, mindelta, regen, newpf, newtype, \
|
||||
magnify, newwidth, newheight
|
||||
|
||||
# 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()
|
||||
[ifile, ofile] = args
|
||||
print 'open film ', ifile
|
||||
ifilm = VFile.VinFile().init(ifile)
|
||||
print 'open output ', ofile
|
||||
ofilm = VFile.VoutFile().init(ofile)
|
||||
sys.exit(2)
|
||||
|
||||
xpf = ypf = None
|
||||
|
||||
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:
|
||||
if continuous:
|
||||
dev = KEYBD
|
||||
else:
|
||||
dev, val = qread()
|
||||
if dev in (ESCKEY, WINQUIT, WINSHUT):
|
||||
try:
|
||||
tin, data, cdata = vin.getnextframe()
|
||||
except EOFError:
|
||||
break
|
||||
if dev == REDRAW:
|
||||
reshapeviewport()
|
||||
elif dev == KEYBD:
|
||||
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
|
||||
nin = nin + 1
|
||||
if regen:
|
||||
tout = nin * regen
|
||||
else:
|
||||
print '(dev, val) =', (dev, val)
|
||||
ofilm.close()
|
||||
tout = tin
|
||||
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]'
|
||||
|
@ -22,7 +22,7 @@ def rgb2jpeg(img, x, y):
|
||||
def jpeggrey2grey(img, width, height):
|
||||
import jpeg
|
||||
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
|
||||
|
||||
def jpeg2rgb(img, width, height):
|
||||
|
Loading…
x
Reference in New Issue
Block a user