]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Added single frame capturing.
authorGuido van Rossum <guido@python.org>
Mon, 10 May 1993 15:07:20 +0000 (15:07 +0000)
committerGuido van Rossum <guido@python.org>
Mon, 10 May 1993 15:07:20 +0000 (15:07 +0000)
Added VCR synchronized capturing.
Added audio capturing (for continuous mode only).
Lots of internal and external improvements.

Demo/sgi/video/Vb.py
Demo/sgi/video/VbForm.fd

index 92b3e061030d0577c988060dfb3e8b82f2b6062d..da868f1fbd94e5cab13b9a84453f2cead4df4d52 100755 (executable)
@@ -1,10 +1,9 @@
 #! /ufs/guido/bin/sgi/python
 
-# Video bag-of-tricks
+# Video bag of tricks: record video(+audio) in various formats and modes
 
 # XXX To do:
 # - audio
-# - single frame recording
 # - improve user interface
 # - help button?
 # - command line options to set initial settings
@@ -12,6 +11,7 @@
 # - ...?
 
 import sys
+import time
 import getopt
 import string
 import os
@@ -29,6 +29,7 @@ import SV
 import VFile
 import VGrabber
 import imageop
+sys.path.append('/ufs/jack/src/av/vcr')
 
 ARROW = 0
 WATCH = 1
@@ -43,27 +44,42 @@ def main():
 
 StopCapture = 'StopCapture'
 
-Labels = ['rgb8', 'grey8', 'grey4', 'grey2', \
+VideoFormatLabels = ['Video off', 'rgb8', 'grey8', 'grey4', 'grey2', \
          'grey2 dith', 'mono dith', 'mono thresh']
-Formats = ['rgb8', 'grey', 'grey4', 'grey2', \
-          'grey2', 'mono', 'mono']
+VideoFormats = ['', 'rgb8', 'grey', 'grey4', 'grey2', \
+         'grey2', 'mono', 'mono']
+
+VideoModeLabels = ['Continuous', 'Burst', 'Single frame', 'VCR sync']
+[VM_CONT, VM_BURST, VM_SINGLE, VM_VCR] = range(1, 5)
+
+AudioFormatLabels = ['Audio off', \
+         '16 bit mono', '16 bit stereo', '8 bit mono', '8 bit stereo']
+[A_OFF, A_16_MONO, A_16_STEREO, A_8_MONO, A_8_STEREO] = range(1, 6)
 
 class VideoBagOfTricks:
 
+       # Init/close stuff
+
        def init(self):
                formdef = flp.parse_form('VbForm', 'form')
                flp.create_full_form(self, formdef)
-               self.g_stop.hide_object()
+               self.g_cont.hide_object()
                self.g_burst.hide_object()
+               self.g_single.hide_object()
+               self.g_vcr.hide_object()
                self.setdefaults()
                self.openvideo()
                self.makewindow()
                self.bindvideo()
-               self.capturing = 0
                self.showform()
                fl.set_event_call_back(self.do_event)
                return self
 
+       def close(self):
+               self.close_video()
+               self.close_audio()
+               raise SystemExit, 0
+
        def showform(self):
                # Get position of video window
                gl.winset(self.window)
@@ -80,18 +96,39 @@ class VideoBagOfTricks:
                                    'Video Bag Of Tricks')
 
        def setdefaults(self):
+               self.vcr = None
+               self.vout = None
+               self.capturing = 0
+               # Video defaults
+               self.vfile = 'film.video'
+               self.vmode = VM_CONT
                self.mono_thresh = 128
-               self.format = 'rgb8'
-               self.c_format.clear_choice()
-               for label in Labels:
-                       self.c_format.addto_choice(label)
-               self.get_format()
+               self.vformat = 'rgb8'
+               self.c_vformat.clear_choice()
+               for label in VideoFormatLabels:
+                       self.c_vformat.addto_choice(label)
+               self.c_vformat.set_choice(1 + VideoFormats.index(self.vformat))
+               self.c_vmode.clear_choice()
+               for label in VideoModeLabels:
+                       self.c_vmode.addto_choice(label)
+               self.c_vmode.set_choice(self.vmode)
+               self.get_vformat()
                self.b_drop.set_button(1)
-               self.b_burst.set_button(0)
                self.in_rate.set_input('2')
                self.in_maxmem.set_input('1.0')
                self.in_nframes.set_input('0')
-               self.in_file.set_input('film.video')
+               self.in_nframes_vcr.set_input('1')
+               self.in_sleeptime.set_input('1.0')
+               # Audio defaults
+               self.aout = None
+               self.aport = None
+               self.afile = 'film.aiff'
+               self.aformat = A_OFF
+               self.c_aformat.clear_choice()
+               for label in AudioFormatLabels:
+                       self.c_aformat.addto_choice(label)
+               self.c_aformat.set_choice(self.aformat)
+               self.get_aformat()
 
        def openvideo(self):
                try:
@@ -99,7 +136,6 @@ class VideoBagOfTricks:
                except sv.error, msg:
                        print 'Error opening video:', msg
                        self.video = None
-                       #sys.exit(1)
                param = [SV.BROADCAST, SV.PAL]
                if self.video: self.video.GetParam(param)
                if param[1] == SV.PAL:
@@ -138,12 +174,6 @@ class VideoBagOfTricks:
                gl.qdevice(DEVICE.WINQUIT)
                gl.qdevice(DEVICE.WINSHUT)
 
-       def settitle(self):
-               gl.winset(self.window)
-               x, y = gl.getsize()
-               title = 'Vb:' + self.in_file.get_input() + ' (%dx%d)' % (x, y)
-               gl.wintitle(title)
-
        def bindvideo(self):
                if not self.video: return
                x, y = gl.getsize()
@@ -167,16 +197,25 @@ class VideoBagOfTricks:
                gl.winset(self.window)
                self.bindvideo()
 
+       def reset(self):
+               self.close_video()
+               self.close_audio()
+
+       # Event handler (catches resize of video window)
+
        def do_event(self, dev, val):
                #print 'Event:', dev, val
                if dev in (DEVICE.WINSHUT, DEVICE.WINQUIT):
-                       self.cb_quit()
+                       self.close()
                if dev == DEVICE.REDRAW and val == self.window:
                        self.rebindvideo()
                        self.settitle()
 
-       def cb_format(self, *args):
-               self.get_format()
+       # Video controls: format, mode, file
+
+       def cb_vformat(self, *args):
+               self.reset()
+               self.get_vformat()
                if self.mono_use_thresh:
                        s = `self.mono_thresh`
                        s = fl.show_input('Please enter mono threshold', s)
@@ -188,126 +227,151 @@ class VideoBagOfTricks:
                                                  `self.mono_thresh`, '')
                self.rebindvideo()
 
+       def cb_vmode(self, *args):
+               self.vmode = self.c_vmode.get_choice()
+               self.form.freeze_form()
+               self.g_cont.hide_object()
+               self.g_burst.hide_object()
+               self.g_single.hide_object()
+               self.g_vcr.hide_object()
+               if self.vmode == VM_CONT:
+                       self.g_cont.show_object()
+               elif self.vmode == VM_BURST:
+                       self.g_burst.show_object()
+               elif self.vmode == VM_SINGLE:
+                       self.g_single.show_object()
+               elif self.vmode == VM_VCR:
+                       self.g_vcr.show_object()
+               self.form.unfreeze_form()
+
+       def cb_vfile(self, *args):
+               filename = self.vfile
+               hd, tl = os.path.split(filename)
+               filename = fl.file_selector('Video save file:', hd, '', tl)
+               if filename:
+                       self.reset()
+                       hd, tl = os.path.split(filename)
+                       if hd == os.getcwd():
+                               filename = tl
+                       self.vfile = filename
+
+       # Video mode specific video controls
+
        def cb_rate(self, *args):
                pass
 
        def cb_drop(self, *args):
                self.rebindvideo()
 
-       def cb_burst(self, *args):
-               if self.b_burst.get_button():
-                       self.in_rate.set_input('1')
-                       self.b_drop.set_button(1)
-##                     self.g_stop.hide_object()
-                       self.g_burst.show_object()
-               else:
-                       self.in_rate.set_input('2')
-                       self.b_drop.set_button(0)
-##                     self.g_stop.show_object()
-                       self.g_burst.hide_object()
-
        def cb_maxmem(self, *args):
                pass
 
        def cb_nframes(self, *args):
                pass
 
-       def cb_file(self, *args):
-               filename = self.in_file.get_input()
-               if filename == '':
-                       filename = 'film.video'
-                       self.in_file.set_input(filename)
-               self.settitle()
+       def cb_fps(self, *args):
+               pass
 
-       def cb_open(self, *args):
-               filename = self.in_file.get_input()
+       def cb_nframes_vcr(self, *args):
+               pass
+
+       def cb_sleeptime(self, *args):
+               pass
+
+       # Audio controls: format, file
+
+       def cb_aformat(self, *args):
+               self.get_aformat()
+
+       def cb_afile(self, *args):
+               filename = self.afile
                hd, tl = os.path.split(filename)
-               filename = fl.file_selector('Select file:', hd, '', tl)
+               filename = fl.file_selector('Audio save file:', hd, '', tl)
                if filename:
+                       self.reset()
                        hd, tl = os.path.split(filename)
                        if hd == os.getcwd():
                                filename = tl
-                       self.in_file.set_input(filename)
-                       self.cb_file()
+                       self.afile = filename
+
+       # General controls: capture, reset, play, quit
 
        def cb_capture(self, *args):
-               if not self.video:
+               if self.capturing:
+                       raise StopCapture
+               if not self.b_capture.get_button():
+                       return
+               if not self.video or not self.vformat:
                        gl.ringbell()
                        return
-               if self.b_burst.get_button():
-                       self.burst_capture()
-               else:
+               if self.vmode == VM_CONT:
                        self.cont_capture()
+               elif self.vmode == VM_BURST:
+                       self.burst_capture()
+               elif self.vmode == VM_SINGLE:
+                       self.single_capture()
+               elif self.vmode == VM_VCR:
+                       self.vcr_capture()
 
-       def cb_stop(self, *args):
-               if self.capturing:
-                       raise StopCapture
-               gl.ringbell()
+       def cb_reset(self, *args):
+               self.reset()
 
        def cb_play(self, *args):
-               filename = self.in_file.get_input()
-               sts = os.system('Vplay -q ' + filename + ' &')
+               sts = os.system('Vplay -q ' + self.vfile + ' &')
 
        def cb_quit(self, *args):
-               raise SystemExit, 0
+               self.close()
+
+       # Capture routines
 
        def burst_capture(self):
                self.setwatch()
                gl.winset(self.window)
                x, y = gl.getsize()
                vformat = SV.RGB8_FRAMES
-               try:
-                       nframes = string.atoi(self.in_nframes.get_input())
-               except string.atoi_error:
-                       nframes = 0
+               nframes = self.getint(self.in_nframes, 0)
                if nframes == 0:
-                       try:
-                               maxmem = \
-                                 float(eval(self.in_maxmem.get_input()))
-                       except:
-                               maxmem = 1.0
+                       maxmem = self.getint(self.in_maxmem, 1.0)
                        memsize = int(maxmem * 1024 * 1024)
-                       nframes = calcnframes(x, y, \
-                                 self.mono or self.grey, memsize)
-                       print 'nframes =', nframes
-               rate = string.atoi(self.in_rate.get_input())
-               info = (vformat, x, y, nframes, rate)
+                       nframes = self.calcnframes()
+               info = (vformat, x, y, nframes, 1)
                try:
                        info2, data, bitvec = self.video.CaptureBurst(info)
                except sv.error, msg:
-                       fl.show_message('Capture error:', str(msg), '')
+                       self.b_capture.set_button(0)
                        self.setarrow()
+                       fl.show_message('Capture error:', str(msg), '')
                        return
                if info <> info2: print info, '<>', info2
                self.save_burst(info2, data, bitvec)
                self.setarrow()
 
+       def calcnframes(self):
+               gl.winset(self.window)
+               x, y = gl.getsize()
+               pixels = x*y
+               pixels = pixels/2       # XXX always assume fields
+               if self.mono or self.grey:
+                       n = memsize/pixels
+               else:
+                       n = memsize/(4*pixels)
+               return max(1, n)
+
        def save_burst(self, info, data, bitvec):
                (vformat, x, y, nframes, rate) = info
-               self.open_file()
+               self.open_if_closed()
                fieldsize = x*y/2
                nskipped = 0
                realframeno = 0
-               tpf = 1000 / 50.0     #XXXX
-               # Trying to find the pattern in frame skipping
-               okstretch = 0
-               skipstretch = 0
+               tpf = 1000 / 50.0     # XXX
                for frameno in range(0, nframes*2):
                        if frameno <> 0 and \
                                  bitvec[frameno] == bitvec[frameno-1]:
                                nskipped = nskipped + 1
-                               if okstretch:
-                                       #print okstretch, 'ok',
-                                       okstretch = 0
-                               skipstretch = skipstretch + 1
                                continue
-                       if skipstretch:
-                               #print skipstretch, 'skipped'
-                               skipstretch = 0
-                       okstretch = okstretch + 1
                        #
                        # Save field.
-                       # XXXX Works only for fields and top-to-bottom
+                       # XXX Works only for fields and top-to-bottom
                        #
                        start = frameno*fieldsize
                        field = data[start:start+fieldsize]
@@ -315,33 +379,17 @@ class VideoBagOfTricks:
                        fn = int(realframeno*tpf)
                        if not self.write_frame(fn, field):
                                break
-               #print okstretch, 'ok',
-               #print skipstretch, 'skipped'
-               #print 'Skipped', nskipped, 'duplicate frames'
-               self.close_file()
 
        def cont_capture(self):
-               self.setwatch()
-               self.g_main.hide_object()
-               self.open_file()
-               vformat = SV.RGB8_FRAMES
-               qsize = 1 # XXX Should be an option?
-               try:
-                       rate = string.atoi(self.in_rate.get_input())
-               except string.atoi_error:
-                       rate = 2
-               x, y = self.vout.getsize()
-               info = (vformat, x, y, qsize, rate)
-               ids = []
-               fps = 59.64 # Fields per second
+               saved_label = self.b_capture.label
+               self.b_capture.label = 'Stop\n' + saved_label
+               self.open_if_closed()
+               self.init_cont()
+               fps = 59.64             # Fields per second
                # XXX (fps of Indigo monitor, not of PAL or NTSC!)
-               tpf = 1000.0 / fps # Time per field in msec
-               info2 = self.video.InitContinuousCapture(info)
-               if info2 <> info:
-                       print 'Info mismatch: requested', info, 'got', info2
+               tpf = 1000.0 / fps      # Time per field in msec
                self.capturing = 1
-               self.g_stop.show_object()
-               self.setarrow()
+               self.start_audio()
                while 1:
                        try:
                                void = fl.check_forms()
@@ -352,26 +400,101 @@ class VideoBagOfTricks:
                        except sv.error:
                                sgi.nap(1)
                                continue
-                       ids.append(id)
-                       id = id + 2*rate
+                       id = id + 2*self.rate
                        data = cd.InterleaveFields(1)
                        cd.UnlockCaptureData()
                        t = id*tpf
                        if not self.write_frame(t, data):
                                break
-               self.setwatch()
-               self.g_stop.hide_object()
+               self.stop_audio()
                self.capturing = 0
+               self.end_cont()
+               self.reset()
+               self.b_capture.label = saved_label
+
+       def single_capture(self):
+               self.open_if_closed()
+               self.init_cont()
+               while 1:
+                       try:
+                               cd, id = self.video.GetCaptureData()
+                               break
+                       except sv.error:
+                               pass
+                       sgi.nap(1)
+               data = cd.InterleaveFields(1)
+               cd.UnlockCaptureData()
+               self.end_cont()
+               t = (self.nframes+1) * (1000/25)
+               return self.write_frame(t, data)
+
+       def vcr_capture(self):
+               if not self.vcr:
+                       import VCR
+                       try:
+                               self.vcr = VCR.VCR().init()
+                       except VCR.error, msg:
+                               self.b_capture.set_button(0)
+                               fl.show_message('VCR error', str(msg), '')
+                               return
+               count = self.getint(self.in_nframes_vcr, 1)
+               if count <= 0: count = 1
+               sleeptime = self.getfloat(self.in_sleeptime, 1.0)
+               for i in range(count):
+                       if i > 0:
+                               time.sleep(sleeptime)
+                       if not self.single_capture():
+                               break
+                       if not self.vcr.step():
+                               break
+
+       # Init/end continuous capture mode
+
+       def init_cont(self):
+               qsize = 1
+               if self.vmode == VM_CONT:
+                       self.rate = self.getint(self.in_rate, 2)
+               else:
+                       self.rate = 2
+               x, y = self.vout.getsize()
+               info = (SV.RGB8_FRAMES, x, y, qsize, self.rate)
+               info2 = self.video.InitContinuousCapture(info)
+               if info2 <> info:
+                       # XXX This is really only debug info
+                       print 'Info mismatch: requested', info, 'got', info2
+
+       def end_cont(self):
                self.video.EndContinuousCapture()
-               self.close_file()
-               self.g_main.show_object()
-               self.setarrow()
 
-       def get_format(self):
-               i = self.c_format.get_choice()
-               label = Labels[i-1]
-               format = Formats[i-1]
-               self.format = format
+       # Misc stuff
+
+       def settitle(self):
+               gl.winset(self.window)
+               x, y = gl.getsize()
+               title = 'Vb:' + self.vfile + ' (%dx%d)' % (x, y)
+               gl.wintitle(title)
+
+       def get_vformat(self):
+               i = self.c_vformat.get_choice()
+               label = VideoFormatLabels[i-1]
+               format = VideoFormats[i-1]
+               self.vformat = format
+               if self.vformat == '':
+                       self.form.freeze_form()
+                       self.g_video.hide_object()
+                       self.g_cont.hide_object()
+                       self.g_burst.hide_object()
+                       self.g_single.hide_object()
+                       self.form.unfreeze_form()
+                       return
+               else:
+                       self.g_video.show_object()
+                       if self.vmode == VM_CONT:
+                               self.g_cont.show_object()
+                       elif self.vmode == VM_BURST:
+                               self.g_burst.show_object()
+                       elif self.vmode == VM_SINGLE:
+                               self.g_single.show_object()
                #
                self.rgb = (format[:3] == 'rgb')
                self.mono = (format == 'mono')
@@ -395,20 +518,40 @@ class VideoBagOfTricks:
                                convertor = imageop.dither2grey2
                self.convertor = convertor
 
-       def open_file(self):
+       def get_aformat(self):
+               self.reset()
+               self.aformat = self.c_aformat.get_choice()
+               if self.aformat == A_OFF:
+                       self.g_audio.hide_object()
+               else:
+                       self.g_audio.show_object()
+
+       def open_if_closed(self):
+               if not self.vout:
+                       self.open_video()
+               if not self.aout:
+                       self.open_audio()
+
+       # File I/O handling
+
+       def open_video(self):
+               self.close_video()
                gl.winset(self.window)
                x, y = gl.getsize()
-               self.cb_file() # Make sure filename is OK
-               filename = self.in_file.get_input()
-               vout = VFile.VoutFile().init(filename)
-               vout.setformat(self.format)
+               vout = VFile.VoutFile().init(self.vfile)
+               vout.setformat(self.vformat)
                vout.setsize(x, y)
-               if self.b_burst.get_button():
+               if self.vmode == VM_BURST:
                        vout.setpf((1, -2))
                vout.writeheader()
                self.vout = vout
+               self.nframes = 0
+               self.t_nframes.label = `self.nframes`
 
        def write_frame(self, t, data):
+               if not self.vout:
+                       gl.ringbell()
+                       return
                if self.convertor:
                        data = self.convertor(data, len(data), 1)
                elif self.mono:
@@ -420,37 +563,127 @@ class VideoBagOfTricks:
                                data = imageop.dither2mono(data, \
                                          len(data), 1)
                try:
-                       self.vout.writeframe(t, data, None)
+                       self.vout.writeframe(int(t), data, None)
                except IOError, msg:
                        if msg == (0, 'Error 0'):
                                msg = 'disk full??'
                        fl.show_message('IOError', str(msg), '')
                        return 0
+               self.nframes = self.nframes + 1
+               self.t_nframes.label = `self.nframes`
                return 1
 
-       def close_file(self):
+       def close_video(self):
+               if not self.vout:
+                       return
+               self.nframes = 0
+               self.t_nframes.label = ''
                try:
                        self.vout.close()
                except IOError, msg:
                        if msg == (0, 'Error 0'):
                                msg = 'disk full??'
                        fl.show_message('IOError', str(msg), '')
-               del self.vout
+               self.vout = None
+
+       # Watch cursor handling
 
        def setwatch(self):
                gl.winset(self.form.window)
                gl.setcursor(WATCH, 0, 0)
+               gl.winset(self.window)
+               gl.setcursor(WATCH, 0, 0)
 
        def setarrow(self):
                gl.winset(self.form.window)
                gl.setcursor(ARROW, 0, 0)
+               gl.winset(self.window)
+               gl.setcursor(ARROW, 0, 0)
+
+       # Numeric field handling
+
+       def getint(self, field, default):
+               try:
+                       value = string.atoi(field.get_input())
+               except string.atoi_error:
+                       value = default
+               field.set_input(`value`)
+               return value
+
+       def getfloat(self, field, default):
+               try:
+                       value = float(eval(field.get_input()))
+               except:
+                       value = float(default)
+               field.set_input(value)
+               return value
+
+       # Audio stuff
+
+       def open_audio(self):
+               if self.aformat == A_OFF:
+                       return
+               import aifc
+               import al
+               import AL
+               import thread
+               self.close_audio()
+               params = [AL.INPUT_RATE, 0]
+               al.getparams(AL.DEFAULT_DEVICE, params)
+               rate = params[1]
+               self.aout = aifc.open(self.afile, 'w')
+               if self.aformat in (A_16_STEREO, A_8_STEREO):
+                       nch = AL.STEREO
+               else:
+                       nch = AL.MONO
+               if self.aformat in (A_16_STEREO, A_16_MONO):
+                       width = AL.SAMPLE_16
+               else:
+                       width = AL.SAMPLE_8
+               self.aout.setnchannels(nch)
+               self.aout.setsampwidth(width)
+               self.aout.setframerate(rate)
+               self.aout.writeframes('')
+               c = al.newconfig()
+               c.setqueuesize(8000)
+               c.setchannels(nch)
+               c.setwidth(width)
+               self.aport = al.openport('Vb audio record', 'r', c)
+               self.audio_stop = 0
+               self.audio_ok = 0
+               self.audio_busy = 1
+               thread.start_new_thread(self.record_audio, ())
+
+       def start_audio(self):
+               if self.aformat == A_OFF:
+                       return
+               self.audio_ok = 1
+
+       def record_audio(self, *args):
+               # This function runs in a separate thread
+               # Currently no semaphores are used
+               while not self.audio_stop:
+                       data = self.aport.readsamps(4000)
+                       if self.audio_ok:
+                               self.aout.writeframesraw(data)
+                       data = None
+               self.audio_busy = 0
+
+       def stop_audio(self):
+               self.audio_ok = 0
+
+       def close_audio(self):
+               if self.aout:
+                       self.audio_ok = 0
+                       self.audio_stop = 1
+                       while self.audio_busy:
+                               time.sleep(0.1)
+                       self.aout.close()
+                       self.aout = None
+               if self.aport:
+                       self.aport.closeport()
+                       self.aport = None
 
-def calcnframes(x, y, grey, memsize):
-       pixels = x*y
-       pixels = pixels/2               # XXX always assume fields
-       if grey: n = memsize/pixels
-       else: n = memsize/(4*pixels)
-       return max(1, n)
 
 try:
        main()
index e3056122a6d1dace860fb852c6c1e3f7803294e1..1c0be3758c334ab2961aab9bc113bec95876025a 100644 (file)
@@ -7,14 +7,14 @@ Number of forms: 1
 
 =============== FORM ===============
 Name: form
-Width: 350.000000
+Width: 450.000000
 Height: 240.000000
-Number of Objects: 23
+Number of Objects: 33
 
 --------------------
 class: 1
 type: 1
-box: 0.000000 0.000000 350.000000 240.000000
+box: 0.000000 0.000000 450.000000 240.000000
 boxtype: 1
 colors: 47 47
 alignment: 4
@@ -26,28 +26,133 @@ name:
 callback: 
 argument: 
 
+--------------------
+class: 11
+type: 5
+box: 330.000000 170.000000 110.000015 60.000004
+boxtype: 1
+colors: 47 47
+alignment: 4
+style: 1
+size: 11.000000
+lcol: 0
+label: Capture
+name: b_capture
+callback: cb_capture
+argument: 0
+
+--------------------
+class: 11
+type: 0
+box: 330.000000 10.000000 110.000008 30.000000
+boxtype: 1
+colors: 47 47
+alignment: 4
+style: 0
+size: 11.000000
+lcol: 0
+label: Quit
+name: b_quit
+callback: cb_quit
+argument: 0
+
+--------------------
+class: 11
+type: 0
+box: 330.000000 50.000000 110.000000 30.000000
+boxtype: 1
+colors: 47 47
+alignment: 4
+style: 0
+size: 11.000000
+lcol: 0
+label: Playback
+name: b_play
+callback: cb_play
+argument: 0
+
+--------------------
+class: 42
+type: 0
+box: 80.000000 200.000000 120.000000 30.000000
+boxtype: 5
+colors: 7 0
+alignment: 2
+style: 0
+size: 11.000000
+lcol: 0
+label: Format:
+name: c_vformat
+callback: cb_vformat
+argument: 0
+
+--------------------
+class: 11
+type: 0
+box: 330.000000 90.000000 110.000000 30.000000
+boxtype: 1
+colors: 47 47
+alignment: 4
+style: 0
+size: 11.000000
+lcol: 0
+label: Reset
+name: b_reset
+callback: cb_reset
+argument: 0
+
+--------------------
+class: 42
+type: 0
+box: 80.000000 50.000000 120.000000 30.000000
+boxtype: 5
+colors: 7 0
+alignment: 2
+style: 0
+size: 11.000000
+lcol: 0
+label: Format:
+name: c_aformat
+callback: cb_aformat
+argument: 0
+
 --------------------
 class: 10000
 type: 0
 box: 0.000000 0.000000 0.000000 0.000000
 boxtype: 0
-colors: 5487 512
+colors: 1668246586 540019308
 alignment: 4
 style: 0
 size: 11.000000
 lcol: 0
 label: 
-name: g_burst
+name: g_audio
 callback: 
 argument: 
 
 --------------------
-class: 1
-type: 1
-box: 140.000000 10.000000 120.000000 120.000000
+class: 11
+type: 0
+box: 10.000000 10.000000 190.000000 30.000000
 boxtype: 1
 colors: 47 47
-alignment: 0
+alignment: 4
+style: 0
+size: 11.000000
+lcol: 0
+label: Set audio file...
+name: b_afile
+callback: cb_afile
+argument: 0
+
+--------------------
+class: 20000
+type: 0
+box: 0.000000 0.000000 0.000000 0.000000
+boxtype: 0
+colors: 876099360 892416522
+alignment: 4
 style: 0
 size: 11.000000
 lcol: 0
@@ -57,33 +162,48 @@ callback:
 argument: 
 
 --------------------
-class: 31
-type: 1
-box: 150.000000 70.000000 100.000000 30.000000
-boxtype: 2
-colors: 13 5
-alignment: 0
+class: 10000
+type: 0
+box: 0.000000 0.000000 0.000000 0.000000
+boxtype: 0
+colors: 1147496041 1852404841
+alignment: 4
 style: 0
 size: 11.000000
 lcol: 0
-label: Max Mbytes:
-name: in_maxmem
-callback: cb_maxmem
+label: 
+name: g_video
+callback: 
+argument: 
+
+--------------------
+class: 42
+type: 0
+box: 80.000000 160.000000 120.000000 30.000000
+boxtype: 5
+colors: 7 0
+alignment: 2
+style: 0
+size: 11.000000
+lcol: 0
+label: Mode:
+name: c_vmode
+callback: cb_vmode
 argument: 0
 
 --------------------
-class: 31
-type: 2
-box: 150.000000 20.000000 100.000000 30.000000
-boxtype: 2
-colors: 13 5
-alignment: 0
+class: 11
+type: 0
+box: 10.000000 110.000000 190.000000 30.000000
+boxtype: 1
+colors: 47 47
+alignment: 4
 style: 0
 size: 11.000000
 lcol: 0
-label: Nr. of fields:
-name: in_nframes
-callback: cb_nframes
+label: Set video file...
+name: b_vfile
+callback: cb_vfile
 argument: 0
 
 --------------------
@@ -91,7 +211,7 @@ class: 20000
 type: 0
 box: 0.000000 0.000000 0.000000 0.000000
 boxtype: 0
-colors: -322390740 -895472437
+colors: 544171552 1331849829
 alignment: 4
 style: 0
 size: 11.000000
@@ -106,110 +226,140 @@ class: 10000
 type: 0
 box: 0.000000 0.000000 0.000000 0.000000
 boxtype: 0
-colors: 1147496041 1852404841
+colors: 0 0
 alignment: 4
 style: 0
 size: 11.000000
 lcol: 0
 label: 
-name: g_main
+name: g_single
 callback: 
 argument: 
 
 --------------------
-class: 1
-type: 1
-box: 10.000000 10.000000 120.000000 120.000000
-boxtype: 1
-colors: 47 47
+class: 31
+type: 2
+box: 220.000000 170.000000 100.000000 30.000000
+boxtype: 2
+colors: 13 5
 alignment: 0
 style: 0
 size: 11.000000
 lcol: 0
+label: Frames/sec
+name: in_fps
+callback: cb_fps
+argument: 0
+
+--------------------
+class: 20000
+type: 0
+box: 0.000000 0.000000 0.000000 0.000000
+boxtype: 0
+colors: 0 0
+alignment: 4
+style: 0
+size: 11.000000
+lcol: 0
 label: 
 name: 
 callback: 
 argument: 
 
 --------------------
-class: 31
-type: 2
-box: 50.000000 70.000000 40.000000 30.000000
-boxtype: 2
-colors: 13 5
-alignment: 0
+class: 10000
+type: 0
+box: 0.000000 0.000000 0.000000 0.000000
+boxtype: 0
+colors: 0 0
+alignment: 4
 style: 0
 size: 11.000000
 lcol: 0
-label: Capture rate:
-name: in_rate
-callback: cb_rate
-argument: 0
+label: 
+name: g_burst
+callback: 
+argument: 
 
 --------------------
-class: 12
+class: 31
 type: 1
-box: 140.000000 140.000000 120.000000 30.000000
-boxtype: 1
-colors: 39 3
-alignment: 4
+box: 220.000000 170.000000 100.000000 30.000000
+boxtype: 2
+colors: 13 5
+alignment: 0
 style: 0
 size: 11.000000
 lcol: 0
-label: Burst mode
-name: b_burst
-callback: cb_burst
+label: Max Mbytes:
+name: in_maxmem
+callback: cb_maxmem
 argument: 0
 
 --------------------
 class: 31
-type: 0
-box: 50.000000 200.000000 209.999985 30.000000
+type: 2
+box: 220.000000 110.000000 100.000000 30.000000
 boxtype: 2
 colors: 13 5
-alignment: 2
+alignment: 0
 style: 0
 size: 11.000000
 lcol: 0
-label: File:
-name: in_file
-callback: cb_file
+label: Nr. of frames:
+name: in_nframes
+callback: cb_nframes
 argument: 0
 
 --------------------
-class: 11
+class: 20000
 type: 0
-box: 270.000000 200.000000 70.000000 30.000000
-boxtype: 1
-colors: 47 47
+box: 0.000000 0.000000 0.000000 0.000000
+boxtype: 0
+colors: 0 0
 alignment: 4
 style: 0
 size: 11.000000
 lcol: 0
-label: Open...
-name: b_open
-callback: cb_open
-argument: 0
+label: 
+name: 
+callback: 
+argument: 
 
 --------------------
-class: 11
+class: 10000
 type: 0
-box: 270.000000 140.000000 70.000015 30.000002
-boxtype: 1
-colors: 47 47
+box: 0.000000 0.000000 0.000000 0.000000
+boxtype: 0
+colors: 0 0
 alignment: 4
-style: 1
+style: 0
 size: 11.000000
 lcol: 0
-label: Capture
-name: b_capture
-callback: cb_capture
+label: 
+name: g_cont
+callback: 
+argument: 
+
+--------------------
+class: 31
+type: 2
+box: 250.000000 170.000000 40.000000 30.000000
+boxtype: 2
+colors: 13 5
+alignment: 0
+style: 0
+size: 11.000000
+lcol: 0
+label: Capture rate:
+name: in_rate
+callback: cb_rate
 argument: 0
 
 --------------------
 class: 2
 type: 0
-box: 20.000000 70.000000 30.000000 30.000000
+box: 220.000000 170.000000 30.000000 30.000000
 boxtype: 0
 colors: 47 47
 alignment: 2
@@ -224,7 +374,7 @@ argument:
 --------------------
 class: 2
 type: 0
-box: 90.000000 70.000000 30.000000 30.000000
+box: 290.000000 170.000000 30.000000 30.000000
 boxtype: 0
 colors: 47 47
 alignment: 2
@@ -237,76 +387,61 @@ callback:
 argument: 
 
 --------------------
-class: 11
+class: 13
 type: 0
-box: 270.000000 10.000000 70.000008 30.000000
-boxtype: 1
-colors: 47 47
+box: 220.000000 110.000000 100.000000 30.000000
+boxtype: 0
+colors: 7 3
 alignment: 4
 style: 0
 size: 11.000000
 lcol: 0
-label: Quit
-name: b_quit
-callback: cb_quit
+label: Fielddrop
+name: b_drop
+callback: cb_drop
 argument: 0
 
 --------------------
-class: 11
+class: 20000
 type: 0
-box: 270.000000 60.000000 70.000000 30.000000
-boxtype: 1
-colors: 47 47
+box: 0.000000 0.000000 0.000000 0.000000
+boxtype: 0
+colors: 0 0
 alignment: 4
 style: 0
 size: 11.000000
 lcol: 0
-label: Play
-name: b_play
-callback: cb_play
-argument: 0
+label: 
+name: 
+callback: 
+argument: 
 
 --------------------
-class: 42
+class: 2
 type: 0
-box: 10.000000 140.000000 120.000000 30.000000
-boxtype: 5
-colors: 7 0
-alignment: 0
-style: 0
-size: 11.000000
-lcol: 0
-label: Video format:
-name: c_format
-callback: cb_format
-argument: 0
-
---------------------
-class: 12
-type: 1
-box: 20.000000 20.000000 100.000000 30.000000
-boxtype: 1
-colors: 39 3
-alignment: 4
+box: 390.000000 130.000000 50.000000 30.000002
+boxtype: 2
+colors: 47 47
+alignment: 2
 style: 0
 size: 11.000000
 lcol: 0
-label: Fielddrop
-name: b_drop
-callback: cb_drop
-argument: 0
+label: 
+name: t_nframes
+callback: 
+argument: 
 
 --------------------
-class: 20000
+class: 2
 type: 0
-box: 0.000000 0.000000 0.000000 0.000000
+box: 320.000000 130.000000 60.000000 30.000000
 boxtype: 0
-colors: 544171552 1331849829
-alignment: 4
+colors: 47 47
+alignment: 2
 style: 0
 size: 11.000000
 lcol: 0
-label: 
+label: Frames:
 name: 
 callback: 
 argument: 
@@ -316,29 +451,44 @@ class: 10000
 type: 0
 box: 0.000000 0.000000 0.000000 0.000000
 boxtype: 0
-colors: 1147496041 1852404841
+colors: 0 0
 alignment: 4
 style: 0
 size: 11.000000
 lcol: 0
 label: 
-name: g_stop
+name: g_vcr
 callback: 
 argument: 
 
 --------------------
-class: 11
-type: 0
-box: 270.000000 140.000000 70.000000 30.000000
-boxtype: 1
-colors: 47 47
-alignment: 4
+class: 31
+type: 2
+box: 220.000000 110.000000 100.000000 30.000000
+boxtype: 2
+colors: 13 5
+alignment: 0
+style: 0
+size: 11.000000
+lcol: 0
+label: Nr. of frames:
+name: in_nframes_vcr
+callback: cb_nframes_vcr
+argument: 0
+
+--------------------
+class: 31
+type: 1
+box: 220.000000 170.000000 100.000000 30.000000
+boxtype: 2
+colors: 13 5
+alignment: 0
 style: 0
 size: 11.000000
 lcol: 0
-label: Stop
-name: b_stop
-callback: cb_stop
+label: Delay:
+name: in_sleeptime
+callback: cb_sleeptime
 argument: 0
 
 --------------------
@@ -346,7 +496,7 @@ class: 20000
 type: 0
 box: 0.000000 0.000000 0.000000 0.000000
 boxtype: 0
-colors: 544171552 1331849829
+colors: 0 0
 alignment: 4
 style: 0
 size: 11.000000