VFile: added new formats 'jpeg' and 'jpeggrey'. Decompression is done

using module 'jpeg' by the Displayer class.  (Unfortunately it's too
slow for real time.)  Print file size in printinfo() method.

Vinfo: added -t option (terse -- one line per file) and usage message.

Vtime: use BasicV{in,out}File classes -- the minimum needed.

Vmkjpeg, Vunjpeg: new utilities for jpeg (de)compression.
This commit is contained in:
Guido van Rossum 1992-09-29 13:40:47 +00:00
parent 3165fe6a56
commit 9e3f335bea
6 changed files with 299 additions and 33 deletions

View File

@ -24,12 +24,13 @@ editor, not in this directory but in /ufs/guido/mm/.)
When we got our own Indigo entry-level video board (in June 1992) and
a version of the Irix video library that supported capturing PAL
format (in August 1992), Sjoerd added an interface to the video
library to Python (sv) and Guido wrote Vrec.py (based upon a
still frame grabber by Sjoerd, in turn based upon SGI demo code in C)
to record a movie using it. Vrec was soon followed by modernized
library to Python (sv) and Guido wrote Vrec.py (based upon a still
frame grabber by Sjoerd, in turn based upon SGI demo code in C) to
record a movie using it. Vrec was soon followed by modernized
versions of the other programs (Vinfo, Vplay, Vtime) and an
interactive editor (Vedit). Finally, VFile was rewritten for more
modularity, functionality and robustness.
modularity, functionality and robustness, and various other tools were
added as needed.
Guido van Rossum
Jack Jansen
@ -39,7 +40,8 @@ modularity, functionality and robustness.
Overview of files
-----------------
cmif-film.ms description of the CMIF video file format
cmif-film.ms description of the CMIF video file format (a little
out of date)
These are programs with a command line interface:
@ -55,6 +57,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)
Vmkjpeg.py compress an rgb or grey video file to jpeg[grey] format
Vunjpeg.py expand a jpeg[grey] video file to rgb or grey format
Vedit.py interactive video editing program
Vsend.py unicast or multicast live video as UDP packets

View File

@ -69,6 +69,11 @@ def conv_rgb8(rgb, d1, d2):
b = (rgb >> 3) & 0x03
return (r/7.0, g/7.0, b/3.0)
def conv_jpeg(r, g, b):
raise Error, 'Attempt to make RGB colormap (jpeg)'
conv_jpeggrey = conv_grey
# Choose one of the above based upon a color system name
@ -107,6 +112,11 @@ def inv_rgb8(r, g, b):
rgb = ((r&7) << 5) | ((b&3) << 3) | (g&7)
return rgb / 255.0, 0, 0
def inv_jpeg(r, g, b):
raise Error, 'Attempt to invert RGB colormap (jpeg)'
inv_jpeggrey = inv_grey
# Choose one of the above based upon a color system name
@ -175,6 +185,13 @@ def grab_hls(w, h, pf):
def grab_hsv(w, h, pf):
raise Error, 'Sorry, grabbing hsv not implemented'
def grab_jpeg(w, h, pf):
# XXX Ought to grab rgb and compress it
raise Error, 'sorry, grabbing jpeg not implemented'
def grab_jpeggrey(w, h, pf):
raise Error, 'sorry, grabbing jpeggrey not implemented'
# Choose one of the above based upon a color system name
@ -196,7 +213,7 @@ class VideoParams:
def init(self):
# Essential parameters
self.format = 'grey' # color system used
# Choose from: 'rgb', 'rgb8', 'hsv', 'yiq', 'hls'
# Choose from: grey, rgb, rgb8, hsv, yiq, hls, jpeg, jpeggrey
self.width = 0 # width of frame
self.height = 0 # height of frame
self.packfactor = 1 # expansion using rectzoom
@ -286,12 +303,22 @@ class Displayer(VideoParams):
(0,0,self.width,self.height))
def showpartframe(self, data, chromdata, (x,y,w,h)):
pf = self.packfactor
if self.format in ('jpeg', 'jpeggrey'):
import jpeg
data, width, height, bytes = jpeg.decompress(data)
if self.format == 'jpeg':
b = 4
else:
b = 1
width, height = width*pf, height*pf
if (width, height, bytes) <> (w, h, b):
raise Error, 'jpeg data has wrong size'
if not self.colormapinited:
self.initcolormap()
if self.fixcolor0:
gl.mapcolor(self.color0)
self.fixcolor0 = 0
pf = self.packfactor
factor = self.magnify
if pf: factor = factor * pf
if chromdata and not self.skipchrom:
@ -326,7 +353,7 @@ class Displayer(VideoParams):
self.colormapinited = 1
self.color0 = None
self.fixcolor0 = 0
if self.format == 'rgb':
if self.format in ('rgb', 'jpeg'):
gl.RGBmode()
gl.gconfig()
gl.RGBcolor(200, 200, 200) # XXX rather light grey
@ -509,11 +536,11 @@ def readfileheader(fp, filename):
format, rest = eval(line[:-1])
except:
raise Error, filename + ': Bad 3.0 color info'
if format == 'rgb':
if format in ('rgb', 'jpeg'):
c0bits = c1bits = c2bits = 0
chrompack = 0
offset = 0
elif format == 'grey':
elif format in ('grey', 'jpeggrey'):
c0bits = rest
c1bits = c2bits = 0
chrompack = 0
@ -606,17 +633,17 @@ def writefileheader(fp, values):
#
# Write color encoding info
#
if format == 'rgb':
data = ('rgb', 0)
elif format == 'grey':
data = ('grey', c0bits)
if format in ('rgb', 'jpeg'):
data = (format, 0)
elif format in ('grey', 'jpeggrey'):
data = (format, c0bits)
else:
data = (format, (c0bits, c1bits, c2bits, chrompack, offset))
fp.write(`data`+'\n')
#
# Write frame geometry info
#
if format == 'rgb':
if format in ('rgb', 'jpeg'):
packfactor = 0
elif packfactor == 0:
packfactor = 1
@ -699,6 +726,7 @@ class BasicVinFile(VideoParams):
def printinfo(self):
print 'File: ', self.filename
print 'Size: ', getfilesize(self.filename)
print 'Version: ', self.version
VideoParams.printinfo(self)
@ -765,6 +793,17 @@ class BasicVinFile(VideoParams):
self.framecount = self.framecount + 1
# Subroutine to return a file's size in bytes
def getfilesize(filename):
import os, stat
try:
st = os.stat(filename)
return st[stat.ST_SIZE]
except os.error:
return 0
# Derived class implementing random access and index cached in the file
class RandomVinFile(BasicVinFile):

View File

@ -20,6 +20,7 @@ import sys
sys.path.append('/ufs/guido/src/video')
import VFile
import getopt
import string
# Global options
@ -27,22 +28,34 @@ import getopt
short = 0
quick = 0
delta = 0
terse = 0
maxwidth = 10
# Main program -- mostly command line parsing
def main():
global short, quick, delta
opts, args = getopt.getopt(sys.argv[1:], 'dqs')
global short, quick, delta, terse, maxwidth
try:
opts, args = getopt.getopt(sys.argv[1:], 'dqst')
except getopt.error, msg:
sys.stdout = sys.stderr
print msg
print 'usage: Vinfo [-d] [-q] [-s] [-t] [file] ...'
sys.exit(2)
for opt, arg in opts:
if opt == '-q':
quick = 1
elif opt == '-d':
if opt == '-d':
delta = 1
elif opt == '-s':
if opt == '-s':
short = 1
if opt == '-t':
terse = short = 1
if not args:
args = ['film.video']
for filename in args:
maxwidth = max(maxwidth, len(filename))
sts = 0
for filename in args:
if process(filename):
@ -65,17 +78,31 @@ def process(filename):
sys.stderr.write(filename + ': EOF in video file\n')
return 1
vin.printinfo()
if terse:
print string.ljust(filename, maxwidth),
kbytes = (VFile.getfilesize(filename) + 1023) / 1024
print string.rjust(`kbytes`, 5) + 'K',
print ' ', string.ljust(`vin.version`, 5),
print string.ljust(vin.format, 8),
print string.rjust(`vin.width`, 4),
print string.rjust(`vin.height`, 4),
sys.stdout.flush()
else:
vin.printinfo()
if quick:
if terse:
print
vin.close()
return
return 0
try:
vin.readcache()
print '[Using cached index]'
if not terse:
print '[Using cached index]'
except VFile.Error:
print '[Constructing index on the fly]'
if not terse:
print '[Constructing index on the fly]'
if not short:
if delta:
@ -107,16 +134,21 @@ def process(filename):
if not short: print
print 'Total', n, 'frames in', t*0.001, 'sec.',
if t: print '-- average', int(n*10000.0/t)*0.1, 'frames/sec',
print
print 'Total data', 0.1 * int(datasize / 102.4), 'Kbytes',
if t:
print '-- average',
print 0.1 * int(datasize / 0.1024 / t), 'Kbytes/sec',
print
if terse:
print string.rjust(`n`, 6),
print string.rjust(`int(n*10000.0/t)*0.1`, 5)
else:
print 'Total', n, 'frames in', t*0.001, 'sec.',
if t: print '-- average', int(n*10000.0/t)*0.1, 'frames/sec',
print
print 'Total data', 0.1 * int(datasize / 102.4), 'Kbytes',
if t:
print '-- average',
print 0.1 * int(datasize / 0.1024 / t), 'Kbytes/sec',
print
vin.close()
return 0
# Don't forget to call the main program

92
Demo/sgi/video/Vmkjpeg.py Executable file
View File

@ -0,0 +1,92 @@
#!/ufs/guido/bin/sgi/python
# Compress an rgb or grey video file to jpeg format
# Usage:
#
# Vmkjpeg [infile [outfile]]
# Options:
#
# infile : input file (default film.video)
# outfile : output file (default out.video)
import sys
import jpeg
sys.path.append('/ufs/guido/src/video')
import VFile
# Main program -- mostly command line parsing
def main():
args = sys.argv[1:]
if len(args) < 1:
args.append('film.video')
if len(args) < 2:
args.append('out.video')
if len(args) > 2:
sys.stderr.write('usage: Vmkjpeg [infile [outfile]]\n')
sys.exit(2)
sts = process(args[0], args[1])
sys.exit(sts)
# Copy one file to another
def process(infilename, outfilename):
try:
vin = VFile.BasicVinFile().init(infilename)
except IOError, msg:
sys.stderr.write(infilename + ': I/O error: ' + `msg` + '\n')
return 1
except VFile.Error, msg:
sys.stderr.write(msg + '\n')
return 1
except EOFError:
sys.stderr.write(infilename + ': EOF in video file\n')
return 1
try:
vout = VFile.BasicVoutFile().init(outfilename)
except IOError, msg:
sys.stderr.write(outfilename + ': I/O error: ' + `msg` + '\n')
return 1
info = vin.getinfo()
if info[0] == 'rgb':
width, height = vin.getsize()
bytes = 4
format = 'jpeg'
elif info[0] == 'grey':
width, height = vin.getsize()
pf = vin.packfactor
width, height = width / pf, height / pf
bytes = 1
format = 'jpeggrey'
else:
sys.stderr.write('Vmkjpeg: input not in rgb or grey format\n')
return 1
info = (format,) + info[1:]
vout.setinfo(info)
vout.writeheader()
n = 0
try:
while 1:
t, data, cdata = vin.getnextframe()
n = n + 1
sys.stderr.write('Frame ' + `n` + '...')
data = jpeg.compress(data, width, height, bytes)
vout.writeframe(t, data, None)
sys.stderr.write('\n')
except EOFError:
pass
return 0
# Don't forget to call the main program
main()

View File

@ -65,7 +65,7 @@ def main():
def process(infilename, outfilename):
try:
vin = VFile.VinFile().init(infilename)
vin = VFile.BasicVinFile().init(infilename)
except IOError, msg:
sys.stderr.write(infilename + ': I/O error: ' + `msg` + '\n')
return 1
@ -77,7 +77,7 @@ def process(infilename, outfilename):
return 1
try:
vout = VFile.VoutFile().init(outfilename)
vout = VFile.BasicVoutFile().init(outfilename)
except IOError, msg:
sys.stderr.write(outfilename + ': I/O error: ' + `msg` + '\n')
return 1

97
Demo/sgi/video/Vunjpeg.py Executable file
View File

@ -0,0 +1,97 @@
#!/ufs/guido/bin/sgi/python
# Decompress a jpeg or jpeggrey video file to rgb format
# Usage:
#
# Vunjpeg [infile [outfile]]
# Options:
#
# infile : input file (default film.video)
# outfile : output file (default out.video)
import sys
import jpeg
sys.path.append('/ufs/guido/src/video')
import VFile
# Main program -- mostly command line parsing
def main():
args = sys.argv[1:]
if len(args) < 1:
args.append('film.video')
if len(args) < 2:
args.append('out.video')
if len(args) > 2:
sys.stderr.write('usage: Vunjpeg [infile [outfile]]\n')
sys.exit(2)
sts = process(args[0], args[1])
sys.exit(sts)
# Copy one file to another
def process(infilename, outfilename):
try:
vin = VFile.BasicVinFile().init(infilename)
except IOError, msg:
sys.stderr.write(infilename + ': I/O error: ' + `msg` + '\n')
return 1
except VFile.Error, msg:
sys.stderr.write(msg + '\n')
return 1
except EOFError:
sys.stderr.write(infilename + ': EOF in video file\n')
return 1
try:
vout = VFile.BasicVoutFile().init(outfilename)
except IOError, msg:
sys.stderr.write(outfilename + ': I/O error: ' + `msg` + '\n')
return 1
info = vin.getinfo()
if info[0] == 'jpeg':
format = 'rgb'
width, height = vin.getsize()
bytes = 4
elif info[0] == 'jpeggrey':
format = 'grey'
width, height = vin.getsize()
pf = vin.packfactor
width, height = width/pf, height/pf
bytes = 1
else:
sys.stderr.write('Vunjpeg: input not in jpeg[grey] format\n')
return 1
info = (format,) + info[1:]
vout.setinfo(info)
vout.writeheader()
sts = 0
n = 0
try:
while 1:
t, data, cdata = vin.getnextframe()
n = n + 1
sys.stderr.write('Frame ' + `n` + '...')
data, w, h, b = jpeg.decompress(data)
if (w, h, b) <> (width, height, bytes):
sys.stderr.write('jpeg data has wrong size\n')
sts = 1
else:
vout.writeframe(t, data, None)
sys.stderr.write('\n')
except EOFError:
pass
return sts
# Don't forget to call the main program
main()