• Linux下实现视频读取(三)---Buffer的准备和数据读取


    前面主要介绍的是:V4L2 的一些设置接口,如亮度,饱和度。曝光时间,帧数,增益。白平衡等。今天看看V4L2 得到数据的几个关键ioctl,Buffer的申请和数据的抓取。



    1. 初始化 Memory Mapping 或 User Pointer I/O.
    int ioctl(int fd, int requestbuf, struct v4l2_requestbuffers * argp);
    參数一:open()所产生的句柄。
    參数二:VIDIOC_REQBUFS
    參数三:in/out结构体。
    struct v4l2_requestbuffers
    {
     __u32 count;
     enum v4l2_buf_type type;
     enum v4l2_memory memory; //Applications set this field to V4L2_MEMORY_MMAP or V4L2_MEMORY_USERPTR
     __u32 reserved[2];
    };

    注意,有两种方式的I/O。 Memory Mapping 和User Pointer。

    Memory Mapping的Buffer由Driver申请为物理连续的内存空间(Kernel空间)。

    在此ioctl调用时被分配,须要早于mmap()动作将他们映射到用户空间。

    1.1:Memory Mapping模式具体解释:
    在使用Memory Mapping模式时,參数三中结构体内每一个field都须要设置。



     __u32 count;   //当memory=V4L2_MEMORY_MMAP时。此处才有效。表明要申请的buffer个数。
     enum v4l2_buf_type type;  //Stream 或者Buffer的类型。

    此处肯定为V4L2_BUF_TYPE_VIDEO_CAPTURE
     enum v4l2_memory memory;  //既然是Memory Mapping模式,则此处设置为:V4L2_MEMORY_MMAP


    注意:count是个输入输出函数。由于你所申请到的Buffer个数不一定就是你所输入的Number。所以在ioctl运行后,driver会将真实申请到的buffer个数填充到此field. 这个数目有可能大于你想要申请的,也可能小与。甚至可能是0个。
    应用程序能够再次调用ioctl--VIDIOC_REQBUFS 来改动buffer个数。但前提是必须先释放已经 mapped 的 buffer ,能够先 munmap ,然后设置參数 count 为 0 来释放全部的 buffer。



    支持Memory  Mapping  I/O方式的前提是:v4l2_capability  中支持V4L2_CAP_STREAMING。
    在这个模式下,数据本身不会被Copy,仅仅是在Kernel和用户态之间交换。在应用程序想要訪问到这些数据之前,它必须调用mmap()影射到用户态。



    同一时候也要注意。通过ioctl申请的内存,是物理内存,无法被交换入Disk,所以一定要释放:munmap()。

    1.2:User Pointer模式:
    User Pointer模式时,应用程序实现申请。


    仅仅须要填充Type=V4L2_BUF_TYPE_VIDEO_CAPTURE。 memory=V4L2_MEMORY_USERPTR

    2. 询问Buffer状态:
    int ioctl(int fd, int request, struct v4l2_buffer* argp);
    參数一:open()所产生的句柄。
    參数二:VIDIOC_QUERYBUF
    參数三:v4l2_buffer 结构体。(IN/OUT參数)

    注意。此ioctl是Memory Mapping的I/O方法之中的一个。User Pointer模式不须要。

    在Buffer在ioctl-VIDIOC_REQBUFS运行时创建后。随时都能够调用此Ioctl得到buffer信息。

    我们首先通过v4l2_buffer结构体看看參数三这个输入输出參数须要输入些什么,以及可以得到什么信息。

    struct v4l2_buffer
    {
     __u32 index;
     enum v4l2_buf_type type;
     __u32 bytesused;
     __u32 flags;
     enum v4l2_field field;
     struct timeval timestamp;
     struct v4l2_timecode timecode;
     __u32 sequence;


     enum v4l2_memory memory;
     union {
     __u32 offset;
     unsigned long userptr;
     } m;
     __u32 length;
     __u32 input;
     __u32 reserved;
    };

    在调用ioctl--VIDIOC_QUERYBUF时,须要写入的项目有:
    enum v4l2_buf_type type; //V4L2_BUF_TYPE_VIDEO_CAPTURE
    __u32 index;  // 这里须要解释一下,由于在调用ioctl-VIDIOC_REQBUFS时,建立了count个Buffer。

    所以,这里index的有效范围是:0到count-1.

    在调用ioctl-VIDIOC_QUERYBUF后,Driver会填充v4l2_buffer 结构体内全部信息供用户使用。
    假设一些正常:
    1. flags 中:V4L2_BUF_FLAG_MAPPED, V4L2_BUF_FLAG_QUEUED and V4L2_BUF_FLAG_DONE被设置。
    2. memory中,V4L2_MEMORY_MMAP被设置。
    3. m.offset中,从将要mapping 的device memory头到数据头的offset.
    4. length 中,填充当前Buffer长度。


    5。

    其他的Field有可能设置。也有可能不被设置。

    这样。mmap()想要有的信息就全了。

    而mmap()之后。Device Driver 申请的或者Device Memory就能映射到用户空间。数据就能够被应用程序使用了。这才是ioctl-VIDIOC_QUERYBUF的关键作用。



    3.和Driver交换buffer: 
    对Camera这种捕获设备来说,Device将数据放到Buffer中,用户得到数据。

    Device再次将数据放到Buffer中。
    那么Device Driver 如何知道哪个Buffer是能够存放数据的呢?这就用到当前这两个ioctl-VIDIOC_QBUF, ioctl-VIDIOC_DQBUF.

    ioctl-VIDIOC_QBUF: 将指定的Buffer放到输入队列中,即向Device表明这个Buffer能够存放东西。


    ioctl-VIDIOC_DQBUF: 将输出队列中的数据 buffer取出。



    在 driver 内部管理着两个 buffer queues ,一个输入队列,一个输出队列。对于 capture device 来说,当输入队列中的 buffer 被塞满数据以后会自己主动变为输出队列,等待调用 VIDIOC_DQBUF 将数据进行处理以后又一次调用 VIDIOC_QBUF 将 buffer 又一次放进输入队列.

    使用方法:
    ioctl--VIDIOC_QBUF:
    int ioctl(int fd, int request, struct v4l2_buffer* argp);
    參数一:open()所产生的句柄。


    參数二:VIDIOC_QBUF
    參数三:v4l2_buffer 结构体。

    (IN/OUT參数)

    參数三是IN/OUT 參数。须要填充
    enum v4l2_buf_type type; //V4L2_BUF_TYPE_VIDEO_CAPTURE
    __u32 index;  // 这里须要解释一下,由于在调用ioctl-VIDIOC_REQBUFS时,建立了count个Buffer。所以,这里index的有效范围是:0到count-1. 
    memory: V4L2_MEMORY_MMAP.

    则这个结构体指明的buffer被送入输出队列,表明此Buffer能够被device 填充数据。



    使用方法:
    ioctl--VIDIOC_DQBUF:
    int ioctl(int fd, int request, struct v4l2_buffer* argp);
    參数一:open()所产生的句柄。


    參数二:VIDIOC_DQBUF
    參数三:v4l2_buffer 结构体。(IN/OUT參数)

    从输出队列中取出一个有数据的Buffer。这个Buffer中的数据被处理后,此Buffer能够通过ioctl-VIDIOC_QBUF再次放入输入队列中去。

  • 相关阅读:
    蓝桥杯 全球变暖(dfs)
    Bzoj3196 Tyvj 1730 二逼平衡树
    Bzoj3110 [Zjoi2013]K大数查询
    Bzoj4004 [JLOI2015]装备购买
    Bzoj2115 [Wc2011] Xor
    Bzoj1257 [CQOI2007]余数之和sum
    HDU1724 Ellipse
    Bzoj2178 圆的面积并
    SPOJ CIRU The area of the union of circles
    CodeForces 232E.Quick Tortoise
  • 原文地址:https://www.cnblogs.com/zsychanpin/p/6699097.html
Copyright © 2020-2023  润新知