From 5e044b7009e40c38e488c658f6fda34920dbce36 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Thu, 25 Feb 1993 14:20:13 +0000 Subject: - 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). --- Demo/sgi/video/README | 6 +- Demo/sgi/video/VFile.py | 323 +++++++++++++++++--------------------- Demo/sgi/video/VGrabber.py | 78 ++++++++++ Demo/sgi/video/Vcopy.py | 375 ++++++++++++++++++++++++++++++--------------- Demo/sgi/video/imgconv.py | 2 +- 5 files changed, 478 insertions(+), 306 deletions(-) create mode 100755 Demo/sgi/video/VGrabber.py diff --git a/Demo/sgi/video/README b/Demo/sgi/video/README index c75ebce..01a01d2 100644 --- a/Demo/sgi/video/README +++ b/Demo/sgi/video/README @@ -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 diff --git a/Demo/sgi/video/VFile.py b/Demo/sgi/video/VFile.py index c61ac04..46f8547 100755 --- a/Demo/sgi/video/VFile.py +++ b/Demo/sgi/video/VFile.py @@ -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 - -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' +# Tables listing bits per pixel for some formats -# Choose one of the above based upon a color system name +bitsperpixel = { \ + 'rgb': 32, \ + 'rgb8': 8, \ + 'grey': 8, \ + 'grey4': 4, \ + 'grey2': 2, \ + 'mono': 1, \ +} -def choose_grabber(format): - try: - return eval('grab_' + format) - except: - raise Error, 'Unknown color system: ' + `format` +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) diff --git a/Demo/sgi/video/VGrabber.py b/Demo/sgi/video/VGrabber.py new file mode 100755 index 0000000..74813b1 --- /dev/null +++ b/Demo/sgi/video/VGrabber.py @@ -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' diff --git a/Demo/sgi/video/Vcopy.py b/Demo/sgi/video/Vcopy.py index f92dfdd..fb7afab 100755 --- a/Demo/sgi/video/Vcopy.py +++ b/Demo/sgi/video/Vcopy.py @@ -1,134 +1,269 @@ -# Copy a video file, interactively, frame-by-frame. +#! /ufs/guido/bin/sgi/python + +# Universal (non-interactive) CMIF video file copier. + + +# 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(): + 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)' + import sys -import getopt -from gl import * -from DEVICE import * +sys.path.append('/ufs/guido/src/video') + import VFile -import string +import imgconv import imageop +import getopt +import string -def report(time, iframe): - print 'Frame', iframe, ': t =', time -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) - -def help(): - print 'Command summary:' - print 'n get next image from input' - print 'w write current image to output' +# 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()) - - 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) - # + # 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 + 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 + + vout.close() + vin.close() + + +# Don't forget to call the main program -main() +try: + main() +except KeyboardInterrupt: + print '[Interrupt]' diff --git a/Demo/sgi/video/imgconv.py b/Demo/sgi/video/imgconv.py index af6d60e..f22c06c 100755 --- a/Demo/sgi/video/imgconv.py +++ b/Demo/sgi/video/imgconv.py @@ -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): -- cgit v0.12