4、CameraDevice 初始化:open() 流程、Session 创建、以及 Pipeline 的建立
好,咱们今天来啃一块硬骨头——CameraDevice 的初始化流程。说白了,就是上层 App 调用 open() 之后,底层到底发生了什么?Session 是怎么创建的?Pipeline 又是怎么搭起来的?
我记得刚接手 Camera HAL 时,被这一套流程绕得晕头转向。后来跟了几次 log,才慢慢理清脉络。今天我把这些经验掰开揉碎讲给你听。
4.1 open() 调用:从 Framework 到 HAL 的第一次握手
App 调用 CameraManager.openCamera(),这只是一个开始。真正的重头戏在 Framework 层。
流程大致是这样的:
- App 通过 Binder 调用到
CameraService。 CameraService调用CameraProviderManager,找到对应的 HAL 实现。- 最终调用到 HAL 层的
camera_device_t::open()。
嗯,这里要注意:HAL 层的 open() 不是简单的打开设备。它要做三件事:
- 初始化硬件资源(比如 sensor、ISP)
- 分配
camera3_device_t结构体 - 注册回调函数(
process_capture_request、flush等)
核心要点: open() 返回的 camera3_device_t 是后续所有操作的基石。如果这里失败了,后面什么都做不了。
我在项目中遇到过一个问题:某款 sensor 在 open() 时初始化时间过长,导致 App 超时崩溃。后来我们加了一个异步初始化策略,才解决这个问题。
4.2 Session 创建:谁在管理你的拍照请求?
Session 这个概念,说白了就是「一次完整的相机使用周期」。从打开相机到关闭相机,就是一个 Session。
但这里有个容易混淆的地方:Framework 层的 Session 和 HAL 层的 Session 不是一回事。
Framework 层的 Session 由 CameraCaptureSession 管理。它负责:
- 接收 App 的拍照请求
- 把请求拆分成多个 capture request
- 把结果返回给 App
HAL 层的 Session 则更底层。它对应的是 camera3_stream_configuration_t。这个结构体定义了:
- 有多少个 stream(预览流、拍照流、视频流等)
- 每个 stream 的格式、分辨率、使用场景
- stream 之间的同步关系
避坑指南: 我曾经因为 stream 配置顺序不对,导致预览和拍照的 buffer 互相覆盖。后来发现 HAL 要求 stream 按优先级排列——预览流在前,拍照流在后。这个细节在文档里只提了一句,坑了不少人。
4.3 Pipeline 的建立:数据流动的骨架
Pipeline 是什么?你可以把它想象成一条流水线。sensor 采集到的原始数据,经过 ISP 处理、算法优化、格式转换,最终变成 App 能用的 YUV 或 JPEG。
建立 Pipeline 的关键步骤:
- 配置 stream:告诉 HAL 你需要哪些数据流。
- 分配 buffer:每个 stream 都需要对应的 buffer 来存放数据。
- 建立通路:把 sensor、ISP、encoder 等模块连接起来。
- 启动 pipeline:开始处理数据。
你想想看,如果 pipeline 没搭好,数据流就会卡住。轻则掉帧,重则死机。
我记得有一次调试 4K 视频录制,发现 pipeline 总是卡在 ISP 阶段。查了半天,原来是 buffer 队列深度不够。ISP 处理速度跟不上 sensor 的输出速度,导致 pipeline 阻塞。
注意: Pipeline 的建立顺序很重要。必须先配置 stream,再分配 buffer,最后启动 pipeline。顺序搞反了,HAL 会直接返回错误。
4.4 代码实战:从 open() 到 pipeline 建立
光说不练假把式。咱们来看一段简化版的代码,展示 open() 到 pipeline 建立的核心逻辑。
// HAL 层的 open() 实现
int camera_device_open(const struct hw_module_t* module,
const char* id,
struct hw_device_t** device) {
camera3_device_t* camera_dev = malloc(sizeof(camera3_device_t));
// 初始化硬件
sensor_init();
isp_init();
// 注册回调
camera_dev->ops = &camera_device_ops;
*device = (struct hw_device_t*)camera_dev;
return 0;
}
// Session 创建:配置 stream
int configure_streams(camera3_device_t* device,
camera3_stream_configuration_t* config) {
// 解析 stream 配置
for (int i = 0; i < config->num_streams; i++) {
camera3_stream_t* stream = config->streams[i];
// 为每个 stream 分配 buffer
allocate_buffers(stream);
}
// 建立 pipeline
build_pipeline(config);
return 0;
}
// Pipeline 建立
void build_pipeline(camera3_stream_configuration_t* config) {
// 连接 sensor -> ISP -> encoder
connect_sensor_to_isp();
connect_isp_to_encoder();
// 启动 pipeline
start_pipeline();
}
这段代码虽然简化了,但核心逻辑都在。你仔细看 configure_streams() 这个函数——它其实就是 Session 创建和 Pipeline 建立的交汇点。
4.5 常见问题与调试技巧
做 Camera HAL 开发,这几个问题你早晚会遇到:
| 问题 | 原因 | 解决方法 |
|---|---|---|
| open() 超时 | 硬件初始化耗时过长 | 异步初始化,或优化硬件驱动 |
| Session 创建失败 | stream 配置不合法 | 检查 stream 格式、分辨率、数量 |
| Pipeline 卡死 | buffer 队列阻塞 | 增加 buffer 深度,或优化处理速度 |
| 数据流错乱 | stream 优先级配置错误 | 按文档要求重新排列 stream 顺序 |
我的调试习惯: 遇到 pipeline 问题,先看 logcat 中 HAL 层的输出。重点关注 configure_streams 和 process_capture_request 的调用时序。如果这两个函数调用正常,问题大概率在 buffer 管理上。
嗯,今天就先讲到这里。CameraDevice 初始化这块内容,说白了就是「打开设备 -> 配置数据流 -> 建立处理流水线」这三步。但每一步都有很多细节,需要你在实际项目中慢慢体会。
下一章咱们聊聊 capture request 的处理流程,那才是真正考验 HAL 功底的地方。