V4l2和HAL-(1)
V4l2设备对应的视频设备节点一般是/dev/video*
这个节点就是暴露给用户空间的一个设备文件
V4L2支持两种采集图像的方式:
1.内存映射方式(mmap),这种方式一般用于连续视频数据的采集
2.直接读取方式(read),这种方式则主要用于静态图片数据的采集
应用程序通过V4L2接口采集数据主要可以分为以下五个步骤:
1.打开视频设备文件,进程视频采集的参数初始化,通过V4L2接口设置视频图像的采集窗口、采集的点阵大小和格式。
2.申请若干视频采集的帧缓冲区,并将这些帧缓冲区从内核空间映射到用户空间,便于应用程序读取/处理视频数据。
3.将申请到的帧缓冲区在视频采集输入队列排队,并启动视频采集
4.驱动开始视频数据的采集,应用程序从视频采集输出队列取出帧缓冲区,将帧缓冲区重新放入视频采集输入队列,循环往复采集连续的视频数据
5.停止视频采集
描述这个过程调用了哪些接口呢,这里有一张很酷的图:
那么我们来按顺序在Android Camera HAL中找到上述过程调用的接口在HAL中的位置:
1.
首先是视频设备的打开,在两个地方找到了调用了::open的动作:
\vendor\mediatek\tv\hardware\interfaces\camera\provider\2.4\default\ExternalCameraProviderImpl_2_4.cpp
\vendor\mediatek\tv\hardware\interfaces\camera\device\3.4\default\MtkExternalCameraDevice.cpp
以deviceAdded为例,首先看看传入的devName是怎么来的
关注930-937行,v4l2DevicePath的内容应该就是/dev/video*这样的字符串,符合酷图所述,这样就通过传入具体的设备节点路径来打开了一个v4l2设备
2.
然后是视频设备能力的查询,关注VIDIOC_QUERYCAP相关的ioctl调用:
很巧的是上一点的deviceAdd里也有这个逻辑,想想也很合理,新加入的设备先给打开查一下成份,逻辑很符合直觉
\vendor\mediatek\tv\hardware\interfaces\camera\provider\2.4\default\ExternalCameraProviderImpl_2_4.cpp
可以看到查询的结果放到capability变量保存,并需要检查设备能力中是否有包含V4L2_CAP_VIDEO_CAPTURE
更多capability相关的宏定义可以在kernel/5.4_12/include/uapi/linux/videodev2.h中找到:
3.按照酷图的步骤,接下来应该是用 VIDIOC_S_STD 设置视频制式,然后VIDIOC_S_CROP设置采集窗口的大小。但在hal中没有看到相关的调用,可能在android hal flow中是两个非必要步骤。这里我们接着看下一个步骤:
\vendor\mediatek\tv\hardware\interfaces\camera\device\3.4\default\MtkExternalCameraDeviceSession.cpp
设置视频参数的动作在configureV4l2StreamLocked中进行,这里也正是hal中开始视频流传输之前做准备工作的位置。
可以看到用于set到设备的fmt由传进来的参数v4l2Fmt赋值,这里也将入参保存至全局变量mV4l2StreamingFmt中,在后续的processOneCaptureRequest也有使用mV4l2StreamingFmt中保存的format,可见其重要性,有必要简单关注一下这个入参的来源:
经过查找,这个参数在ExternalCameraDeviceSession::configureStreams中传入configureV4l2StreamLocked
SupportedV4L2Format类型描述了设备支持的视频格式,包括长、宽、像素格式、帧率等。这里应该是通过一些限制条件进行了一些长宽格式等方面的筛选。筛选过后的对象最终传入configureV4l2StreamLocked进行ioctl
4.
酷图中所示VIDIOC_S_PARM的调用主要用来设置帧率到设备中,顺带一提上图所示的VIDIOC_S_CTRL在hal也没有找到对应的调用
从其所属函数setV4l2FpsLocked也可以看出来,这个函数也是在上一步的configureV4l2StreamLocked中调用,其时序也与酷图一致。可以看到这里调用 ioctl来设置相机设备参数,并对设置的结果进行验证和处理。如果设置失败或与预期帧率有较大偏差,则返回相应的错误码。
至此,通过V4L2接口进行数据采集的前期准备就完成了一个阶段,这个阶段也基本对应了camera hal中的configureStream前半阶段,接下来就要进入buffer的管理部分,我们下期再见。