| /********************************************************** | 
 | Copyright 1991, 1992, 1993 by Stichting Mathematisch Centrum, | 
 | Amsterdam, The Netherlands. | 
 |  | 
 |                         All Rights Reserved | 
 |  | 
 | Permission to use, copy, modify, and distribute this software and its  | 
 | documentation for any purpose and without fee is hereby granted,  | 
 | provided that the above copyright notice appear in all copies and that | 
 | both that copyright notice and this permission notice appear in  | 
 | supporting documentation, and that the names of Stichting Mathematisch | 
 | Centrum or CWI not be used in advertising or publicity pertaining to | 
 | distribution of the software without specific, written prior permission. | 
 |  | 
 | STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO | 
 | THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | 
 | FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE | 
 | FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 
 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 
 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | 
 | OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 
 |  | 
 | ******************************************************************/ | 
 |  | 
 | /* SV module -- interface to the Indigo video board */ | 
 |  | 
 | #include <sys/time.h> | 
 | #include <svideo.h> | 
 | #include "allobjects.h" | 
 | #include "import.h" | 
 | #include "modsupport.h" | 
 | #include "compile.h" | 
 | #include "ceval.h" | 
 |  | 
 | typedef struct { | 
 | 	OB_HEAD | 
 | 	SV_nodeP ob_svideo; | 
 | 	svCaptureInfo ob_info; | 
 | } svobject; | 
 |  | 
 | typedef struct { | 
 | 	OB_HEAD | 
 | 	void *ob_capture; | 
 | 	int ob_mustunlock; | 
 | 	svCaptureInfo ob_info; | 
 | 	svobject *ob_svideo; | 
 | } captureobject; | 
 |  | 
 | static object *SvError;		/* exception sv.error */ | 
 |  | 
 | static object *newcaptureobject PROTO((svobject *, void *, int)); | 
 |  | 
 | /* Set a SV-specific error from svideo_errno and return NULL */ | 
 | static object * | 
 | sv_error() | 
 | { | 
 | 	err_setstr(SvError, svStrerror(svideo_errno)); | 
 | 	return NULL; | 
 | } | 
 |  | 
 | static object * | 
 | svc_conversion(self, args, function, factor) | 
 | 	captureobject *self; | 
 | 	object *args; | 
 | 	void (*function)(); | 
 | 	int factor; | 
 | { | 
 | 	object *output; | 
 | 	int invert; | 
 |  | 
 | 	if (!getargs(args, "i", &invert)) | 
 | 		return NULL; | 
 |  | 
 | 	output = newsizedstringobject(NULL, self->ob_info.width * self->ob_info.height * factor); | 
 | 	if (output == NULL) | 
 | 		return NULL; | 
 |  | 
 | 	(*function)((boolean) invert, self->ob_capture, getstringvalue(output), | 
 | 		    self->ob_info.width, self->ob_info.height); | 
 |  | 
 | 	return output; | 
 | } | 
 |  | 
 | static object * | 
 | svc_YUVtoRGB(self, args) | 
 | 	captureobject *self; | 
 | 	object *args; | 
 | { | 
 | 	switch (self->ob_info.format) { | 
 | 	case SV_YUV411_FRAMES: | 
 | 	case SV_YUV411_FRAMES_AND_BLANKING_BUFFER: | 
 | 		break; | 
 | 	default: | 
 | 		err_setstr(SvError, "data had bad format"); | 
 | 		return NULL; | 
 | 	} | 
 | 	return svc_conversion(self, args, svYUVtoRGB, sizeof(long)); | 
 | } | 
 |  | 
 | static object * | 
 | svc_RGB8toRGB32(self, args) | 
 | 	captureobject *self; | 
 | 	object *args; | 
 | { | 
 | 	if (self->ob_info.format != SV_RGB8_FRAMES) { | 
 | 		err_setstr(SvError, "data has bad format"); | 
 | 		return NULL; | 
 | 	} | 
 | 	return svc_conversion(self, args, svRGB8toRGB32, sizeof(long)); | 
 | } | 
 |  | 
 | static object * | 
 | svc_InterleaveFields(self, args) | 
 | 	captureobject *self; | 
 | 	object *args; | 
 | { | 
 | 	if (self->ob_info.format != SV_RGB8_FRAMES) { | 
 | 		err_setstr(SvError, "data has bad format"); | 
 | 		return NULL; | 
 | 	} | 
 | 	return svc_conversion(self, args, svInterleaveFields, 1); | 
 | } | 
 |  | 
 | static object * | 
 | svc_GetFields(self, args) | 
 | 	captureobject *self; | 
 | 	object *args; | 
 | { | 
 | 	object *f1, *f2, *ret; | 
 | 	int fieldsize; | 
 |  | 
 | 	if (self->ob_info.format != SV_RGB8_FRAMES) { | 
 | 		err_setstr(SvError, "data has bad format"); | 
 | 		return NULL; | 
 | 	} | 
 |  | 
 | 	fieldsize = self->ob_info.width * self->ob_info.height / 2; | 
 | 	f1 = newsizedstringobject((char *) self->ob_capture, fieldsize); | 
 | 	f2 = newsizedstringobject((char *) self->ob_capture + fieldsize, fieldsize); | 
 | 	ret = mkvalue("(OO)", f1, f2); | 
 | 	XDECREF(f1); | 
 | 	XDECREF(f2); | 
 | 	return ret; | 
 | } | 
 | 	 | 
 | static object * | 
 | svc_UnlockCaptureData(self, args) | 
 | 	captureobject *self; | 
 | 	object *args; | 
 | { | 
 | 	if (!getnoarg(args)) | 
 | 		return NULL; | 
 |  | 
 | 	if (!self->ob_mustunlock) { | 
 | 		err_setstr(SvError, "buffer should not be unlocked"); | 
 | 		return NULL; | 
 | 	} | 
 |  | 
 | 	if (svUnlockCaptureData(self->ob_svideo->ob_svideo, self->ob_capture)) | 
 | 		return sv_error(); | 
 |  | 
 | 	self->ob_mustunlock = 0; | 
 |  | 
 | 	INCREF(None); | 
 | 	return None; | 
 | } | 
 |  | 
 | #ifdef USE_GL | 
 | #include <gl.h> | 
 |  | 
 | static object * | 
 | svc_lrectwrite(self, args) | 
 | 	captureobject *self; | 
 | 	object *args; | 
 | { | 
 | 	Screencoord x1, x2, y1, y2; | 
 |  | 
 | 	if (!getargs(args, "(hhhh)", &x1, &x2, &y1, &y2)) | 
 | 		return NULL; | 
 |  | 
 | 	lrectwrite(x1, x2, y1, y2, (unsigned long *) self->ob_capture); | 
 |  | 
 | 	INCREF(None); | 
 | 	return None; | 
 | } | 
 | #endif | 
 |  | 
 | static object * | 
 | writefile(self, args) | 
 | 	captureobject *self; | 
 | 	object *args; | 
 | { | 
 | 	object *file; | 
 | 	int size; | 
 |  | 
 | 	if (!getargs(args, "O", &file)) | 
 | 		return NULL; | 
 |  | 
 | 	if (!is_fileobject(file)) { | 
 | 		err_setstr(SvError, "not a file object"); | 
 | 		return NULL; | 
 | 	} | 
 |  | 
 | 	size = self->ob_info.width * self->ob_info.height; | 
 |  | 
 | 	if (fwrite(self->ob_capture, sizeof(long), size, getfilefile(file)) != size) { | 
 | 		err_setstr(SvError, "writing failed"); | 
 | 		return NULL; | 
 | 	} | 
 |  | 
 | 	INCREF(None); | 
 | 	return None; | 
 | } | 
 |  | 
 | static object * | 
 | svc_FindVisibleRegion(self, args) | 
 | 	captureobject *self; | 
 | 	object *args; | 
 | { | 
 | 	void *visible; | 
 | 	int width; | 
 |  | 
 | 	if (!getnoarg(args)) | 
 | 		return NULL; | 
 |  | 
 | 	if (svFindVisibleRegion(self->ob_svideo->ob_svideo, self->ob_capture, &visible, self->ob_info.width)) | 
 | 		return sv_error(); | 
 |  | 
 | 	if (visible == NULL) { | 
 | 		err_setstr(SvError, "data in wrong format"); | 
 | 		return NULL; | 
 | 	} | 
 |  | 
 | 	return newcaptureobject(self->ob_svideo, visible, 0); | 
 | } | 
 |  | 
 | static struct methodlist capture_methods[] = { | 
 | 	{"YUVtoRGB",		svc_YUVtoRGB}, | 
 | 	{"RGB8toRGB32",		svc_RGB8toRGB32}, | 
 | 	{"InterleaveFields",	svc_InterleaveFields}, | 
 | 	{"UnlockCaptureData",	svc_UnlockCaptureData}, | 
 | 	{"FindVisibleRegion",	svc_FindVisibleRegion}, | 
 | 	{"GetFields",		svc_GetFields}, | 
 | #ifdef USE_GL | 
 | 	{"lrectwrite",		svc_lrectwrite}, | 
 | #endif | 
 | 	{"writefile",		writefile}, | 
 | 	{NULL,			NULL} 		/* sentinel */ | 
 | }; | 
 |  | 
 | static void | 
 | capture_dealloc(self) | 
 | 	captureobject *self; | 
 | { | 
 | 	if (self->ob_capture != NULL) { | 
 | 		if (self->ob_mustunlock) | 
 | 			(void) svUnlockCaptureData(self->ob_svideo->ob_svideo, self->ob_capture); | 
 | 		self->ob_capture = NULL; | 
 | 		DECREF(self->ob_svideo); | 
 | 		self->ob_svideo = NULL; | 
 | 	} | 
 | 	DEL(self); | 
 | } | 
 |  | 
 | static object * | 
 | capture_getattr(self, name) | 
 | 	svobject *self; | 
 | 	char *name; | 
 | { | 
 | 	return findmethod(capture_methods, (object *)self, name); | 
 | } | 
 |  | 
 | typeobject Capturetype = { | 
 | 	OB_HEAD_INIT(&Typetype) | 
 | 	0,			/*ob_size*/ | 
 | 	"capture",		/*tp_name*/ | 
 | 	sizeof(captureobject),	/*tp_size*/ | 
 | 	0,			/*tp_itemsize*/ | 
 | 	/* methods */ | 
 | 	capture_dealloc,	/*tp_dealloc*/ | 
 | 	0,			/*tp_print*/ | 
 | 	capture_getattr,	/*tp_getattr*/ | 
 | 	0,			/*tp_setattr*/ | 
 | 	0,			/*tp_compare*/ | 
 | 	0,			/*tp_repr*/ | 
 | }; | 
 |  | 
 | static object * | 
 | newcaptureobject(self, ptr, mustunlock) | 
 | 	svobject *self; | 
 | 	void *ptr; | 
 | 	int mustunlock; | 
 | { | 
 | 	captureobject *p; | 
 |  | 
 | 	p = NEWOBJ(captureobject, &Capturetype); | 
 | 	if (p == NULL) | 
 | 		return NULL; | 
 | 	p->ob_svideo = self; | 
 | 	INCREF(self); | 
 | 	p->ob_capture = ptr; | 
 | 	p->ob_mustunlock = mustunlock; | 
 | 	p->ob_info = self->ob_info; | 
 | 	return (object *) p; | 
 | } | 
 |  | 
 | static object * | 
 | sv_GetCaptureData(self, args) | 
 | 	svobject *self; | 
 | 	object *args; | 
 | { | 
 | 	void *ptr; | 
 | 	long fieldID; | 
 | 	object *res, *c; | 
 |  | 
 | 	if (!getnoarg(args)) | 
 | 		return NULL; | 
 |  | 
 | 	if (svGetCaptureData(self->ob_svideo, &ptr, &fieldID)) | 
 | 		return sv_error(); | 
 |  | 
 | 	if (ptr == NULL) { | 
 | 		err_setstr(SvError, "no data available"); | 
 | 		return NULL; | 
 | 	} | 
 |  | 
 | 	c = newcaptureobject(self, ptr, 1); | 
 | 	if (c == NULL) | 
 | 		return NULL; | 
 | 	res = mkvalue("(Oi)", c, fieldID); | 
 | 	DECREF(c); | 
 | 	return res; | 
 | } | 
 |  | 
 | static object * | 
 | sv_BindGLWindow(self, args) | 
 | 	svobject *self; | 
 | 	object *args; | 
 | { | 
 | 	long wid; | 
 | 	int mode; | 
 |  | 
 | 	if (!getargs(args, "(ii)", &wid, &mode)) | 
 | 		return NULL; | 
 |  | 
 | 	if (svBindGLWindow(self->ob_svideo, wid, mode)) | 
 | 		return sv_error(); | 
 |  | 
 | 	INCREF(None); | 
 | 	return None; | 
 | } | 
 |  | 
 | static object * | 
 | sv_EndContinuousCapture(self, args) | 
 | 	svobject *self; | 
 | 	object *args; | 
 | { | 
 |  | 
 | 	if (!getnoarg(args)) | 
 | 		return NULL; | 
 |  | 
 | 	if (svEndContinuousCapture(self->ob_svideo)) | 
 | 		return sv_error(); | 
 |  | 
 | 	INCREF(None); | 
 | 	return None; | 
 | } | 
 |  | 
 | static object * | 
 | sv_IsVideoDisplayed(self, args) | 
 | 	svobject *self; | 
 | 	object *args; | 
 | { | 
 | 	int v; | 
 |  | 
 | 	if (!getnoarg(args)) | 
 | 		return NULL; | 
 |  | 
 | 	v = svIsVideoDisplayed(self->ob_svideo); | 
 | 	if (v == -1) | 
 | 		return sv_error(); | 
 |  | 
 | 	return newintobject((long) v); | 
 | } | 
 |  | 
 | static object * | 
 | sv_OutputOffset(self, args) | 
 | 	svobject *self; | 
 | 	object *args; | 
 | { | 
 | 	int x_offset; | 
 | 	int y_offset; | 
 |  | 
 | 	if (!getargs(args, "(ii)", &x_offset, &y_offset)) | 
 | 		return NULL; | 
 |  | 
 | 	if (svOutputOffset(self->ob_svideo, x_offset, y_offset)) | 
 | 		return sv_error(); | 
 |  | 
 | 	INCREF(None); | 
 | 	return None; | 
 | } | 
 |  | 
 | static object * | 
 | sv_PutFrame(self, args) | 
 | 	svobject *self; | 
 | 	object *args; | 
 | { | 
 | 	char *buffer; | 
 |  | 
 | 	if (!getargs(args, "s", &buffer)) | 
 | 		return NULL; | 
 |  | 
 | 	if (svPutFrame(self->ob_svideo, buffer)) | 
 | 		return sv_error(); | 
 |  | 
 | 	INCREF(None); | 
 | 	return None; | 
 | } | 
 |  | 
 | static object * | 
 | sv_QuerySize(self, args) | 
 | 	svobject *self; | 
 | 	object *args; | 
 | { | 
 | 	int w; | 
 | 	int h; | 
 | 	int rw; | 
 | 	int rh; | 
 |  | 
 | 	if (!getargs(args, "(ii)", &w, &h)) | 
 | 		return NULL; | 
 |  | 
 | 	if (svQuerySize(self->ob_svideo, w, h, &rw, &rh)) | 
 | 		return sv_error(); | 
 |  | 
 | 	return mkvalue("(ii)", (long) rw, (long) rh); | 
 | } | 
 |  | 
 | static object * | 
 | sv_SetSize(self, args) | 
 | 	svobject *self; | 
 | 	object *args; | 
 | { | 
 | 	int w; | 
 | 	int h; | 
 |  | 
 | 	if (!getargs(args, "(ii)", &w, &h)) | 
 | 		return NULL; | 
 |  | 
 | 	if (svSetSize(self->ob_svideo, w, h)) | 
 | 		return sv_error(); | 
 |  | 
 | 	INCREF(None); | 
 | 	return None; | 
 | } | 
 |  | 
 | static object * | 
 | sv_SetStdDefaults(self, args) | 
 | 	svobject *self; | 
 | 	object *args; | 
 | { | 
 |  | 
 | 	if (!getnoarg(args)) | 
 | 		return NULL; | 
 |  | 
 | 	if (svSetStdDefaults(self->ob_svideo)) | 
 | 		return sv_error(); | 
 |  | 
 | 	INCREF(None); | 
 | 	return None; | 
 | } | 
 |  | 
 | static object * | 
 | sv_UseExclusive(self, args) | 
 | 	svobject *self; | 
 | 	object *args; | 
 | { | 
 | 	boolean onoff; | 
 | 	int mode; | 
 |  | 
 | 	if (!getargs(args, "(ii)", &onoff, &mode)) | 
 | 		return NULL; | 
 |  | 
 | 	if (svUseExclusive(self->ob_svideo, onoff, mode)) | 
 | 		return sv_error(); | 
 |  | 
 | 	INCREF(None); | 
 | 	return None; | 
 | } | 
 |  | 
 | static object * | 
 | sv_WindowOffset(self, args) | 
 | 	svobject *self; | 
 | 	object *args; | 
 | { | 
 | 	int x_offset; | 
 | 	int y_offset; | 
 |  | 
 | 	if (!getargs(args, "(ii)", &x_offset, &y_offset)) | 
 | 		return NULL; | 
 |  | 
 | 	if (svWindowOffset(self->ob_svideo, x_offset, y_offset)) | 
 | 		return sv_error(); | 
 |  | 
 | 	INCREF(None); | 
 | 	return None; | 
 | } | 
 |  | 
 | static object * | 
 | sv_CaptureBurst(self, args) | 
 | 	svobject *self; | 
 | 	object *args; | 
 | { | 
 | 	int bytes, i; | 
 | 	svCaptureInfo info; | 
 | 	void *bitvector = NULL; | 
 | 	object *videodata, *bitvecobj, *res; | 
 | 	static object *evenitem, *odditem; | 
 |  | 
 | 	if (!getargs(args, "(iiiii)", &info.format, &info.width, &info.height, | 
 | 		     &info.size, &info.samplingrate)) | 
 | 		return NULL; | 
 |  | 
 | 	switch (info.format) { | 
 | 	case SV_RGB8_FRAMES: | 
 | 		bitvector = malloc(SV_BITVEC_SIZE(info.size)); | 
 | 		break; | 
 | 	case SV_YUV411_FRAMES_AND_BLANKING_BUFFER: | 
 | 		break; | 
 | 	default: | 
 | 		err_setstr(SvError, "illegal format specified"); | 
 | 		return NULL; | 
 | 	} | 
 |  | 
 | 	if (svQueryCaptureBufferSize(self->ob_svideo, &info, &bytes)) { | 
 | 		if (bitvector) | 
 | 			free(bitvector); | 
 | 		return sv_error(); | 
 | 	} | 
 |  | 
 | 	videodata = newsizedstringobject(NULL, bytes); | 
 | 	if (videodata == NULL) { | 
 | 		if (bitvector) | 
 | 			free(bitvector); | 
 | 		return NULL; | 
 | 	} | 
 |  | 
 | 	/* XXX -- need to do something about the bitvector */ | 
 | 	if (svCaptureBurst(self->ob_svideo, &info, getstringvalue(videodata), | 
 | 			   bitvector)) { | 
 | 		if (bitvector) | 
 | 			free(bitvector); | 
 | 		DECREF(videodata); | 
 | 		return sv_error(); | 
 | 	} | 
 |  | 
 | 	if (bitvector) { | 
 | 		if (evenitem == NULL) { | 
 | 			evenitem = newintobject(0); | 
 | 			if (evenitem == NULL) { | 
 | 				free(bitvector); | 
 | 				DECREF(videodata); | 
 | 				return NULL; | 
 | 			} | 
 | 		} | 
 | 		if (odditem == NULL) { | 
 | 			odditem = newintobject(1); | 
 | 			if (odditem == NULL) { | 
 | 				free(bitvector); | 
 | 				DECREF(videodata); | 
 | 				return NULL; | 
 | 			} | 
 | 		} | 
 | 		bitvecobj = newtupleobject(2 * info.size); | 
 | 		if (bitvecobj == NULL) { | 
 | 			free(bitvecobj); | 
 | 			DECREF(videodata); | 
 | 			return NULL; | 
 | 		} | 
 | 		for (i = 0; i < 2 * info.size; i++) { | 
 | 			if (SV_GET_FIELD(bitvector, i) == SV_EVEN_FIELD) { | 
 | 				INCREF(evenitem); | 
 | 				settupleitem(bitvecobj, i, evenitem); | 
 | 			} else { | 
 | 				INCREF(odditem); | 
 | 				settupleitem(bitvecobj, i, odditem); | 
 | 			} | 
 | 		} | 
 | 		free(bitvector); | 
 | 	} else { | 
 | 		bitvecobj = None; | 
 | 		INCREF(None); | 
 | 	} | 
 |  | 
 | 	res = mkvalue("((iiiii)OO)", info.format, info.width, info.height, | 
 | 		       info.size, info.samplingrate, videodata, bitvecobj); | 
 | 	DECREF(videodata); | 
 | 	DECREF(bitvecobj); | 
 | 	return res; | 
 | } | 
 |  | 
 | static object * | 
 | sv_CaptureOneFrame(self, args) | 
 | 	svobject *self; | 
 | 	object *args; | 
 | { | 
 | 	svCaptureInfo info; | 
 | 	int format, width, height; | 
 | 	int bytes; | 
 | 	object *videodata, *res; | 
 | 	 | 
 | 	if (!getargs(args, "(iii)", &format, &width, &height)) | 
 | 		return NULL; | 
 | 	info.format = format; | 
 | 	info.width = width; | 
 | 	info.height = height; | 
 | 	info.size = 0; | 
 | 	info.samplingrate = 0; | 
 | 	if (svQueryCaptureBufferSize(self->ob_svideo, &info, &bytes)) | 
 | 		return sv_error(); | 
 | 	videodata = newsizedstringobject(NULL, bytes); | 
 | 	if (videodata == NULL) | 
 | 		return NULL; | 
 | 	if (svCaptureOneFrame(self->ob_svideo, format, &width, &height, | 
 | 			      getstringvalue(videodata))) { | 
 | 		DECREF(videodata); | 
 | 		return sv_error(); | 
 | 	} | 
 |  | 
 | 	res = mkvalue("(iiO)", width, height, videodata); | 
 | 	DECREF(videodata); | 
 | 	return res; | 
 | } | 
 |  | 
 | static object * | 
 | sv_InitContinuousCapture(self, args) | 
 | 	svobject *self; | 
 | 	object *args; | 
 | { | 
 | 	svCaptureInfo info; | 
 |  | 
 | 	if (!getargs(args, "(iiiii)", &info.format, &info.width, &info.height, | 
 | 		     &info.size, &info.samplingrate)) | 
 | 		return NULL; | 
 |  | 
 | 	if (svInitContinuousCapture(self->ob_svideo, &info)) | 
 | 		return sv_error(); | 
 |  | 
 | 	self->ob_info = info; | 
 |  | 
 | 	return mkvalue("(iiiii)", info.format, info.width, info.height, | 
 | 		       info.size, info.samplingrate); | 
 | } | 
 |  | 
 | static object * | 
 | sv_LoadMap(self, args) | 
 | 	svobject *self; | 
 | 	object *args; | 
 | { | 
 | 	object *rgb, *v, *cell; | 
 | 	rgb_tuple *mapp; | 
 | 	int maptype; | 
 | 	int i, j;		/* indices */ | 
 |  | 
 | 	if (!getargs(args, "(iO)", &maptype, &rgb)) | 
 | 		return NULL; | 
 | 	if (!is_listobject(rgb) || getlistsize(rgb) != 256) { | 
 | 		err_badarg(); | 
 | 		return NULL; | 
 | 	} | 
 | 	mapp = NEW(rgb_tuple, 256); | 
 | 	if (mapp == NULL) | 
 | 		return err_nomem(); | 
 | 	for (i = 0; i < 256; i++) { | 
 | 		v = getlistitem(rgb, i); | 
 | 		if (!is_tupleobject(v) || gettuplesize(v) != 3) { | 
 | 			DEL(mapp); | 
 | 			err_badarg(); | 
 | 			return NULL; | 
 | 		} | 
 | 		for (j = 0; j < 3; j++) { | 
 | 			cell = gettupleitem(v, j); | 
 | 			if (!is_intobject(cell)) { | 
 | 				DEL(mapp); | 
 | 				err_badarg(); | 
 | 				return NULL; | 
 | 			} | 
 | 			switch (j) { | 
 | 			case 0: mapp[i].red = getintvalue(cell); break; | 
 | 			case 1: mapp[i].blue = getintvalue(cell); break; | 
 | 			case 2: mapp[i].green = getintvalue(cell); break; | 
 | 			} | 
 | 		} | 
 | 	} | 
 |  | 
 | 	if (svLoadMap(self->ob_svideo, maptype, mapp)) { | 
 | 		DEL(mapp); | 
 | 		return sv_error(); | 
 | 	} | 
 |  | 
 | 	DEL(mapp); | 
 |  | 
 | 	INCREF(None); | 
 | 	return None; | 
 | } | 
 | 		 | 
 | static object * | 
 | sv_CloseVideo(self, args) | 
 | 	svobject *self; | 
 | 	object *args; | 
 | { | 
 | 	if (!getnoarg(args)) | 
 | 		return NULL; | 
 |  | 
 | 	if (svCloseVideo(self->ob_svideo)) | 
 | 		return sv_error(); | 
 | 	self->ob_svideo = NULL; | 
 |  | 
 | 	INCREF(None); | 
 | 	return None; | 
 | } | 
 |  | 
 | static object * | 
 | doParams(self, args, func, modified) | 
 | 	svobject *self; | 
 | 	object *args; | 
 | 	int (*func)(SV_nodeP, long *, int); | 
 | 	int modified; | 
 | { | 
 | 	object *list, *v; | 
 | 	long *PVbuffer; | 
 | 	long length; | 
 | 	int i; | 
 | 	 | 
 | 	if (!getargs(args, "O", &list)) | 
 | 		return NULL; | 
 | 	if (!is_listobject(list)) { | 
 | 		err_badarg(); | 
 | 		return NULL; | 
 | 	} | 
 | 	length = getlistsize(list); | 
 | 	PVbuffer = NEW(long, length); | 
 | 	if (PVbuffer == NULL) | 
 | 		return err_nomem(); | 
 | 	for (i = 0; i < length; i++) { | 
 | 		v = getlistitem(list, i); | 
 | 		if (!is_intobject(v)) { | 
 | 			DEL(PVbuffer); | 
 | 			err_badarg(); | 
 | 			return NULL; | 
 | 		} | 
 | 		PVbuffer[i] = getintvalue(v); | 
 | 	} | 
 |  | 
 | 	if ((*func)(self->ob_svideo, PVbuffer, length)) { | 
 | 		DEL(PVbuffer); | 
 | 		return sv_error(); | 
 | 	} | 
 |  | 
 | 	if (modified) { | 
 | 		for (i = 0; i < length; i++) | 
 | 			setlistitem(list, i, newintobject(PVbuffer[i])); | 
 | 	} | 
 |  | 
 | 	DEL(PVbuffer); | 
 |  | 
 | 	INCREF(None); | 
 | 	return None; | 
 | } | 
 |  | 
 | static object * | 
 | sv_GetParam(self, args) | 
 | 	object *self, *args; | 
 | { | 
 | 	return doParams(self, args, svGetParam, 1); | 
 | } | 
 |  | 
 | static object * | 
 | sv_GetParamRange(self, args) | 
 | 	object *self, *args; | 
 | { | 
 | 	return doParams(self, args, svGetParamRange, 1); | 
 | } | 
 |  | 
 | static object * | 
 | sv_SetParam(self, args) | 
 | 	object *self, *args; | 
 | { | 
 | 	return doParams(self, args, svSetParam, 0); | 
 | } | 
 |  | 
 | static struct methodlist svideo_methods[] = { | 
 | 	{"BindGLWindow",	sv_BindGLWindow}, | 
 | 	{"EndContinuousCapture",sv_EndContinuousCapture}, | 
 | 	{"IsVideoDisplayed",	sv_IsVideoDisplayed}, | 
 | 	{"OutputOffset",	sv_OutputOffset}, | 
 | 	{"PutFrame",		sv_PutFrame}, | 
 | 	{"QuerySize",		sv_QuerySize}, | 
 | 	{"SetSize",		sv_SetSize}, | 
 | 	{"SetStdDefaults",	sv_SetStdDefaults}, | 
 | 	{"UseExclusive",	sv_UseExclusive}, | 
 | 	{"WindowOffset",	sv_WindowOffset}, | 
 | 	{"InitContinuousCapture",sv_InitContinuousCapture}, | 
 | 	{"CaptureBurst",	sv_CaptureBurst}, | 
 | 	{"CaptureOneFrame",	sv_CaptureOneFrame}, | 
 | 	{"GetCaptureData",	sv_GetCaptureData}, | 
 | 	{"CloseVideo",		sv_CloseVideo}, | 
 | 	{"LoadMap",		sv_LoadMap}, | 
 | 	{"GetParam",		sv_GetParam}, | 
 | 	{"GetParamRange",	sv_GetParamRange}, | 
 | 	{"SetParam",		sv_SetParam}, | 
 | 	{NULL,			NULL} 		/* sentinel */ | 
 | }; | 
 |  | 
 | static object * | 
 | sv_conversion(self, args, function, inputfactor, factor) | 
 | 	object *self, *args; | 
 | 	void (*function)(); | 
 | 	int inputfactor, factor; | 
 | { | 
 | 	int invert, width, height, inputlength; | 
 | 	char *input; | 
 | 	object *output; | 
 |  | 
 | 	if (!getargs(args, "(is#ii)", &invert, &input, &inputlength, &width, &height)) | 
 | 		return NULL; | 
 |  | 
 | 	if (width * height * inputfactor > inputlength) { | 
 | 		err_setstr(SvError, "input buffer not long enough"); | 
 | 		return NULL; | 
 | 	} | 
 |  | 
 | 	output = newsizedstringobject(NULL, width * height * factor); | 
 | 	if (output == NULL) | 
 | 		return NULL; | 
 |  | 
 | 	(*function)(invert, input, getstringvalue(output), width, height); | 
 |  | 
 | 	return output; | 
 | } | 
 |  | 
 | static object * | 
 | sv_InterleaveFields(self, args) | 
 | 	object *self, *args; | 
 | { | 
 | 	return sv_conversion(self, args, svInterleaveFields, 1, 1); | 
 | } | 
 |  | 
 | static object * | 
 | sv_RGB8toRGB32(self, args) | 
 | 	object *self, *args; | 
 | { | 
 | 	return sv_conversion(self, args, svRGB8toRGB32, 1, sizeof(long)); | 
 | } | 
 |  | 
 | static object * | 
 | sv_YUVtoRGB(self, args) | 
 | 	object *self, *args; | 
 | { | 
 | 	return sv_conversion(self, args, svYUVtoRGB, 2, sizeof(long)); | 
 | } | 
 |  | 
 | static void | 
 | svideo_dealloc(self) | 
 | 	svobject *self; | 
 | { | 
 | 	if (self->ob_svideo != NULL) | 
 | 		(void) svCloseVideo(self->ob_svideo); | 
 | 	DEL(self); | 
 | } | 
 |  | 
 | static object * | 
 | svideo_getattr(self, name) | 
 | 	svobject *self; | 
 | 	char *name; | 
 | { | 
 | 	return findmethod(svideo_methods, (object *)self, name); | 
 | } | 
 |  | 
 | typeobject Svtype = { | 
 | 	OB_HEAD_INIT(&Typetype) | 
 | 	0,			/*ob_size*/ | 
 | 	"sv",			/*tp_name*/ | 
 | 	sizeof(svobject),	/*tp_size*/ | 
 | 	0,			/*tp_itemsize*/ | 
 | 	/* methods */ | 
 | 	svideo_dealloc,		/*tp_dealloc*/ | 
 | 	0,			/*tp_print*/ | 
 | 	svideo_getattr,		/*tp_getattr*/ | 
 | 	0,			/*tp_setattr*/ | 
 | 	0,			/*tp_compare*/ | 
 | 	0,			/*tp_repr*/ | 
 | }; | 
 |  | 
 | static object * | 
 | newsvobject(svp) | 
 | 	SV_nodeP svp; | 
 | { | 
 | 	svobject *p; | 
 |  | 
 | 	p = NEWOBJ(svobject, &Svtype); | 
 | 	if (p == NULL) | 
 | 		return NULL; | 
 | 	p->ob_svideo = svp; | 
 | 	p->ob_info.format = 0; | 
 | 	p->ob_info.size = 0; | 
 | 	p->ob_info.width = 0; | 
 | 	p->ob_info.height = 0; | 
 | 	p->ob_info.samplingrate = 0; | 
 | 	return (object *) p; | 
 | } | 
 |  | 
 | static object * | 
 | sv_OpenVideo(self, args) | 
 | 	object *self, *args; | 
 | { | 
 | 	SV_nodeP svp; | 
 |  | 
 | 	if (!getnoarg(args)) | 
 | 		return NULL; | 
 |  | 
 | 	svp = svOpenVideo(); | 
 | 	if (svp == NULL) | 
 | 		return sv_error(); | 
 |  | 
 | 	return newsvobject(svp); | 
 | } | 
 |  | 
 | static struct methodlist sv_methods[] = { | 
 | 	{"InterleaveFields",	sv_InterleaveFields}, | 
 | 	{"RGB8toRGB32",		sv_RGB8toRGB32}, | 
 | 	{"YUVtoRGB",		sv_YUVtoRGB}, | 
 | 	{"OpenVideo",		sv_OpenVideo}, | 
 | 	{NULL,			NULL}	/* Sentinel */ | 
 | }; | 
 |  | 
 | void | 
 | initsv() | 
 | { | 
 | 	object *m, *d; | 
 |  | 
 | 	m = initmodule("sv", sv_methods); | 
 | 	d = getmoduledict(m); | 
 |  | 
 | 	SvError = newstringobject("sv.error"); | 
 | 	if (SvError == NULL || dictinsert(d, "error", SvError) != 0) | 
 | 		fatal("can't define sv.error"); | 
 | } |