v4l2简介

系统 1893 0

V4L是linux内核中关于视频设备的子系统,为linux下的视频驱动提供了统一的接口,使应用程序可以使用统一的API操作不同的视频设备,简化视频系统的开发与维护

V4L2相比与V4L有更好的扩展性和灵活性

(一)V4L2支持设备:

V4L2可以支持多种设备,可以有以下几种接口:

1)视频采集接口

2)视频输出接口

3)直接传输视频接口:将视频采集设备上采集的信号直接输出到视频输出设备上,不用经过系统CPU

4)视频间隔消隐信号接口(VBI Interface):使引用可以访问传输消隐期的视频信号

5)收音机接口:

 

(二)V4L2设备处理流程

打开V4L2设备节点

      
        int
      
       fd = open(
      
        "
      
      
        /dev/video0
      
      
        "
      
      ,O_RDWR |O_NONBLOCK);
    

配置设备/查询设备属性

      
        int
      
       ioctl (
      
        int
      
       fd, unsigned 
      
        long
      
      
        int
      
       request, ...
      
        /*
      
      
        args
      
      
        */
      
      ) ;
    

常见的request命令:

VIDIOC_REQBUFS:在内核空间中分配帧缓冲区

      
        struct
      
      
         v4l2_requestbuffers req;

req.count
      
      =
      
        4
      
      
        ;

req.type
      
      =
      
        V4L2_BUF_TYPE_VIDEO_CAPTURE;

req.memory
      
      =
      
        V4L2_MEMORY_MMAP;

ioctl(fd,VIDIOC_REQBUFS,
      
      &req);
    

VIDIOC_QUERYBUF:将REQBUFS中分配的缓存转换成物理地址,并将物理地址映射到用户空间

      
        for
      
       (n_buffers = 
      
        0
      
      ; n_buffers < req.count; ++
      
        n_buffers)

{

        
      
      
        struct
      
      
         v4l2_buffer buf;

        memset(
      
      &buf,
      
        0
      
      ,
      
        sizeof
      
      
        (buf));

        buf.type 
      
      =
      
        V4L2_BUF_TYPE_VIDEO_CAPTURE;

        buf.memory 
      
      =
      
        V4L2_MEMORY_MMAP;

        buf.index 
      
      =
      
        n_buffers;

        
      
      
        if
      
       (-
      
        1
      
       == ioctl(fd, VIDIOC_QUERYBUF, &
      
        buf))

        {

                printf(
      
      
        "
      
      
        error in VIDIOC_QUERYBUF\n
      
      
        "
      
      
        );

                
      
      
        return
      
       -
      
        1
      
      
        ;

        }

        buffers[n_buffers].length
      
      =
      
         buf.length;

        buffers[n_buffers].start
      
      =mmap (NULL,buf.length,PROT_READ |
      
         PROT_WRITE ,MAP_SHARED,fd, buf.m.offset);

        
      
      
        if
      
       (MAP_FAILED==
      
         buffers[n_buffers].start)

                
      
      
        return
      
       -
      
        1
      
      
        ;

}
      
    

VIDIOC_QUERYCAP:查询驱动功能

      
        struct
      
      
         v4l2_capability cap;


      
      
        if
      
      ( ioctl(fd,VIDIOC_QUERYCAP,&cap) == -
      
        1
      
      
        )

        printf(
      
      
        "
      
      
        error\n
      
      
        "
      
      
        );

printf(
      
      
        "
      
      
        capability:\n
      
      
        "
      
      
        );

printf(
      
      
        "
      
      
        driver:%s\n
      
      
        "
      
      
        ,cap.driver);

printf(
      
      
        "
      
      
        card:%s\n
      
      
        "
      
      
        ,cap.card);

printf(
      
      
        "
      
      
        bus info:%s\n
      
      
        "
      
      
        ,cap.bus_info);

printf(
      
      
        "
      
      
        version:%d\n
      
      
        "
      
      
        ,cap.version);

printf(
      
      
        "
      
      
        capabilities:%x\n
      
      
        "
      
      ,cap.capabilities);
    

VIDIOC_ENUM_FMT:获取当前驱动支持的视频格式

      
        struct
      
      
         v4l2_fmtdesc fmtdesc;

fmtdesc.index 
      
      = 
      
        0
      
      
        ;

fmtdesc.type
      
      =
      
        V4L2_BUF_TYPE_VIDEO_CAPTURE;

printf(
      
      
        "
      
      
        fmtdesc:\n
      
      
        "
      
      
        );


      
      
        while
      
      (ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) != -
      
        1
      
      
        )

{

        printf(
      
      
        "
      
      
        \t%d.%s\n
      
      
        "
      
      ,fmtdesc.index+
      
        1
      
      
        ,fmtdesc.description);

        fmtdesc.index
      
      ++
      
        ;

}
      
    

VIDIOC_G/S_FMT:读取/设置当前驱动的视频捕捉格式

      
        struct
      
      
         v4l2_format format;

memset(
      
      &format, 
      
        0
      
      , 
      
        sizeof
      
      (
      
        struct
      
      
         v4l2_format));

format.type 
      
      =
      
         V4L2_BUF_TYPE_VIDEO_CAPTURE;


      
      
        if
      
      ( ioctl(fd, VIDIOC_G_FMT, &format) == -
      
        1
      
      
        )

{

        printf(
      
      
        "
      
      
        VIDIOC_G_FMT error\n
      
      
        "
      
      
        );

        
      
      
        return
      
       -
      
        1
      
      
        ;

}


      
      
        struct
      
      
         v4l2_pix_format pix_format;

pix_format 
      
      =
      
         format.fmt.pix;

printf(
      
      
        "
      
      
        pix_format\n
      
      
        "
      
      
        );

printf(
      
      
        "
      
      
        width:%d\n
      
      
        "
      
      
        ,pix_format.width);

printf(
      
      
        "
      
      
        height:%d\n
      
      
        "
      
      
        ,pix_format.height);

printf(
      
      
        "
      
      
        bytesperline:%d\n
      
      
        "
      
      
        ,pix_format.bytesperline);

printf(
      
      
        "
      
      
        sizeimage:%d\n
      
      
        "
      
      ,pix_format.sizeimage);
    

VIDIOC_TRY_FMT:验证当前驱动的显示格式

VIDIOC_CROPCAP:查询驱动的修剪能力

VIDIOC_G/S_CROP:读取/设置视频信号的边框

      
        struct
      
      
         v4l2_cropcap cropcap;


      
      
        struct
      
      
         v4l2_crop crop;

cropcap.type 
      
      =
      
         V4L2_BUF_TYPE_VIDEO_CAPTURE;  


      
      
        if
      
      (
      
        0
      
       == ioctl(fd, VIDIOC_CROPCAP, &
      
        cropcap))  

{  

        crop.type 
      
      =
      
         V4L2_BUF_TYPE_VIDEO_CAPTURE;  

        crop.c 
      
      =
      
         cropcap.defrect;  

        
      
      
        if
      
      (-
      
        1
      
       == ioctl(fd, VIDIOC_S_CROP, &
      
        crop))

        {

                printf(
      
      
        "
      
      
        VIDIOC_S_CROP error\n
      
      
        "
      
      
        );

                
      
      
        return
      
       -
      
        1
      
      
        ;

        }

}
      
    

VIDIOC_QBUF:把缓存区放入缓存队列

VIDIOC_DQBUF:把缓存去从缓存队列中取出

      unsigned 
      
        int
      
      
         i;


      
      
        enum
      
      
         v4l2_buf_type type;


      
      
        for
      
       (i = 
      
        0
      
      ; i< 
      
        4
      
      ; ++
      
        i)

{

        
      
      
        struct
      
      
         v4l2_buffer 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);


      
      
        struct
      
      
         v4l2_buffer buf;

buf.type 
      
      =
      
         V4L2_BUF_TYPE_VIDEO_CAPTURE;

buf.memory 
      
      =
      
        V4L2_MEMORY_MMAP;


      
      
        if
      
      ( ioctl (fd,VIDIOC_DQBUF, &buf)==-
      
        1
      
      
        )

{

        printf(
      
      
        "
      
      
        error in VIDIOC_DQBUF\n
      
      
        "
      
      
        );

        
      
      
        return
      
       -
      
        1
      
      
        ;

}
      
    

VIDIOC_STREAMON:开始视频显示函数

VIDIOC_STREAMOFF:结束视频显示函数

VIDIOC_QUERYSTD:检查当前视频设备支持的标准,亚洲一般使用PAL制式摄像头,欧洲一般使用NTSC摄像头

      
        v4l2_std_id std;


      
      
        int
      
      
         ret;


      
      
        do
      
      
        

{

          ret 
      
      = ioctl(fd,VIDIOC_QUERYSTD,&
      
        std);                  

}
      
      
        while
      
      (-
      
        1
      
      ==ret && errno==
      
        EAGAIN);


      
      
        switch
      
      
        (std)

{


      
      
        case
      
      
         V4L2_STD_NTSC:

   
      
      
        //


      
      
        case
      
      
         V4L2_STD_PAL:

   
      
      
        //
      
         

} 
    

处理v4l2视频数据

v4l2设定了三种应用程序与驱动的交互方式:

1)直接读取设备文件方式read/write

2)mmap映射方式

3)用户指针方式

mmap方式:驱动将内部数据空间映射到应用程序空间上,双方直接在这个空间上进行数据交换

用户指针方式:首先由应用程序申请一段缓冲区,然后将缓冲区传给驱动,驱动将其作为缓冲区,从而实现内存共享

直接read/write:一般配合select使用,直接读取设备文件的方式进行I/O

关闭设备

调用close关闭文件描述符,如果进行了内存映射,关闭之前还需要munmap解除映射

v4l2简介


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论