天天看點

利用V4L2編寫的USB攝像頭程式2【經OK6410驗證成功】

#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define CLEAR(x) memset (&(x), 0, sizeof (x))struct buffer { //緩沖幀結構體 void * start; size_t length;};static char * dev_name = "/dev/video2";//攝像頭裝置名static int fd = -1;struct buffer * buffers = NULL;static unsigned int n_buffers = 0;FILE *file_fd;//static unsigned long file_length;static unsigned char *file_name;擷取幀資料//static int read_frame (void){struct v4l2_buffer buf;CLEAR (buf);buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;buf.memory = V4L2_MEMORY_MMAP;ioctl (fd, VIDIOC_DQBUF, &buf); //出列采集的幀緩沖assert (buf.index < n_buffers); printf ("buf.index number is %d.\n",buf.index);fwrite(buffers[buf.index].start, buffers[buf.index].length, 1, file_fd); //将其寫入檔案中 ioctl (fd, VIDIOC_QBUF, &buf); //再将其入列return 1;}int main (int argc,char ** argv){enum v4l2_buf_type type;unsigned int i;file_fd = fopen("qin.jpg", "w");//圖檔檔案名fd = open ("/dev/video2", O_RDWR | O_NONBLOCK, 0);//打開裝置struct v4l2_capability cap; //擷取攝像頭參數CLEAR(cap);ioctl (fd, VIDIOC_QUERYCAP, &cap); printf("driver:%s\n",cap.driver);printf("card:%s\n",cap.card);printf("bus_info:%s\n",cap.bus_info);printf("version:%d:%d:%d\n",(cap.version>>16)&0xff,(cap.version>>8)&0xff,(cap.version)&0xff);struct v4l2_fmtdesc fmtdesc; //檢視所支援的格式CLEAR(cap);fmtdesc.index=0; //格式序号,可能有多個序号,第一個序号為0;fmtdesc.type=V4L2_BUF_TYPE_VIDEO_CAPTURE; while(-1!=(ioctl(fd,VIDIOC_ENUM_FMT,&fmtdesc))) //檢測可以支援哪些格式。{printf("fmtdesc.description:%s\n",fmtdesc.description);printf("fmtdesc.pixelformat:%ld\n",fmtdesc.pixelformat);fmtdesc.index++;}struct v4l2_format before_fmt,fmt,after_fmt,test_fmt; //分别檢視設定前、中、後的格式情況,以及一個驗證例子!!!CLEAR(before_fmt);CLEAR(fmt);CLEAR(after_fmt);//====printf("\nThe initial FMT information:\n");before_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //FMT設定前的初始狀态ioctl(fd, VIDIOC_G_FMT, &before_fmt);printf("width:%ld\n",before_fmt.fmt.pix.width);printf("height:%ld\n",before_fmt.fmt.pix.height);printf("pixelformat:%ld\n",before_fmt.fmt.pix.pixelformat);printf("bytesperline:%ld\n",before_fmt.fmt.pix.bytesperline);printf("sizeimage:%ld\n",before_fmt.fmt.pix.sizeimage);//====//printf("\nSetting FMT information....\n");fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //設定FMT的格式fmt.fmt.pix.width = 640;fmt.fmt.pix.height = 480;fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; //此處随便設,系統會自動修改!!fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;ioctl(fd, VIDIOC_S_FMT, &fmt);//====printf("\nAfter set FMT information:\n");after_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //顯示設定後的FMT格式ioctl(fd, VIDIOC_G_FMT, &after_fmt);printf("width:%ld\n",before_fmt.fmt.pix.width); printf("height:%ld\n",before_fmt.fmt.pix.height);printf("pixelformat:%ld\n",before_fmt.fmt.pix.pixelformat); printf("bytesperline:%ld\n",before_fmt.fmt.pix.bytesperline);printf("sizeimage:%ld\n",before_fmt.fmt.pix.sizeimage);//====if(fmtdesc.pixelformat & fmt.fmt.pix.pixelformat) // 如果格式V4L2_PIX_FMT_YUYV與攝像頭本身不一樣,系統會自動修改!!!{ printf("\nThis USB camera format:%s\n",fmtdesc.description); //顯示目前幀格式資訊!例如:MJPEG}//====printf("\nThis is an example: whether the USB camera support the :V4L2_PIX_FMT_RGB32?\n");test_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;test_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32;if(-1==ioctl(fd, VIDIOC_TRY_FMT, &test_fmt)) //檢測是否支援RGB32格式! if(errno==EINVAL) printf("Can not support format RGB32!\n"); printf("\n To apply the buffer from the memory!\n");struct v4l2_requestbuffers req;CLEAR(req);req.count = 4;req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;req.memory = V4L2_MEMORY_MMAP;ioctl(fd, VIDIOC_REQBUFS, &req);//====if (req.count < 2) printf("Insufficient buffer memory!!\n");buffers = calloc (req.count, sizeof (*buffers));//記憶體中建立對應空間//====for(n_buffers=0;n_buffers<req.count;n_buffers++){struct v4l2_buffer buf;CLEAR (buf); buf.index = n_buffers; buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; //區分是MMAP 還是USERPTR if(-1==ioctl(fd, VIDIOC_QUERYBUF, &buf)) //把VIDIOC_QUERYBUF配置設定的資料緩存轉換為實體位址! printf ("VIDIOC_QUERYBUF error/n"); buffers[n_buffers].length = buf.length; buffers[n_buffers].start = mmap(NULL,buf.length,PROT_READ | PROT_WRITE,MAP_SHARED,fd, buf.m.offset);//通過mmap建立映射關系 if (MAP_FAILED == buffers[n_buffers].start) printf ("mmap failed/n");}for (i = 0; i < n_buffers; ++i) //{struct v4l2_buffer buf;CLEAR (buf);buf.index = i;buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; if(-1==ioctl(fd, VIDIOC_QBUF, &buf)) //将申請到的緩沖幀列隊! printf ("VIDIOC_QBUF failed/n");}type = V4L2_BUF_TYPE_VIDEO_CAPTURE;if (-1 == ioctl (fd, VIDIOC_STREAMON, &type)) //開始捕捉圖像資料 printf ("VIDIOC_STREAMON failed/n");for (;;) //這一段涉及到異步IO{ fd_set fds; struct timeval tv; int r; FD_ZERO (&fds);//将指定的檔案描述符集清空 FD_SET (fd, &fds);//在檔案描述符集合中增加一個新的檔案描述符 tv.tv_sec = 3; tv.tv_usec = 0; r = select (fd + 1, &fds, NULL, NULL, &tv);//判斷是否可讀(即攝像頭是否準備好),tv是定時 if (-1 == r) { if (EINTR == errno) continue; printf ("select err/n"); } if (0 == r) { fprintf (stderr, "select timeout/n"); exit (EXIT_FAILURE); } if (read_frame ())//如果可讀,執行read_frame ()函數,并跳出循環 break;}unmap:for (i = 0; i < n_buffers; ++i) if (-1 == munmap (buffers[i].start, buffers[i].length)) printf ("munmap error");close (fd);fclose (file_fd);exit (EXIT_SUCCESS);return 0;}

繼續閱讀