您的位置:首页 > Web前端

V4L2 API详解 <三> Buffer的准备和数据读取

2013-12-23 16:26 459 查看
作者: Sam (甄峰)  sam_code@hotmail.com前面主要介绍的是:V4L2 的一些设置接口,如亮度,饱和度,曝光时间,帧数,增益,白平衡等。今天看看V4L2 得到数据的几个关键ioctl,Buffer的申请和数据的抓取。1. 初始化 Memory Mapping 或 User Pointer I/O.int ioctl(int fd, int requestbuf, structv4l2_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_USERPTR2. 询问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 内部管理着两个 bufferqueues ,一个输入队列,一个输出队列。对于 capturedevice 来说,当输入队列中的 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再次放入输入队列中去。4. 开始和结束捕获:ioctl--VIDIOC_STREAMON. ioctl--VIDIOC_STREAMOFF非常简单的调用。就是开始和结束。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: