📄 vfile.py
字号:
# Permanently make the first color index current gl.color(self.color0[0]) # Install the colormap in the window (may be overridden for Glx window) def install_colormap(self, map): if not self.quiet: sys.stderr.write(' Installing ' + `len(map)` + \ ' entries...') for irgb in map: gl.mapcolor(irgb) gl.gflush() # send the colormap changes to the X server# 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().# Raise Error if there is an error in the infodef readfileheader(fp, filename): # # Get identifying header # line = fp.readline(20) if line == 'CMIF video 0.0\n': version = 0.0 elif line == 'CMIF video 1.0\n': version = 1.0 elif line == 'CMIF video 2.0\n': version = 2.0 elif line == 'CMIF video 3.0\n': version = 3.0 elif line == 'CMIF video 3.1\n': version = 3.1 else: # XXX Could be version 0.0 without identifying header raise Error, \ filename + ': Unrecognized file header: ' + `line`[:20] compressheader = None # # Get color encoding info # (The format may change to 'rgb' later when packfactor == 0) # if version <= 1.0: format = 'grey' c0bits, c1bits, c2bits = 8, 0, 0 chrompack = 0 offset = 0 elif version == 2.0: line = fp.readline() try: c0bits, c1bits, c2bits, chrompack = eval(line[:-1]) except: raise Error, filename + ': Bad 2.0 color info' if c1bits or c2bits: format = 'yiq' else: format = 'grey' offset = 0 elif version in (3.0, 3.1): line = fp.readline() try: format, rest = eval(line[:-1]) except: raise Error, filename + ': Bad 3.[01] color info' if format in ('rgb', 'jpeg'): c0bits = c1bits = c2bits = 0 chrompack = 0 offset = 0 elif format == 'compress': c0bits = c1bits = c2bits = 0 chrompack = 0 offset = 0 compressheader = rest elif format in ('grey', 'jpeggrey', 'mono', 'grey2', 'grey4'): c0bits = rest c1bits = c2bits = 0 chrompack = 0 offset = 0 else: # XXX ought to check that the format is valid try: 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 # line = fp.readline() try: x = eval(line[:-1]) except: raise Error, filename + ': Bad (w,h,pf) info' if type(x) <> type(()): raise Error, filename + ': Bad (w,h,pf) info' if len(x) == 3: width, height, packfactor = x if packfactor == 0 and version < 3.0: format = 'rgb' c0bits = 0 elif len(x) == 2 and version <= 1.0: width, height = x packfactor = 2 else: raise Error, filename + ': Bad (w,h,pf) info' if type(packfactor) is type(0): if packfactor == 0: packfactor = 1 xpf = ypf = packfactor else: xpf, ypf = 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) # values = (format, width, height, packfactor, \ c0bits, c1bits, c2bits, offset, chrompack, compressheader) return (version, values)# Read a *frame* header -- separate functions per version.# Return (timecode, datasize, chromdatasize).# Raise EOFError if end of data is reached.# Raise Error if data is bad.def readv0frameheader(fp): line = fp.readline() if not line or line == '\n': raise EOFError try: t = eval(line[:-1]) except: raise Error, 'Bad 0.0 frame header' return (t, 0, 0)def readv1frameheader(fp): line = fp.readline() if not line or line == '\n': raise EOFError try: t, datasize = eval(line[:-1]) except: raise Error, 'Bad 1.0 frame header' return (t, datasize, 0)def readv2frameheader(fp): line = fp.readline() if not line or line == '\n': raise EOFError try: t, datasize = eval(line[:-1]) except: raise Error, 'Bad 2.0 frame header' return (t, datasize, 0)def readv3frameheader(fp): line = fp.readline() if not line or line == '\n': raise EOFError try: t, datasize, chromdatasize = x = eval(line[:-1]) except: raise Error, 'Bad 3.[01] frame header' return x# Write a CMIF video file header (always version 3.1)def writefileheader(fp, values): (format, width, height, packfactor, \ c0bits, c1bits, c2bits, offset, chrompack) = values # # Write identifying header # fp.write('CMIF video 3.1\n') # # Write color encoding info # if format in ('rgb', 'jpeg'): data = (format, 0) elif format in ('grey', 'jpeggrey', 'mono', 'grey2', 'grey4'): data = (format, c0bits) else: data = (format, (c0bits, c1bits, c2bits, chrompack, offset)) fp.write(`data`+'\n') # # Write frame geometry info # data = (width, height, packfactor) fp.write(`data`+'\n') def writecompressfileheader(fp, cheader, values): (format, width, height, packfactor, \ c0bits, c1bits, c2bits, offset, chrompack) = values # # Write identifying header # fp.write('CMIF video 3.1\n') # # Write color encoding info # data = (format, cheader) fp.write(`data`+'\n') # # Write frame geometry info # data = (width, height, packfactor) fp.write(`data`+'\n')# Basic class for reading CMIF video filesclass BasicVinFile(VideoParams): def __init__(self, filename): if type(filename) != type(''): fp = filename filename = '???' elif filename == '-': fp = sys.stdin else: fp = open(filename, 'r') self.initfp(fp, filename) def initfp(self, fp, filename): VideoParams.__init__(self) self.fp = fp self.filename = filename self.version, values = readfileheader(fp, filename) self.setinfo(values) self.freeze() if self.version == 0.0: w, h, pf = self.width, self.height, self.packfactor if pf == 0: self._datasize = w*h*4 else: self._datasize = (w/pf) * (h/pf) self._readframeheader = self._readv0frameheader elif self.version == 1.0: self._readframeheader = readv1frameheader elif self.version == 2.0: self._readframeheader = readv2frameheader elif self.version in (3.0, 3.1): self._readframeheader = readv3frameheader else: raise Error, \ filename + ': Bad version: ' + `self.version` self.framecount = 0 self.atframeheader = 1 self.eofseen = 0 self.errorseen = 0 try: self.startpos = self.fp.tell() self.canseek = 1 except IOError: self.startpos = -1 self.canseek = 0 def _readv0frameheader(self, fp): t, ds, cs = readv0frameheader(fp) ds = self._datasize return (t, ds, cs) def close(self): self.fp.close() del self.fp del self._readframeheader def rewind(self): if not self.canseek: raise Error, self.filename + ': can\'t seek' self.fp.seek(self.startpos) self.framecount = 0 self.atframeheader = 1 self.eofseen = 0 self.errorseen = 0 def warmcache(self): print '[BasicVinFile.warmcache() not implemented]' def printinfo(self): print 'File: ', self.filename print 'Size: ', getfilesize(self.filename) print 'Version: ', self.version VideoParams.printinfo(self) def getnextframe(self): t, ds, cs = self.getnextframeheader() data, cdata = self.getnextframedata(ds, cs) return (t, data, cdata) def skipnextframe(self): t, ds, cs = self.getnextframeheader() self.skipnextframedata(ds, cs) return t def getnextframeheader(self): if self.eofseen: raise EOFError if self.errorseen: raise CallError if not self.atframeheader: raise CallError self.atframeheader = 0 try: return self._readframeheader(self.fp) except Error, msg: self.errorseen = 1 # Patch up the error message raise Error, self.filename + ': ' + msg except EOFError: self.eofseen = 1 raise EOFError def getnextframedata(self, ds, cs): if self.eofseen: raise EOFError if self.errorseen: raise CallError if self.atframeheader: raise CallError if ds: data = self.fp.read(ds) if len(data) < ds: self.eofseen = 1 raise EOFError else: data = '' if cs: cdata = self.fp.read(cs) if len(cdata) < cs: self.eofseen = 1 raise EOFError else: cdata = '' self.atframeheader = 1 self.framecount = self.framecount + 1 return (data, cdata) def skipnextframedata(self, ds, cs): if self.eofseen: raise EOFError if self.errorseen: raise CallError if self.atframeheader: raise CallError # Note that this won't raise EOFError for a partial frame # since there is no easy way to tell whether a seek # ended up beyond the end of the file if self.canseek: self.fp.seek(ds + cs, 1) # Relative seek else: dummy = self.fp.read(ds + cs) del dummy self.atframeheader = 1 self.framecount = self.framecount + 1# Subroutine to return a file's size in bytesdef getfilesize(filename): import os, stat try: st = os.stat(filename) return st[stat.ST_SIZE] except os.error: return 0# Derived class implementing random access and index cached in the fileclass RandomVinFile(BasicVinFile): def initfp(self, fp, filename): BasicVinFile.initfp(self, fp, filename) self.index = [] def warmcache(self): if len(self.index) == 0: try: self.readcache() except Error: self.buildcache() else: print '[RandomVinFile.warmcache(): too late]' self.rewind() def buildcache(self): self.index = [] self.rewind() while 1: try: dummy = self.skipnextframe() except EOFError: break self.rewind() def writecache(self): # Raises IOerror if the file is not seekable & writable! import marshal if len(self.index) == 0: self.buildcache() if len(self.index) == 0: raise Error, self.filename + ': No frames' self.fp.seek(0, 2) self.fp.write('\n/////CMIF/////\n') pos = self.fp.tell() data = `pos` data = '\n-*-*-CMIF-*-*-\n' + data + ' '*(15-len(data)) + '\n' try: marshal.dump(self.index, self.fp) self.fp.write(data) self.fp.flush() finally: self.rewind() def readcache(self): # Raises Error if there is no cache in the file import marshal if len(self.index) <> 0: raise CallError self.fp.seek(-32, 2) data = self.fp.read() if data[:16] <> '\n-*-*-CMIF-*-*-\n' or data[-1:] <> '\n': self.rewind() raise Error, self.filename + ': No cache' pos = eval(data[16:-1]) self.fp.seek(pos) try: self.index = marshal.load(self.fp) except TypeError: self.rewind() raise Error, self.filename + ': Bad cache' self.rewind() def getnextframeheader(self): if self.framecount < len(self.index): return self._getindexframeheader(self.framecount) if self.framecount > len(self.index): raise AssertError, \ 'managed to bypass index?!?' rv = BasicVinFile.getnextframeheader(self) if self.canseek: pos = self.fp.tell() self.index.append((rv, pos)) return rv def getrandomframe(self, i): t, ds, cs = self.getrandomframeheader(i) data, cdata = self.getnextframedata(ds, cs) return t, data, cdata def getrandomframeheader(self, i): if i < 0: raise ValueError, 'negative frame index' if not self.canseek: raise Error, self.filename + ': can\'t seek' if i < len(self.index): return self._getindexframeheader(i) if len(self.index) > 0: rv = self.getrandomframeheader(len(self.index)-1) else: self.rewind() rv = self.getnextframeheader() while i > self.framecount: self.skipnextframedata() rv = self.getnextframeheader() return rv def _getindexframeheader(self, i): (rv, pos) = self.index[i] self.fp.seek(pos) self.framecount = i self.atframeheader = 0 self.eofseen = 0 self.errorseen = 0 return rv# Basic class for writing CMIF video filesclass BasicVoutFile(VideoParams): def __init__(self, filename): if type(filename) != type(''): fp = filename filename = '???' elif filename == '-': fp = sys.stdout else: fp = open(filename, 'w') self.initfp(fp, filename) def initfp(self, fp, filename): VideoParams.__init__(self) self.fp = fp self.filename = filename self.version = 3.1 # In case anyone inquries def flush(self): self.fp.flush() def close(self): self.fp.close() del self.fp def prealloc(self, nframes): 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 writeheader(self): if self.frozen: raise CallError if self.format == 'compress': writecompressfileheader(self.fp, self.compressheader, \ self.getinfo()) else: writefileheader(self.fp, self.getinfo()) self.freeze() self.atheader = 1 self.framecount = 0 def rewind(self): self.fp.seek(0) self.unfreeze() self.atheader = 1 self.framecount = 0 def printinfo(self): print 'File: ', self.filename VideoParams.printinfo(self) def writeframe(self, t, data, cdata): if data: ds = len(data) else: ds = 0 if cdata: cs = len(cdata) else: cs = 0 self.writeframeheader(t, ds, cs) self.writeframedata(data, cdata) def writeframeheader(self, t, ds, cs): if not self.frozen: self.writeheader() if not self.atheader: raise CallError data = `(t, ds, cs)` n = len(data) if n < 63: data = data + ' '*(63-n) self.fp.write(data + '\n') self.atheader = 0 def writeframedata(self, data, cdata): 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:class VinFile(RandomVinFile, Displayer): def initfp(self, fp, filename): Displayer.__init__(self) RandomVinFile.initfp(self, fp, filename) def shownextframe(self): t, data, cdata = self.getnextframe() self.showframe(data, cdata) return tclass VoutFile(BasicVoutFile, Displayer): def initfp(self, fp, filename): Displayer.__init__(self)## Grabber.__init__(self) # XXX not needed BasicVoutFile.initfp(self, fp, filename)# Simple test program (VinFile only)def test(): import time if sys.argv[1:]: filename = sys.argv[1] else: filename = 'film.video' vin = VinFile(filename) vin.printinfo() gl.foreground() gl.prefsize(vin.getsize()) wid = gl.winopen(filename) vin.initcolormap() t0 = time.time() while 1: try: t, data, cdata = vin.getnextframe() except EOFError: break dt = t0 + t - time.time() if dt > 0: time.time(dt) vin.showframe(data, cdata) time.sleep(2)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -