• V4L2学习笔记


    简介:

    Video4linux2(简称V4L2),是linux中关于视频设备的内核驱动。

    在Linux中,视频设备是设备文件,可以像访问普通文件一样对其进行读写。

    摄像头文件一般放在在/dev/video0下。

    流程:

    1、打开视频设备。  

      int g_videofd = open(“/dev/video0”, O_RDWR, 0); //选项可为 O_RDWR| O_NONBLOCK,非阻塞,即无数据依然返回。


    2、取得设备的capability。(重要)//l inux-2.6.30/include/linux/videodev2.h定义

     1 int VIPP_VIDEO_Queryinfo() 
     2 {
     3     int ret;
     4     struct v4l2_capability cap;
     5 
     6     ret = ioctl(g_videofd, VIDIOC_QUERYCAP, &cap);
     7     if (ret < 0) {
     8         printf("VIDIOC_QUERYCAP failed (%d)
    ",ret);
     9         return ret;
    10     }
    11 
    12     printf(“ Capability Informations:
    ”);        //  
    13     printf(" driver: %s
    ", cap.driver);           // 
    14     printf(“ card: %s
    ”,     cap.card);        // 
    15     printf(“ bus_info: %s
    ”, cap.bus_info);    //
    16     printf(“ version: %08X
    ”, cap.version);    // 
    17     printf(“ version: %u.%u.%u
    ”, (cap.version>>16)&0xff, (cap.version>>8)&0xff,             cap.version&0xff);        // 
    18     printf(" capabilities: %08X
    ", cap.capabilities);
    19     printf(" reserved: %08X.%08X.%08X.%08X
    ",cap.reserved[0],cap.reserved[1],
    20         cap.reserved[2],cap.reserved[3]);    // 
    21 
    22     return 0;
    23 }
    View Code

    3、设置视频的制式和帧格式。

      注意:如果该视频设备驱动不支持你所设定的图像格式,视频驱动会重新修改struct v4l2_format结构体变量的值为该视频设备所支持的                      图像格式,所以在程序设计中,设定完所有的视频格式后,要获取实际的视频格式,要重新读取struct v4l2_format结构体变量。

     1 int VIPP_VIDEO_Setparam(int width, int height, int format)
     2 {
     3     int ret;
     4     memset(&gst_videofmt, 0, sizeof(gst_videofmt));
     5     gst_videofmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //数据流类型,必须永远是                    //V4L2_BUF_TYPE_VIDEO_CAPTURE
     6     gst_videofmt.fmt.pix.width = width;
     7     gst_videofmt.fmt.pix.height = height;
     8     gst_videofmt.fmt.pix.pixelformat = format;
     9     gst_videofmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
    10     ret = ioctl(g_videofd, VIDIOC_S_FMT, &gst_videofmt);//设置当前驱动的频捕获格式 
    11     if (ret < 0) {    
    12         printf("VIDIOC_S_FMT failed (%d)
    ", ret);    
    13         return ret;    
    14     }
    15 
    16     gst_videofmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32;
    17     if (ioctl(g_videofd, VIDIOC_TRY_FMT, &gst_videofmt) == -1)//验证当前驱动的显示格式 
    18     {
    19         if ( errno == EINVAL ){
    20             printf("not support format RGB32
    ");
    21             return (-1);        
    22         }
    23     }
    24     return 0;
    25 }
    View Code

    4、向系统申请帧缓冲(一般不超过5个)。

    struct v4l2_requestbuffers reqbuf;
     
    reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;     
           // 数据流类型,必须永远是V4L2_BUF_TYPE_VIDEO_CAPTURE 
    reqbuf.memory = V4L2_MEMORY_MMAP; 
            // V4L2_MEMORY_MMAP或 V4L2_MEMORY_USERPTR(内存片段由应用程序自己分配)
    reqbuf.count = count;  //缓存数量,也就是说在缓存队列里保持多少张照片,一般不超过5个
     
    ret = ioctl(g_videofd , VIDIOC_REQBUFS, &reqbuf);
    if(ret < 0) {
       printf("VIDIOC_REQBUFS failed (%d) ", ret);  
       return ret;
    }

    5、将申请到的帧缓冲映射到用户空间。

    6、将申请到的帧缓冲全部入队列。

    for(i = 0; i< count; i++) {    
        gst_videobuf.index = i;     // 要获取内核视频缓冲区的信息编号
        gst_videobuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; // 数据流类型
        gst_videobuf.memory = V4L2_MEMORY_MMAP;
                  
        //把内核空间缓冲区映射到用户空间缓冲区
        ret = ioctl(g_videofd , VIDIOC_QUERYBUF, &gst_videobuf);
        if(ret < 0) {
            printf("VIDIOC_QUERYBUF (%d) failed (%d)
    ", i, ret);        
            return ret;        
        }
        frame[i].length = gst_videobuf.length;        // 图像的大小
        frame[i].start = (char *) mmap(0, gst_videobuf.length, PROT_READ|PROT_WRITE,                 MAP_SHARED, g_videofd, gst_videobuf.m.offset);
        if (frame[i].start == MAP_FAILED) {
            printf("mmap (%d) failed: %s
    ", i, strerror(errno));
            return -1; 
        }
        ret = ioctl(g_videofd , VIDIOC_QBUF, &gst_videobuf);    
        if (ret < 0){
            printf ("VIDIOC_QBUF (%d) failed (%d)
    ", i, ret);
            return -1; 
        }
    }
    View Code

    7、开始视频的采集。

      启动视频采集命令,应用程序调用VIDIOC_STREAMON启动视频采集命令后,视频设备驱动程序开始采集视频数据,并把采集到的视频       数据保存到视频驱动的视频缓冲区中

    int VIPP_VIDEO_Streamon()
    {
        int ret;
        enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        ret = ioctl(g_videofd, VIDIOC_STREAMON, &type);
        if (ret < 0) {
            printf("VIDIOC_STREAMON failed (%d)
    ", ret);
            return ret;
        }
    
        return 0;
    }
    View Code

    8、出队列以取得已采集数据的帧缓冲,取得原始采集数据。

    int VIPP_VIDEO_ReleaseStream()
    {
        int ret;
        
        ret = ioctl(g_videofd, VIDIOC_QBUF, &gst_videobuf);    
        if (ret < 0) {        
            LOG("VIDIOC_QBUF failed (%d)
    ", ret);        
            return ret;        
        }
    
        return 0;
    }
    View Code

    9、把原始数据保存入文件中。

      char filename[100] = {0};
      FILE *fp = NULL;
      sprintf(filename, "Image%d.%d_jpeg", i, j);
      fp = fopen(filename, "w");
      fwrite(frame[i].start, 1, frame[i].length, fp);
      fclose(fp);
    10、将缓冲重新入队列尾,这样可以循环采集。

    int VIPP_VIDEO_ReleaseStream()
    {
        int ret;    
        ret = ioctl(g_videofd, VIDIOC_QBUF, &gst_videobuf);    
        if (ret < 0) {        
            printf("VIDIOC_QBUF failed (%d)
    ", ret);        
            return ret;        
        }
    
        return 0;
    }
    View Code

    11、停止视频的采集。

    int VIPP_VIDEO_Streamoff()
    {
        int ret;
        enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    
        ret = ioctl(g_videofd, VIDIOC_STREAMOFF, &type);
        if (ret < 0) {
            printf("VIDIOC_STREAMON failed (%d)
    ", ret);
            return ret;
    
        }
        return 0;    
    }
    View Code

    12、关闭视频设备文件。

    int VIPP_VIDEO_End()
    {
        int i;
    
        for (i=0; i < COUNT; i++) {
            munmap(frame[i].start, frame[i].length);
        }
        close(g_videofd);
        
        return 0;
    }
    View Code

    相关结构体:

    struct v4l2_requestbuffers  //申请帧缓冲,对应命令VIDIOC_REQBUFS
    struct v4l2_capability      //视频设备的功能,对应命令VIDIOC_QUERYCAP
    struct v4l2_input           //视频输入信息,对应命令VIDIOC_ENUMINPUT
    struct v4l2_standard        //视频的制式,比如PAL,NTSC,对应命令VIDIOC_ENUMSTD
    struct v4l2_format          //帧的格式,对应命令VIDIOC_G_FMT、VIDIOC_S_FMT等
    struct v4l2_buffer          //驱动中的一帧图像缓存,对应命令VIDIOC_QUERYBUF
    struct v4l2_crop            //视频信号矩形边框
    v4l2_std_id                 //视频制式

    常用命令:

    VIDIOC_REQBUFS:分配内存
    VIDIOC_QUERYBUF:把VIDIOC_REQBUFS中分配的数据缓存转换成物理地址 
    VIDIOC_QUERYCAP:查询驱动功能
    VIDIOC_ENUM_FMT:获取当前驱动支持的视频格式
    VIDIOC_S_FMT:设置当前驱动的频捕获格式
    VIDIOC_G_FMT:读取当前驱动的频捕获格式
    VIDIOC_TRY_FMT:验证当前驱动的显示格式
    VIDIOC_CROPCAP:查询驱动的修剪能力
    VIDIOC_S_CROP:设置视频信号的边框
    VIDIOC_G_CROP:读取视频信号的边框
    VIDIOC_QBUF:把数据从缓存中读取出来
    VIDIOC_DQBUF:把数据放回缓存队列
    VIDIOC_STREAMON:开始视频显示函数
    VIDIOC_STREAMOFF:结束视频显示函数
    VIDIOC_QUERYSTD:检查当前视频设备支持的标准,例如PAL或NTSC。

  • 相关阅读:
    终于有了自己的blog了。
    [Asp.Net+C#]Datagrid使用技巧二(怎样让对动态创建的列进行排序)
    [Asp.Net+C#]Datagrid使用技巧一(怎样灵活控制表头)
    CentOS下配置iptables防火墙
    ios中提示信息的实现及自动消失
    ios导航条添加按钮
    NSAutoreleasePool自动释放池
    什么是Tollfree bridging
    Android开发中的drawable(hdpi,mdpi,ldpi)和WVGA,HVGA,QVGA的区别以及联系
    文章逐步迁移过来
  • 原文地址:https://www.cnblogs.com/funnylinux/p/3524327.html
Copyright © 2020-2023  润新知