今天呢,我们来讲一个摄像头模块,V4L2,我们先来讲讲他的应用编程先:
1.1 buffer的管理
使用摄像头时,核心是"获得数据"。所以先讲如何获取数据,即如何得到buffer。
摄像头采集数据时,是一帧又一帧地连续采集。所以需要申请若干个buffer,驱动程序把数据放入buffer,APP从buffer得到数据。这些buffer可以使用链表来管理。
驱动程序周而复始地做如下事情:
-
从硬件采集到数据
-
把"空闲链表"取出buffer,把数据存入buffer
-
把含有数据的buffer放入"完成链表"
APP也会周而复始地做如下事情:
-
监测"完成链表",等待它含有buffer
-
从"完成链表"中取出buffer
-
处理数据
-
把buffer放入"空闲链表"
链表操作示意图如下:
1.2 完整的使用流程
参考mjpg-streamer和video2lcd,总结了摄像头的使用流程,如下:
-
open:打开设备节点/dev/videoX
-
ioctl VIDIOC_QUERYCAP:Query Capbility,查询能力,比如
-
确认它是否是"捕获设备",因为有些节点是输出设备
-
确认它是否支持mmap操作,还是仅支持read/write操作
-
-
ioctl VIDIOC_ENUM_FMT:枚举它支持的格式
-
ioctl VIDIOC_S_FMT:在上面枚举出来的格式里,选择一个来设置格式
-
ioctl VIDIOC_REQBUFS:申请buffer,APP可以申请很多个buffer,但是驱动程序不一定能申请到
-
ioctl VIDIOC_QUERYBUF和mmap:查询buffer信息、映射
-
如果申请到了N个buffer,这个ioctl就应该执行N次
-
执行mmap后,APP就可以直接读写这些buffer
-
-
ioctl VIDIOC_QBUF:把buffer放入"空闲链表"
-
如果申请到了N个buffer,这个ioctl就应该执行N次
-
-
ioctl VIDIOC_STREAMON:启动摄像头
-
这里是一个循环:使用poll/select监测buffer,然后从"完成链表"中取出buffer,处理后再放入"空闲链表"
-
poll/select
-
ioctl VIDIOC_DQBUF:从"完成链表"中取出buffer
-
处理:前面使用mmap映射了每个buffer的地址,处理时就可以直接使用地址来访问buffer
-
ioclt VIDIOC_QBUF:把buffer放入"空闲链表"
-
-
ioctl VIDIOC_STREAMOFF:停止摄像头