Linux 獲取攝像頭資料並實時顯示
阿新 • • 發佈:2019-02-09
聯想筆記本z475,Ubuntu16;
使用v4l2獲取攝像頭資料;
使用SDL來顯示YUV資料;
#include<fcntl.h> #include<unistd.h> #include<stdio.h> #include<stdlib.h> #include<string.h> #include<errno.h> #include<sys/ioctl.h> #include<sys/mman.h> #include<linux/videodev2.h> //#include<SDL2/SDL.h>//if SDL2 then use texture instead of overlay #include<SDL/SDL.h> #define DEV_CAMERA "/dev/video0" #define REQBUF_COUNT 4 #define handle_err(msg) \ do { perror(msg); exit(EXIT_FAILURE); } while(0) #define FREE(fp) \ while(fp) { free(fp); fp =NULL; } typedef struct { void* start; unsigned int length; }BUFFER; SDL_Surface *pscreen = NULL; SDL_Overlay *overlay = NULL; SDL_Rect drect; SDL_Event sdlevent; SDL_mutex *affmutex = NULL; unsigned char frmrate; unsigned char *p = NULL; unsigned int currtime; unsigned int lasttime; char* status = NULL; int process_image(BUFFER *buf, int width, int height); int main() { //SDL INIT //if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER ) < 0) if (SDL_Init(SDL_INIT_EVERYTHING) < 0) { fprintf(stderr, "Can not initialize SDL: %s\n", SDL_GetError()); exit(1); } //dev info struct v4l2_capability cap; int fd; //fd = open(DEV_CAMERA,O_RDONLY);//the mmap MAP_SHARED will fail:Invalid argument fd = open(DEV_CAMERA,O_RDWR); if(fd<0) { printf("can not open %s\n",DEV_CAMERA); return -1; } ioctl(fd,VIDIOC_QUERYCAP,&cap); printf("DriverName:%s\nCard Name:%s\nBus info:%s\nDriverVersion:%u.%u.%u\n",cap.driver,cap.card,cap.bus_info,(cap.version>>16) & 0xFF,(cap.version>>8) & 0xFF,cap.version & 0xFF); //format struct v4l2_fmtdesc fmtdesc; fmtdesc.index = 0; fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; printf("support format:\n"); while(ioctl(fd,VIDIOC_ENUM_FMT,&fmtdesc) != -1) { printf("\t%d.%s\n",1 + fmtdesc.index++,fmtdesc.description); } struct v4l2_format fmt; fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ioctl(fd,VIDIOC_G_FMT,&fmt); printf("Current format information:\n\twidth:%d\n\theight:%d\n",fmt.fmt.pix.width,fmt.fmt.pix.height); fmtdesc.index = 0; fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; while(ioctl(fd,VIDIOC_ENUM_FMT,&fmtdesc) != -1) { if(fmtdesc.pixelformat & fmt.fmt.pix.pixelformat) { printf("\tformat:%s\n",fmtdesc.description); break; } fmtdesc.index++; } fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32; if(ioctl(fd,VIDIOC_TRY_FMT,&fmt) == -1) { perror("ioctl err"); if(errno == EINVAL) printf("not support format RGB32\n"); } else printf("RGB32 is supported\n"); //query buf struct v4l2_requestbuffers reqbuf; reqbuf.count = REQBUF_COUNT; reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; reqbuf.memory = V4L2_MEMORY_MMAP; ioctl(fd,VIDIOC_REQBUFS,&reqbuf); BUFFER *buffers; buffers = (BUFFER*)calloc(reqbuf.count,sizeof(*buffers)); if(!buffers) { handle_err("calloc"); } for(unsigned int n_buf = 0;n_buf < reqbuf.count;n_buf++) { struct v4l2_buffer buf; memset(&buf,0,sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = n_buf; if(-1 == ioctl(fd,VIDIOC_QUERYBUF,&buf)) { handle_err("ioctl"); } buffers[n_buf].length = buf.length; printf("buf.length = %d,buf.m.offset = %d\n", buf.length,buf.m.offset); buffers[n_buf].start = mmap(NULL,buf.length,PROT_READ|PROT_WRITE,MAP_SHARED,fd,buf.m.offset); //buffers[n_buf].start = mmap(NULL,buf.length,PROT_READ,MAP_SHARED,fd,buf.m.offset); if(MAP_FAILED == buffers[n_buf].start) { handle_err("mmap"); } } //get camera data unsigned int i; enum v4l2_buf_type type; for(i=0;i<reqbuf.count;i++) { struct v4l2_buffer buf; memset(&buf,0,sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = i; ioctl(fd,VIDIOC_QBUF,&buf); } type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ioctl(fd,VIDIOC_STREAMON,&type); int width = fmt.fmt.pix.width; int height = fmt.fmt.pix.height; pscreen = SDL_SetVideoMode(width, height, 0, SDL_SWSURFACE ); overlay = SDL_CreateYUVOverlay(width, height, SDL_YUY2_OVERLAY, pscreen);//format:YUYV use SDL_YUY2_OVERLAY p = (unsigned char *) overlay->pixels[0]; drect.x = 0; drect.y = 0; drect.w = pscreen->w; drect.h = pscreen->h; int quit = 0; while (quit == 0) { while (SDL_PollEvent(&sdlevent)) { if (sdlevent.type == SDL_QUIT) { quit =1; break; } } for(i =0;i<reqbuf.count;i++) { struct v4l2_buffer buf; memset(&buf,0,sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; ioctl(fd,VIDIOC_DQBUF,&buf); //deal with data process_image(&buffers[i],fmt.fmt.pix.width,fmt.fmt.pix.height); ioctl(fd,VIDIOC_QBUF,&buf); } } SDL_DestroyMutex(affmutex); SDL_FreeYUVOverlay(overlay); printf("Clean Up done Quit \n"); SDL_Quit(); type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ioctl(fd,VIDIOC_STREAMOFF,&type); for(i=0;i<reqbuf.count;i++) { if(-1 == munmap(buffers[i].start,buffers[i].length)) { handle_err("munmap"); } } FREE(buffers); close(fd); } int process_image(BUFFER *buf,int width,int height) { affmutex = SDL_CreateMutex(); SDL_LockSurface(pscreen); SDL_LockYUVOverlay(overlay); memcpy(p, buf->start, width * height * 2 /*buf->length*/); SDL_UnlockYUVOverlay(overlay); SDL_UnlockSurface(pscreen); SDL_DisplayYUVOverlay(overlay, &drect); /* dispaly it */ SDL_WM_SetCaption("Jun's camera", NULL); SDL_Delay(40); return 0; }