]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Added mono, grey2 and grey4 formats
authorJack Jansen <jack.jansen@cwi.nl>
Wed, 23 Dec 1992 15:37:20 +0000 (15:37 +0000)
committerJack Jansen <jack.jansen@cwi.nl>
Wed, 23 Dec 1992 15:37:20 +0000 (15:37 +0000)
Demo/sgi/video/LiveVideoIn.py
Demo/sgi/video/LiveVideoOut.py
Demo/sgi/video/VFile.py
Demo/sgi/video/Vrec.py
Demo/sgi/video/Vrecc.py [new file with mode: 0755]

index d0ea8587272eb7c20fcb2bc49a41b2944f655281..47fae67fb6bd39d909894115351003619e476686 100755 (executable)
@@ -43,10 +43,10 @@ class LiveVideoIn:
                if realvw < vw:
                        realvw = vw
                self.realwidth, self.realheight = v.QuerySize(realvw, vh)
-               if not type in ('rgb8', 'grey', 'mono'):
-                       raise 'Incorrent video data type'
+               if not type in ('rgb8', 'grey', 'mono', 'grey2', 'grey4'):
+                       raise 'Incorrent video data type', type
                self.type = type
-               if type in ('grey', 'mono'):
+               if type in ('grey', 'grey4', 'grey2', 'mono'):
                        v.SetParam([SV.COLOR, SV.MONO, SV.INPUT_BYPASS, 1])
                else:
                        v.SetParam([SV.COLOR, SV.DEFAULT_COLOR, \
@@ -116,11 +116,21 @@ class LiveVideoIn:
                        if self.type == 'mono':
                                self.data = imageop.dither2mono(self.data, \
                                          self.width, self.height)
+                       elif self.type == 'grey2':
+                               self.data = imageop.dither2grey2(self.data, \
+                                         self.width, self.height)
+                       elif self.type == 'grey4':
+                               self.data = imageop.grey2grey4(self.data, \
+                                         self.width, self.height)
                data = self.data[self.dataoffset:self.dataoffset+self.pktsize]
                lpos = self.lpos
                self.dataoffset = self.dataoffset + self.pktsize
                if self.type == 'mono':
                        self.lpos = self.lpos + self.lpp*8
+               elif self.type == 'grey2':
+                       self.lpos = self.lpos + self.lpp*4
+               elif self.type == 'grey4':
+                       self.lpos = self.lpos + self.lpp*2
                else:
                        self.lpos = self.lpos + self.lpp
                return lpos, data
index 23d03da845330ef48551686b013a8c23ce01a402..0ac64d2cdc5df04c0dcb8b013aa4ff7e7d738733 100755 (executable)
@@ -18,8 +18,8 @@ class LiveVideoOut:
                self.vw = vw
                self.vh = vh
                self.disp = Displayer().init()
-               if not type in ('rgb8', 'grey', 'mono'):
-                       raise 'Incorrent live video output type'
+               if not type in ('rgb8', 'grey', 'mono', 'grey2', 'grey4'):
+                       raise 'Incorrent live video output type', type
                info = (type, vw, vh, 1, 8, 0, 0, 0, 0)
                self.disp.setinfo(info)
                self.wid = wid
@@ -62,6 +62,10 @@ class LiveVideoOut:
                        # Unfortunately size-check is difficult for
                        # packed video
                        nline = (len(data)*8)/self.vw
+               elif self.disp.format == 'grey2':
+                       nline = (len(data)*4)/self.vw
+               elif self.disp.format == 'grey4':
+                       nline = (len(data)*2)/self.vw
                else:
                        nline = len(data)/self.vw
                        if nline*self.vw <> len(data):
@@ -76,3 +80,16 @@ class LiveVideoOut:
 
        def close(self):
                pass
+
+       # Call this to set optional mirroring of video
+       def setmirror(self, mirrored):
+               f, w, h, pf, c0, c1, c2, o, cp = self.disp.getinfo()
+               if type(pf) == type(()):
+                       xpf, ypf = pf
+               else:
+                       xpf = ypf = pf
+               xpf = abs(xpf)
+               if mirrored:
+                       xpf = -xpf
+               info = (f, w, h, (xpf, ypf), c0, c1, c2, o, cp)
+               self.disp.setinfo(inf0)
index 5c05ed0cec0185e554f1b37fff81e91a72981428..3d2bd8ce81729c36d93f33cb8df2be2ee9735d94 100755 (executable)
@@ -22,6 +22,7 @@ import sys
 import gl
 import GL
 import colorsys
+import imageop
 
 
 # Exception raised for various occasions
@@ -50,6 +51,12 @@ MAXMAP = 4096 - 256
 def conv_grey(l, x, y):
        return colorsys.yiq_to_rgb(l, 0, 0)
 
+def conv_grey4(l, x, y):
+       return colorsys.yiq_to_rgb(l*17, 0, 0)
+
+def conv_mono(l, x, y):
+       return colorsys.yiq_to_rgb(l*255, 0, 0)
+
 def conv_yiq(y, i, q):
        return colorsys.yiq_to_rgb(y, (i-0.5)*1.2, q-0.5)
 
@@ -73,7 +80,7 @@ def conv_jpeg(r, g, b):
        raise Error, 'Attempt to make RGB colormap (jpeg)'
 
 conv_jpeggrey = conv_grey
-conv_mono = conv_grey
+conv_grey2 = conv_grey
 
 
 # Choose one of the above based upon a color system name
@@ -144,6 +151,15 @@ def is_entry_indigo():
        b = gl.getgdesc(GL.GD_BITS_NORM_SNG_BLUE)
        return (r, g, b) == (3, 3, 2)
 
+#
+# Predicate function to see whether this machine supports pixmode(PM_SIZE)
+# with values 1 or 4.
+#
+# XXX Temporarily disabled, since it is unclear which machines support
+# XXX which pixelsizes.
+#
+def support_packed_pixels():
+       return 0   # To be architecture-dependent
 
 # Routines to grab data, per color system (only a few really supported).
 # (These functions are used via eval with a constructed argument!)
@@ -215,7 +231,7 @@ class VideoParams:
                # Essential parameters
                self.format = 'grey'    # color system used
                # Choose from: grey, rgb, rgb8, hsv, yiq, hls, jpeg, jpeggrey,
-               #              mono
+               #              mono, grey2, grey4
                self.width = 0          # width of frame
                self.height = 0         # height of frame
                self.packfactor = 1     # expansion using rectzoom
@@ -264,6 +280,26 @@ class VideoParams:
                print 'Bits:    ', self.c0bits, self.c1bits, self.c2bits
                print 'Offset:  ', self.offset
 
+       # Calculate data size, if possible
+       def calcframesize(self):
+               if self.format == 'rgb':
+                       return self.width*self.height*4
+               if self.format in ('jpeg', 'jpeggrey'):
+                       raise CallError
+               if type(self.packfactor) == type(()):
+                       xpf, ypf = self.packfactor
+               else:
+                       xpf = ypf = self.packfactor
+               if ypf < 0: ypf = -ypf
+               size = (self.width/xpf)*(self.height/ypf)
+               if self.format == 'grey4':
+                       size = (size+1)/2
+               elif self.format == 'grey2':
+                       size = (size+3)/4
+               elif self.format == 'mono':
+                       size = (size+7)/8
+               return size
+
 
 # Class to display video frames in a window.
 # It is the caller's responsibility to ensure that the correct window
@@ -287,6 +323,7 @@ class Displayer(VideoParams):
                self.skipchrom = 0      # don't skip chrominance data
                self.color0 = None      # magic, used by clearto()
                self.fixcolor0 = 0      # don't need to fix color0
+               self.mustunpack = (not support_packed_pixels())
                return self
 
        # setinfo() must reset some internal flags
@@ -306,34 +343,65 @@ class Displayer(VideoParams):
 
        def showpartframe(self, data, chromdata, (x,y,w,h)):
                pf = self.packfactor
+               pmsize = 8
+               if pf:
+                       if type(pf) == type(()):
+                               xpf, ypf = pf
+                       else:
+                               xpf = ypf = pf
+                       if ypf < 0:
+                               gl.pixmode(GL.PM_TTOB, 1)
+                               ypf = -ypf
+                       if xpf < 0:
+                               gl.pixmode(GL.PM_RTOL, 1)
+                               xpf = -xpf
+               else:
+                       xpf = ypf = 1
                if self.format in ('jpeg', 'jpeggrey'):
                        import jpeg
                        data, width, height, bytes = jpeg.decompress(data)
                        if self.format == 'jpeg':
                                b = 4
-                               p = 1
+                               xp = yp = 1
                        else:
                                b = 1
-                               p = pf
-                       if (width, height, bytes) <> (w/p, h/p, b):
+                               xp = xpf
+                               yp = ypf
+                       if (width, height, bytes) <> (w/xp, h/yp, b):
                                raise Error, 'jpeg data has wrong size'
-               elif self.format == 'mono':
-                       import imageop
-                       data = imageop.mono2grey(data, w, h, 0x20, 0xdf)
+               elif self.format in ('mono', 'grey4'):
+                       if self.mustunpack:
+                               if self.format == 'mono':
+                                       data = imageop.mono2grey(data, \
+                                                 w/xpf, h/ypf, 0x20, 0xdf)
+                               elif self.format == 'grey4':
+                                       data = imageop.grey42grey(data, \
+                                                 w/xpf, h/ypf)
+                       else:
+                               # We don't need to unpack, the hardware
+                               # can do it.
+                               if self.format == 'mono':
+                                       pmsize = 1
+                               else:
+                                       pmsize = 4
+               elif self.format == 'grey2':
+                       data = imageop.grey22grey(data, w/xpf, h/ypf)
                if not self.colormapinited:
                        self.initcolormap()
                if self.fixcolor0:
                        gl.mapcolor(self.color0)
                        self.fixcolor0 = 0
-               factor = self.magnify
-               if pf: factor = factor * pf
+               xfactor = yfactor = self.magnify
+               if pf:
+                       xfactor = xfactor * xpf
+                       yfactor = yfactor * ypf
                if chromdata and not self.skipchrom:
                        cp = self.chrompack
-                       cx = int(x*factor*cp) + self.xorigin
-                       cy = int(y*factor*cp) + self.yorigin
+                       cx = int(x*xfactor*cp) + self.xorigin
+                       cy = int(y*yfactor*cp) + self.yorigin
                        cw = (w+cp-1)/cp
                        ch = (h+cp-1)/cp
-                       gl.rectzoom(factor*cp, factor*cp)
+                       gl.rectzoom(xfactor*cp, yfactor*cp)
                        gl.pixmode(GL.PM_SIZE, 16)
                        gl.writemask(self.mask - ((1 << self.c0bits) - 1))
                        gl.lrectwrite(cx, cy, cx + cw - 1, cy + ch - 1, \
@@ -341,14 +409,14 @@ class Displayer(VideoParams):
                #
                if pf:
                        gl.writemask((1 << self.c0bits) - 1)
-                       gl.pixmode(GL.PM_SIZE, 8)
-                       w = w/pf
-                       h = h/pf
-                       x = x/pf
-                       y = y/pf
-               gl.rectzoom(factor, factor)
-               x = int(x*factor)+self.xorigin
-               y = int(y*factor)+self.yorigin
+                       gl.pixmode(GL.PM_SIZE, pmsize)
+                       w = w/xpf
+                       h = h/ypf
+                       x = x/xpf
+                       y = y/ypf
+               gl.rectzoom(xfactor, yfactor)
+               x = int(x*xfactor)+self.xorigin
+               y = int(y*yfactor)+self.yorigin
                gl.lrectwrite(x, y, x + w - 1, y + h - 1, data)
                gl.gflush()
 
@@ -422,7 +490,10 @@ class Displayer(VideoParams):
        # by clear() and clearto()
 
        def _initcmap(self):
-               convcolor = choose_conversion(self.format)
+               if self.format in ('mono', 'grey4') and self.mustunpack:
+                       convcolor = conv_grey
+               else:
+                       convcolor = choose_conversion(self.format)
                maxbits = gl.getgdesc(GL.GD_BITS_NORM_SNG_CMODE)
                if maxbits > 11:
                        maxbits = 11
@@ -496,7 +567,7 @@ class Grabber(VideoParams):
 
 
 # Read a CMIF video file header.
-# Return (version, values) where version is 0.0, 1.0, 2.0 or 3.0,
+# Return (version, values) where version is 0.0, 1.0, 2.0 or 3.[01],
 # and values is ready for setinfo().
 # Raise Error if there is an error in the info
 
@@ -513,6 +584,8 @@ def readfileheader(fp, filename):
                version = 2.0
        elif line == 'CMIF video 3.0\n':
                version = 3.0
+       elif line == 'CMIF video 3.1\n':
+               version = 3.1
        else:
                # XXX Could be version 0.0 without identifying header
                raise Error, \
@@ -537,19 +610,19 @@ def readfileheader(fp, filename):
                else:
                        format = 'grey'
                offset = 0
-       elif version == 3.0:
+       elif version in (3.0, 3.1):
                line = fp.readline()
                try:
                        format, rest = eval(line[:-1])
                except:
-                       raise Error, filename + ': Bad 3.0 color info'
+                       raise Error, filename + ': Bad 3.[01] color info'
                if format == 'xrgb8':
                        format = 'rgb8' # rgb8 upside-down, for X
                if format in ('rgb', 'jpeg'):
                        c0bits = c1bits = c2bits = 0
                        chrompack = 0
                        offset = 0
-               elif format in ('grey', 'jpeggrey', 'mono'):
+               elif format in ('grey', 'jpeggrey', 'mono', 'grey2', 'grey4'):
                        c0bits = rest
                        c1bits = c2bits = 0
                        chrompack = 0
@@ -559,7 +632,7 @@ def readfileheader(fp, filename):
                        try:
                            c0bits, c1bits, c2bits, chrompack, offset = rest
                        except:
-                           raise Error, filename + ': Bad 3.0 color info'
+                           raise Error, filename + ': Bad 3.[01] color info'
        #
        # Get frame geometry info
        #
@@ -580,7 +653,13 @@ def readfileheader(fp, filename):
                packfactor = 2
        else:
                raise Error, filename + ': Bad (w,h,pf) info'
-       if packfactor > 1:
+       if type(packfactor) == type(()):
+               xpf, ypf = packfactor
+               xpf = abs(xpf)
+               ypf = abs(ypf)
+               width = (width/xpf) * xpf
+               height = (height/ypf) * ypf
+       elif packfactor > 1:
                width = (width / packfactor) * packfactor
                height = (height / packfactor) * packfactor
        #
@@ -629,11 +708,11 @@ def readv3frameheader(fp):
        try:
                t, datasize, chromdatasize = x = eval(line[:-1])
        except:
-               raise Error, 'Bad 3.0 frame header'
+               raise Error, 'Bad 3.[01] frame header'
        return x
 
 
-# Write a CMIF video file header (always version 3.0)
+# Write a CMIF video file header (always version 3.1)
 
 def writefileheader(fp, values):
        (format, width, height, packfactor, \
@@ -641,13 +720,13 @@ def writefileheader(fp, values):
        #
        # Write identifying header
        #
-       fp.write('CMIF video 3.0\n')
+       fp.write('CMIF video 3.1\n')
        #
        # Write color encoding info
        #
        if format in ('rgb', 'jpeg'):
                data = (format, 0)
-       elif format in ('grey', 'jpeggrey', 'mono'):
+       elif format in ('grey', 'jpeggrey', 'mono', 'grey2', 'grey4'):
                data = (format, c0bits)
        else:
                data = (format, (c0bits, c1bits, c2bits, chrompack, offset))
@@ -691,7 +770,7 @@ class BasicVinFile(VideoParams):
                        self._readframeheader = readv1frameheader
                elif self.version == 2.0:
                        self._readframeheader = readv2frameheader
-               elif self.version == 3.0:
+               elif self.version in (3.0, 3.1):
                        self._readframeheader = readv3frameheader
                else:
                        raise Error, \
@@ -950,6 +1029,14 @@ class BasicVoutFile(VideoParams):
                self.fp.close()
                del self.fp
 
+       def prealloc(self, nframes):
+               if not self.headerwritten: raise CallError
+               data = '\xff' * self.calcframesize()
+               pos = self.fp.tell()
+               for i in range(nframes):
+                       self.fp.write(data)
+               self.fp.seek(pos)
+
        def setinfo(self, values):
                if self.headerwritten: raise CallError
                VideoParams.setinfo(self, values)
index f6814cd1fd03683a8fc476cc484e4cf75e1238e3..689e8cf5a8fe46a1f7d16d4010839edac31fff39 100755 (executable)
 # -w width      : initial window width (default interactive placement)
 # -n            : Don't write to file, only timing info
 # -d           : drop fields if needed
-# -g           : greyscale
+# -g bits      : greyscale (2, 4 or 8 bits)
+# -G            : 2-bit greyscale dithered
 # -m           : monochrome dithered
 # -M value     : monochrome tresholded with value
+# -f           : Capture fields (in stead of frames)
+# -P frames    : preallocate space for 'frames' frames
 # 
 # moviefile     : here goes the movie data (default film.video);
 #                 the format is documented in cmif-film.ms
@@ -53,6 +56,7 @@ import posix
 import getopt
 import string
 import imageop
+import sgi
 
 # Main program
 
@@ -66,9 +70,12 @@ def main():
        drop = 0
        mono = 0
        grey = 0
+       greybits = 0
        monotreshold = -1
+       fields = 0
+       preallocspace = 0
 
-       opts, args = getopt.getopt(sys.argv[1:], 'aq:r:w:ndgmM:')
+       opts, args = getopt.getopt(sys.argv[1:], 'aq:r:w:ndg:mM:GfP:')
        for opt, arg in opts:
                if opt == '-a':
                        audio = 1
@@ -87,11 +94,21 @@ def main():
                        drop = 1
                elif opt == '-g':
                        grey = 1
+                       greybits = string.atoi(arg)
+                       if not greybits in (2,4,8):
+                               print 'Only 2, 4 or 8 bit greyscale supported'
+               elif opt == '-G':
+                       grey = 1
+                       greybits = -2
                elif opt == '-m':
                        mono = 1
                elif opt == '-M':
                        mono = 1
                        monotreshold = string.atoi(arg)
+               elif opt == '-f':
+                       fields = 1
+               elif opt == '-P':
+                       preallocspace = string.atoi(arg)
 
        if args[2:]:
                sys.stderr.write('usage: Vrec [options] [file [audiofile]]\n')
@@ -172,7 +189,8 @@ def main():
                        if val == 1:
                                info = format, x, y, qsize, rate
                                record(v, info, filename, audiofilename,\
-                                         mono, grey, monotreshold)
+                                         mono, grey, greybits, monotreshold, \
+                                         fields, preallocspace)
                elif dev == DEVICE.REDRAW:
                        # Window resize (or move)
                        x, y = gl.getsize()
@@ -189,7 +207,8 @@ def main():
 # Record until the mouse is released (or any other GL event)
 # XXX audio not yet supported
 
-def record(v, info, filename, audiofilename, mono, grey, monotreshold):
+def record(v, info, filename, audiofilename, mono, grey, greybits, \
+         monotreshold, fields, preallocspace):
        import thread
        format, x, y, qsize, rate = info
        fps = 59.64 # Fields per second
@@ -199,20 +218,36 @@ def record(v, info, filename, audiofilename, mono, grey, monotreshold):
                vout = VFile.VoutFile().init(filename)
                if mono:
                        vout.format = 'mono'
-               elif grey:
+               elif grey and greybits == 8:
                        vout.format = 'grey'
+               elif grey:
+                       vout.format = 'grey'+`abs(greybits)`
                else:
                        vout.format = 'rgb8'
                vout.width = x
                vout.height = y
+               if fields:
+                       vout.packfactor = (1,-2)
                vout.writeheader()
+               if preallocspace:
+                       print 'Preallocating space...'
+                       vout.prealloc(preallocspace)
+                       print 'done.'
                MAXSIZE = 20 # XXX should be a user option
                import Queue
                queue = Queue.Queue().init(MAXSIZE)
                done = thread.allocate_lock()
                done.acquire_lock()
+               convertor = None
+               if grey:
+                       if greybits == 2:
+                               convertor = imageop.grey2grey2
+                       elif greybits == 4:
+                               convertor = imageop.grey2grey4
+                       elif greybits == -2:
+                               convertor = imageop.dither2grey2
                thread.start_new_thread(saveframes, \
-                         (vout, queue, done, mono, monotreshold))
+                         (vout, queue, done, mono, monotreshold, convertor))
                if audiofilename:
                        audiodone = thread.allocate_lock()
                        audiodone.acquire_lock()
@@ -222,27 +257,33 @@ def record(v, info, filename, audiofilename, mono, grey, monotreshold):
        lastid = 0
        t0 = time.millitimer()
        count = 0
-       timestamps = []
        ids = []
        v.InitContinuousCapture(info)
        while not gl.qtest():
                try:
                        cd, id = v.GetCaptureData()
                except sv.error:
-                       time.millisleep(10) # XXX is this necessary?
+                       #time.millisleep(10) # XXX is this necessary?
+                       sgi.nap(1)      # XXX Try by Jack
                        continue
-               timestamps.append(time.millitimer())
                ids.append(id)
                
                id = id + 2*rate
 ##             if id <> lastid + 2*rate:
 ##                     print lastid, id
                lastid = id
-               data = cd.InterleaveFields(1)
-               cd.UnlockCaptureData()
                count = count+1
-               if filename:
-                       queue.put((data, int(id*tpf)))
+               if fields:
+                       data1, data2 = cd.GetFields()
+                       cd.UnlockCaptureData()
+                       if filename:
+                               queue.put((data1, int(id*tpf)))
+                               queue.put((data2, int((id+1)*tpf)))
+               else:
+                       data = cd.InterleaveFields(1)
+                       cd.UnlockCaptureData()
+                       if filename:
+                               queue.put((data, int(id*tpf)))
        t1 = time.millitimer()
        gl.wintitle('(busy) ' + filename)
        print lastid, 'fields in', t1-t0, 'msec',
@@ -253,13 +294,6 @@ def record(v, info, filename, audiofilename, mono, grey, monotreshold):
                print count*200.0/lastid, '%,',
                print count*rate*200.0/lastid, '% of wanted rate',
        print
-       t0 = timestamps[0]
-       del timestamps[0]
-       print 'Times:',
-       for t1 in timestamps:
-               print t1-t0,
-               t0 = t1
-       print
        print 'Ids:',
        t0 = ids[0]
        del ids[0]
@@ -279,19 +313,20 @@ def record(v, info, filename, audiofilename, mono, grey, monotreshold):
 
 # Thread to save the frames to the file
 
-def saveframes(vout, queue, done, mono, monotreshold):
+def saveframes(vout, queue, done, mono, monotreshold, convertor):
        while 1:
                x = queue.get()
                if not x:
                        break
                data, t = x
-               if mono and monotreshold >= 0:
+               if convertor:
+                       data = convertor(data, len(data), 1)
+               elif mono and monotreshold >= 0:
                        data = imageop.grey2mono(data, len(data), 1,\
                                  monotreshold)
                elif mono:
                        data = imageop.dither2mono(data, len(data), 1)
                vout.writeframe(t, data, None)
-               del data
        sys.stderr.write('Done writing video\n')
        vout.close()
        done.release_lock()
diff --git a/Demo/sgi/video/Vrecc.py b/Demo/sgi/video/Vrecc.py
new file mode 100755 (executable)
index 0000000..6a539f8
--- /dev/null
@@ -0,0 +1,281 @@
+#! /ufs/guido/bin/sgi/python-405
+#! /ufs/guido/bin/sgi/python
+
+# Capture a continuous CMIF movie using the Indigo video library and board
+
+
+# Usage:
+#
+# makemovie [-r rate] [-w width] [moviefile]
+
+
+# Options:
+#
+# -r rate       : capture 1 out of every 'rate' frames (default 1)
+# -w width      : initial window width (default interactive placement)
+# -d           : drop fields if needed
+# -g bits      : greyscale (2, 4 or 8 bits)
+# -G            : 2-bit greyscale dithered
+# -m           : monochrome dithered
+# -M value     : monochrome tresholded with value
+# -f           : Capture fields (in stead of frames)
+# -n number     : Capture 'number' fields (default 60)
+# 
+# moviefile     : here goes the movie data (default film.video);
+#                 the format is documented in cmif-film.ms
+
+
+# User interface:
+#
+# Start the application.  Resize the window to the desired movie size.
+# Press the left mouse button to start recording, release it to end
+# recording.  You can record as many times as you wish, but each time
+# you overwrite the output file(s), so only the last recording is
+# kept.
+#
+# Press ESC or select the window manager Quit or Close window option
+# to quit.  If you quit before recording anything, the output file(s)
+# are not touched.
+
+
+import sys
+sys.path.append('/ufs/guido/src/video')
+import sv, SV
+import VFile
+import gl, GL, DEVICE
+import al, AL
+import time
+import posix
+import getopt
+import string
+import imageop
+import sgi
+
+# Main program
+
+def main():
+       format = SV.RGB8_FRAMES
+       rate = 1
+       width = 0
+       drop = 0
+       mono = 0
+       grey = 0
+       greybits = 0
+       monotreshold = -1
+       fields = 0
+       number = 60
+
+       opts, args = getopt.getopt(sys.argv[1:], 'r:w:dg:mM:Gfn:')
+       for opt, arg in opts:
+               if opt == '-r':
+                       rate = string.atoi(arg)
+                       if rate < 2:
+                               sys.stderr.write('-r rate must be >= 2\n')
+                               sys.exit(2)
+               elif opt == '-w':
+                       width = string.atoi(arg)
+               elif opt == '-d':
+                       drop = 1
+               elif opt == '-g':
+                       grey = 1
+                       greybits = string.atoi(arg)
+                       if not greybits in (2,4,8):
+                               print 'Only 2, 4 or 8 bit greyscale supported'
+               elif opt == '-G':
+                       grey = 1
+                       greybits = -2
+               elif opt == '-m':
+                       mono = 1
+               elif opt == '-M':
+                       mono = 1
+                       monotreshold = string.atoi(arg)
+               elif opt == '-f':
+                       fields = 1
+               elif opt == '-n':
+                       number = string.atoi(arg)
+
+       if args[2:]:
+               sys.stderr.write('usage: Vrec [options] [file]\n')
+               sys.exit(2)
+
+       if args:
+               filename = args[0]
+       else:
+               filename = 'film.video'
+
+       v = sv.OpenVideo()
+       # Determine maximum window size based on signal standard
+       param = [SV.BROADCAST, 0]
+       v.GetParam(param)
+       if param[1] == SV.PAL:
+               x = SV.PAL_XMAX
+               y = SV.PAL_YMAX
+       elif param[1] == SV.NTSC:
+               x = SV.NTSC_XMAX
+               y = SV.NTSC_YMAX
+       else:
+               print 'Unknown video standard', param[1]
+               sys.exit(1)
+
+       gl.foreground()
+       gl.maxsize(x, y)
+       gl.keepaspect(x, y)
+       gl.stepunit(8, 6)
+       if width:
+               gl.prefsize(width, width*3/4)
+       win = gl.winopen(filename)
+       if width:
+               gl.maxsize(x, y)
+               gl.keepaspect(x, y)
+               gl.stepunit(8, 6)
+               gl.winconstraints()
+       x, y = gl.getsize()
+       print x, 'x', y
+
+       v.SetSize(x, y)
+
+       if drop:
+               param = [SV.FIELDDROP, 1, SV.GENLOCK, SV.GENLOCK_OFF]
+       else:
+               param = [SV.FIELDDROP, 0, SV.GENLOCK, SV.GENLOCK_ON]
+       if mono or grey:
+               param = param+[SV.COLOR, SV.MONO, SV.INPUT_BYPASS, 1]
+       else:
+               param = param+[SV.COLOR, SV.DEFAULT_COLOR, SV.INPUT_BYPASS, 0]
+       v.SetParam(param)
+
+       v.BindGLWindow(win, SV.IN_REPLACE)
+
+       gl.qdevice(DEVICE.LEFTMOUSE)
+       gl.qdevice(DEVICE.WINQUIT)
+       gl.qdevice(DEVICE.WINSHUT)
+       gl.qdevice(DEVICE.ESCKEY)
+
+       print 'Press left mouse to start recording'
+
+       while 1:
+               dev, val = gl.qread()
+               if dev == DEVICE.LEFTMOUSE:
+                       if val == 1:
+                               info = format, x, y, number, rate
+                               record(v, info, filename, mono, grey, \
+                                         greybits, monotreshold, fields)
+               elif dev == DEVICE.REDRAW:
+                       # Window resize (or move)
+                       x, y = gl.getsize()
+                       print x, 'x', y
+                       v.SetSize(x, y)
+                       v.BindGLWindow(win, SV.IN_REPLACE)
+               elif dev in (DEVICE.ESCKEY, DEVICE.WINQUIT, DEVICE.WINSHUT):
+                       # Quit
+                       v.CloseVideo()
+                       gl.winclose(win)
+                       break
+
+
+# Record until the mouse is released (or any other GL event)
+# XXX audio not yet supported
+
+def record(v, info, filename, mono, grey, greybits, monotreshold, fields):
+       import thread
+       format, x, y, number, rate = info
+       fps = 59.64 # Fields per second
+       # XXX (Strange: need fps of Indigo monitor, not of PAL or NTSC!)
+       tpf = 1000.0 / fps # Time per field in msec
+       #
+       # Go grab
+       #
+       gl.wintitle('(rec) ' + filename)
+       try:
+               ninfo, data, bitvec = v.CaptureBurst(info)
+       except sv.error, arg:
+               print 'CaptureBurst failed:', arg
+               print 'info:', info
+               gl.wintitle(filename)
+               return
+       gl.wintitle('(save) '+ filename)
+       #
+       # Check results
+       #
+       if info <> ninfo:
+               print 'Sorry, format changed.'
+               print 'Wanted:',info
+               print 'Got   :',ninfo
+               gl.wintitle(filename)
+               return
+       # print bitvec
+       if x*y*number <> len(data):
+               print 'Funny data length: wanted',x,'*',y,'*', number,'=',\
+                         x*y*number,'got',len(data)
+               gl.wintitle(filename)
+               return
+       #
+       # Save
+       #
+       if filename:
+               #
+               # Construct header and write it
+               #
+               vout = VFile.VoutFile().init(filename)
+               if mono:
+                       vout.format = 'mono'
+               elif grey and greybits == 8:
+                       vout.format = 'grey'
+               elif grey:
+                       vout.format = 'grey'+`abs(greybits)`
+               else:
+                       vout.format = 'rgb8'
+               vout.width = x
+               vout.height = y
+               if fields:
+                       vout.packfactor = (1,-2)
+               else:
+                       print 'Sorry, can only save fields at the moment'
+                       gl.wintitle(filename)
+                       return
+               vout.writeheader()
+               #
+               # Compute convertor, if needed
+               #
+               convertor = None
+               if grey:
+                       if greybits == 2:
+                               convertor = imageop.grey2grey2
+                       elif greybits == 4:
+                               convertor = imageop.grey2grey4
+                       elif greybits == -2:
+                               convertor = imageop.dither2grey2
+               fieldsize = x*y/2
+               nskipped = 0
+               realframeno = 0
+               tpf = 1000 / 50.0     #XXXX
+               for frameno in range(0, number*2):
+                       if frameno <> 0 and \
+                                 bitvec[frameno] == bitvec[frameno-1]:
+                               nskipped = nskipped + 1
+                               continue
+                       #
+                       # Save field.
+                       # XXXX Works only for fields and top-to-bottom
+                       #
+                       start = frameno*fieldsize
+                       field = data[start:start+fieldsize]
+                       if convertor:
+                               field = convertor(field, x, y)
+                       elif mono and monotreshold >= 0:
+                               field = imageop.grey2mono(field, x, y, \
+                                         1, monotreshold)
+                       elif mono:
+                               field = imageop.dither2mono(field, x, y)
+                       vout.writeframe(int(realframeno*tpf), field, None)
+               print 'Skipped',nskipped,'duplicate frames'
+               vout.close()
+                       
+       gl.wintitle('(done) ' + filename)
+
+# Don't forget to call the main program
+
+try:
+       main()
+except KeyboardInterrupt:
+       print '[Interrupt]'