1 /**********************************************************
2 Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose and without fee is hereby granted,
9 provided that the above copyright notice appear in all copies and that
10 both that copyright notice and this permission notice appear in
11 supporting documentation, and that the names of Stichting Mathematisch
12 Centrum or CWI not be used in advertising or publicity pertaining to
13 distribution of the software without specific, written prior permission.
15 STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18 FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 ******************************************************************/
25 /* SV module -- interface to the Indigo video board */
29 #include "allobjects.h"
31 #include "modsupport.h"
34 #include "yuv.h" /* for YUV conversion functions */
39 svCaptureInfo ob_info
;
46 svCaptureInfo ob_info
;
50 static object
*SvError
; /* exception sv.error */
52 static object
*newcaptureobject
PROTO((svobject
*, void *, int));
54 /* Set a SV-specific error from svideo_errno and return NULL */
58 err_setstr(SvError
, svStrerror(svideo_errno
));
63 svc_conversion(self
, args
, function
, factor
)
72 if (!getargs(args
, "i", &invert
))
75 output
= newsizedstringobject(NULL
, (int) (self
->ob_info
.width
* self
->ob_info
.height
* factor
));
79 (*function
)((boolean
) invert
, self
->ob_capture
, getstringvalue(output
),
80 self
->ob_info
.width
, self
->ob_info
.height
);
86 * 3 functions to convert from Starter Video YUV 4:1:1 format to
87 * Compression Library 4:2:2 Duplicate Chroma format.
90 svc_YUVtoYUV422DC(self
, args
)
94 if (self
->ob_info
.format
!= SV_YUV411_FRAMES
) {
95 err_setstr(SvError
, "data has bad format");
98 return svc_conversion(self
, args
, yuv_sv411_to_cl422dc
, 2.0);
102 svc_YUVtoYUV422DC_quarter(self
, args
)
106 if (self
->ob_info
.format
!= SV_YUV411_FRAMES
) {
107 err_setstr(SvError
, "data has bad format");
110 return svc_conversion(self
, args
, yuv_sv411_to_cl422dc_quartersize
, 0.5);
114 svc_YUVtoYUV422DC_sixteenth(self
, args
)
118 if (self
->ob_info
.format
!= SV_YUV411_FRAMES
) {
119 err_setstr(SvError
, "data has bad format");
122 return svc_conversion(self
, args
, yuv_sv411_to_cl422dc_sixteenthsize
, 0.125);
126 svc_YUVtoRGB(self
, args
)
130 switch (self
->ob_info
.format
) {
131 case SV_YUV411_FRAMES
:
132 case SV_YUV411_FRAMES_AND_BLANKING_BUFFER
:
135 err_setstr(SvError
, "data had bad format");
138 return svc_conversion(self
, args
, svYUVtoRGB
, (float) sizeof(long));
142 svc_RGB8toRGB32(self
, args
)
146 if (self
->ob_info
.format
!= SV_RGB8_FRAMES
) {
147 err_setstr(SvError
, "data has bad format");
150 return svc_conversion(self
, args
, svRGB8toRGB32
, (float) sizeof(long));
154 svc_InterleaveFields(self
, args
)
158 if (self
->ob_info
.format
!= SV_RGB8_FRAMES
) {
159 err_setstr(SvError
, "data has bad format");
162 return svc_conversion(self
, args
, svInterleaveFields
, 1.0);
166 svc_GetFields(self
, args
)
170 object
*f1
, *f2
, *ret
;
173 if (self
->ob_info
.format
!= SV_RGB8_FRAMES
) {
174 err_setstr(SvError
, "data has bad format");
178 fieldsize
= self
->ob_info
.width
* self
->ob_info
.height
/ 2;
179 f1
= newsizedstringobject((char *) self
->ob_capture
, fieldsize
);
180 f2
= newsizedstringobject((char *) self
->ob_capture
+ fieldsize
, fieldsize
);
181 ret
= mkvalue("(OO)", f1
, f2
);
188 svc_UnlockCaptureData(self
, args
)
195 if (!self
->ob_mustunlock
) {
196 err_setstr(SvError
, "buffer should not be unlocked");
200 if (svUnlockCaptureData(self
->ob_svideo
->ob_svideo
, self
->ob_capture
))
203 self
->ob_mustunlock
= 0;
213 svc_lrectwrite(self
, args
)
217 Screencoord x1
, x2
, y1
, y2
;
219 if (!getargs(args
, "(hhhh)", &x1
, &x2
, &y1
, &y2
))
222 lrectwrite(x1
, x2
, y1
, y2
, (unsigned long *) self
->ob_capture
);
230 svc_writefile(self
, args
)
237 if (!getargs(args
, "O", &file
))
240 if (!is_fileobject(file
)) {
241 err_setstr(SvError
, "not a file object");
245 size
= self
->ob_info
.width
* self
->ob_info
.height
;
247 if (fwrite(self
->ob_capture
, sizeof(long), size
, getfilefile(file
)) != size
) {
248 err_setstr(SvError
, "writing failed");
257 svc_FindVisibleRegion(self
, args
)
267 if (svFindVisibleRegion(self
->ob_svideo
->ob_svideo
, self
->ob_capture
, &visible
, self
->ob_info
.width
))
270 if (visible
== NULL
) {
271 err_setstr(SvError
, "data in wrong format");
275 return newcaptureobject(self
->ob_svideo
, visible
, 0);
278 static struct methodlist capture_methods
[] = {
279 {"YUVtoRGB", (method
)svc_YUVtoRGB
},
280 {"RGB8toRGB32", (method
)svc_RGB8toRGB32
},
281 {"InterleaveFields", (method
)svc_InterleaveFields
},
282 {"UnlockCaptureData", (method
)svc_UnlockCaptureData
},
283 {"FindVisibleRegion", (method
)svc_FindVisibleRegion
},
284 {"GetFields", (method
)svc_GetFields
},
285 {"YUVtoYUV422DC", (method
)svc_YUVtoYUV422DC
},
286 {"YUVtoYUV422DC_quarter",(method
)svc_YUVtoYUV422DC_quarter
},
287 {"YUVtoYUV422DC_sixteenth",(method
)svc_YUVtoYUV422DC_sixteenth
},
289 {"lrectwrite", (method
)svc_lrectwrite
},
291 {"writefile", (method
)svc_writefile
},
292 {NULL
, NULL
} /* sentinel */
296 capture_dealloc(self
)
299 if (self
->ob_capture
!= NULL
) {
300 if (self
->ob_mustunlock
)
301 (void) svUnlockCaptureData(self
->ob_svideo
->ob_svideo
, self
->ob_capture
);
302 self
->ob_capture
= NULL
;
303 DECREF(self
->ob_svideo
);
304 self
->ob_svideo
= NULL
;
310 capture_getattr(self
, name
)
314 return findmethod(capture_methods
, (object
*)self
, name
);
317 typeobject Capturetype
= {
318 OB_HEAD_INIT(&Typetype
)
320 "capture", /*tp_name*/
321 sizeof(captureobject
), /*tp_size*/
324 (destructor
)capture_dealloc
, /*tp_dealloc*/
326 (getattrfunc
)capture_getattr
, /*tp_getattr*/
333 newcaptureobject(self
, ptr
, mustunlock
)
340 p
= NEWOBJ(captureobject
, &Capturetype
);
346 p
->ob_mustunlock
= mustunlock
;
347 p
->ob_info
= self
->ob_info
;
352 sv_GetCaptureData(self
, args
)
363 if (svGetCaptureData(self
->ob_svideo
, &ptr
, &fieldID
))
367 err_setstr(SvError
, "no data available");
371 c
= newcaptureobject(self
, ptr
, 1);
374 res
= mkvalue("(Oi)", c
, fieldID
);
380 sv_BindGLWindow(self
, args
)
387 if (!getargs(args
, "(ii)", &wid
, &mode
))
390 if (svBindGLWindow(self
->ob_svideo
, wid
, mode
))
398 sv_EndContinuousCapture(self
, args
)
406 if (svEndContinuousCapture(self
->ob_svideo
))
414 sv_IsVideoDisplayed(self
, args
)
423 v
= svIsVideoDisplayed(self
->ob_svideo
);
427 return newintobject((long) v
);
431 sv_OutputOffset(self
, args
)
438 if (!getargs(args
, "(ii)", &x_offset
, &y_offset
))
441 if (svOutputOffset(self
->ob_svideo
, x_offset
, y_offset
))
449 sv_PutFrame(self
, args
)
455 if (!getargs(args
, "s", &buffer
))
458 if (svPutFrame(self
->ob_svideo
, buffer
))
466 sv_QuerySize(self
, args
)
475 if (!getargs(args
, "(ii)", &w
, &h
))
478 if (svQuerySize(self
->ob_svideo
, w
, h
, &rw
, &rh
))
481 return mkvalue("(ii)", (long) rw
, (long) rh
);
485 sv_SetSize(self
, args
)
492 if (!getargs(args
, "(ii)", &w
, &h
))
495 if (svSetSize(self
->ob_svideo
, w
, h
))
503 sv_SetStdDefaults(self
, args
)
511 if (svSetStdDefaults(self
->ob_svideo
))
519 sv_UseExclusive(self
, args
)
526 if (!getargs(args
, "(ii)", &onoff
, &mode
))
529 if (svUseExclusive(self
->ob_svideo
, onoff
, mode
))
537 sv_WindowOffset(self
, args
)
544 if (!getargs(args
, "(ii)", &x_offset
, &y_offset
))
547 if (svWindowOffset(self
->ob_svideo
, x_offset
, y_offset
))
555 sv_CaptureBurst(self
, args
)
561 void *bitvector
= NULL
;
562 object
*videodata
, *bitvecobj
, *res
;
563 static object
*evenitem
, *odditem
;
565 if (!getargs(args
, "(iiiii)", &info
.format
, &info
.width
, &info
.height
,
566 &info
.size
, &info
.samplingrate
))
569 switch (info
.format
) {
571 bitvector
= malloc(SV_BITVEC_SIZE(info
.size
));
573 case SV_YUV411_FRAMES_AND_BLANKING_BUFFER
:
576 err_setstr(SvError
, "illegal format specified");
580 if (svQueryCaptureBufferSize(self
->ob_svideo
, &info
, &bytes
)) {
586 videodata
= newsizedstringobject(NULL
, bytes
);
587 if (videodata
== NULL
) {
593 /* XXX -- need to do something about the bitvector */
594 if (svCaptureBurst(self
->ob_svideo
, &info
, getstringvalue(videodata
),
603 if (evenitem
== NULL
) {
604 evenitem
= newintobject(0);
605 if (evenitem
== NULL
) {
611 if (odditem
== NULL
) {
612 odditem
= newintobject(1);
613 if (odditem
== NULL
) {
619 bitvecobj
= newtupleobject(2 * info
.size
);
620 if (bitvecobj
== NULL
) {
625 for (i
= 0; i
< 2 * info
.size
; i
++) {
626 if (SV_GET_FIELD(bitvector
, i
) == SV_EVEN_FIELD
) {
628 settupleitem(bitvecobj
, i
, evenitem
);
631 settupleitem(bitvecobj
, i
, odditem
);
640 res
= mkvalue("((iiiii)OO)", info
.format
, info
.width
, info
.height
,
641 info
.size
, info
.samplingrate
, videodata
, bitvecobj
);
648 sv_CaptureOneFrame(self
, args
)
653 int format
, width
, height
;
655 object
*videodata
, *res
;
657 if (!getargs(args
, "(iii)", &format
, &width
, &height
))
659 info
.format
= format
;
661 info
.height
= height
;
663 info
.samplingrate
= 0;
664 if (svQueryCaptureBufferSize(self
->ob_svideo
, &info
, &bytes
))
666 videodata
= newsizedstringobject(NULL
, bytes
);
667 if (videodata
== NULL
)
669 if (svCaptureOneFrame(self
->ob_svideo
, format
, &width
, &height
,
670 getstringvalue(videodata
))) {
675 res
= mkvalue("(iiO)", width
, height
, videodata
);
681 sv_InitContinuousCapture(self
, args
)
687 if (!getargs(args
, "(iiiii)", &info
.format
, &info
.width
, &info
.height
,
688 &info
.size
, &info
.samplingrate
))
691 if (svInitContinuousCapture(self
->ob_svideo
, &info
))
694 self
->ob_info
= info
;
696 return mkvalue("(iiiii)", info
.format
, info
.width
, info
.height
,
697 info
.size
, info
.samplingrate
);
701 sv_LoadMap(self
, args
)
705 object
*rgb
, *v
, *cell
;
708 int i
, j
; /* indices */
710 if (!getargs(args
, "(iO)", &maptype
, &rgb
))
712 if (!is_listobject(rgb
) || getlistsize(rgb
) != 256) {
716 mapp
= NEW(rgb_tuple
, 256);
719 for (i
= 0; i
< 256; i
++) {
720 v
= getlistitem(rgb
, i
);
721 if (!is_tupleobject(v
) || gettuplesize(v
) != 3) {
726 for (j
= 0; j
< 3; j
++) {
727 cell
= gettupleitem(v
, j
);
728 if (!is_intobject(cell
)) {
734 case 0: mapp
[i
].red
= getintvalue(cell
); break;
735 case 1: mapp
[i
].blue
= getintvalue(cell
); break;
736 case 2: mapp
[i
].green
= getintvalue(cell
); break;
741 if (svLoadMap(self
->ob_svideo
, maptype
, mapp
)) {
753 sv_CloseVideo(self
, args
)
760 if (svCloseVideo(self
->ob_svideo
))
762 self
->ob_svideo
= NULL
;
769 doParams(self
, args
, func
, modified
)
772 int (*func
)(SV_nodeP
, long *, int);
780 if (!getargs(args
, "O", &list
))
782 if (!is_listobject(list
)) {
786 length
= getlistsize(list
);
787 PVbuffer
= NEW(long, length
);
788 if (PVbuffer
== NULL
)
790 for (i
= 0; i
< length
; i
++) {
791 v
= getlistitem(list
, i
);
792 if (!is_intobject(v
)) {
797 PVbuffer
[i
] = getintvalue(v
);
800 if ((*func
)(self
->ob_svideo
, PVbuffer
, length
)) {
806 for (i
= 0; i
< length
; i
++)
807 setlistitem(list
, i
, newintobject(PVbuffer
[i
]));
817 sv_GetParam(self
, args
)
820 return doParams(self
, args
, svGetParam
, 1);
824 sv_GetParamRange(self
, args
)
827 return doParams(self
, args
, svGetParamRange
, 1);
831 sv_SetParam(self
, args
)
834 return doParams(self
, args
, svSetParam
, 0);
837 static struct methodlist svideo_methods
[] = {
838 {"BindGLWindow", (method
)sv_BindGLWindow
},
839 {"EndContinuousCapture",(method
)sv_EndContinuousCapture
},
840 {"IsVideoDisplayed", (method
)sv_IsVideoDisplayed
},
841 {"OutputOffset", (method
)sv_OutputOffset
},
842 {"PutFrame", (method
)sv_PutFrame
},
843 {"QuerySize", (method
)sv_QuerySize
},
844 {"SetSize", (method
)sv_SetSize
},
845 {"SetStdDefaults", (method
)sv_SetStdDefaults
},
846 {"UseExclusive", (method
)sv_UseExclusive
},
847 {"WindowOffset", (method
)sv_WindowOffset
},
848 {"InitContinuousCapture",(method
)sv_InitContinuousCapture
},
849 {"CaptureBurst", (method
)sv_CaptureBurst
},
850 {"CaptureOneFrame", (method
)sv_CaptureOneFrame
},
851 {"GetCaptureData", (method
)sv_GetCaptureData
},
852 {"CloseVideo", (method
)sv_CloseVideo
},
853 {"LoadMap", (method
)sv_LoadMap
},
854 {"GetParam", (method
)sv_GetParam
},
855 {"GetParamRange", (method
)sv_GetParamRange
},
856 {"SetParam", (method
)sv_SetParam
},
857 {NULL
, NULL
} /* sentinel */
861 sv_conversion(self
, args
, function
, inputfactor
, factor
)
867 int invert
, width
, height
, inputlength
;
871 if (!getargs(args
, "(is#ii)", &invert
, &input
, &inputlength
, &width
, &height
))
874 if (width
* height
* inputfactor
> inputlength
) {
875 err_setstr(SvError
, "input buffer not long enough");
879 output
= newsizedstringobject(NULL
, (int) (width
* height
* factor
));
883 (*function
)(invert
, input
, getstringvalue(output
), width
, height
);
889 sv_InterleaveFields(self
, args
)
892 return sv_conversion(self
, args
, svInterleaveFields
, 1, 1.0);
896 sv_RGB8toRGB32(self
, args
)
899 return sv_conversion(self
, args
, svRGB8toRGB32
, 1, (float) sizeof(long));
903 sv_YUVtoRGB(self
, args
)
906 return sv_conversion(self
, args
, svYUVtoRGB
, 2, (float) sizeof(long));
913 if (self
->ob_svideo
!= NULL
)
914 (void) svCloseVideo(self
->ob_svideo
);
919 svideo_getattr(self
, name
)
923 return findmethod(svideo_methods
, (object
*)self
, name
);
926 typeobject Svtype
= {
927 OB_HEAD_INIT(&Typetype
)
930 sizeof(svobject
), /*tp_size*/
933 (destructor
)svideo_dealloc
, /*tp_dealloc*/
935 (getattrfunc
)svideo_getattr
, /*tp_getattr*/
947 p
= NEWOBJ(svobject
, &Svtype
);
951 p
->ob_info
.format
= 0;
953 p
->ob_info
.width
= 0;
954 p
->ob_info
.height
= 0;
955 p
->ob_info
.samplingrate
= 0;
960 sv_OpenVideo(self
, args
)
972 return newsvobject(svp
);
975 static struct methodlist sv_methods
[] = {
976 {"InterleaveFields", (method
)sv_InterleaveFields
},
977 {"RGB8toRGB32", (method
)sv_RGB8toRGB32
},
978 {"YUVtoRGB", (method
)sv_YUVtoRGB
},
979 {"OpenVideo", (method
)sv_OpenVideo
},
980 {NULL
, NULL
} /* Sentinel */
988 m
= initmodule("sv", sv_methods
);
989 d
= getmoduledict(m
);
991 SvError
= newstringobject("sv.error");
992 if (SvError
== NULL
|| dictinsert(d
, "error", SvError
) != 0)
993 fatal("can't define sv.error");