1. Camera HAL概述:HAL在Android相机架构中的位置、HAL的主要职责、HAL版本演进(HAL1 vs HAL3)
各位同学,咱们今天正式开讲Camera HAL。说实话,我做了这么多年嵌入式,每次带新人入门,第一件事就是让他们搞明白HAL到底是个什么角色。你想想看,一个手机上有那么多摄像头,从按下快门到出照片,中间经过了多少层软件?HAL就是那个承上启下的关键节点。
1.1 HAL在Android相机架构中的位置
先看一张宏观的图(我这里用文字描述一下):
应用层 (Camera App)
↓
Framework层 (Camera API2 / CameraService)
↓
HAL层 (Camera HAL)
↓
Kernel层 (V4L2 / 传感器驱动)
↓
硬件层 (Sensor / ISP / 镜头)
HAL夹在Framework和Kernel之间。说白了,它就是个翻译官。Framework说「我要拍照」,HAL得把这个指令翻译成硬件能听懂的话。反过来,硬件采集到的原始数据,也得通过HAL包装成Framework能处理的格式。
我个人习惯把HAL比作「中间人」。它不直接操作寄存器,也不直接跟App打交道。但它决定了整个相机系统的上限。我在项目中遇到过好几次,明明硬件性能很强,但HAL写得烂,导致拍照卡顿、预览延迟。嗯,这里要注意,HAL的代码质量直接决定了用户体验。
1.2 HAL的主要职责
HAL到底干哪些活?我总结了一下,核心职责有这么几块:
- 设备管理:打开/关闭摄像头设备,管理多个摄像头(比如前后摄、广角、长焦)。
- 流配置:App要什么分辨率的预览流、拍照流、视频流,HAL得协调好。
- 缓冲区管理:分配、填充、回收图像缓冲区。这块最容易出内存泄漏。
- 3A控制:自动对焦(AF)、自动曝光(AE)、自动白平衡(AWB)。说白了就是让画面清晰、亮度合适、颜色自然。
- 元数据传递:把硬件的状态信息(比如当前对焦位置、曝光时间)打包成元数据,传给Framework。
- 错误处理:硬件出问题了(比如传感器挂了),HAL得优雅地通知上层,而不是直接崩掉。
重点:HAL不是简单的「数据搬运工」。它要做大量的策略决策。比如,当App同时请求预览流和拍照流时,HAL得决定怎么分配ISP带宽、怎么调度DMA传输。这些决策直接影响帧率和延迟。
1.3 HAL版本演进:HAL1 vs HAL3
Android相机HAL经历了两个主要版本。我刚开始做的时候还是HAL1时代,后来HAL3出来,整个架构都变了。咱们来对比一下。
HAL1:简单但僵化
HAL1的设计思路是「一条流水线」。App发出请求,HAL按部就班地执行:预览→拍照→编码。流程是固定的,你很难插进去自定义操作。
// HAL1的典型调用流程
camera_device->ops->start_preview(dev);
camera_device->ops->take_picture(dev);
camera_device->ops->stop_preview(dev);
你看,每个操作都是同步的、阻塞的。App调了take_picture,就得等HAL把整张照片处理完才能干别的事。这在单摄时代还行,但到了多摄、高帧率、HDR这些场景,HAL1就完全不够用了。
避坑指南:我曾经在一个项目里用HAL1做双摄虚化,结果发现根本没法同时控制两个传感器的曝光参数。因为HAL1的接口设计就是「一次只能处理一个请求」。最后只能硬着头皮在HAL层做同步,代码写得极其丑陋。
HAL3:灵活但复杂
HAL3彻底推翻了HAL1的设计。它引入了「请求-结果」模型。App可以同时发出多个请求,每个请求可以指定不同的参数(比如分辨率、帧率、3A模式)。HAL异步处理这些请求,然后返回结果。
// HAL3的典型调用流程
// App发送一个捕获请求
camera3_capture_request_t req;
req.frame_number = 1;
req.settings = &settings; // 包含AE、AF、AWB等参数
req.num_output_buffers = 2; // 同时输出预览流和拍照流
// HAL处理完成后回调
process_capture_result(..., camera3_capture_result_t *result);
HAL3最大的优势是「解耦」。App可以独立控制每个请求的参数。比如,预览流用30fps、1080p,拍照流用全分辨率、带HDR。HAL内部可以并行处理,互不干扰。
| 对比项 | HAL1 | HAL3 |
|---|---|---|
| 请求模型 | 同步、串行 | 异步、并行 |
| 参数控制 | 全局设置 | 逐帧设置 |
| 多流支持 | 有限(通常只能一路预览+一路拍照) | 灵活(可同时输出多路流) |
| 元数据 | 简单(基本只有EXIF) | 丰富(包含3A状态、传感器时间戳等) |
| 性能调优空间 | 小(接口固定,很难优化) | 大(可以精细控制每个环节) |
个人经验:我建议新项目直接上HAL3。虽然HAL3的接口比HAL1复杂得多,但它的灵活性是HAL1没法比的。特别是做多摄、高帧率、计算摄影这些功能时,HAL3几乎是唯一的选择。当然,如果你的硬件非常老旧(比如只有一颗VGA传感器),那HAL1也够用。
1.4 小结
这一章咱们把HAL的定位、职责和版本演进捋了一遍。说白了,HAL就是Android相机系统的「腰」。腰不好,整个系统都站不起来。HAL1是过去式,HAL3是现在和未来。下一章我会深入HAL3的架构细节,包括它的核心数据结构、请求生命周期、以及怎么在HAL层做性能调优。
嗯,最后说一句。如果你现在还在维护HAL1的代码,我建议你尽早规划迁移。我在好几个项目里见过,因为HAL1的限制,导致新功能加不进去,最后只能重写整个HAL。那滋味,不好受。