2. Camera HAL架构概览
Android Camera HAL3(即Camera3 HAL)是Android系统从Lollipop(API 21)开始引入的新一代相机硬件抽象层架构。与HAL1相比,HAL3重新设计了数据流模型,将相机子系统抽象为管道(Pipeline),支持每帧级别的参数控制、多路输出流以及更高效的缓冲区管理。理解HAL3架构是进行V4L2驱动调试与数据流分析的基础。
2.1 Android Camera HAL3架构
HAL3架构的核心设计理念是“请求-结果”模型。上层框架(CameraService)向HAL提交捕获请求(Capture Request),HAL根据请求配置传感器、ISP和V4L2驱动,最终返回捕获结果(Capture Result)及填充好的图像缓冲区。整个架构分为三层:
- 应用框架层(Application Framework):Camera2 API,通过Binder与CameraService通信。
- 相机服务层(CameraService):管理权限、设备生命周期、流配置,并直接调用HAL接口。
- HAL实现层(Camera HAL):厂商实现的动态库(如
camera.<vendor>.so),包含CameraModule、CameraDevice、CameraStream等核心模块,向下通过V4L2驱动操作硬件。
关键概念:HAL3的“管道”模型允许应用同时提交多个待处理请求,HAL内部可以流水线式处理,实现高帧率与低延迟。这与HAL1的同步操作模型有本质区别。
2.2 HAL与V4L2驱动的接口层
在典型的嵌入式Linux + Android平台上,Camera HAL向下与V4L2驱动交互。接口层主要完成以下工作:
- 设备节点管理:通过
open()系统调用打开/dev/video*节点,获取文件描述符。 - 格式与分辨率协商:使用
VIDIOC_S_FMT/VIDIOC_TRY_FMT设置传感器输出格式(如YUYV、MJPEG、NV12)和分辨率。 - 缓冲区管理:通过
VIDIOC_REQBUFS申请V4L2缓冲区,并使用VIDIOC_QBUF/VIDIOC_DQBUF进行入队/出队操作。 - 流控制:调用
VIDIOC_STREAMON/VIDIOC_STREAMOFF启动/停止数据流。 - 控制参数传递:使用
VIDIOC_S_CTRL/VIDIOC_G_CTRL设置曝光、增益、白平衡等V4L2控制参数。
| HAL层操作 | V4L2 IOCTL | 说明 |
|---|---|---|
| 打开设备 | open("/dev/video0", O_RDWR) |
获取V4L2设备文件描述符 |
| 查询能力 | VIDIOC_QUERYCAP |
检查驱动是否支持视频捕获、流I/O等 |
| 设置格式 | VIDIOC_S_FMT |
配置像素格式、宽度、高度 |
| 申请缓冲区 | VIDIOC_REQBUFS |
分配V4L2缓冲区(mmap或用户指针模式) |
| 入队缓冲区 | VIDIOC_QBUF |
将空缓冲区放入驱动队列 |
| 出队缓冲区 | VIDIOC_DQBUF |
从驱动队列取出已填充数据的缓冲区 |
| 启动流 | VIDIOC_STREAMON |
开始视频数据捕获 |
| 停止流 | VIDIOC_STREAMOFF |
停止视频数据捕获 |
| 设置控制 | VIDIOC_S_CTRL |
设置曝光、增益等参数 |
调试提示:在HAL层与V4L2驱动之间增加IOCTL日志(如使用
strace 或内核 dynamic debug)是定位配置问题的有效手段。重点关注 VIDIOC_S_FMT 的返回值以及 VIDIOC_REQBUFS 申请的缓冲区数量。
2.3 HAL层核心模块职责
HAL3规范定义了三个核心模块,它们共同构成了HAL实现的主体:
2.3.1 CameraModule
职责:作为HAL的入口点,负责枚举系统中可用的相机设备、加载设备信息并管理设备生命周期。
- 实现
camera_module_t结构体,提供get_number_of_cameras()和get_camera_info()接口。 - 在初始化时扫描V4L2设备节点(如
/dev/video0~/dev/videoN),匹配传感器驱动。 - 为每个物理相机创建一个
CameraDevice实例。
2.3.2 CameraDevice
职责:代表一个物理相机设备,负责处理来自CameraService的捕获请求,并管理数据流。
- 实现
camera3_device_t结构体,核心接口包括initialize()、configure_streams()、process_capture_request()。 - configure_streams():根据上层需求配置输出流(如预览流、拍照流、视频流),并在此阶段与V4L2驱动协商格式和分辨率。
- process_capture_request():接收捕获请求,解析其中的设置(如3A参数、输出缓冲区句柄),然后驱动V4L2进行帧捕获。
2.3.3 CameraStream
职责:管理单个数据流的缓冲区队列和生命周期,是数据传递的载体。
- 每个
CameraStream对应一个camera3_stream_t,包含格式、分辨率、使用标志(如GRALLOC_USAGE_HW_TEXTURE)等信息。 - 负责将HAL层的图像缓冲区(通常通过Gralloc分配)与V4L2的缓冲区进行映射或拷贝。
- 在多路输出流场景下,
CameraStream需要处理不同流之间的同步与裁剪。
常见陷阱:在
configure_streams() 阶段,HAL必须根据所有输出流的最大分辨率来配置V4L2驱动。如果某个流请求了驱动不支持的分辨率或格式,VIDIOC_S_FMT 可能会静默调整到最接近的值,导致上层应用收到格式不匹配的缓冲区。务必在HAL层校验 S_FMT 的实际返回结果。
2.4 模块职责总结
| 模块 | 核心接口/结构体 | 主要职责 | 与V4L2的交互点 |
|---|---|---|---|
| CameraModule | camera_module_t |
设备枚举、信息查询、模块初始化 | 扫描 /dev/video* 节点 |
| CameraDevice | camera3_device_t |
流配置、请求处理、3A控制 | VIDIOC_S_FMT, VIDIOC_REQBUFS, VIDIOC_STREAMON/OFF |
| CameraStream | camera3_stream_t |
缓冲区队列管理、格式转换、数据传递 | VIDIOC_QBUF, VIDIOC_DQBUF, 缓冲区映射 |
理解这三个模块的职责划分,有助于在调试时快速定位问题所在:如果应用无法打开相机,问题可能在 CameraModule 的设备枚举阶段;如果预览画面卡顿或花屏,问题可能在 CameraStream 的缓冲区管理或 CameraDevice 的流配置阶段;如果拍照参数不生效,则需检查 CameraDevice 的请求处理逻辑与V4L2控制的映射关系。