New program: Video Bag Of Tricks.  Will eventually replace Vrec and
Vrecb.  Has a user interface dialog to set options etc.
diff --git a/Demo/sgi/video/Vb.py b/Demo/sgi/video/Vb.py
new file mode 100755
index 0000000..d79113c
--- /dev/null
+++ b/Demo/sgi/video/Vb.py
@@ -0,0 +1,300 @@
+#! /ufs/guido/bin/sgi/python
+
+# Video bag-of-tricks
+
+import sys
+import getopt
+import string
+import os
+sts = os.system('makemap')		# Must be before "import fl"
+import sgi
+import gl
+import GL
+import DEVICE
+import fl
+import FL
+import flp
+import watchcursor
+import sv
+import SV
+import VFile
+import VGrabber
+import imageop
+
+ARROW = 0
+WATCH = 1
+watchcursor.defwatch(WATCH)
+
+def main():
+	vb = VideoBagOfTricks().init()
+	while 1:
+		dummy = fl.do_forms()
+		[dummy]
+
+StopCapture = 'StopCapture'
+
+formats = ['rgb24', 'rgb8', 'grey8', 'grey4', 'grey2', \
+	   'grey2_dith', 'mono_dith', 'mono_thresh']
+formatmap = {'rgb24': 'rgb', 'grey8': 'grey'}
+
+class VideoBagOfTricks:
+
+	def init(self):
+		formdef = flp.parse_form('VbForm', 'form')
+		flp.create_full_form(self, formdef)
+		self.setdefaults()
+		self.openvideo()
+		self.makewindow()
+		self.bindvideo()
+		self.capturing = 0
+		self.b_stop.hide_object()
+		self.form.show_form(FL.PLACE_SIZE, FL.TRUE, \
+				    'Video Bag Of Tricks')
+		fl.set_event_call_back(self.do_event)
+		return self
+
+	def setwatch(self):
+		gl.winset(self.form.window)
+		gl.setcursor(WATCH, 0, 0)
+
+	def setarrow(self):
+		gl.winset(self.form.window)
+		gl.setcursor(ARROW, 0, 0)
+
+	def setdefaults(self):
+		self.format = 'rgb8'
+		self.c_format.clear_choice()
+		for label in formats:
+			self.c_format.addto_choice(label)
+		self.c_format.set_choice(1 + formats.index(self.format))
+		self.mono_thresh = 128
+		self.mono_use_thresh = 0
+		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')
+
+	def openvideo(self):
+		self.video = sv.OpenVideo()
+		param = [SV.BROADCAST, 0]
+		self.video.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)
+		self.maxx, self.maxy = x, y
+
+	def makewindow(self):
+		x, y = self.maxx, self.maxy
+		gl.foreground()
+		gl.maxsize(x, y)
+		gl.keepaspect(x, y)
+		gl.stepunit(8, 6)
+		width = 256 # XXX
+		if width:
+			height = width*3/4
+			x1 = 150
+			x2 = x1 + width-1
+			y2 = 768-150
+			y1 = y2-height+1
+			gl.prefposition(x1, x2, y1, y2)
+		self.window = gl.winopen('Vb: initializing')
+		self.settitle()
+		if width:
+			gl.maxsize(x, y)
+			gl.keepaspect(x, y)
+			gl.stepunit(8, 6)
+			gl.winconstraints()
+		gl.qdevice(DEVICE.LEFTMOUSE)
+		gl.qdevice(DEVICE.WINQUIT)
+		gl.qdevice(DEVICE.WINSHUT)
+
+	def settitle(self):
+		gl.winset(self.window)
+		gl.wintitle(self.maketitle())
+
+	def bindvideo(self):
+		x, y = gl.getsize()
+		self.video.SetSize(x, y)
+		drop = self.b_drop.get_button()
+		if drop:
+			param = [SV.FIELDDROP, 1, SV.GENLOCK, SV.GENLOCK_OFF]
+		else:
+			param = [SV.FIELDDROP, 0, SV.GENLOCK, SV.GENLOCK_ON]
+		if self.getformat()[:3] == 'rgb':
+			param = param+[SV.COLOR, SV.DEFAULT_COLOR, \
+				       SV.DITHER, 1, \
+				       SV.INPUT_BYPASS, 0]
+		else:
+			param = param+[SV.COLOR, SV.MONO, SV.DITHER, 0, \
+				       SV.INPUT_BYPASS, 1]
+		self.video.BindGLWindow(self.window, SV.IN_REPLACE)
+		self.video.SetParam(param)
+
+	def rebindvideo(self):
+		gl.winset(self.window)
+		self.bindvideo()
+
+	def do_event(self, dev, val):
+		#print 'Event:', dev, val
+		if dev in (DEVICE.WINSHUT, DEVICE.WINQUIT):
+			self.cb_quit()
+		if dev == DEVICE.REDRAW and val == self.window:
+			self.rebindvideo()
+			self.settitle()
+
+	def cb_format(self, *args):
+		i = self.c_format.get_choice()
+		label = format = formats[i-1]
+		if '_' in format:
+			i = string.find(format, '_')
+			format = format[:i]
+		if formatmap.has_key(format):
+			format = formatmap[format]
+		self.format = format
+		#
+		if label == 'mono_thresh':
+			self.mono_use_thresh = 1
+			s = `self.mono_thresh`
+			s = fl.show_input('Please enter mono threshold', s)
+			if s:
+				try:
+					self.mono_thresh = string.atoi(s)
+				except string.atoi_error:
+					fl.show_message( \
+						  'Bad input, using ' + \
+						  `self.mono_thresh`)
+		else:
+			self.mono_use_thresh = 0
+		#
+		self.rebindvideo()
+
+	def getformat(self):
+		return self.format
+
+	def cb_rate(self, *args):
+		pass
+
+	def cb_drop(self, *args):
+		self.rebindvideo()
+
+	def cb_burst(self, *args):
+		pass
+
+	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_open(self, *args):
+		filename = self.in_file.get_input()
+		hd, tl = os.path.split(filename)
+		filename = fl.file_selector('Select file:', hd, '', tl)
+		if filename:
+			hd, tl = os.path.split(filename)
+			if hd == os.getcwd():
+				filename = tl
+			self.in_file.set_input(filename)
+			self.cb_file()
+
+	def cb_play(self, *args):
+		filename = self.in_file.get_input()
+		sts = os.system('Vplay -q ' + filename + ' &')
+
+	def cb_stop(self, *args):
+		if self.capturing:
+			raise StopCapture
+		gl.ringbell()
+
+	def cb_capture(self, *args):
+		self.setwatch()
+		self.cb_file() # Make sure filename is OK
+		filename = self.in_file.get_input()
+		format = self.getformat()
+		vout = VFile.VoutFile().init(filename)
+		vout.setformat(format)
+		gl.winset(self.window)
+		x, y = gl.getsize()
+		vout.setsize(x, y)
+		vout.writeheader()
+		convertor = None
+		if format[:4] == 'grey':
+			s = format[4:]
+			if s:
+				greybits = string.atoi(s)
+			else:
+				greybits = 8
+			# XXX Should get this from somewhere else?
+			if greybits == 2:
+				convertor = imageop.grey2grey2
+			elif greybits == 4:
+				convertor = imageop.grey2grey4
+			elif greybits == -2:
+				convertor = imageop.dither2grey2
+		vformat = SV.RGB8_FRAMES
+		qsize = 0
+		rate = eval(self.in_rate.get_input())
+		info = (vformat, x, y, qsize, rate)
+		ids = []
+		tpf = 50
+		self.video.InitContinuousCapture(info)
+		self.capturing = 1
+		self.setarrow()
+		self.b_stop.show_object()
+		while 1:
+			try:
+				void = fl.check_forms()
+			except StopCapture:
+				self.capturing = 0
+				break
+			try:
+				cd, id = self.video.GetCaptureData()
+			except sv.error:
+				sgi.nap(1)
+				continue
+			ids.append(id)
+			id = id + 2*rate
+			data = cd.InterleaveFields(1)
+			cd.UnlockCaptureData()
+			t = id*tpf
+			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)
+		self.setwatch()
+		vout.close()
+		self.b_stop.hide_object()
+		self.video.EndContinuousCapture()
+		self.setarrow()
+
+	def cb_quit(self, *args):
+		raise SystemExit, 0
+
+	def maketitle(self):
+		x, y = gl.getsize()
+		return 'Vb:' + self.in_file.get_input() + ' (%dx%d)' % (x, y)
+
+try:
+	main()
+except KeyboardInterrupt:
+	print '[Interrupt]'
+	sys.exit(1)
diff --git a/Demo/sgi/video/VbForm.fd b/Demo/sgi/video/VbForm.fd
new file mode 100644
index 0000000..164c2c7
--- /dev/null
+++ b/Demo/sgi/video/VbForm.fd
@@ -0,0 +1,270 @@
+Magic: 12321
+
+Internal Form Definition File
+    (do not change)
+
+Number of forms: 1
+
+=============== FORM ===============
+Name: form
+Width: 350.000000
+Height: 240.000000
+Number of Objects: 17
+
+--------------------
+class: 1
+type: 1
+box: 0.000000 0.000000 350.000000 240.000000
+boxtype: 1
+colors: 47 47
+alignment: 4
+style: 0
+size: 11.000000
+lcol: 0
+label: 
+name: 
+callback: 
+argument: 
+
+--------------------
+class: 1
+type: 2
+box: 140.000000 10.000000 120.000000 160.000000
+boxtype: 2
+colors: 47 47
+alignment: 0
+style: 0
+size: 11.000000
+lcol: 0
+label: Burst mode:
+name: 
+callback: 
+argument: 
+
+--------------------
+class: 1
+type: 2
+box: 10.000000 10.000000 120.000000 160.000000
+boxtype: 2
+colors: 47 47
+alignment: 0
+style: 0
+size: 11.000000
+lcol: 0
+label: Options:
+name: 
+callback: 
+argument: 
+
+--------------------
+class: 31
+type: 2
+box: 60.000000 50.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: 31
+type: 1
+box: 150.000000 70.000000 100.000000 30.000000
+boxtype: 2
+colors: 13 5
+alignment: 0
+style: 0
+size: 11.000000
+lcol: 0
+label: Max Mbytes:
+name: in_maxmem
+callback: cb_maxmem
+argument: 0
+
+--------------------
+class: 31
+type: 2
+box: 150.000000 20.000000 100.000000 30.000000
+boxtype: 2
+colors: 13 5
+alignment: 0
+style: 0
+size: 11.000000
+lcol: 0
+label: Nr. of fields:
+name: in_nframes
+callback: cb_nframes
+argument: 0
+
+--------------------
+class: 12
+type: 1
+box: 150.000000 130.000000 100.000000 30.000000
+boxtype: 1
+colors: 39 3
+alignment: 4
+style: 0
+size: 11.000000
+lcol: 0
+label: Burst mode
+name: b_burst
+callback: cb_burst
+argument: 0
+
+--------------------
+class: 31
+type: 0
+box: 50.000000 200.000000 209.999985 30.000000
+boxtype: 2
+colors: 13 5
+alignment: 2
+style: 0
+size: 11.000000
+lcol: 0
+label: File:
+name: in_file
+callback: cb_file
+argument: 0
+
+--------------------
+class: 11
+type: 0
+box: 270.000000 200.000000 70.000000 30.000000
+boxtype: 1
+colors: 47 47
+alignment: 4
+style: 0
+size: 11.000000
+lcol: 0
+label: Open...
+name: b_open
+callback: cb_open
+argument: 0
+
+--------------------
+class: 11
+type: 0
+box: 270.000000 110.000000 70.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: 13
+type: 1
+box: 20.000000 20.000000 110.000000 30.000000
+boxtype: 0
+colors: 7 3
+alignment: 4
+style: 0
+size: 11.000000
+lcol: 0
+label: "Fielddrop"
+name: b_drop
+callback: cb_drop
+argument: 0
+
+--------------------
+class: 2
+type: 0
+box: 30.000000 50.000000 30.000000 30.000000
+boxtype: 0
+colors: 47 47
+alignment: 2
+style: 0
+size: 11.000000
+lcol: 0
+label: 1/
+name: 
+callback: 
+argument: 
+
+--------------------
+class: 2
+type: 0
+box: 100.000000 50.000000 30.000000 30.000000
+boxtype: 0
+colors: 47 47
+alignment: 2
+style: 0
+size: 11.000000
+lcol: 0
+label: fr
+name: 
+callback: 
+argument: 
+
+--------------------
+class: 11
+type: 0
+box: 270.000000 10.000000 70.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: 270.000000 60.000000 70.000000 30.000000
+boxtype: 1
+colors: 47 47
+alignment: 4
+style: 0
+size: 11.000000
+lcol: 0
+label: Play
+name: b_play
+callback: cb_play
+argument: 0
+
+--------------------
+class: 42
+type: 0
+box: 20.000000 110.000000 100.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: 11
+type: 0
+box: 0.000000 0.000000 350.000000 240.000000
+boxtype: 1
+colors: 47 47
+alignment: 4
+style: 0
+size: 11.000000
+lcol: 0
+label: Stop capture
+name: b_stop
+callback: cb_stop
+argument: 0
+
+==============================
+create_the_forms