V4l2和HAL-(2)
上一篇基本上说完了前三个大步骤,接下来我们跟着这张图继续看v4l2接口的buffer管理是如何进行的:
上回在setV4l2FpsLocked函数中调用了VIDIOC_S_PARM进行了视频帧率的设置。下一步则是开始申请缓冲区准备采集视频流:
5.
在HAL中,我们可以很轻易在上一个VIDIOC_S_PARM步骤(setV4l2FpsLocked中)之后不远处就找到请求buffer的ioctl,即VIDIOC_REQBUFS
同时也可以看到这里request下来还要和mCfg.numVideoBuffers中指定的buffer数量比一下,最终保存到mV4L2BufferCount里,这里歪一嘴看一下mCfg中指定的各种参数和默认值,保存位置在:
\vendor\mediatek\tv\hardware\interfaces\camera\device\3.4\default\MtkExternalCameraUtils.cpp
3266行可以看到v4l2BufferCount最终会是kDefaultNumVideoBuffer或kDefaultNumStillBuffer所指定的4或者2,最后req_buffers中的count成员也需要不小于上述的4或者2。需要注意的是,申请buffer的时候需要配置memory成员为 V4L2_MEMORY_MMAP,这也就对上了前一篇提到的图像采集方式,同时也只有memory字段为MMAP时count字段才会生效。
至此,我们已经向内核申请到了用来存放视频流数据的缓存,但是这些缓存仍处于内核空间,无法直接操作。
6&7.
按照酷图所示,到这一步,就要根据申请到的缓存数量去分别查询这些缓存的具体信息,即VIDIOC_QUERYBUF,因为我们仍无法操作处于内核空间的buffer,因此需要将他们通过mmap映射到用户空间,这就要求必须知道他们的大小、偏移等信息,这些信息统一被储存到v4l2_buffer结构体中,在mmap调用结束后,依次把这些空的buffer加入采集队列,也就是VIDIOC_QBUF,这两个调用也是接着configureV4l2StreamLocked函数里VIDIOC_REQBUFS之后进行的过程。
(ps:在尚未开启摄像头取像之前,需要将空的缓存一一入队,因此这里QUERYBUF之后就一一调用QBUF来完成入队操作。参考来源)
这时,细心的朋友应该发现了一个问题,那就是我们可以看到camera HAL中在VIDIOC_QUERYBUF和VIDIOC_QBUF中间并没有mmap过程,这是怎么回事呢?直接说结论:mmap会在之后的flow中有所体现。那么为什么没有在QUERYBUF之后立刻mmap呢,我个人是这样理解的:这里仅对buffer进行了查询和入队操作,还没有采集好的数据进来存放,所以可以暂时不mmap,等真正使用的时候再进行映射,这个过程会在下一篇视频数据采集的flow中详细介绍。