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...).
diff --git a/Demo/sgi/video/README b/Demo/sgi/video/README
index eedb85f..85855a9 100644
--- a/Demo/sgi/video/README
+++ b/Demo/sgi/video/README
@@ -100,6 +100,10 @@
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:
diff --git a/Demo/sgi/video/VFile.py b/Demo/sgi/video/VFile.py
index 17f677f..b16b2ab 100755
--- a/Demo/sgi/video/VFile.py
+++ b/Demo/sgi/video/VFile.py
@@ -52,116 +52,12 @@
# 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)
+# XXX it's a total mess now -- VFile is a new base class
+# XXX to support common functionality (e.g. showframe)
- 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
@@ -179,96 +75,12 @@
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 @@
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 @@
# 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 @@
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
diff --git a/Demo/sgi/video/Vedit.py b/Demo/sgi/video/Vedit.py
new file mode 100755
index 0000000..fa8631a
--- /dev/null
+++ b/Demo/sgi/video/Vedit.py
@@ -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()
diff --git a/Demo/sgi/video/VeditForm.fd b/Demo/sgi/video/VeditForm.fd
new file mode 100644
index 0000000..6bffa98
--- /dev/null
+++ b/Demo/sgi/video/VeditForm.fd
@@ -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
diff --git a/Demo/sgi/video/Viewer.py b/Demo/sgi/video/Viewer.py
new file mode 100755
index 0000000..6203562
--- /dev/null
+++ b/Demo/sgi/video/Viewer.py
@@ -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()
diff --git a/Demo/sgi/video/Vplay.py b/Demo/sgi/video/Vplay.py
index 5ab623d..b8d06a1 100755
--- a/Demo/sgi/video/Vplay.py
+++ b/Demo/sgi/video/Vplay.py
@@ -200,13 +200,15 @@
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 @@
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 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: