#! /ufs/guido/bin/sgi/python
#! /ufs/guido/src/video/py

# Capture a CMIF movie using the Indigo video library and board


# Usage:
#
# makemovie [-q queuesize] [-t recordtime] [-a] [moviefile [audiofile]]


# Options:
#
# -q queuesize  : set the capture queue size (default and max 16)
# -t recordtime : set the record time in seconds (default 5 seconds)
# -a            : record audio as well
# moviefile     : here goes the movie data (default film.video);
#                 the format is documented in cmif-film.ms
# audiofile     : with -a, here goes the audio data (default film.aiff);
#                 audio data is recorded in AIFF format, using the
#                 input sampling rate, source and volume set by the
#                 audio panel, in mono, 8 bits/sample


# User interface:
#
# Start the application.  Resize the window to the desired movie size.
# Click the left mouse button to start recording (recording starts
# when you release the mouse button).  Recording time is specified by
# the -t option (XXX this should change).
#
# Press ESC or select the window manager Quit or Close window option
# to quit.  (You can do this without recording -- then the output
# files are untouched.)
#
# (It is possible to record more than once; but this doesn't set the
# time stamps correctly yet, and doesn't work at all with audio.  So
# don't use.)


# XXX To do:
#
# fix timestamps for second and further recordings
# fix audio      "   "      "   "       "
# flush audio buffer when recording starts
# make code more readable


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


def main():
	QSIZE = 16
	TIME = 5
	audio = 0

	opts, args = getopt.getopt(sys.argv[1:], 'aq:t:')
	for opt, arg in opts:
		if opt == '-a':
			audio = 1
		elif opt == '-q':
			QSIZE = string.atoi(arg)
		elif opt == '-t':
			TIME = string.atoi(arg)

	if args:
		filename = args[0]
	else:
		filename = 'film.video'

	if audio:
		if args[1:]:
			audiofilename = args[1]
		else:
			audiofilename = 'film.aiff'

	gl.foreground()

	x, y = SV.PAL_XMAX / 4, SV.PAL_YMAX / 4
	print x, 'x', y

	gl.minsize(40, 30)
	gl.stepunit(8, 6)
	gl.maxsize(SV.PAL_XMAX, SV.PAL_YMAX)
	gl.keepaspect(SV.PAL_XMAX, SV.PAL_YMAX)
	win = gl.winopen(filename)
	x, y = gl.getsize()
	print x, 'x', y

	v = sv.OpenVideo()
	v.BindGLWindow(win, SV.IN_REPLACE)
	v.SetSize(x, y)
	v.BindGLWindow(win, SV.IN_REPLACE)

	v.SetCaptureFormat(SV.RGB_FRAMES)
	v.SetCaptureMode(SV.BLOCKING_CAPTURE)
	v.SetQueueSize(QSIZE)
	v.InitCapture()
	if v.GetQueueSize() != QSIZE:
		QSIZE = v.GetQueueSize()
		print 'Warning: QSIZE reduced to', QSIZE

	gl.qdevice(DEVICE.LEFTMOUSE)
	gl.qdevice(DEVICE.WINQUIT)
	gl.qdevice(DEVICE.WINSHUT)
	gl.qdevice(DEVICE.ESCKEY)

	print 'Click left mouse to start recording', TIME, 'seconds'
	ofile = None
	afile = None
	# Mouse down opens the file & freezes window
	# Mouse up starts recording frames

	while 1:
		dev, val = gl.qread()
		if dev == DEVICE.LEFTMOUSE:
			# Start recording
			if val == 1:
				# Mouse down -- preparations
				if ofile == None:
					ofile = VFile.VoutFile().init(filename)
					ofile.format = 'rgb8'
					ofile.width = x
					ofile.height = y
					ofile.writeheader()
					# XXX other format bits?
				# The window can't be resized from now
				gl.prefsize(x, y)
				gl.winconstraints()
				gl.wintitle('* ' + filename)
				if audio:
					afile = initaudio(audiofilename)
				continue
			# Mouse up -- start actual recording
			global recording, stop_recording
			if audio:
				stop_recording = 0
				recording.release()
			t0 = time.millitimer()
			v.StartCapture()
			while 1:
				t = time.millitimer() - t0
				if t >= TIME*1000:
					break
				if v.GetCaptured() > 2:
					doframe(v, ofile, x, y, t)
			v.StopCapture()
			stop_recording = 1
			while v.GetCaptured() > 0:
				doframe(v, ofile, x, y, t)
				t = time.millitimer() - t0
			gl.wintitle(filename)
		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
			if ofile:
				ofile.close()
			if afile:
				afile.destroy()
			posix._exit(0)
			# EndCapture dumps core...
			v.EndCapture()
			v.CloseVideo()
			gl.winclose(win)

def doframe(v, ofile, x, y, t):
	cd, start = v.GetCaptureData()
	data = cd.interleave(x, y)
	cd.UnlockCaptureData()
	ofile.writeframe(t, data, None)

AQSIZE = 16000

def initaudio(filename):
	import thread, aiff
	global recording, stop_recording
	afile = aiff.Aiff().init(filename, 'w')
	afile.nchannels = AL.MONO
	afile.sampwidth = AL.SAMPLE_8
	params = [AL.INPUT_RATE, 0]
	al.getparams(AL.DEFAULT_DEVICE, params)
	print 'rate =', params[1]
	afile.samprate = params[1]
	c = al.newconfig()
	c.setchannels(AL.MONO)
	c.setqueuesize(AQSIZE)
	c.setwidth(AL.SAMPLE_8)
	aport = al.openport(filename, 'r', c)
	recording = thread.allocate_lock()
	recording.acquire()
	stop_recording = 0
	thread.start_new_thread(recorder, (afile, aport))
	return afile

def recorder(afile, aport):
	# XXX recording more than one fragment doesn't work
	# XXX (the thread never dies)
	recording.acquire()
	while not stop_recording:
		data = aport.readsamps(AQSIZE/2)
		afile.writesampsraw(data)
		del data

main()