V4L2采集图像基本流程

参考 http://blog.csdn.net/tsuibeyond/article/details/50654823

         http://www.cnblogs.com/surpassal/archive/2012/12/19/zed_webcam_lab1.html

      1.打开设备fd = open(FILE_VIDEO1, O_RDWR))

       2.取得设备的capability 看看设备具有什么功能 比如是否具有视频输入 或者音频输入输出等 VIDIOC QUERYCAP struct v4l2 capabilit

      3 选择视频输入 一个视频设备可以有多个视频输入 VIDIOC S INPUT struct v4l2 input

      4 设置视频的制式和帧格式 制式包括PAL NTSC 帧的格式个包括宽度和高度等 VIDIOC S STD VIDIOC S FMT struct v4l2 std id struct v4l2 format 

      5 向驱动申请帧缓冲 一般不超过5个 struct v4l2 requestbuffers 

      6 将申请到的帧缓冲映射到用户空间 这样就可以直接操作采集到的帧了 而不必去复制 mmap 

      7 将申请到的帧缓冲全部入队列 以便存放采集到的数据 VIDIOC QBUF struct v4l2 buffer 

      8 开始视频的采集 VIDIOC STREAMON

      9 出队列以取得已采集数据的帧缓冲 取得原始采集数据 VIDIOC DQBUF 

      10 将缓冲重新入队列尾 这样可以循环采集 VIDIOC QBUF 

     11 停止视频的采集 VIDIOC STREAMOFF 12 关闭视频设备 close fd ;

  

  1. #include <errno.h>  
  2. #include <fcntl.h>  
  3. #include <linux/videodev2.h>  
  4. #include <stdint.h>  
  5. #include <stdio.h>  
  6. #include <string.h>  
  7. #include <sys/ioctl.h>  
  8. #include <sys/mman.h>  
  9. #include <unistd.h>  
  10. #include <opencv2/core/core.hpp>  
  11. #include <opencv2/highgui/highgui.hpp>  
  12. #include <iostream>  
  13.   
  14. uchar *buffer;                          //buffers 指针记录缓冲帧  
  15.   
  16. #define IMAGEWIDTH 640  
  17. #define IMAGEHEIGHT 480  
  18.   
  19. #define TRUE 1  
  20. #define FALSE 0  
  21.   
  22. #define FILE_VIDEO1 "/dev/video0"  
  23.   
  24. static int fd;                          //设备描述符  
  25. struct v4l2_streamparm setfps;          //结构体v4l2_streamparm来描述视频流的属性  
  26. struct v4l2_capability cap;             //取得设备的capability,看看设备具有什么功能,比如是否具有视频输入,或者音频输入输出等  
  27. struct v4l2_fmtdesc fmtdesc;            //枚举设备所支持的image format:  VIDIOC_ENUM_FMT  
  28. struct v4l2_format fmt,fmtack;          //子结构体struct v4l2_pix_format设置摄像头采集视频的宽高和类型:V4L2_PIX_FMT_YYUV V4L2_PIX_FMT_YUYV  
  29. struct v4l2_requestbuffers req;         //向驱动申请帧缓冲的请求,里面包含申请的个数  
  30. struct v4l2_buffer buf;                 //代表驱动中的一帧  
  31. enum   v4l2_buf_type type;              //帧类型  
  32.   
  33. int init_v4l2(void);                    //初始化  
  34. int v4l2_grab(void);                    //采集  
  35.   
  36.   
  37.   
  38. int main()  
  39. {  
  40.         printf("first~~\n");  
  41.         if(init_v4l2() == FALSE){      //打开摄像头  
  42.             printf("Init fail~~\n");  
  43.             exit(1);  
  44.         }  
  45.         printf("second~~\n");  
  46.         if(v4l2_grab() == FALSE){  
  47.             printf("grab fail~~\n");  
  48.             exit(2);  
  49.         }  
  50.         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;           //Stream 或者Buffer的类型。此处肯定为V4L2_BUF_TYPE_VIDEO_CAPTURE  
  51.         buf.memory = V4L2_MEMORY_MMAP;                    //既然是Memory Mapping模式,则此处设置为:V4L2_MEMORY_MMAP  
  52.         printf("third~~\n");  
  53.         cvNamedWindow("one",CV_WINDOW_AUTOSIZE);  
  54.         IplImage* img;  
  55.         CvMat cvmat;  
  56.         int i = 100;  
  57.         double t;  
  58.         while(1){  
  59.                 t = (double)cvGetTickCount();                      //调用时钟测时间  
  60.                 ioctl(fd,VIDIOC_DQBUF,&buf);  
  61.                 buf.index = 0;  
  62.                 cvmat = cvMat(IMAGEHEIGHT,IMAGEWIDTH,CV_8UC3,(void*)buffer);//CV_8UC3  
  63.                 //t = (double)cvGetTickCount();  
  64.                 img = cvDecodeImage(&cvmat,1);  
  65.                 //t=(double)cvGetTickCount()-t;  
  66.                 //printf("used time is %gms\n",(t/(cvGetTickFrequency()*1000)));  
  67.                 if(!img)    printf("No img\n");  
  68.                 cvShowImage("one",img);  
  69.                 cvReleaseImage(&img);  
  70.                 ioctl(fd,VIDIOC_QBUF,&buf);                      //在 driver 内部管理着两个 buffer queues ,一个输入队列,一个输出队列。  
  71.                                                  //对于 capture device 来说,当输入队列中的 buffer 被塞满数据以后会自动变为输出队列,  
  72.                                                  //等待调用 VIDIOC_DQBUF 将数据进行处理以后重新调用 VIDIOC_QBUF 将 buffer 重新放进输入队列.  
  73.                 if((cvWaitKey(1)&255) == 27)    exit(0);  
  74.                 t=(double)cvGetTickCount()-t;  
  75.                 printf("used time is %gms\n",(t/(cvGetTickFrequency()*1000)));  
  76.         }  
  77.   
  78.         ioctl(fd,VIDIOC_STREAMOFF,&type);         // 停止视频采集命令,应用程序调用VIDIOC_ STREAMOFF停止视频采集命令后,视频设备驱动程序不在采集视频数据。  
  79.         return 0;  
  80. }  
  81.   
  82. int init_v4l2(void){  
  83.         if ((fd = open(FILE_VIDEO1, O_RDWR)) == -1){  
  84.             printf("Opening video device error\n");  
  85.             return FALSE;  
  86.         }  
  87.         if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == -1){               // 查询视频设备的功能  
  88.                 printf("unable Querying Capabilities\n");  
  89.                 return FALSE;  
  90.         }  
  91.         else  
  92. /* 
  93.         { 
  94.         printf( "Driver Caps:\n" 
  95.                 "  Driver: \"%s\"\n" 
  96.                 "  Card: \"%s\"\n" 
  97.                 "  Bus: \"%s\"\n" 
  98.                 "  Version: %d\n" 
  99.                 "  Capabilities: %x\n", 
  100.                 cap.driver, 
  101.                 cap.card, 
  102.                 cap.bus_info, 
  103.                 cap.version, 
  104.                 cap.capabilities); 
  105.  
  106.         } 
  107.  
  108.         if((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == V4L2_CAP_VIDEO_CAPTURE){ 
  109.             printf("Camera device %s: support capture\n",FILE_VIDEO1); 
  110.         } 
  111.         if((cap.capabilities & V4L2_CAP_STREAMING) == V4L2_CAP_STREAMING){ 
  112.             printf("Camera device %s: support streaming.\n",FILE_VIDEO1); 
  113.         } 
  114. */  
  115.         fmtdesc.index = 0;  
  116.         fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  117.         printf("Support format: \n");  
  118.         while(ioctl(fd,VIDIOC_ENUM_FMT,&fmtdesc) != -1){        // 获取当前视频设备支持的视频格式  
  119.             printf("\t%d. %s\n",fmtdesc.index+1,fmtdesc.description);  
  120.             fmtdesc.index++;  
  121.         }  
  122.         //set fmt  
  123.         fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  124.         fmt.fmt.pix.width = IMAGEWIDTH;                    
  125.         fmt.fmt.pix.height = IMAGEHEIGHT;  
  126.         fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; //*************************V4L2_PIX_FMT_YUYV****************可以选择  
  127.         fmt.fmt.pix.field = V4L2_FIELD_NONE;  
  128.   
  129.         if (ioctl(fd, VIDIOC_S_FMT, &fmt) == -1){    // 设置视频设备的视频数据格式,例如设置视频图像数据的长、宽,图像格式(JPEG、YUYV格式)  
  130.             printf("Setting Pixel Format error\n");  
  131.             return FALSE;  
  132.         }  
  133.         if(ioctl(fd,VIDIOC_G_FMT,&fmt) == -1){   //获取图像格式  
  134.             printf("Unable to get format\n");  
  135.             return FALSE;  
  136.         }  
  137. //        else  
  138.   
  139. /*        {  
  140.             printf("fmt.type:\t%d\n",fmt.type);         //可以输出图像的格式  
  141.             printf("pix.pixelformat:\t%c%c%c%c\n",fmt.fmt.pix.pixelformat & 0xFF,(fmt.fmt.pix.pixelformat >> 8) & 0xFF,\  
  142.                    (fmt.fmt.pix.pixelformat >> 16) & 0xFF, (fmt.fmt.pix.pixelformat >> 24) & 0xFF);  
  143.             printf("pix.height:\t%d\n",fmt.fmt.pix.height);  
  144.             printf("pix.field:\t%d\n",fmt.fmt.pix.field);  
  145.         }  
  146. */  
  147. /* 
  148.         setfps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 
  149.         setfps.parm.capture.timeperframe.numerator = 100; 
  150.         setfps.parm.capture.timeperframe.denominator = 100; 
  151.         printf("init %s is OK\n",FILE_VIDEO1); 
  152. */  
  153.         return TRUE;  
  154. }  
  155.   
  156. int v4l2_grab(void){  
  157.     //struct v4l2_requestbuffers req = {0};  
  158.     //4  request for 4 buffers  
  159.     req.count = 1;  
  160.     req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  161.     req.memory = V4L2_MEMORY_MMAP;  
  162.   
  163.     if (ioctl(fd, VIDIOC_REQBUFS, &req) == -1)        //开启内存映射或用户指针I/O  
  164.     {  
  165.         printf("Requesting Buffer error\n");  
  166.         return FALSE;  
  167.     }  
  168.     //5 mmap for buffers  
  169.     buffer = (uchar*)malloc(req.count * sizeof(*buffer));  
  170.     if(!buffer){  
  171.         printf("Out of memory\n");  
  172.         return FALSE;  
  173.     }  
  174.     unsigned int n_buffers;  
  175.     for(n_buffers = 0;n_buffers < req.count; n_buffers++){  
  176.     //struct v4l2_buffer buf = {0};  
  177.     buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  178.     buf.memory = V4L2_MEMORY_MMAP;  
  179.     buf.index = n_buffers;  
  180.     if(ioctl(fd, VIDIOC_QUERYBUF, &buf) == -1){ // 查询已经分配的V4L2的视频缓冲区的相关信息,包括视频缓冲区的使用状态、在内核空间的偏移地址、缓冲区长度等。  
  181.         printf("Querying Buffer error\n");  
  182.         return FALSE;  
  183.         }  
  184.   
  185.     buffer = (uchar*)mmap (NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);  
  186.   
  187.     if(buffer == MAP_FAILED){  
  188.         printf("buffer map error\n");  
  189.         return FALSE;  
  190.         }  
  191.     printf("Length: %d\nAddress: %p\n", buf.length, buffer);  
  192.     printf("Image Length: %d\n", buf.bytesused);  
  193.     }  
  194.     //6 queue  
  195.     for(n_buffers = 0;n_buffers <req.count;n_buffers++){  
  196.         buf.index = n_buffers;  
  197.         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  198.         buf.memory = V4L2_MEMORY_MMAP;  
  199.         if(ioctl(fd,VIDIOC_QBUF,&buf)){    // 投放一个空的视频缓冲区到视频缓冲区输入队列中   
  200.             printf("query buffer error\n");  
  201.             return FALSE;  
  202.         }  
  203.     }  
  204.     //7 starting  
  205.     type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  206.     if(ioctl(fd,VIDIOC_STREAMON,&type) == -1){ //  
  207.         printf("stream on error\n");  
  208.         return FALSE;  
  209.     }  
  210.     return TRUE;  
  211. }  



可以设置采集图像的大小类型。

http://download.csdn.net/detail/yuyangyg/9780338  这里面有V4L2的一些资料

猜你喜欢

转载自blog.csdn.net/guo1988kui/article/details/79900229