webcam linux

BlitzMax Forums/BlitzMax Programming/webcam linux

splinux(Posted 2005) [#1]
another topic related with the "serial port linux":
how could i grab pictures from a camera with Linux and BMax?
i have installed my quickcam clicksmart and works with gnome meeting.
now i have to grab images from BMax.
i know that camera is /dev/video0 and the module is spca5xx.

could anyone help me?


Hummelpups(Posted 2005) [#2]
look at a C Forum for more information, google it!
can't be that difficult.
Is it USB? Or Com Port?

IMurDOOM


splinux(Posted 2005) [#3]
it's usb.
logitech quickcam clicksmart 420.
module: SPCA5XX, the last.


Chris C(Posted 2005) [#4]
check out video4linux, if your cam works with it there should be a library you can make a binding for.

I did see somthing about using libs on linux with max on the forum somewhere but I cant remember


splinux(Posted 2005) [#5]
yes, but how could i dielogue with the module which controls the camera to grab images?


Chris C(Posted 2005) [#6]
you need to read up on video4linux and research how to use a library (.a in linux) with blitzmax


splinux(Posted 2005) [#7]
i found some sample code which i can compile(the code is c written).
i've tryied to import that file with bmx(that file has only the functions with a main to test them), make export for the main function and exec it.
now the problem is that to compile the c code i've used the -lSDL -lSDLmain params for gcc, but with bmax i can't, or not?
this is the question: could i set gcc params that bmk will use when compile?

PS: maybe i'll rewrite all the code using bmax or importing only a few commands
PS2: if it will work, i'll probably program a max mod for it, and public i under GPL.


splinux(Posted 2005) [#8]
so? could i tell gcc to use lSDL and lSDLmain params?


Chris C(Posted 2005) [#9]
you could but I wouldnt !!
I think import "-lSDL" used to work or somthing like but you should be looking at what the SDL portions actually *do* and writing max code for it...


splinux(Posted 2005) [#10]
yes, but there is a function, creatergbsurfacefrom which i don't know what format use and transform into, so i need to experiment.


splinux(Posted 2005) [#11]
ok. thanks.
i've tryied it and now it works.

i have no time to study all the video4linux api's docs, so i've searched for sample programs to learn from them.
there are a few very simple to save datas to *.pnm(so it has to be converted for bmax) and other ones which display the image on the video.
to display frames to the screen they use SDL libraries, and so there are a few other problems.
now that is resolved, it will be possible to do a program which will init-stop the cam and put it on the screen(with an update function).
probably i'll change it, however it could be fast.

maybe the next week i *could*(i have to see what i need to do) release a TEST version of the module, with just a few functions, but i don't know.


splinux(Posted 2005) [#12]
******************
PS: from a few days are appeared into the blitzshowcase section some topic about webcams, webcam programming and games with webcam, all using blitz3D.
i, for these reasons and other of mine, am interested into this project, a Linux Webcam Module for BMax, so i'll program it.
But, are there anyone other interested in it?
if other people is interested, i will search to speed up the things and release it as soon as possible, otherwise i'll be slower.
******************


Chris C(Posted 2005) [#13]
you could experiment replacing creatergbsurfacefrom with somthing that puts the pixels into an opengl texture, or if you poke about in the brl modules you might see a way to blat the pixles directly into the back buffer

Let me know how you get on, I have an old video4linux compatible tv card i might put back into my machine...


splinux(Posted 2005) [#14]
i found other sources,..
i'm studying them. however there is one which uses opengl and svgalib.
it has that function with gl, so it will be simple to use with bmax.
i'm installing svgalib, but i don't think i'll use it, it's only to test that source.
maybe the piece of code gl written will be translated to max, so max will handle the camera's input.
all the help is welcome.


splinux(Posted 2005) [#15]
after studyied the raw files formats, and some other c code, i found that every pixel is coded like this:
rgbrgbrgbrgbrgb... where r, g and b are single bytes.


Chris C(Posted 2005) [#16]
so I guess you need to make an opengl texture with rgb format instead of rgba ??


splinux(Posted 2005) [#17]
or otherwise i can program a routine to write every pixel to the screen, or to an image.
however i still have many problems.
i didn't have much time to study the code.
maybe in a few days i will can make some previsions about a possible release.
actually i think it could be exit a demo release, with just a few functions.


Chris C(Posted 2005) [#18]
i thought about looping through each 3 bytes at a time and writing them to a texture / screen but thats gonna be very slow.

I think somthing like opengl pbuffers might be the way to go...


splinux(Posted 2005) [#19]
ok. however i can't get the image because of some problems with grabbing frames.
actually i have some 200 lines lenght c code, with some difficult parts to analyze.
some days ago i've got it, but i couldn't process it because i didn't know that format.
the file was deleted and now i have some problems, but many files, so i hope to program something into a few days.


splinux(Posted 2005) [#20]
i think tomorrow i will rewrite the c code deviding it into various functions.
if anyone would like to help me, all the help is welcome.


Chris C(Posted 2005) [#21]
post the c code maybe i can help convert some of it??


splinux(Posted 2005) [#22]
it's from a program called videodog.
it's one of the eldest sources of the program, modifyied to make a .pnm image, when the original program could only print the file content.
you have to compile it with gcc, and then exec it in this way:
./videodog -x 320 -y 240 -d /dev/video0 -w 3 -p
and it will create an a.pnm image.


#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <asm/types.h>
#include <linux/videodev.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <asm/types.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#define VERSION "0.06"
#define OPTSTR "hx:y:w:d:pu:c:b:l:sni:"
#define DOT fprintf(stderr,".");
void showhelp(void) {
fprintf (stderr,"Video Dog tool Version %s\n", VERSION);
fprintf (stderr,"Gleicon S. Moraes\n");
fprintf (stderr,"Options you really need:\n");
fprintf (stderr,"-x (number) image width\n");
fprintf (stderr,"-y (number) image height\n");
fprintf (stderr,"-w (number) image depth (in bytes) \n");
fprintf (stderr,"-d device (like /dev/video0 )\n");
fprintf (stderr,"-p set the output in pnm format (24 or 8 bits only)\n");
fprintf (stderr, "Other options :\n");
fprintf (stderr,"-h just show this lines, doesn't help you ok ?\n");
fprintf (stderr,"-i input number (0 is the default) \n");
fprintf (stderr,"-u image Hue\n");
fprintf (stderr,"-c image Contrast\n");
fprintf (stderr,"-b image Brightness \n");
fprintf (stderr,"-l image Colour\n");
fprintf (stderr,"-s show device report\n");
fprintf (stderr,"-n Dont capture an image, just setup the device (Useful if you want to correct something before start grabbing)\n");
exit(0);
}
/* global */
unsigned short int pnm=1;
FILE *fp;
int x=0, y=0, w=0;
unsigned char *v_device; /* device */
static struct video_picture grab_pic;
static struct video_capability grab_cap;
static struct video_channel grab_vid;
static struct video_mmap grab_buf;
static int grab_fd, grab_size;
static unsigned char *grab_data;
int hue=-1, contrast=-1, brightness=-1, colour=-1, nograb=0,
showc=0i, channel=0;
/* prototype */
void swap_rgb24(unsigned char *, int );
unsigned char* grab_one(int *, int *);
int grab_init();
/* signal handler */
void _sighandler (int sig) {
switch (sig){
case SIGINT: /* ctrl+x */
free (v_device);
close (grab_fd);
munmap(grab_data, grab_size);
fprintf (stderr, "Caught SIGINT - Cleaning \n");
break;
}
}
void set_picture() {
if (hue > -1) grab_pic.hue=hue;
if (contrast > -1) grab_pic.contrast=contrast;
if (brightness > -1) grab_pic.brightness=brightness;
if (colour > -1) grab_pic.colour=colour;
if (ioctl(grab_fd, VIDIOCSPICT, &grab_pic) == -1) {
perror ("PICTURE");
exit (1);
}
}
void set_channel() { /* do nothing if the device doesn't
allow it */
if (ioctl(grab_fd, VIDIOCGCHAN, &grab_vid) == -1) return;
grab_vid.channel=channel;
if (ioctl(grab_fd, VIDIOCSCHAN, &grab_vid) == -1) return;
}
void show_cap() { /* mostra settings atuais */
fprintf (stderr,"\nVideo DOG tool Version %s\n", VERSION);
fprintf (stderr, "Device Name: %s\n", grab_cap.name);
fprintf (stderr, "Device: %s\n", v_device);
fprintf (stderr, "Max Width : %d\n", grab_cap.maxwidth);
fprintf (stderr, "Max Height : %d\n", grab_cap.maxheight);
fprintf (stderr, "Current Settings :\n\n");
fprintf (stderr, "\tInput : %i\n", grab_vid.channel);
fprintf (stderr, "\tBrightness : %i\n",
grab_pic.brightness);
fprintf (stderr, "\tHue : %i\n", grab_pic.hue);
fprintf (stderr, "\tColour : %i\n", grab_pic.colour);
fprintf (stderr, "\tContrast : %i\n", grab_pic.contrast);
fprintf (stderr, "\n");
}
int main (int argc, char **argv) {
int c;
signal (SIGINT, _sighandler);
while ((c = getopt (argc, argv, OPTSTR)) != EOF)
switch (c) {
case 'x':
x=atoi(optarg);
break;
case 'y':
y=atoi(optarg);
break;
case 'w':
w=atoi(optarg);
break;
case 'p':
pnm=1;
break;
case 'd':
v_device= (char *)malloc ((strlen(optarg) *
sizeof(char))+1);
memset(v_device, 0, strlen(optarg));
strncpy(v_device, optarg, strlen(optarg) -1
);
break;
case 'i':
channel=atoi(optarg);
break;
case 'u':
hue=atoi(optarg);
break;
case 'c':
contrast=atoi(optarg);
break;
case 'b':
brightness=atoi(optarg);
break;
case 'l':
colour=atoi(optarg);
break;
case 'n':
nograb=1;
break;
case 's':
showc=1;
break;
case 'h':
default:
showhelp();
break;
}
if (!x || !y || !w ) nograb=1;
if (!v_device) {
fprintf (stderr, " I NEED A DEVICE NAME \n");
showhelp();
}
grab_init();
set_picture();
set_channel();
if (showc) show_cap();
if (pnm) {
fp=fopen("a.pnm", "w+");
if (w == 1) {
fprintf(fp, "P5\n%d %d\n255\n", x, y);
}
if (w == 3) {
fprintf(fp, "P6\n%d %d\n255\n", x, y);
}
}
if (!nograb) fwrite ((unsigned char*)grab_one( &x, &y),x * y * w, 1, fp);
free (v_device);
close (grab_fd);
fclose(fp);
munmap(grab_data, grab_size);
} /* main */
void swap_rgb24(unsigned char *mem, int n) {
unsigned char c;
unsigned char *p = mem;
int i = n ;
while (--i) {
c = p[0];
p[0] = p[2];
p[2] = c;
p += 3;
}
}
int grab_init() {
if ((grab_fd = open(v_device,O_RDWR)) == -1 ) {
perror("open videodev");
exit(1);
}
if (ioctl(grab_fd,VIDIOCGCAP,&grab_cap) == -1) {
fprintf(stderr,"wrong device\n");
exit(1);
}
memset (&grab_pic, 0, sizeof(struct video_picture));
if (ioctl (grab_fd, VIDIOCGPICT, &grab_pic) == -1) {
fprintf (stderr, "no pict");
exit(1);
}
switch (w) {
case 1:
grab_buf.format = VIDEO_PALETTE_GREY;
break;
case 2:
grab_buf.format = VIDEO_PALETTE_RGB565;
break;
case 3:
default:
grab_buf.format = VIDEO_PALETTE_RGB24;
break;
}
grab_buf.frame = 0;
grab_buf.width = x;
grab_buf.height = y;
grab_size = x * y * w;
grab_data =
mmap(0,grab_size,PROT_READ|PROT_WRITE,MAP_SHARED,grab_fd,0);
return(1);
}
unsigned char* grab_one(int *width, int *height) {
for (;;) {
if (-1 == ioctl(grab_fd,VIDIOCMCAPTURE,&grab_buf)) {
perror("ioctl VIDIOCMCAPTURE");
} else {
if (-1 ==
ioctl(grab_fd,VIDIOCSYNC,&grab_buf)) {
perror("ioctl VIDIOCSYNC");
} else {
//DOT
fprintf(stderr,"len: %d\n", grab_size);
if (w == 3) swap_rgb24(grab_data,
grab_buf.width * grab_buf.height);
*width = grab_buf.width;
*height = grab_buf.height;
return grab_data;
}
}
}
}



PS: not ALL the code has to be used, only some functions(like grab_init and grab_one).
we could modify the main funcion naming it as cam_setup and then program a blitz interface to receive the data(returned by grab_one).
then we'll be able to convert it using ogl or blitz functions.
at the moment the only grab program i can make is using c, with max is more difficult because they will be liked toghether, passing datas each other.

in the future the program might have some functions to adjust/read the camera parameters.

PS2: in which way can i make a code box under this forum?


Chris C(Posted 2005) [#23]
well the only thing I'm not sure about is usinf ioctl in max, but with a tiny bit of imported C code you could just call a routine that calls ioctl

extern
function m_ioctl(fd:int,dev:int,cap:byte ptr)
end extern

if you make an opengl texture with the GL_RGBA8 format you should then just be able to bind the texture and draw a quad using it...


splinux(Posted 2005) [#24]
yes, but look at there lines of code:

unsigned char *v_device; /* device */
static struct video_picture grab_pic;
static struct video_capability grab_cap;
static struct video_channel grab_vid;
static struct video_mmap grab_buf;
static int grab_fd, grab_size;
static unsigned char *grab_data;


how could i declare them with bmax? they use structs from videodev.h.


splinux(Posted 2005) [#25]
oh, another thing: the c's open() hasn't a corresponding function in bmax, because bmax uses TStram to store the returned infos.
so, if we want to communicate with iotl, we have to use the c function importing it too.


Chris C(Posted 2005) [#26]
yeah, it would probably be better to do most of it with C and import the C routines into a max file

max is really weak when you need to access C structs especially if they are nested

I'd do a C function that grabs a frame and puts it in a byte array supplied by max, then in max you can create a texture with and display it.

extern
grabinit(dev:string)
grab(buf:byte ptr)
end extern

you basically have all the C code to write the two routines


splinux(Posted 2005) [#27]
we have to add a cam_close func because otherwise the camera will give us error.
good idea the grab(buf:byte ptr), so we don't have to call c:byte ptr=grab(), which
could give us problems returning the data and in this way is faster.
today i have many things to do(i'm configuring my new wireless router), however tomorrow i'll do most of the translation.


splinux(Posted 2005) [#28]
ok. wireless is ok under Linux too.
now i can return working on this project.

that idea of write only 3 functions with c is great, however these functions will not be used by users, the users will use bmax written functions which will handle the primary 3.
just a moment and i'll start planning the module.


splinux(Posted 2005) [#29]
Chris C: how much trnslation have you made?


Chris C(Posted 2005) [#30]
none! I was just giving you pointers... WAY too busy at the moment, sorry if you got the wrong end of the stick...


splinux(Posted 2005) [#31]
i'm too busy, too, so i haven't translated anything.
i'll start maybe tomorrow.