Blame |
Last modification |
View Log
| RSS feed
/*
* Revision: 5.2 Date: 2000/08/25
* Video capture subrutine for Linux/Video4Linux devices
* author: Nakazawa,Atsushi ( nakazawa@inolab.sys.es.osaka-u.ac.jp )
* Hirokazu Kato ( kato@sys.im.hiroshima-cu.ac.jp )
*
* Modified by Wayne Piekarski (wayne@tinmith.net) - 2005/03/29
* Added support to automatically adjust camera parameters if needed
*
* Revision: 5.3 Date: 2004/11/18
* Rev Date Who Changes
* 5.3 2004-11-18 RG -adding patch done by Uwe Woessner for YUV support on V4L.
* (Thanks a lot for this contribution !!)
* -modify default video options
* (no overhead if define externally)
* -adding full V4L options support
* -adding eyetoy support
*
*/
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <linux/types.h>
#include <linux/videodev.h>
#include <AR/config.h>
#include <AR/ar.h>
#include <AR/video.h>
#include "ccvt.h"
#ifdef USE_EYETOY
#include "jpegtorgb.h"
#endif
#define MAXCHANNEL 10
static AR2VideoParamT
*gVid
= NULL
;
int arVideoDispOption
( void )
{
return ar2VideoDispOption
();
}
int arVideoOpen
( char *config
)
{
if( gVid
!= NULL
) {
printf("Device has been opened!!\n");
return -1;
}
gVid
= ar2VideoOpen
( config
);
if( gVid
== NULL
) return -1;
return 0;
}
int arVideoClose
( void )
{
int result
;
if( gVid
== NULL
) return -1;
result
= ar2VideoClose
(gVid
);
gVid
= NULL
;
return (result
);
}
int arVideoInqSize
( int *x
, int *y
)
{
if( gVid
== NULL
) return -1;
return ar2VideoInqSize
( gVid
, x
, y
);
}
ARUint8
*arVideoGetImage
( void )
{
if( gVid
== NULL
) return NULL
;
return ar2VideoGetImage
( gVid
);
}
int arVideoCapStart
( void )
{
if( gVid
== NULL
) return -1;
return ar2VideoCapStart
( gVid
);
}
int arVideoCapStop
( void )
{
if( gVid
== NULL
) return -1;
return ar2VideoCapStop
( gVid
);
}
int arVideoCapNext
( void )
{
if( gVid
== NULL
) return -1;
return ar2VideoCapNext
( gVid
);
}
/*-------------------------------------------*/
int ar2VideoDispOption
( void )
{
printf("ARVideo may be configured using one or more of the following options,\n");
printf("separated by a space:\n\n");
printf("DEVICE CONTROLS:\n");
printf(" -dev=filepath\n");
printf(" specifies device file.\n");
printf(" -channel=N\n");
printf(" specifies source channel.\n");
printf(" -noadjust\n");
printf(" prevent adjusting the width/height/channel if not suitable.\n");
printf(" -width=N\n");
printf(" specifies expected width of image.\n");
printf(" -height=N\n");
printf(" specifies expected height of image.\n");
printf(" -palette=[RGB|YUV420P]\n");
printf(" specifies the camera palette (WARNING:all are not supported on each camera !!).\n");
printf("IMAGE CONTROLS (WARNING: every options are not supported by all camera !!):\n");
printf(" -brightness=N\n");
printf(" specifies brightness. (0.0 <-> 1.0)\n");
printf(" -contrast=N\n");
printf(" specifies contrast. (0.0 <-> 1.0)\n");
printf(" -saturation=N\n");
printf(" specifies saturation (color). (0.0 <-> 1.0) (for color camera only)\n");
printf(" -hue=N\n");
printf(" specifies hue. (0.0 <-> 1.0) (for color camera only)\n");
printf(" -whiteness=N\n");
printf(" specifies whiteness. (0.0 <-> 1.0) (REMARK: gamma for some drivers, otherwise for greyscale camera only)\n");
printf(" -color=N\n");
printf(" specifies saturation (color). (0.0 <-> 1.0) (REMARK: obsolete !! use saturation control)\n\n");
printf("OPTION CONTROLS:\n");
printf(" -mode=[PAL|NTSC|SECAM]\n");
printf(" specifies TV signal mode (for tv/capture card).\n");
printf("\n");
return 0;
}
AR2VideoParamT
*ar2VideoOpen
( char *config_in
)
{
AR2VideoParamT
*vid
;
struct video_capability vd
;
struct video_channel vc
[MAXCHANNEL
];
struct video_picture vp
;
char *config
, *a
, line
[256];
int i
;
int adjust
= 1;
/* If no config string is supplied, we should use the environment variable, otherwise set a sane default */
if (!config_in
|| !(config_in
[0])) {
/* None suppplied, lets see if the user supplied one from the shell */
char *envconf
= getenv ("ARTOOLKIT_CONFIG");
if (envconf
&& envconf
[0]) {
config
= envconf
;
printf ("Using config string from environment [%s].\n", envconf
);
} else {
config
= NULL
;
printf ("No video config string supplied, using defaults.\n");
}
} else {
config
= config_in
;
printf ("Using supplied video config string [%s].\n", config_in
);
}
arMalloc
( vid
, AR2VideoParamT
, 1 );
strcpy( vid
->dev
, DEFAULT_VIDEO_DEVICE
);
vid
->channel
= DEFAULT_VIDEO_CHANNEL
;
vid
->width
= DEFAULT_VIDEO_WIDTH
;
vid
->height
= DEFAULT_VIDEO_HEIGHT
;
#if (AR_DEFAULT_PIXEL_FORMAT == AR_PIXEL_FORMAT_BGRA)
vid
->palette
= VIDEO_PALETTE_RGB32
; /* palette format */
#elif (AR_DEFAULT_PIXEL_FORMAT == AR_PIXEL_FORMAT_BGR) || (AR_DEFAULT_PIXEL_FORMAT == AR_PIXEL_FORMAT_RGB)
vid
->palette
= VIDEO_PALETTE_RGB24
; /* palette format */
#endif
vid
->contrast
= -1.
;
vid
->brightness
= -1.
;
vid
->saturation
= -1.
;
vid
->hue
= -1.
;
vid
->whiteness
= -1.
;
vid
->mode
= DEFAULT_VIDEO_MODE
;
vid
->debug
= 0;
vid
->videoBuffer
=NULL
;
a
= config
;
if( a
!= NULL
) {
for(;;) {
while( *a
== ' ' || *a
== '\t' ) a
++;
if( *a
== '\0' ) break;
if( strncmp( a
, "-dev=", 5 ) == 0 ) {
sscanf( a
, "%s", line
);
if( sscanf( &line
[5], "%s", vid
->dev
) == 0 ) {
ar2VideoDispOption
();
free( vid
);
return 0;
}
}
else if( strncmp( a
, "-channel=", 9 ) == 0 ) {
sscanf( a
, "%s", line
);
if( sscanf( &line
[9], "%d", &vid
->channel
) == 0 ) {
ar2VideoDispOption
();
free( vid
);
return 0;
}
}
else if( strncmp( a
, "-width=", 7 ) == 0 ) {
sscanf( a
, "%s", line
);
if( sscanf( &line
[7], "%d", &vid
->width
) == 0 ) {
ar2VideoDispOption
();
free( vid
);
return 0;
}
}
else if( strncmp( a
, "-height=", 8 ) == 0 ) {
sscanf( a
, "%s", line
);
if( sscanf( &line
[8], "%d", &vid
->height
) == 0 ) {
ar2VideoDispOption
();
free( vid
);
return 0;
}
}
else if( strncmp( a
, "-palette=", 9 ) == 0 ) {
if( strncmp( &a
[9], "RGB", 3) == 0 ) {
#if (AR_DEFAULT_PIXEL_FORMAT == AR_PIXEL_FORMAT_BGRA)
vid
->palette
= VIDEO_PALETTE_RGB32
; /* palette format */
#elif (AR_DEFAULT_PIXEL_FORMAT == AR_PIXEL_FORMAT_BGR)|| (AR_DEFAULT_PIXEL_FORMAT == AR_PIXEL_FORMAT_RGB)
vid
->palette
= VIDEO_PALETTE_RGB24
; /* palette format */
#endif
}
else if( strncmp( &a
[9], "YUV420P", 7 ) == 0 ) {
vid
->palette
= VIDEO_PALETTE_YUV420P
;
}
}
else if( strncmp ( a
, "-noadjust", 9 ) == 0 ) {
adjust
= 0;
}
else if( strncmp( a
, "-contrast=", 10 ) == 0 ) {
sscanf( a
, "%s", line
);
if( sscanf( &line
[10], "%lf", &vid
->contrast
) == 0 ) {
ar2VideoDispOption
();
free( vid
);
return 0;
}
}
else if( strncmp( a
, "-brightness=", 12 ) == 0 ) {
sscanf( a
, "%s", line
);
if( sscanf( &line
[12], "%lf", &vid
->brightness
) == 0 ) {
ar2VideoDispOption
();
free( vid
);
return 0;
}
}
else if( strncmp( a
, "-saturation=", 12 ) == 0 ) {
sscanf( a
, "%s", line
);
if( sscanf( &line
[12], "%lf", &vid
->saturation
) == 0 ) {
ar2VideoDispOption
();
free( vid
);
return 0;
}
}
else if( strncmp( a
, "-hue=", 5 ) == 0 ) {
sscanf( a
, "%s", line
);
if( sscanf( &line
[5], "%lf", &vid
->hue
) == 0 ) {
ar2VideoDispOption
();
free( vid
);
return 0;
}
}
else if( strncmp( a
, "-whiteness=", 11 ) == 0 ) {
sscanf( a
, "%s", line
);
if( sscanf( &line
[11], "%lf", &vid
->whiteness
) == 0 ) {
ar2VideoDispOption
();
free( vid
);
return 0;
}
}
else if( strncmp( a
, "-color=", 7 ) == 0 ) {
sscanf( a
, "%s", line
);
if( sscanf( &line
[7], "%lf", &vid
->saturation
) == 0 ) {
ar2VideoDispOption
();
free( vid
);
return 0;
}
}
else if( strncmp( a
, "-mode=", 6 ) == 0 ) {
if( strncmp( &a
[6], "PAL", 3 ) == 0 ) vid
->mode
= VIDEO_MODE_PAL
;
else if( strncmp( &a
[6], "NTSC", 4 ) == 0 ) vid
->mode
= VIDEO_MODE_NTSC
;
else if( strncmp( &a
[6], "SECAM", 5 ) == 0 ) vid
->mode
= VIDEO_MODE_SECAM
;
else {
ar2VideoDispOption
();
free( vid
);
return 0;
}
}
else if( strncmp( a
, "-debug", 6 ) == 0 ) {
vid
->debug
= 1;
}
else {
ar2VideoDispOption
();
free( vid
);
return 0;
}
while( *a
!= ' ' && *a
!= '\t' && *a
!= '\0') a
++;
}
}
vid
->fd
= open
(vid
->dev
, O_RDWR
);// O_RDONLY ?
if(vid
->fd
< 0){
printf("video device (%s) open failed\n",vid
->dev
);
free( vid
);
return 0;
}
if(ioctl
(vid
->fd
,VIDIOCGCAP
,&vd
) < 0){
printf("ioctl failed\n");
free( vid
);
return 0;
}
if( vid
->debug
) {
printf("=== debug info ===\n");
printf(" vd.name = %s\n",vd.
name);
printf(" vd.channels = %d\n",vd.
channels);
printf(" vd.maxwidth = %d\n",vd.
maxwidth);
printf(" vd.maxheight = %d\n",vd.
maxheight);
printf(" vd.minwidth = %d\n",vd.
minwidth);
printf(" vd.minheight = %d\n",vd.
minheight);
}
/* adjust capture size if needed */
if (adjust
)
{
if (vid
->width
>= vd.
maxwidth)
vid
->width
= vd.
maxwidth;
if (vid
->height
>= vd.
maxheight)
vid
->height
= vd.
maxheight;
if (vid
->debug
)
printf ("arVideoOpen: width/height adjusted to (%d, %d)\n", vid
->width
, vid
->height
);
}
/* check capture size */
if(vd.
maxwidth < vid
->width
|| vid
->width
< vd.
minwidth ||
vd.
maxheight < vid
->height
|| vid
->height
< vd.
minheight ) {
printf("arVideoOpen: width or height oversize \n");
free( vid
);
return 0;
}
/* adjust channel if needed */
if (adjust
)
{
if (vid
->channel
>= vd.
channels)
vid
->channel
= 0;
if (vid
->debug
)
printf ("arVideoOpen: channel adjusted to 0\n");
}
/* check channel */
if(vid
->channel
< 0 || vid
->channel
>= vd.
channels){
printf("arVideoOpen: channel# is not valid. \n");
free( vid
);
return 0;
}
if( vid
->debug
) {
printf("==== capture device channel info ===\n");
}
for(i
= 0;i
< vd.
channels && i
< MAXCHANNEL
; i
++){
vc
[i
].
channel = i
;
if(ioctl
(vid
->fd
,VIDIOCGCHAN
,&vc
[i
]) < 0){
printf("error: acquireing channel(%d) info\n",i
);
free( vid
);
return 0;
}
if( vid
->debug
) {
printf(" channel = %d\n", vc
[i
].
channel);
printf(" name = %s\n", vc
[i
].
name);
printf(" tuners = %d", vc
[i
].
tuners);
printf(" flag = 0x%08x",vc
[i
].
flags);
if(vc
[i
].
flags & VIDEO_VC_TUNER
)
printf(" TUNER");
if(vc
[i
].
flags & VIDEO_VC_AUDIO
)
printf(" AUDIO");
printf("\n");
printf(" vc[%d].type = 0x%08x", i
, vc
[i
].
type);
if(vc
[i
].
type & VIDEO_TYPE_TV
)
printf(" TV");
if(vc
[i
].
type & VIDEO_TYPE_CAMERA
)
printf(" CAMERA");
printf("\n");
}
}
/* select channel */
vc
[vid
->channel
].
norm = vid
->mode
; /* 0: PAL 1: NTSC 2:SECAM 3:AUTO */
if(ioctl
(vid
->fd
, VIDIOCSCHAN
, &vc
[vid
->channel
]) < 0){
printf("error: selecting channel %d\n", vid
->channel
);
free( vid
);
return 0;
}
if(ioctl
(vid
->fd
, VIDIOCGPICT
, &vp
)) {
printf("error: getting palette\n");
free( vid
);
return 0;
}
if( vid
->debug
) {
printf("=== debug info ===\n");
printf(" vp.brightness= %d\n",vp.
brightness);
printf(" vp.hue = %d\n",vp.
hue);
printf(" vp.colour = %d\n",vp.
colour);
printf(" vp.contrast = %d\n",vp.
contrast);
printf(" vp.whiteness = %d\n",vp.
whiteness);
printf(" vp.depth = %d\n",vp.
depth);
printf(" vp.palette = %d\n",vp.
palette);
}
/* set video picture */
if ((vid
->brightness
+1.
)>0.001)
vp.
brightness = 32767 * 2.0 *vid
->brightness
;
if ((vid
->contrast
+1.
)>0.001)
vp.
contrast = 32767 * 2.0 *vid
->contrast
;
if ((vid
->hue
+1.
)>0.001)
vp.
hue = 32767 * 2.0 *vid
->hue
;
if ((vid
->whiteness
+1.
)>0.001)
vp.
whiteness = 32767 * 2.0 *vid
->whiteness
;
if ((vid
->saturation
+1.
)>0.001)
vp.
colour = 32767 * 2.0 *vid
->saturation
;
vp.
depth = 24;
vp.
palette = vid
->palette
;
if(ioctl
(vid
->fd
, VIDIOCSPICT
, &vp
)) {
printf("error: setting configuration !! bad palette mode..\n TIPS:try other palette mode (or with new failure contact ARToolKit Developer)\n");
free( vid
);
return 0;
}
if (vid
->palette
==VIDEO_PALETTE_YUV420P
)
arMalloc
( vid
->videoBuffer
, ARUint8
, vid
->width
*vid
->height
*3 );
if( vid
->debug
) {
if(ioctl
(vid
->fd
, VIDIOCGPICT
, &vp
)) {
printf("error: getting palette\n");
free( vid
);
return 0;
}
printf("=== debug info ===\n");
printf(" vp.brightness= %d\n",vp.
brightness);
printf(" vp.hue = %d\n",vp.
hue);
printf(" vp.colour = %d\n",vp.
colour);
printf(" vp.contrast = %d\n",vp.
contrast);
printf(" vp.whiteness = %d\n",vp.
whiteness);
printf(" vp.depth = %d\n",vp.
depth);
printf(" vp.palette = %d\n",vp.
palette);
}
/* get mmap info */
if(ioctl
(vid
->fd
,VIDIOCGMBUF
,&vid
->vm
) < 0){
printf("error: videocgmbuf\n");
free( vid
);
return 0;
}
if( vid
->debug
) {
printf("===== Image Buffer Info =====\n");
printf(" size = %d[bytes]\n", vid
->vm.
size);
printf(" frames = %d\n", vid
->vm.
frames);
}
if(vid
->vm.
frames < 2){
printf("this device can not be supported by libARvideo.\n");
printf("(vm.frames < 2)\n");
free( vid
);
return 0;
}
/* get memory mapped io */
if((vid
->map
= (ARUint8
*)mmap
(0, vid
->vm.
size, PROT_READ
|PROT_WRITE
, MAP_SHARED
, vid
->fd
, 0)) < 0){
printf("error: mmap\n");
free( vid
);
return 0;
}
/* setup for vmm */
vid
->vmm.
frame = 0;
vid
->vmm.
width = vid
->width
;
vid
->vmm.
height = vid
->height
;
vid
->vmm.
format= vid
->palette
;
vid
->video_cont_num
= -1;
#ifdef USE_EYETOY
JPEGToRGBInit
(vid
->width
,vid
->height
);
#endif
return vid
;
}
int ar2VideoClose
( AR2VideoParamT
*vid
)
{
if(vid
->video_cont_num
>= 0){
ar2VideoCapStop
( vid
);
}
close
(vid
->fd
);
if(vid
->videoBuffer
!=NULL
)
free(vid
->videoBuffer
);
free( vid
);
return 0;
}
int ar2VideoCapStart
( AR2VideoParamT
*vid
)
{
if(vid
->video_cont_num
>= 0){
printf("arVideoCapStart has already been called.\n");
return -1;
}
vid
->video_cont_num
= 0;
vid
->vmm.
frame = vid
->video_cont_num
;
if(ioctl
(vid
->fd
, VIDIOCMCAPTURE
, &vid
->vmm
) < 0) {
return -1;
}
vid
->vmm.
frame = 1 - vid
->vmm.
frame;
if( ioctl
(vid
->fd
, VIDIOCMCAPTURE
, &vid
->vmm
) < 0) {
return -1;
}
return 0;
}
int ar2VideoCapNext
( AR2VideoParamT
*vid
)
{
if(vid
->video_cont_num
< 0){
printf("arVideoCapStart has never been called.\n");
return -1;
}
vid
->vmm.
frame = 1 - vid
->vmm.
frame;
ioctl
(vid
->fd
, VIDIOCMCAPTURE
, &vid
->vmm
);
return 0;
}
int ar2VideoCapStop
( AR2VideoParamT
*vid
)
{
if(vid
->video_cont_num
< 0){
printf("arVideoCapStart has never been called.\n");
return -1;
}
if(ioctl
(vid
->fd
, VIDIOCSYNC
, &vid
->video_cont_num
) < 0){
printf("error: videosync\n");
return -1;
}
vid
->video_cont_num
= -1;
return 0;
}
ARUint8
*ar2VideoGetImage
( AR2VideoParamT
*vid
)
{
ARUint8
*buf
;
if(vid
->video_cont_num
< 0){
printf("arVideoCapStart has never been called.\n");
return NULL
;
}
if(ioctl
(vid
->fd
, VIDIOCSYNC
, &vid
->video_cont_num
) < 0){
printf("error: videosync\n");
return NULL
;
}
vid
->video_cont_num
= 1 - vid
->video_cont_num
;
if(vid
->video_cont_num
== 0)
buf
=(vid
->map
+ vid
->vm.
offsets[1]);
else
buf
=(vid
->map
+ vid
->vm.
offsets[0]);
if(vid
->palette
== VIDEO_PALETTE_YUV420P
)
{
ccvt_420p_bgr24
(vid
->width
, vid
->height
, buf
, buf
+(vid
->width
*vid
->height
),
buf
+(vid
->width
*vid
->height
)+(vid
->width
*vid
->height
)/4,
vid
->videoBuffer
);
return vid
->videoBuffer
;
}
#ifdef USE_EYETOY
buf
=JPEGToRGB
(buf
,vid
->width
, vid
->height
);
#endif
return buf
;
}
int ar2VideoInqSize
(AR2VideoParamT
*vid
, int *x
,int *y
)
{
*x
= vid
->vmm.
width;
*y
= vid
->vmm.
height;
return 0;
}