概述
上一节我们了解了v4l2 api的使用方法,这一节我们来看下相关框架。不过这里先不介绍media framework,media的相关内容后面的文章再讲。
框架图
这个框架图分为4个部分:用户空间、v4l2核心、平台驱动、寄存器。这里的平台驱动指的是camera interface(CAMIF)驱动,例如三星的fimc驱动,下面我会以fimc驱动为例子讲述这里的平台驱动。上一节我们知道了获取摄像头图像是一般流程:
1、以O_RDWR | O_NONBLOCK的方式open设备节点,为啥是O_NONBLOCK,因为在VIDIOC_DQBUF的时候如果在输出队列中没有数据,那默认是阻塞的。
2、通过VIDIOC_QUERYCAP获取摄像头的相关信息。
3、通过VIDIOC_S_FMT设置摄像头格式
4、通过VIDIOC_REQBUFS请求buffer,一般是4个buffer。
5、通过VIDIOC_QUERYBUF查询buffer,如果buffer已请求成功,则调用mmap映射驱动分配的buffer到应用层
6、通过VIDIOC_QBUF把buffer放到传入队列
7、通过VIDIOC_STREAMON启动流传输
8、在文件描述符上poll或者select等待数据
9、被唤醒后通过VIDIOC_DQBUF从传出队列中取出数据,同时会告诉你数据放在哪个buffer。
10、处理图像、显示图像,然后回到6操作继续。
这个框架图以buffer为核心描述了VIDIOC_REQBUFS、VIDIOC_QBUF、VIDIOC_STREAMON和VIDIOC_DQBUF涉及到的操作。我们以这几个ioctl宏来讲下v4l2框架。
VIDIOC_REQBUFS
fimc驱动实现了v4l2_ioctl_ops的成员函数vidioc_reqbufs。通过对/dev/videox节点的VIDIOC_REQBUFS操作会调用到vb2_ioctl_reqbufs,来看下vb2_ioctl_reqbufs里面的操作。
//注:以缩进的形式或者"---->"来表示函数调用。
int vb2_ioctl_reqbufs(struct file *file, void *priv,struct v4l2_requestbuffers *p){
struct video_device *vdev = video_devdata(file);
.....
res = vb2_core_reqbufs(vdev->queue, p->memory, &p->count);---->
---> {
__vb2_queue_alloc(q, memory, num_buffers, num_planes, plane_sizes) --->
-->{
for (buffer = 0; buffer < num_buffers; ++buffer) {
//用户层指定的buffer数量
struct vb2_buffer *vb;
vb = kzalloc(q->buf_struct_size, GFP_KERNEL);
vb->vb2_queue = q;
..... //fill vb
if (memory == VB2_MEMORY_MMAP) {
//上层指定stream I/O方式为mmap
ret = __vb2_buf_mem_alloc(vb)