mirror of https://github.com/python/cpython
Created Vedit.py, the video editor. This uses the classes in Viewer.py.
Viewer.py in turn requires changes to VFile.py (unfortunately that file is now a complete mess...).
This commit is contained in:
parent
e1b4d7ce14
commit
9ee7e15966
|
@ -100,6 +100,10 @@ Vtime.py (unrelated to vtime!!!) Copy a video file,
|
|||
manipulating the time codes (e.g. faster/slower, or
|
||||
regenerate time codes, or drop frames too close apart)
|
||||
|
||||
Vedit.py interactive video editing program
|
||||
|
||||
Viewer.py two viewer classes used by Vedit
|
||||
|
||||
|
||||
The following are C programs, either for efficiency or because they
|
||||
need to link with a C library:
|
||||
|
|
|
@ -52,116 +52,12 @@ def conv_rgb8(rgb,d1,d2):
|
|||
# xorigin, yorigin
|
||||
# fallback
|
||||
|
||||
class VinFile:
|
||||
|
||||
# init() and initfp() raise Error if the header is bad.
|
||||
# init() raises whatever open() raises if the file can't be opened.
|
||||
|
||||
def init(self, filename):
|
||||
if filename == '-':
|
||||
return self.initfp(sys.stdin, filename)
|
||||
return self.initfp(open(filename, 'r'), filename)
|
||||
|
||||
def initfp(self, fp, filename):
|
||||
self.colormapinited = 0
|
||||
self.magnify = 1.0
|
||||
self.xorigin = self.yorigin = 0
|
||||
self.fallback = 1
|
||||
self.skipchrom = 0
|
||||
self.fp = fp
|
||||
self.filename = filename
|
||||
self.quiet = 0
|
||||
#
|
||||
line = self.fp.readline()
|
||||
if line == 'CMIF video 1.0\n':
|
||||
self.version = 1.0
|
||||
elif line == 'CMIF video 2.0\n':
|
||||
self.version = 2.0
|
||||
elif line == 'CMIF video 3.0\n':
|
||||
self.version = 3.0
|
||||
else:
|
||||
raise Error, self.filename + ': bad video format'
|
||||
#
|
||||
if self.version < 2.0:
|
||||
self.c0bits, self.c1bits, self.c2bits = 8, 0, 0
|
||||
self.chrompack = 0
|
||||
self.offset = 0
|
||||
self.format = 'grey'
|
||||
elif self.version == 2.0:
|
||||
line = self.fp.readline()
|
||||
try:
|
||||
self.c0bits, self.c1bits, self.c2bits, \
|
||||
self.chrompack = eval(line[:-1])
|
||||
if self.c1bits or self.c2bits:
|
||||
self.format = 'yiq'
|
||||
else:
|
||||
self.format = 'grey'
|
||||
self.offset = 0
|
||||
except:
|
||||
raise Error, \
|
||||
self.filename + ': bad 2.0 color info'
|
||||
elif self.version == 3.0:
|
||||
line = self.fp.readline()
|
||||
try:
|
||||
self.format, rest = eval(line[:-1])
|
||||
if self.format == 'rgb':
|
||||
self.offset = 0
|
||||
self.c0bits = 0
|
||||
self.c1bits = 0
|
||||
self.c2bits = 0
|
||||
self.chrompack = 0
|
||||
elif self.format == 'grey':
|
||||
self.offset = 0
|
||||
self.c0bits = rest
|
||||
self.c1bits = self.c2bits = \
|
||||
self.chrompack = 0
|
||||
else:
|
||||
self.c0bits,self.c1bits,self.c2bits,\
|
||||
self.chrompack,self.offset = rest
|
||||
except:
|
||||
raise Error, \
|
||||
self.filename + ': bad 3.0 color info'
|
||||
|
||||
try:
|
||||
self.convcolor = eval('conv_'+self.format)
|
||||
except:
|
||||
raise Error, \
|
||||
self.filename + ': unknown colorsys ' + self.format
|
||||
#
|
||||
line = self.fp.readline()
|
||||
try:
|
||||
x = eval(line[:-1])
|
||||
if self.version > 1.0 or len(x) == 3:
|
||||
self.width, self.height, self.packfactor = x
|
||||
if self.packfactor == 0:
|
||||
self.format = 'rgb'
|
||||
else:
|
||||
sef.width, self.height = x
|
||||
self.packfactor = 2
|
||||
except:
|
||||
raise Error, self.filename + ': bad (w,h,pf) info'
|
||||
self.frameno = 0
|
||||
self.framecache = []
|
||||
self.hascache = 0
|
||||
#
|
||||
return self
|
||||
|
||||
def warmcache(self):
|
||||
if self.hascache: return
|
||||
n = 0
|
||||
try:
|
||||
while 1:
|
||||
void = self.skipnextframe()
|
||||
n = n + 1
|
||||
except EOFError:
|
||||
pass
|
||||
if not self.hascache:
|
||||
raise Error, 'Cannot warm cache'
|
||||
|
||||
def close(self):
|
||||
self.fp.close()
|
||||
self.fp = None
|
||||
# XXX it's a total mess now -- VFile is a new base class
|
||||
# XXX to support common functionality (e.g. showframe)
|
||||
|
||||
class VFile:
|
||||
|
||||
#
|
||||
# getinfo returns all info pertaining to a film. The returned tuple
|
||||
|
@ -179,96 +75,12 @@ class VinFile:
|
|||
self.fp.seek(0)
|
||||
x = self.initfp(self.fp, self.filename)
|
||||
|
||||
def rewind(self):
|
||||
if self.hascache:
|
||||
self.frameno = 0
|
||||
else:
|
||||
self.reopen()
|
||||
|
||||
def position(self):
|
||||
if self.frameno >= len(self.framecache):
|
||||
raise EOFError
|
||||
self.fp.seek(self.framecache[self.frameno][0])
|
||||
|
||||
# getnextframe() raises EOFError (built-in) if there is no next frame,
|
||||
# or if the next frame is broken.
|
||||
# So to getnextframeheader(), getnextframedata() and skipnextframe().
|
||||
|
||||
def getnextframe(self):
|
||||
time, size, chromsize = self.getnextframeheader()
|
||||
data, chromdata = self.getnextframedata(size, chromsize)
|
||||
return time, data, chromdata
|
||||
|
||||
def getnextframedata(self, size, chromsize):
|
||||
if self.hascache:
|
||||
self.position()
|
||||
self.frameno = self.frameno + 1
|
||||
data = self.fp.read(size)
|
||||
if len(data) <> size: raise EOFError
|
||||
if chromsize:
|
||||
chromdata = self.fp.read(chromsize)
|
||||
if len(chromdata) <> chromsize: raise EOFError
|
||||
else:
|
||||
chromdata = None
|
||||
#
|
||||
return data, chromdata
|
||||
|
||||
def skipnextframe(self):
|
||||
time, size, chromsize = self.getnextframeheader()
|
||||
self.skipnextframedata(size, chromsize)
|
||||
return time
|
||||
|
||||
def skipnextframedata(self, size, chromsize):
|
||||
if self.hascache:
|
||||
self.frameno = self.frameno + 1
|
||||
return
|
||||
# Note that this won't raise EOFError for a partial frame.
|
||||
def setconvcolor(self):
|
||||
try:
|
||||
self.fp.seek(size + chromsize, 1) # Relative seek
|
||||
self.convcolor = eval('conv_'+self.format)
|
||||
except:
|
||||
# Assume it's a pipe -- read the data to discard it
|
||||
dummy = self.fp.read(size + chromsize)
|
||||
|
||||
def getnextframeheader(self):
|
||||
if self.hascache:
|
||||
if self.frameno >= len(self.framecache):
|
||||
raise EOFError
|
||||
return self.framecache[self.frameno][1]
|
||||
line = self.fp.readline()
|
||||
if not line:
|
||||
self.hascache = 1
|
||||
raise EOFError
|
||||
#
|
||||
w, h, pf = self.width, self.height, self.packfactor
|
||||
try:
|
||||
x = eval(line[:-1])
|
||||
if type(x) in (type(0), type(0.0)):
|
||||
time = x
|
||||
if pf == 0:
|
||||
size = w * h * 4
|
||||
else:
|
||||
size = (w/pf) * (h/pf)
|
||||
elif len(x) == 2:
|
||||
time, size = x
|
||||
cp = self.chrompack
|
||||
if cp:
|
||||
cw = (w + cp - 1) / cp
|
||||
ch = (h + cp - 1) / cp
|
||||
chromsize = 2 * cw * ch
|
||||
else:
|
||||
chromsize = 0
|
||||
else:
|
||||
time, size, chromsize = x
|
||||
except:
|
||||
raise Error, self.filename + ': bad frame header'
|
||||
cdata = (self.fp.tell(), (time, size, chromsize))
|
||||
self.framecache.append(cdata)
|
||||
return time, size, chromsize
|
||||
|
||||
def shownextframe(self):
|
||||
time, data, chromdata = self.getnextframe()
|
||||
self.showframe(data, chromdata)
|
||||
return time
|
||||
raise Error, \
|
||||
self.filename + ': unknown colorsys ' + self.format
|
||||
|
||||
def showframe(self, data, chromdata):
|
||||
w, h, pf = self.width, self.height, self.packfactor
|
||||
|
@ -369,6 +181,205 @@ class VinFile:
|
|||
gl.mapcolor(index, r, g, b)
|
||||
void = gl.gflush()
|
||||
|
||||
|
||||
|
||||
class VinFile(VFile):
|
||||
|
||||
# init() and initfp() raise Error if the header is bad.
|
||||
# init() raises whatever open() raises if the file can't be opened.
|
||||
|
||||
def init(self, filename):
|
||||
if filename == '-':
|
||||
return self.initfp(sys.stdin, filename)
|
||||
return self.initfp(open(filename, 'r'), filename)
|
||||
|
||||
def initfp(self, fp, filename):
|
||||
self.colormapinited = 0
|
||||
self.magnify = 1.0
|
||||
self.xorigin = self.yorigin = 0
|
||||
self.fallback = 1
|
||||
self.skipchrom = 0
|
||||
self.fp = fp
|
||||
self.filename = filename
|
||||
self.quiet = 0
|
||||
#
|
||||
line = self.fp.readline()
|
||||
if line == 'CMIF video 1.0\n':
|
||||
self.version = 1.0
|
||||
elif line == 'CMIF video 2.0\n':
|
||||
self.version = 2.0
|
||||
elif line == 'CMIF video 3.0\n':
|
||||
self.version = 3.0
|
||||
else:
|
||||
raise Error, self.filename + ': bad video format'
|
||||
#
|
||||
if self.version < 2.0:
|
||||
self.c0bits, self.c1bits, self.c2bits = 8, 0, 0
|
||||
self.chrompack = 0
|
||||
self.offset = 0
|
||||
self.format = 'grey'
|
||||
elif self.version == 2.0:
|
||||
line = self.fp.readline()
|
||||
try:
|
||||
self.c0bits, self.c1bits, self.c2bits, \
|
||||
self.chrompack = eval(line[:-1])
|
||||
if self.c1bits or self.c2bits:
|
||||
self.format = 'yiq'
|
||||
else:
|
||||
self.format = 'grey'
|
||||
self.offset = 0
|
||||
except:
|
||||
raise Error, \
|
||||
self.filename + ': bad 2.0 color info'
|
||||
elif self.version == 3.0:
|
||||
line = self.fp.readline()
|
||||
try:
|
||||
self.format, rest = eval(line[:-1])
|
||||
if self.format == 'rgb':
|
||||
self.offset = 0
|
||||
self.c0bits = 0
|
||||
self.c1bits = 0
|
||||
self.c2bits = 0
|
||||
self.chrompack = 0
|
||||
elif self.format == 'grey':
|
||||
self.offset = 0
|
||||
self.c0bits = rest
|
||||
self.c1bits = self.c2bits = \
|
||||
self.chrompack = 0
|
||||
else:
|
||||
self.c0bits,self.c1bits,self.c2bits,\
|
||||
self.chrompack,self.offset = rest
|
||||
except:
|
||||
raise Error, \
|
||||
self.filename + ': bad 3.0 color info'
|
||||
|
||||
self.setconvcolor()
|
||||
#
|
||||
line = self.fp.readline()
|
||||
try:
|
||||
x = eval(line[:-1])
|
||||
if self.version > 1.0 or len(x) == 3:
|
||||
self.width, self.height, self.packfactor = x
|
||||
if self.packfactor == 0:
|
||||
self.format = 'rgb'
|
||||
else:
|
||||
sef.width, self.height = x
|
||||
self.packfactor = 2
|
||||
except:
|
||||
raise Error, self.filename + ': bad (w,h,pf) info'
|
||||
self.frameno = 0
|
||||
self.framecache = []
|
||||
self.hascache = 0
|
||||
#
|
||||
return self
|
||||
|
||||
def warmcache(self):
|
||||
if self.hascache: return
|
||||
n = 0
|
||||
try:
|
||||
while 1:
|
||||
void = self.skipnextframe()
|
||||
n = n + 1
|
||||
except EOFError:
|
||||
pass
|
||||
if not self.hascache:
|
||||
raise Error, 'Cannot warm cache'
|
||||
|
||||
def close(self):
|
||||
self.fp.close()
|
||||
self.fp = None
|
||||
|
||||
def rewind(self):
|
||||
if self.hascache:
|
||||
self.frameno = 0
|
||||
else:
|
||||
self.reopen()
|
||||
|
||||
def position(self):
|
||||
if self.frameno >= len(self.framecache):
|
||||
raise EOFError
|
||||
self.fp.seek(self.framecache[self.frameno][0])
|
||||
|
||||
# getnextframe() raises EOFError (built-in) if there is no next frame,
|
||||
# or if the next frame is broken.
|
||||
# So to getnextframeheader(), getnextframedata() and skipnextframe().
|
||||
|
||||
def getnextframe(self):
|
||||
time, size, chromsize = self.getnextframeheader()
|
||||
data, chromdata = self.getnextframedata(size, chromsize)
|
||||
return time, data, chromdata
|
||||
|
||||
def getnextframedata(self, size, chromsize):
|
||||
if self.hascache:
|
||||
self.position()
|
||||
self.frameno = self.frameno + 1
|
||||
data = self.fp.read(size)
|
||||
if len(data) <> size: raise EOFError
|
||||
if chromsize:
|
||||
chromdata = self.fp.read(chromsize)
|
||||
if len(chromdata) <> chromsize: raise EOFError
|
||||
else:
|
||||
chromdata = None
|
||||
#
|
||||
return data, chromdata
|
||||
|
||||
def skipnextframe(self):
|
||||
time, size, chromsize = self.getnextframeheader()
|
||||
self.skipnextframedata(size, chromsize)
|
||||
return time
|
||||
|
||||
def skipnextframedata(self, size, chromsize):
|
||||
if self.hascache:
|
||||
self.frameno = self.frameno + 1
|
||||
return
|
||||
# Note that this won't raise EOFError for a partial frame.
|
||||
try:
|
||||
self.fp.seek(size + chromsize, 1) # Relative seek
|
||||
except:
|
||||
# Assume it's a pipe -- read the data to discard it
|
||||
dummy = self.fp.read(size + chromsize)
|
||||
|
||||
def getnextframeheader(self):
|
||||
if self.hascache:
|
||||
if self.frameno >= len(self.framecache):
|
||||
raise EOFError
|
||||
return self.framecache[self.frameno][1]
|
||||
line = self.fp.readline()
|
||||
if not line:
|
||||
self.hascache = 1
|
||||
raise EOFError
|
||||
#
|
||||
w, h, pf = self.width, self.height, self.packfactor
|
||||
try:
|
||||
x = eval(line[:-1])
|
||||
if type(x) in (type(0), type(0.0)):
|
||||
time = x
|
||||
if pf == 0:
|
||||
size = w * h * 4
|
||||
else:
|
||||
size = (w/pf) * (h/pf)
|
||||
elif len(x) == 2:
|
||||
time, size = x
|
||||
cp = self.chrompack
|
||||
if cp:
|
||||
cw = (w + cp - 1) / cp
|
||||
ch = (h + cp - 1) / cp
|
||||
chromsize = 2 * cw * ch
|
||||
else:
|
||||
chromsize = 0
|
||||
else:
|
||||
time, size, chromsize = x
|
||||
except:
|
||||
raise Error, self.filename + ': bad frame header'
|
||||
cdata = (self.fp.tell(), (time, size, chromsize))
|
||||
self.framecache.append(cdata)
|
||||
return time, size, chromsize
|
||||
|
||||
def shownextframe(self):
|
||||
time, data, chromdata = self.getnextframe()
|
||||
self.showframe(data, chromdata)
|
||||
return time
|
||||
|
||||
#
|
||||
# A set of routines to grab images from windows
|
||||
#
|
||||
|
@ -417,7 +428,7 @@ def grab_hsv(w, h, pf):
|
|||
# Notably it will accept almost any garbage and write it to the video
|
||||
# output file
|
||||
#
|
||||
class VoutFile:
|
||||
class VoutFile(VFile):
|
||||
def init(self, filename):
|
||||
if filename == '-':
|
||||
return self.initfp(sys.stdout, filename)
|
||||
|
@ -434,21 +445,21 @@ class VoutFile:
|
|||
self.offset = 0
|
||||
self.chrompack = 0
|
||||
self.headerwritten = 0
|
||||
self.quiet = 0
|
||||
self.magnify = 1
|
||||
self.setconvcolor()
|
||||
self.xorigin = self.yorigin = 0
|
||||
return self
|
||||
|
||||
def close(self):
|
||||
self.fp.close()
|
||||
x = self.initfp(None, None)
|
||||
|
||||
def getinfo(self):
|
||||
return (self.format, self.width, self.height, self.packfactor,\
|
||||
self.c0bits, self.c1bits, self.c2bits, self.offset, \
|
||||
self.chrompack)
|
||||
|
||||
def setinfo(self, values):
|
||||
self.format, self.width, self.height, self.packfactor,\
|
||||
self.c0bits, self.c1bits, self.c2bits, self.offset, \
|
||||
self.chrompack = values
|
||||
self.setconvcolor()
|
||||
|
||||
def writeheader(self):
|
||||
self.headerwritten = 1
|
||||
|
|
|
@ -0,0 +1,247 @@
|
|||
#! /ufs/guido/bin/sgi/python
|
||||
|
||||
# Edit CMIF movies interactively -- copy one or more files to an output file
|
||||
|
||||
|
||||
# Possibilities:
|
||||
#
|
||||
# - convert between formats (grey, rgb, rgb8, ...)
|
||||
# - change size
|
||||
# - cut out a given area of the image
|
||||
# - change time base (a la Vtime)
|
||||
# - skip stretches of frames
|
||||
|
||||
|
||||
import sys
|
||||
import os
|
||||
import gl, GL, DEVICE
|
||||
import fl, FL
|
||||
import flp
|
||||
import Viewer
|
||||
import getopt
|
||||
import string
|
||||
|
||||
|
||||
def main():
|
||||
qsize = 20
|
||||
opts, args = getopt.getopt(sys.argv[1:], 'q:')
|
||||
for o, a in opts:
|
||||
if o == '-q':
|
||||
qsize = string.atoi(a)
|
||||
ed = Editor().init(qsize)
|
||||
if args[0:]:
|
||||
ed.open_input(args[0])
|
||||
if args[1:]:
|
||||
ed.open_output(args[1])
|
||||
while 1:
|
||||
dummy = fl.do_forms()
|
||||
|
||||
|
||||
class Editor:
|
||||
|
||||
def init(self, qsize):
|
||||
self.qsize = qsize
|
||||
self.vin = None
|
||||
self.vout = None
|
||||
self.ifile = ''
|
||||
self.ofile = ''
|
||||
formdef = flp.parse_form('VeditForm', 'form')
|
||||
flp.create_full_form(self, formdef)
|
||||
self.form.show_form(FL.PLACE_SIZE, FL.TRUE, 'Vedit')
|
||||
fl.set_event_call_back(self.do_event)
|
||||
return self
|
||||
|
||||
def do_event(self, (dev, val)):
|
||||
if dev == DEVICE.REDRAW:
|
||||
if self.vin:
|
||||
self.vin.redraw(val)
|
||||
if self.vout:
|
||||
self.vout.redraw(val)
|
||||
|
||||
|
||||
def iocheck(self):
|
||||
self.msg('')
|
||||
if self.vin == None and self.vout == None:
|
||||
self.err('Please open input and output files first')
|
||||
return 0
|
||||
return self.icheck() and self.ocheck()
|
||||
|
||||
def icheck(self):
|
||||
self.msg('')
|
||||
if self.vin == None:
|
||||
self.err('Please open an input file first')
|
||||
return 0
|
||||
return 1
|
||||
|
||||
def ocheck(self):
|
||||
self.msg('')
|
||||
if self.vout == None:
|
||||
self.err('Please open an output file first')
|
||||
return 0
|
||||
return 1
|
||||
|
||||
|
||||
def cb_in_new(self, args):
|
||||
self.msg('')
|
||||
hd, tl = os.path.split(self.ifile)
|
||||
filename = fl.file_selector('Input video file', hd, '', tl)
|
||||
if not filename: return
|
||||
self.open_input(filename)
|
||||
|
||||
def cb_in_close(self, args):
|
||||
self.msg('')
|
||||
self.close_input()
|
||||
|
||||
def cb_in_skip(self, args):
|
||||
if not self.icheck(): return
|
||||
if not self.vin.get(): self.err('End of input file')
|
||||
self.ishow()
|
||||
|
||||
def cb_in_back(self, args):
|
||||
if not self.icheck(): return
|
||||
if not self.vin.backup(): self.err('Input buffer exhausted')
|
||||
self.ishow()
|
||||
|
||||
def cb_in_rewind(self, args):
|
||||
if not self.icheck(): return
|
||||
self.vin.rewind()
|
||||
self.ishow()
|
||||
|
||||
|
||||
def cb_copy(self, args):
|
||||
if not self.iocheck(): return
|
||||
data = self.vin.get()
|
||||
if data:
|
||||
if self.vout.getinfo() <> self.vin.getinfo():
|
||||
print 'Copying info...'
|
||||
self.vout.setinfo(self.vin.getinfo())
|
||||
self.vout.put(data)
|
||||
self.oshow()
|
||||
self.ishow()
|
||||
|
||||
def cb_uncopy(self, args):
|
||||
if not self.iocheck(): return
|
||||
if not self.vout.backup():
|
||||
self.err('Output buffer exhausted')
|
||||
return
|
||||
self.oshow()
|
||||
if not self.vin.backup():
|
||||
self.err('Input buffer exhausted')
|
||||
return
|
||||
self.ishow()
|
||||
|
||||
|
||||
def cb_out_new(self, args):
|
||||
self.msg('')
|
||||
hd, tl = os.path.split(self.ofile)
|
||||
filename = fl.file_selector('Output video file', hd, '', tl)
|
||||
if not filename: return
|
||||
self.open_output(filename)
|
||||
|
||||
def cb_out_close(self, args):
|
||||
self.msg('')
|
||||
self.close_output()
|
||||
|
||||
def cb_out_skip(self, arg):
|
||||
if not self.ocheck(): return
|
||||
if not self.vout.forward(): self.err('Output buffer exhausted')
|
||||
self.oshow()
|
||||
|
||||
def cb_out_back(self, args):
|
||||
if not self.ocheck(): return
|
||||
if not self.vout.backup(): self.err('Output buffer exhausted')
|
||||
self.oshow()
|
||||
|
||||
def cb_out_rewind(self, args):
|
||||
if not self.ocheck(): return
|
||||
self.vout.rewind()
|
||||
self.oshow()
|
||||
|
||||
|
||||
def cb_quit(self, args):
|
||||
self.close_input()
|
||||
self.close_output()
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def open_input(self, filename):
|
||||
self.ifile = filename
|
||||
basename = os.path.split(filename)[1]
|
||||
title = 'in: ' + basename
|
||||
try:
|
||||
vin = Viewer.InputViewer().init(filename, \
|
||||
title, self.qsize)
|
||||
except:
|
||||
self.err('Can\'t open input file', filename)
|
||||
return
|
||||
self.close_input()
|
||||
self.vin = vin
|
||||
self.in_file.label = basename
|
||||
self.ishow()
|
||||
|
||||
def close_input(self):
|
||||
if self.vin:
|
||||
self.msg('Closing input file...')
|
||||
self.vin.close()
|
||||
self.msg('')
|
||||
self.vin = None
|
||||
self.in_file.label = '(none)'
|
||||
self.format('in')
|
||||
|
||||
def ishow(self):
|
||||
self.vin.show()
|
||||
self.format('in')
|
||||
|
||||
def open_output(self, filename):
|
||||
self.ofile = filename
|
||||
basename = os.path.split(filename)[1]
|
||||
title = 'out: ' + basename
|
||||
try:
|
||||
vout = Viewer.OutputViewer().init(filename, \
|
||||
title, self.qsize)
|
||||
except:
|
||||
self.err('Can\'t open output file', filename)
|
||||
return
|
||||
self.close_output()
|
||||
self.vout = vout
|
||||
self.out_file.label = basename
|
||||
if self.vin:
|
||||
self.vout.setinfo(self.vin.getinfo())
|
||||
self.oshow()
|
||||
|
||||
def close_output(self):
|
||||
if self.vout:
|
||||
self.msg('Closing output file...')
|
||||
self.vout.close()
|
||||
self.msg('')
|
||||
self.vout = None
|
||||
self.out_file.label = '(none)'
|
||||
self.format('out')
|
||||
|
||||
def oshow(self):
|
||||
self.vout.show()
|
||||
self.format('out')
|
||||
|
||||
|
||||
def msg(self, *args):
|
||||
str = string.strip(string.join(args))
|
||||
self.msg_area.label = str
|
||||
|
||||
def err(self, *args):
|
||||
gl.ringbell()
|
||||
apply(self.msg, args)
|
||||
|
||||
def format(self, io):
|
||||
v = getattr(self, 'v' + io)
|
||||
if v == None:
|
||||
left = right = pos = 0
|
||||
else:
|
||||
left, right = v.qsizes()
|
||||
pos = v.tell()
|
||||
left = pos - left
|
||||
right = pos + right
|
||||
getattr(self, io + '_info1').label = `left`
|
||||
getattr(self, io + '_info2').label = `pos`
|
||||
getattr(self, io + '_info3').label = `right`
|
||||
|
||||
main()
|
|
@ -0,0 +1,360 @@
|
|||
Magic: 12321
|
||||
|
||||
Internal Form Definition File
|
||||
(do not change)
|
||||
|
||||
Number of forms: 1
|
||||
|
||||
=============== FORM ===============
|
||||
Name: form
|
||||
Width: 480.000000
|
||||
Height: 350.000000
|
||||
Number of Objects: 23
|
||||
|
||||
--------------------
|
||||
class: 1
|
||||
type: 1
|
||||
box: 0.000000 0.000000 480.000000 350.000000
|
||||
boxtype: 1
|
||||
colors: 47 47
|
||||
alignment: 4
|
||||
style: 0
|
||||
size: 11.000000
|
||||
lcol: 0
|
||||
label:
|
||||
name:
|
||||
callback:
|
||||
argument:
|
||||
|
||||
--------------------
|
||||
class: 11
|
||||
type: 4
|
||||
box: 170.000000 110.000000 140.000000 40.000000
|
||||
boxtype: 1
|
||||
colors: 47 47
|
||||
alignment: 4
|
||||
style: 0
|
||||
size: 11.000000
|
||||
lcol: 0
|
||||
label: -> Copy ->
|
||||
name:
|
||||
callback: cb_copy
|
||||
argument: 0
|
||||
|
||||
--------------------
|
||||
class: 11
|
||||
type: 4
|
||||
box: 10.000000 110.000000 140.000000 40.000000
|
||||
boxtype: 1
|
||||
colors: 47 47
|
||||
alignment: 4
|
||||
style: 0
|
||||
size: 11.000000
|
||||
lcol: 0
|
||||
label: Forward
|
||||
name:
|
||||
callback: cb_in_skip
|
||||
argument: 0
|
||||
|
||||
--------------------
|
||||
class: 11
|
||||
type: 0
|
||||
box: 10.000000 10.000000 140.000000 40.000000
|
||||
boxtype: 1
|
||||
colors: 47 47
|
||||
alignment: 4
|
||||
style: 0
|
||||
size: 11.000000
|
||||
lcol: 0
|
||||
label: Rewind input
|
||||
name:
|
||||
callback: cb_in_rewind
|
||||
argument: 0
|
||||
|
||||
--------------------
|
||||
class: 11
|
||||
type: 0
|
||||
box: 330.000000 10.000000 140.000000 40.000000
|
||||
boxtype: 1
|
||||
colors: 47 47
|
||||
alignment: 4
|
||||
style: 0
|
||||
size: 11.000000
|
||||
lcol: 0
|
||||
label: Reset output
|
||||
name:
|
||||
callback: cb_out_rewind
|
||||
argument: 0
|
||||
|
||||
--------------------
|
||||
class: 11
|
||||
type: 0
|
||||
box: 10.000000 260.000000 80.000000 40.000000
|
||||
boxtype: 1
|
||||
colors: 47 47
|
||||
alignment: 4
|
||||
style: 0
|
||||
size: 11.000000
|
||||
lcol: 0
|
||||
label: Input file...
|
||||
name:
|
||||
callback: cb_in_new
|
||||
argument: 0
|
||||
|
||||
--------------------
|
||||
class: 11
|
||||
type: 0
|
||||
box: 330.000000 260.000000 80.000000 40.000000
|
||||
boxtype: 1
|
||||
colors: 47 47
|
||||
alignment: 4
|
||||
style: 0
|
||||
size: 11.000000
|
||||
lcol: 0
|
||||
label: Output file...
|
||||
name:
|
||||
callback: cb_out_new
|
||||
argument: 0
|
||||
|
||||
--------------------
|
||||
class: 2
|
||||
type: 0
|
||||
box: 10.000000 210.000000 140.000000 40.000000
|
||||
boxtype: 6
|
||||
colors: 47 47
|
||||
alignment: 2
|
||||
style: 0
|
||||
size: 11.000000
|
||||
lcol: 0
|
||||
label: (none)
|
||||
name: in_file
|
||||
callback:
|
||||
argument:
|
||||
|
||||
--------------------
|
||||
class: 2
|
||||
type: 0
|
||||
box: 330.000000 210.000000 140.000000 40.000000
|
||||
boxtype: 6
|
||||
colors: 47 47
|
||||
alignment: 2
|
||||
style: 0
|
||||
size: 11.000000
|
||||
lcol: 0
|
||||
label: (none)
|
||||
name: out_file
|
||||
callback:
|
||||
argument:
|
||||
|
||||
--------------------
|
||||
class: 2
|
||||
type: 0
|
||||
box: 10.000000 160.000000 30.000000 30.000000
|
||||
boxtype: 6
|
||||
colors: 47 47
|
||||
alignment: 2
|
||||
style: 0
|
||||
size: 8.000000
|
||||
lcol: 0
|
||||
label:
|
||||
name: in_info1
|
||||
callback:
|
||||
argument:
|
||||
|
||||
--------------------
|
||||
class: 11
|
||||
type: 0
|
||||
box: 170.000000 260.000000 140.000000 40.000000
|
||||
boxtype: 1
|
||||
colors: 47 47
|
||||
alignment: 4
|
||||
style: 0
|
||||
size: 11.000000
|
||||
lcol: 0
|
||||
label: Quit
|
||||
name:
|
||||
callback: cb_quit
|
||||
argument: 0
|
||||
|
||||
--------------------
|
||||
class: 11
|
||||
type: 4
|
||||
box: 330.000000 60.000000 140.000000 40.000000
|
||||
boxtype: 1
|
||||
colors: 47 47
|
||||
alignment: 4
|
||||
style: 0
|
||||
size: 11.000000
|
||||
lcol: 0
|
||||
label: Back
|
||||
name:
|
||||
callback: cb_out_back
|
||||
argument: 0
|
||||
|
||||
--------------------
|
||||
class: 11
|
||||
type: 4
|
||||
box: 10.000000 60.000000 140.000000 40.000000
|
||||
boxtype: 1
|
||||
colors: 47 47
|
||||
alignment: 4
|
||||
style: 0
|
||||
size: 11.000000
|
||||
lcol: 0
|
||||
label: Back
|
||||
name:
|
||||
callback: cb_in_back
|
||||
argument: 0
|
||||
|
||||
--------------------
|
||||
class: 11
|
||||
type: 4
|
||||
box: 330.000000 110.000000 140.000000 40.000000
|
||||
boxtype: 1
|
||||
colors: 47 47
|
||||
alignment: 4
|
||||
style: 0
|
||||
size: 11.000000
|
||||
lcol: 0
|
||||
label: Forward
|
||||
name:
|
||||
callback: cb_out_skip
|
||||
argument: 0
|
||||
|
||||
--------------------
|
||||
class: 11
|
||||
type: 4
|
||||
box: 170.000000 60.000000 140.000000 40.000000
|
||||
boxtype: 1
|
||||
colors: 47 47
|
||||
alignment: 4
|
||||
style: 0
|
||||
size: 11.000000
|
||||
lcol: 0
|
||||
label: Uncopy
|
||||
name:
|
||||
callback: cb_uncopy
|
||||
argument: 0
|
||||
|
||||
--------------------
|
||||
class: 11
|
||||
type: 0
|
||||
box: 100.000000 260.000000 50.000000 40.000000
|
||||
boxtype: 1
|
||||
colors: 47 47
|
||||
alignment: 4
|
||||
style: 0
|
||||
size: 11.000000
|
||||
lcol: 0
|
||||
label: Close
|
||||
name:
|
||||
callback: cb_in_close
|
||||
argument: 0
|
||||
|
||||
--------------------
|
||||
class: 11
|
||||
type: 0
|
||||
box: 420.000000 260.000000 50.000000 40.000000
|
||||
boxtype: 1
|
||||
colors: 47 47
|
||||
alignment: 4
|
||||
style: 0
|
||||
size: 11.000000
|
||||
lcol: 0
|
||||
label: Close
|
||||
name:
|
||||
callback: cb_out_close
|
||||
argument: 0
|
||||
|
||||
--------------------
|
||||
class: 2
|
||||
type: 0
|
||||
box: 10.000000 310.000000 460.000000 30.000000
|
||||
boxtype: 6
|
||||
colors: 47 47
|
||||
alignment: 2
|
||||
style: 0
|
||||
size: 11.000000
|
||||
lcol: 0
|
||||
label: CMIF Video Editor, by Guido van Rossum
|
||||
name: msg_area
|
||||
callback:
|
||||
argument:
|
||||
|
||||
--------------------
|
||||
class: 2
|
||||
type: 0
|
||||
box: 50.000000 160.000000 60.000004 40.000000
|
||||
boxtype: 6
|
||||
colors: 47 47
|
||||
alignment: 2
|
||||
style: 0
|
||||
size: 11.000000
|
||||
lcol: 0
|
||||
label:
|
||||
name: in_info2
|
||||
callback:
|
||||
argument:
|
||||
|
||||
--------------------
|
||||
class: 2
|
||||
type: 0
|
||||
box: 120.000000 160.000000 30.000000 30.000000
|
||||
boxtype: 6
|
||||
colors: 47 47
|
||||
alignment: 2
|
||||
style: 0
|
||||
size: 8.000000
|
||||
lcol: 0
|
||||
label:
|
||||
name: in_info3
|
||||
callback:
|
||||
argument:
|
||||
|
||||
--------------------
|
||||
class: 2
|
||||
type: 0
|
||||
box: 330.000000 160.000000 30.000000 30.000000
|
||||
boxtype: 6
|
||||
colors: 47 47
|
||||
alignment: 2
|
||||
style: 0
|
||||
size: 8.000000
|
||||
lcol: 0
|
||||
label:
|
||||
name: out_info1
|
||||
callback:
|
||||
argument:
|
||||
|
||||
--------------------
|
||||
class: 2
|
||||
type: 0
|
||||
box: 370.000000 160.000000 60.000004 40.000000
|
||||
boxtype: 6
|
||||
colors: 47 47
|
||||
alignment: 2
|
||||
style: 0
|
||||
size: 11.000000
|
||||
lcol: 0
|
||||
label:
|
||||
name: out_info2
|
||||
callback:
|
||||
argument:
|
||||
|
||||
--------------------
|
||||
class: 2
|
||||
type: 0
|
||||
box: 440.000000 160.000000 30.000000 30.000000
|
||||
boxtype: 6
|
||||
colors: 47 47
|
||||
alignment: 2
|
||||
style: 0
|
||||
size: 8.000000
|
||||
lcol: 0
|
||||
label:
|
||||
name: out_info3
|
||||
callback:
|
||||
argument:
|
||||
|
||||
==============================
|
||||
create_the_forms
|
|
@ -0,0 +1,242 @@
|
|||
import gl, GL
|
||||
import VFile
|
||||
import os
|
||||
|
||||
|
||||
class InputViewer:
|
||||
|
||||
def init(self, filename, title, qsize):
|
||||
try:
|
||||
self.vin = VFile.VinFile().init(filename)
|
||||
except (EOFError, VFile.Error):
|
||||
raise IOError, 'bad video input file'
|
||||
if not title:
|
||||
title = os.path.split(filename)[1]
|
||||
self.filename = filename
|
||||
self.title = title
|
||||
self.qsize = qsize
|
||||
gl.foreground()
|
||||
gl.prefsize(self.vin.width, self.vin.height)
|
||||
self.wid = -1
|
||||
self.reset()
|
||||
return self
|
||||
|
||||
def close(self):
|
||||
self.vin.close()
|
||||
if self.wid > 0:
|
||||
gl.winclose(self.wid)
|
||||
|
||||
def rewind(self):
|
||||
self.vin.rewind()
|
||||
self.reset()
|
||||
|
||||
def getinfo(self):
|
||||
return self.vin.getinfo()
|
||||
|
||||
# Internal
|
||||
def reset(self):
|
||||
if self.wid > 0:
|
||||
gl.winset(self.wid)
|
||||
gl.clear()
|
||||
self.vin.initcolormap()
|
||||
self.queue = []
|
||||
self.qindex = 0
|
||||
self.lost = 0
|
||||
self.lastt = 0
|
||||
self.eofread = 0
|
||||
|
||||
# Internal
|
||||
def fillq(self):
|
||||
if self.qindex < len(self.queue) or self.eofread: return
|
||||
try:
|
||||
t, d, cd = self.vin.getnextframe()
|
||||
except EOFError:
|
||||
self.eofread = 1
|
||||
return
|
||||
dt = t - self.lastt
|
||||
self.lastt = t
|
||||
self.queue.append(dt, d, cd)
|
||||
while len(self.queue) > self.qsize:
|
||||
del self.queue[0]
|
||||
self.qindex = self.qindex - 1
|
||||
self.lost = self.lost + 1
|
||||
|
||||
def show(self):
|
||||
if self.wid < 0:
|
||||
gl.foreground()
|
||||
gl.prefsize(self.vin.width, self.vin.height)
|
||||
self.wid = gl.winopen(self.title)
|
||||
gl.clear()
|
||||
self.vin.initcolormap()
|
||||
self.fillq()
|
||||
gl.winset(self.wid)
|
||||
if self.qindex >= len(self.queue):
|
||||
gl.clear()
|
||||
return
|
||||
dt, d, cd = self.queue[self.qindex]
|
||||
self.vin.showframe(d, cd)
|
||||
|
||||
def redraw(self, wid):
|
||||
if wid == self.wid >= 0:
|
||||
gl.winset(self.wid)
|
||||
gl.reshapeviewport()
|
||||
self.show()
|
||||
|
||||
def get(self):
|
||||
if self.qindex >= len(self.queue):
|
||||
self.fillq()
|
||||
if self.eofread:
|
||||
return None
|
||||
item = self.queue[self.qindex]
|
||||
self.qindex = self.qindex + 1
|
||||
return item
|
||||
|
||||
def backup(self):
|
||||
if self.qindex == 0:
|
||||
return 0
|
||||
self.qindex = self.qindex - 1
|
||||
return 1
|
||||
|
||||
def tell(self):
|
||||
return self.lost + self.qindex
|
||||
|
||||
def qsizes(self):
|
||||
return self.qindex, len(self.queue) - self.qindex
|
||||
|
||||
|
||||
class OutputViewer:
|
||||
|
||||
def init(self, filename, title, qsize):
|
||||
try:
|
||||
self.vout = VFile.VoutFile().init(filename)
|
||||
except (EOFError, VFile.Error):
|
||||
raise IOError, 'bad video output file'
|
||||
if not title:
|
||||
title = os.path.split(filename)[1]
|
||||
self.filename = filename
|
||||
self.title = title
|
||||
self.qsize = qsize
|
||||
gl.foreground()
|
||||
self.wid = -1
|
||||
self.reset()
|
||||
return self
|
||||
|
||||
def close(self):
|
||||
while self.queue:
|
||||
self.flushq()
|
||||
self.vout.close()
|
||||
if self.wid > 0:
|
||||
gl.winclose(self.wid)
|
||||
|
||||
def rewind(self):
|
||||
info = self.vout.getinfo()
|
||||
self.vout.close()
|
||||
self.vout = VFile.VoutFile().init(self.filename)
|
||||
self.vout.setinfo(info)
|
||||
self.reset()
|
||||
|
||||
def getinfo(self):
|
||||
return self.vout.getinfo()
|
||||
|
||||
def setinfo(self, info):
|
||||
if info == self.getinfo(): return # No change
|
||||
self.vout.setinfo(info)
|
||||
if self.wid > 0:
|
||||
gl.winclose(self.wid)
|
||||
self.wid = -1
|
||||
|
||||
# Internal
|
||||
def reset(self):
|
||||
if self.wid > 0:
|
||||
gl.winset(self.wid)
|
||||
gl.clear()
|
||||
self.vout.initcolormap()
|
||||
self.queue = []
|
||||
self.spares = []
|
||||
self.written = 0
|
||||
self.lastt = 0
|
||||
|
||||
# Internal
|
||||
def flushq(self):
|
||||
if self.written == 0:
|
||||
self.vout.writeheader()
|
||||
dt, d, cd = self.queue[0]
|
||||
self.lastt = self.lastt + dt
|
||||
self.vout.writeframe(self.lastt, d, cd)
|
||||
del self.queue[0]
|
||||
self.written = self.written + 1
|
||||
|
||||
def show(self):
|
||||
if self.wid < 0:
|
||||
gl.foreground()
|
||||
gl.prefsize(self.vout.width, self.vout.height)
|
||||
self.wid = gl.winopen(self.title)
|
||||
gl.clear()
|
||||
self.vout.initcolormap()
|
||||
gl.winset(self.wid)
|
||||
if not self.queue:
|
||||
gl.clear()
|
||||
return
|
||||
dt, d, cd = self.queue[-1]
|
||||
self.vout.showframe(d, cd)
|
||||
|
||||
def redraw(self, wid):
|
||||
if wid == self.wid >= 0:
|
||||
gl.winset(self.wid)
|
||||
gl.reshapeviewport()
|
||||
self.show()
|
||||
|
||||
def backup(self):
|
||||
if len(self.queue) < 1: return 0
|
||||
self.spares.insert(0, self.queue[-1])
|
||||
del self.queue[-1]
|
||||
return 1
|
||||
|
||||
def forward(self):
|
||||
if not self.spares: return 0
|
||||
self.queue.append(self.spares[0])
|
||||
del self.spares[0]
|
||||
return 1
|
||||
|
||||
def put(self, item):
|
||||
self.queue.append(item)
|
||||
self.spares = []
|
||||
while len(self.queue) > self.qsize:
|
||||
self.flushq()
|
||||
|
||||
def tell(self):
|
||||
return self.written + len(self.queue)
|
||||
|
||||
def qsizes(self):
|
||||
return len(self.queue), len(self.spares)
|
||||
|
||||
|
||||
def test():
|
||||
import sys
|
||||
a = InputViewer().init(sys.argv[1], '')
|
||||
b = OutputViewer().init(sys.argv[2], '')
|
||||
b.setinfo(a.getinfo())
|
||||
|
||||
while 1:
|
||||
a.show()
|
||||
data = a.get()
|
||||
if data is None:
|
||||
break
|
||||
b.put(data)
|
||||
b.show()
|
||||
|
||||
while a.backup():
|
||||
data = a.get()
|
||||
b.put(data)
|
||||
b.show()
|
||||
if a.backup(): a.show()
|
||||
|
||||
while 1:
|
||||
data = a.get()
|
||||
if data is None:
|
||||
break
|
||||
b.put(data)
|
||||
b.show()
|
||||
a.show()
|
||||
|
||||
b.close()
|
|
@ -200,13 +200,15 @@ def playonce(vin):
|
|||
vin.magnify = magnify
|
||||
|
||||
if threading:
|
||||
MAXSIZE = 20 # Don't read ahead too much
|
||||
import thread
|
||||
queue = []
|
||||
import Queue
|
||||
queue = Queue.Queue().init(MAXSIZE)
|
||||
stop = []
|
||||
thread.start_new_thread(read_ahead, (vin, queue, stop))
|
||||
# Get the read-ahead thread going
|
||||
while len(queue) < 5 and None not in queue:
|
||||
time.millisleep(10)
|
||||
while queue.qsize() < MAXSIZE/2 and not stop:
|
||||
time.millisleep(100)
|
||||
|
||||
tin = 0
|
||||
told = 0
|
||||
|
@ -227,21 +229,18 @@ def playonce(vin):
|
|||
if debug: sys.stderr.write('\n')
|
||||
if threading:
|
||||
stop.append(None)
|
||||
while len(stop) < 2:
|
||||
time.millisleep(10)
|
||||
while 1:
|
||||
item = queue.get()
|
||||
if item == None: break
|
||||
return (dev != LEFTMOUSE)
|
||||
if dev == REDRAW:
|
||||
gl.reshapeviewport()
|
||||
if data: vin.showframe(data, cdata)
|
||||
if threading:
|
||||
if not queue:
|
||||
if debug: sys.stderr.write('.')
|
||||
time.millisleep(10)
|
||||
continue
|
||||
q0 = queue[0]
|
||||
if q0 == None: break
|
||||
del queue[0]
|
||||
tin, data, cdata = q0
|
||||
if debug and queue.empty(): sys.stderr.write('.')
|
||||
item = queue.get()
|
||||
if item == None: break
|
||||
tin, data, cdata = item
|
||||
else:
|
||||
try:
|
||||
tin, size, csize = vin.getnextframeheader()
|
||||
|
@ -301,13 +300,13 @@ def playonce(vin):
|
|||
|
||||
def read_ahead(vin, queue, stop):
|
||||
try:
|
||||
while not stop: queue.append(vin.getnextframe())
|
||||
while not stop: queue.put(vin.getnextframe())
|
||||
except EOFError:
|
||||
queue.append(None)
|
||||
pass
|
||||
queue.put(None)
|
||||
stop.append(None)
|
||||
|
||||
|
||||
|
||||
# Don't forget to call the main program
|
||||
|
||||
try:
|
||||
|
|
Loading…
Reference in New Issue