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

View File

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

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