📄 spcav4l.c
字号:
/****************************************************************************# spcav4l: v4l library. ##This package work with the spca5xx based webcam with the raw jpeg feature. ##All the decoding is in user space with the help of libjpeg. ##. ## Copyright (C) 2003 2004 2005 Michel Xhaard ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## #****************************************************************************/#include "spcaframe.h"#include "spcav4l.h"#include "utils.h"#include "jdatatype.h"#include "encoder.h"static int init_v4l (struct vdIn *vd);static int checkpalette (struct vdIn *vd);static int check_palettesize(struct vdIn *vd );static struct bridge_list Blist[]={ {BRIDGE_SPCA505,"SPCA505"}, {BRIDGE_SPCA506,"SPCA506"}, {BRIDGE_SPCA501,"SPCA501"}, {BRIDGE_SPCA508,"SPCA508"}, {BRIDGE_SPCA504,"SPCA504"}, {BRIDGE_SPCA500,"SPCA500"}, {BRIDGE_SPCA504B,"SPCA504B"}, {BRIDGE_SPCA533,"SPCA533"}, {BRIDGE_SPCA504C,"SPCA504C"}, {BRIDGE_SPCA561,"SPCA561"}, {BRIDGE_SPCA536,"SPCA536"}, {BRIDGE_SONIX,"SN9C102"}, {BRIDGE_ZR364XX,"ZR364XX"}, {BRIDGE_ZC3XX,"ZC301-2"}, {BRIDGE_CX11646,"CX11646"}, {BRIDGE_TV8532,"TV8532"}, {BRIDGE_ETOMS,"ET61XX51"}, {BRIDGE_SN9CXXX,"SN9CXXX"}, {BRIDGE_MR97311,"MR97311"}, {BRIDGE_UNKNOW,"UNKNOW"}, {-1,NULL}};/* Camera type jpeg yuvy yyuv yuyv grey gbrg*/static struct palette_list Plist[] ={ {JPEG,"JPEG"}, {YUVY,"YUVY"}, {YYUV,"YYUV"}, {YUYV,"YUYV"}, {GREY,"GREY"}, {GBRG,"GBRG"}, {SN9C,"SN9C"}, {GBGR,"GBGR"}, {UNOW,"UNOW"}, {-1,NULL}};/***************************************************************************** Public****************************************************************************/intinit_videoIn (struct vdIn *vd, char *device, int width, int height, int format, int grabmethod){ int err = -1; int i; if (vd == NULL || device == NULL) return -1; if (width == 0 || height == 0) return -1; if(grabmethod < 0 || grabmethod > 1) grabmethod = 1; //read by default; // check format vd->videodevice = NULL; vd->cameraname = NULL; vd->videodevice = NULL; vd->videodevice = (char *) realloc (vd->videodevice, 16); vd->cameraname = (char *) realloc (vd->cameraname, 32); snprintf (vd->videodevice, 12, "%s", device); printf("video %s \n",vd->videodevice); memset (vd->cameraname, 0, sizeof (vd->cameraname)); memset(vd->bridge, 0, sizeof(vd->bridge)); vd->signalquit = 1; vd->hdrwidth = width; vd->hdrheight = height; /* compute the max frame size */ vd->formatIn = format; vd->bppIn = GetDepth (vd->formatIn); vd->grabMethod = grabmethod; //mmap or read vd->pFramebuffer = NULL; /* init and check all setting */ err = init_v4l (vd); /* allocate the 4 frames output buffer */ for (i = 0; i < OUTFRMNUMB; i++) { vd->ptframe[i] = NULL; vd->ptframe[i] = (unsigned char *) realloc (vd->ptframe[i], sizeof(struct frame_t) + (size_t) vd->framesizeIn ); vd->framelock[i] = 0; } vd->frame_cour = 0; pthread_mutex_init (&vd->grabmutex, NULL); return err;}intclose_v4l (struct vdIn *vd){ int i; if (vd->grabMethod) { printf ("unmapping frame buffer\n"); munmap (vd->pFramebuffer, vd->mmapsize); } else { free(vd->pFramebuffer); vd->pFramebuffer = NULL; } printf ("close video_device\n"); close (vd->fd); /* dealloc the whole buffers */ if (vd->videodevice) { free (vd->videodevice); vd->videodevice = NULL; } if (vd->cameraname) { free (vd->cameraname); vd->cameraname = NULL; } for (i = 0; i < OUTFRMNUMB; i++) { if (vd->ptframe[i]) { free (vd->ptframe[i]); vd->ptframe[i] = NULL; vd->framelock[i] = 0; printf ("freeing output buffer %d\n",i); } } pthread_mutex_destroy (&vd->grabmutex);}int convertframe(unsigned char *dst,unsigned char *src, int width,int height, int formatIn, int qualite){ int i;unsigned char tmp; int jpegsize =0; switch (formatIn){ case VIDEO_PALETTE_JPEG: jpegsize = get_jpegsize(src, width*height); if(jpegsize > 0) memcpy(dst,src,jpegsize); break; case VIDEO_PALETTE_YUV420P: jpegsize = encode_image(src,dst,qualite,YUVto420,width,height); break; case VIDEO_PALETTE_RGB24: jpegsize = encode_image(src,dst,qualite,RGBto420,width,height); break; case VIDEO_PALETTE_RGB565: jpegsize = encode_image(src,dst,qualite,RGB565to420,width,height); break; case VIDEO_PALETTE_RGB32: jpegsize = encode_image(src,dst,qualite,RGB32to420,width,height); break; default: break; }return jpegsize;}int v4lGrab (struct vdIn *vd ){ static int frame = 0; int len; int status; int count = 0; int size; int erreur = 0; int jpegsize = 0; int qualite = 1024; struct frame_t *headerframe; double timecourant =0; double temps = 0; timecourant = ms_time(); if (vd->grabMethod) { vd->vmmap.height = vd->hdrheight; vd->vmmap.width = vd->hdrwidth; vd->vmmap.format = vd->formatIn; if (ioctl (vd->fd, VIDIOCSYNC,&vd->vmmap.frame) < 0) { perror ("cvsync err\n"); erreur = -1; } /* Is there someone using the frame */ while((vd->framelock[vd->frame_cour] != 0) && vd->signalquit) usleep(1000); pthread_mutex_lock (&vd->grabmutex); /* memcpy (vd->ptframe[vd->frame_cour]+ sizeof(struct frame_t), vd->pFramebuffer + vd->videombuf.offsets[vd->vmmap.frame] , vd->framesizeIn); jpegsize =jpeg_compress(vd->ptframe[vd->frame_cour]+ sizeof(struct frame_t),vd->framesizeIn, vd->pFramebuffer + vd->videombuf.offsets[vd->vmmap.frame] ,vd->hdrwidth, vd->hdrheight, qualite); */ temps = ms_time(); jpegsize= convertframe(vd->ptframe[vd->frame_cour]+ sizeof(struct frame_t), vd->pFramebuffer + vd->videombuf.offsets[vd->vmmap.frame], vd->hdrwidth,vd->hdrheight,vd->formatIn,qualite); headerframe=(struct frame_t*)vd->ptframe[vd->frame_cour]; snprintf(headerframe->header,5,"%s","SPCA"); headerframe->seqtimes = ms_time(); headerframe->deltatimes=(int)(headerframe->seqtimes-timecourant); headerframe->w = vd->hdrwidth; headerframe->h = vd->hdrheight; headerframe->size = (( jpegsize < 0)?0:jpegsize); headerframe->format = vd->formatIn; headerframe->nbframe = frame++; // printf("compress frame %d times %f\n",frame, headerframe->seqtimes-temps); pthread_mutex_unlock (&vd->grabmutex); /************************************/ if ((ioctl (vd->fd, VIDIOCMCAPTURE, &(vd->vmmap))) < 0) { perror ("cmcapture"); printf (">>cmcapture err %d\n", status); erreur = -1; } vd->vmmap.frame = (vd->vmmap.frame + 1) % vd->videombuf.frames; vd->frame_cour = (vd->frame_cour +1) % OUTFRMNUMB; //printf("frame nb %d\n",vd->vmmap.frame); } else { /* read method */ size = vd->framesizeIn; len = read (vd->fd, vd->pFramebuffer, size); if (len <= 0 ) { printf ("v4l read error\n"); printf ("len %d asked %d \n", len, size); return 0; } /* Is there someone using the frame */ while((vd->framelock[vd->frame_cour] != 0)&& vd->signalquit) usleep(1000); pthread_mutex_lock (&vd->grabmutex); /* memcpy (vd->ptframe[vd->frame_cour]+ sizeof(struct frame_t), vd->pFramebuffer, vd->framesizeIn); jpegsize =jpeg_compress(vd->ptframe[vd->frame_cour]+ sizeof(struct frame_t),len, vd->pFramebuffer, vd->hdrwidth, vd->hdrheight, qualite); */ temps = ms_time(); jpegsize= convertframe(vd->ptframe[vd->frame_cour]+ sizeof(struct frame_t), vd->pFramebuffer , vd->hdrwidth,vd->hdrheight,vd->formatIn,qualite); headerframe=(struct frame_t*)vd->ptframe[vd->frame_cour]; snprintf(headerframe->header,5,"%s","SPCA"); headerframe->seqtimes = ms_time(); headerframe->deltatimes=(int)(headerframe->seqtimes-timecourant); headerframe->w = vd->hdrwidth; headerframe->h = vd->hdrheight; headerframe->size = (( jpegsize < 0)?0:jpegsize);; headerframe->format = vd->formatIn; headerframe->nbframe = frame++; // printf("compress frame %d times %f\n",frame, headerframe->seqtimes-temps); vd->frame_cour = (vd->frame_cour +1) % OUTFRMNUMB; pthread_mutex_unlock (&vd->grabmutex); /************************************/ } return erreur;}/****************************************************************************** Private******************************************************************************/static intGetVideoPict (struct vdIn *vd){ if (ioctl (vd->fd, VIDIOCGPICT, &vd->videopict) < 0) exit_fatal ("Couldnt get videopict params with VIDIOCGPICT"); printf ("VIDIOCGPICT brightnes=%d hue=%d color=%d contrast=%d whiteness=%d" "depth=%d palette=%d\n", vd->videopict.brightness, vd->videopict.hue, vd->videopict.colour, vd->videopict.contrast, vd->videopict.whiteness, vd->videopict.depth, vd->videopict.palette); return 0;}static intSetVideoPict (struct vdIn *vd){ if (ioctl (vd->fd, VIDIOCSPICT, &vd->videopict) < 0) exit_fatal ("Couldnt set videopict params with VIDIOCSPICT"); printf ("VIDIOCSPICT brightnes=%d hue=%d color=%d contrast=%d whiteness=%d" "depth=%d palette=%d\n", vd->videopict.brightness, vd->videopict.hue, vd->videopict.colour, vd->videopict.contrast, vd->videopict.whiteness, vd->videopict.depth, vd->videopict.palette); return 0;}static void spcaPrintParam (int fd,struct video_param *videoparam);static void spcaSetTimeInterval(int fd, struct video_param *videoparam, unsigned short time);static void spcaSetQuality(int fd, struct video_param *videoparam, unsigned char index);static intinit_v4l (struct vdIn *vd){ int f; int erreur = 0; int err; if ((vd->fd = open (vd->videodevice, O_RDWR)) == -1) exit_fatal ("ERROR opening V4L interface"); if (ioctl (vd->fd, VIDIOCGCAP, &(vd->videocap)) == -1) exit_fatal ("Couldn't get videodevice capability"); printf ("Camera found: %s \n", vd->videocap.name); snprintf (vd->cameraname, 32, "%s", vd->videocap.name); erreur = GetVideoPict (vd); if (ioctl (vd->fd, VIDIOCGCHAN, &vd->videochan) == -1) { printf ("Hmm did not support Video_channel\n"); vd->cameratype = UNOW; } else { if (vd->videochan.name){ printf ("Bridge found: %s \n", vd->videochan.name); snprintf (vd->bridge, 9, "%s", vd->videochan.name); vd->cameratype = GetStreamId (vd->videochan.name); spcaPrintParam (vd->fd,&vd->videoparam); } else { printf ("Bridge not found not a spca5xx Webcam Probing the hardware !!\n"); vd->cameratype = UNOW; } } printf ("StreamId: %d Camera\n", vd->cameratype);/* probe all available palette and size */ if (probePalette(vd ) < 0) { exit_fatal ("could't probe video palette Abort !"); } if (probeSize(vd ) < 0) { exit_fatal ("could't probe video size Abort !"); }/* now check if the needed setting match the available if not find a new set and populate the change */ err = check_palettesize(vd); printf (" Format asked %d check %d\n",vd->formatIn, err); vd->videopict.palette = vd->formatIn; vd->videopict.depth = GetDepth (vd->formatIn); vd->bppIn = GetDepth (vd->formatIn); vd->framesizeIn = (vd->hdrwidth * vd->hdrheight * vd->bppIn) >> 3; erreur = SetVideoPict (vd); erreur = GetVideoPict (vd); if (vd->formatIn != vd->videopict.palette || vd->bppIn != vd->videopict.depth) exit_fatal ("could't set video palette Abort !"); if (erreur < 0) exit_fatal ("could't set video palette Abort !"); if (vd->grabMethod) { printf (" grabbing method default MMAP asked \n"); // MMAP VIDEO acquisition memset (&(vd->videombuf), 0, sizeof (vd->videombuf)); if (ioctl (vd->fd, VIDIOCGMBUF, &(vd->videombuf)) < 0) { perror (" init VIDIOCGMBUF FAILED\n"); } printf ("VIDIOCGMBUF size %d frames %d offets[0]=%d offsets[1]=%d\n", vd->videombuf.size, vd->videombuf.frames, vd->videombuf.offsets[0], vd->videombuf.offsets[1]); vd->pFramebuffer = (unsigned char *) mmap (0, vd->videombuf.size, PROT_READ | PROT_WRITE, MAP_SHARED, vd->fd, 0); vd->mmapsize = vd->videombuf.size; vd->vmmap.height = vd->hdrheight; vd->vmmap.width = vd->hdrwidth; vd->vmmap.format = vd->formatIn; for (f = 0; f < vd->videombuf.frames; f++) { vd->vmmap.frame = f; if (ioctl (vd->fd, VIDIOCMCAPTURE, &(vd->vmmap))) { perror ("cmcapture"); } } vd->vmmap.frame = 0; } else { /* read method */ /* allocate the read buffer */ vd->pFramebuffer = (unsigned char *) realloc (vd->pFramebuffer, (size_t) vd->framesizeIn); printf (" grabbing method READ asked \n"); if (ioctl (vd->fd, VIDIOCGWIN, &(vd->videowin)) < 0) perror ("VIDIOCGWIN failed \n"); vd->videowin.height = vd->hdrheight; vd->videowin.width = vd->hdrwidth; if (ioctl (vd->fd, VIDIOCSWIN, &(vd->videowin)) < 0) perror ("VIDIOCSWIN failed \n"); printf ("VIDIOCSWIN height %d width %d \n", vd->videowin.height, vd->videowin.width); } vd->frame_cour = 0; return erreur;}staticint probePalette ( struct vdIn *vd ){ /* probe palette and set a default one for unknow cams*/ int pal[] ={VIDEO_PALETTE_JPEG,VIDEO_PALETTE_YUV420P,VIDEO_PALETTE_RGB24,VIDEO_PALETTE_RGB565,VIDEO_PALETTE_RGB32}; struct video_picture pict; int masq = 0x1; int i; int availpal = 0; int defaut = 1; /* initialize the internal struct */ if (ioctl (vd->fd, VIDIOCGPICT, &pict) < 0) { perror ("Couldnt get videopict params with VIDIOCGPICT\n"); return -1; } /* try each palette we have we skip raw_jpeg */ for(i = 0; i < 5 ; i++){ pict.palette = pal[i]; /* maybe correct the bug on qca driver depth always 24 ? */ pict.depth = GetDepth (pal[i]); printf("try palette %d depth %d\n",pict.palette,pict.depth); if (ioctl (vd->fd, VIDIOCSPICT, &pict) < 0) { printf("Couldnt set palette first try %d \n", pal[i]); } if (ioctl (vd->fd, VIDIOCGPICT, &pict) < 0) { printf("Couldnt get palette %d \n", pal[i]); } if (pict.palette != pal[i]){ printf("Damned second try fail \n"); } else { availpal = availpal | masq ; printf("Available palette %d \n", pal[i]); if (defaut){ defaut = 0; //vd->formatIn = pal[i]; // vd->bppIn = GetDepth (pal[i]); } } masq = masq << 1; } vd->palette = availpal; //should set default palette here ? return 1; }staticint probeSize ( struct vdIn *vd ){ /* probe size and set a default one for unknow cams */ int size[] = { 640,480,384,288,352,288,320,240,192,144,176,144,160,120 }; struct video_window win; int maxw,minw,maxh,minh; int masq = 0x1; int i = 0; int defaut = 1 ; /* initialize de parameters */ maxw = vd->videocap.maxwidth; minw = vd->videocap.minwidth; maxh = vd->videocap.maxheight; minh = vd->videocap.minheight; printf("probe size in \n"); while (size[i] > maxw){ printf("skip size %d x %d\n",size[i],size[i+1]); i += 2; masq = masq << 1; if (i > 13) break; } /* initialize the internal struct */ if (ioctl (vd->fd, VIDIOCGWIN, &win) < 0) { perror ("VIDIOCGWIN failed \n"); return -1; } /* now i is on the first possible width */ while ((size[i] >= minw) && i < 13) { win.width = size[i]; win.height = size[i+1]; if (ioctl (vd->fd, VIDIOCSWIN, &win) < 0) { printf ("VIDIOCSWIN reject width %d height %d \n", win.width, win.height); } else { vd->sizeothers = vd->sizeothers | masq; printf ("Available Resolutions width %d heigth %d \n", win.width, win.height); if (defaut) { // vd->hdrwidth = win.width; // vd->hdrheight = win.height; defaut = 0; } } masq = masq << 1 ; i += 2; } return 1; }intchangeSize (struct vdIn *vd){ int erreur; erreur = GetVideoPict (vd); vd->formatIn = vd->videopict.palette; vd->bppIn = vd->videopict.depth; /* To Compute the estimate frame size perhaps not need !!! */ if ((vd->bppIn = GetDepth (vd->formatIn)) < 0) { perror ("getdepth failed \n"); exit (1); } if (vd->grabMethod) { vd->vmmap.height = vd->hdrheight; vd->vmmap.width = vd->hdrwidth;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -