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:
Guido van Rossum 1992-08-25 12:29:30 +00:00
parent e1b4d7ce14
commit 9ee7e15966
6 changed files with 1080 additions and 217 deletions

View file

@ -100,6 +100,10 @@ Vtime.py (unrelated to vtime!!!) Copy a video file,
manipulating the time codes (e.g. faster/slower, or manipulating the time codes (e.g. faster/slower, or
regenerate time codes, or drop frames too close apart) 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 The following are C programs, either for efficiency or because they
need to link with a C library: need to link with a C library:

View file

@ -52,116 +52,12 @@ def conv_rgb8(rgb,d1,d2):
# xorigin, yorigin # xorigin, yorigin
# fallback # 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): # XXX it's a total mess now -- VFile is a new base class
if filename == '-': # XXX to support common functionality (e.g. showframe)
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
class VFile:
# #
# getinfo returns all info pertaining to a film. The returned tuple # getinfo returns all info pertaining to a film. The returned tuple
@ -179,96 +75,12 @@ class VinFile:
self.fp.seek(0) self.fp.seek(0)
x = self.initfp(self.fp, self.filename) x = self.initfp(self.fp, self.filename)
def rewind(self): def setconvcolor(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: try:
self.fp.seek(size + chromsize, 1) # Relative seek self.convcolor = eval('conv_'+self.format)
except: except:
# Assume it's a pipe -- read the data to discard it raise Error, \
dummy = self.fp.read(size + chromsize) self.filename + ': unknown colorsys ' + self.format
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
def showframe(self, data, chromdata): def showframe(self, data, chromdata):
w, h, pf = self.width, self.height, self.packfactor w, h, pf = self.width, self.height, self.packfactor
@ -369,6 +181,205 @@ class VinFile:
gl.mapcolor(index, r, g, b) gl.mapcolor(index, r, g, b)
void = gl.gflush() 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 # 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 # Notably it will accept almost any garbage and write it to the video
# output file # output file
# #
class VoutFile: class VoutFile(VFile):
def init(self, filename): def init(self, filename):
if filename == '-': if filename == '-':
return self.initfp(sys.stdout, filename) return self.initfp(sys.stdout, filename)
@ -434,21 +445,21 @@ class VoutFile:
self.offset = 0 self.offset = 0
self.chrompack = 0 self.chrompack = 0
self.headerwritten = 0 self.headerwritten = 0
self.quiet = 0
self.magnify = 1
self.setconvcolor()
self.xorigin = self.yorigin = 0
return self return self
def close(self): def close(self):
self.fp.close() self.fp.close()
x = self.initfp(None, None) 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): def setinfo(self, values):
self.format, self.width, self.height, self.packfactor,\ self.format, self.width, self.height, self.packfactor,\
self.c0bits, self.c1bits, self.c2bits, self.offset, \ self.c0bits, self.c1bits, self.c2bits, self.offset, \
self.chrompack = values self.chrompack = values
self.setconvcolor()
def writeheader(self): def writeheader(self):
self.headerwritten = 1 self.headerwritten = 1

247
Demo/sgi/video/Vedit.py Executable file
View file

@ -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()

360
Demo/sgi/video/VeditForm.fd Normal file
View file

@ -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

242
Demo/sgi/video/Viewer.py Executable file
View file

@ -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()

View file

@ -200,13 +200,15 @@ def playonce(vin):
vin.magnify = magnify vin.magnify = magnify
if threading: if threading:
MAXSIZE = 20 # Don't read ahead too much
import thread import thread
queue = [] import Queue
queue = Queue.Queue().init(MAXSIZE)
stop = [] stop = []
thread.start_new_thread(read_ahead, (vin, queue, stop)) thread.start_new_thread(read_ahead, (vin, queue, stop))
# Get the read-ahead thread going # Get the read-ahead thread going
while len(queue) < 5 and None not in queue: while queue.qsize() < MAXSIZE/2 and not stop:
time.millisleep(10) time.millisleep(100)
tin = 0 tin = 0
told = 0 told = 0
@ -227,21 +229,18 @@ def playonce(vin):
if debug: sys.stderr.write('\n') if debug: sys.stderr.write('\n')
if threading: if threading:
stop.append(None) stop.append(None)
while len(stop) < 2: while 1:
time.millisleep(10) item = queue.get()
if item == None: break
return (dev != LEFTMOUSE) return (dev != LEFTMOUSE)
if dev == REDRAW: if dev == REDRAW:
gl.reshapeviewport() gl.reshapeviewport()
if data: vin.showframe(data, cdata) if data: vin.showframe(data, cdata)
if threading: if threading:
if not queue: if debug and queue.empty(): sys.stderr.write('.')
if debug: sys.stderr.write('.') item = queue.get()
time.millisleep(10) if item == None: break
continue tin, data, cdata = item
q0 = queue[0]
if q0 == None: break
del queue[0]
tin, data, cdata = q0
else: else:
try: try:
tin, size, csize = vin.getnextframeheader() tin, size, csize = vin.getnextframeheader()
@ -301,13 +300,13 @@ def playonce(vin):
def read_ahead(vin, queue, stop): def read_ahead(vin, queue, stop):
try: try:
while not stop: queue.append(vin.getnextframe()) while not stop: queue.put(vin.getnextframe())
except EOFError: except EOFError:
queue.append(None) pass
queue.put(None)
stop.append(None) stop.append(None)
# Don't forget to call the main program # Don't forget to call the main program
try: try: