camera3_device_t 结构体:设备接口定义
好,咱们接着往下聊。上一章我讲了 HAL3 的整体架构,今天咱们聚焦到一个具体的结构体——camera3_device_t。这个结构体,说白了就是 Camera HAL 设备在 Framework 眼中的「门面」。Framework 要操作相机设备,全得通过它。
我个人习惯把 camera3_device_t 理解成「设备句柄的升级版」。它不像 camera3_callback_ops_t 那样只负责回调,它承载了真正的设备操作入口。
结构体定义解析
先看定义,在 hardware/libhardware/include/hardware/camera3.h 中:
typedef struct camera3_device {
hw_device_t common;
camera3_device_ops_t *ops;
void *priv;
} camera3_device_t;
嗯,就三个字段。但每个字段都不简单。
| 字段 | 类型 | 说明 |
|---|---|---|
| common | hw_device_t | Android HAL 设备通用头,包含 open/close 等基础接口 |
| ops | camera3_device_ops_t * | 函数指针表,所有相机操作入口 |
| priv | void * | 私有数据指针,HAL 实现方自己用 |
核心要点:common 是 Android HAL 层的统一规范,所有硬件设备都必须以 hw_device_t 开头。这样 Framework 才能用统一的方式打开、关闭设备。
ops 函数指针表
这才是重头戏。camera3_device_ops_t 里定义了十几个函数指针,我挑几个最关键的说说。
typedef struct camera3_device_ops {
int (*initialize)(const struct camera3_device *,
const camera3_callback_ops_t *callback_ops);
int (*configure_streams)(const struct camera3_device *,
camera3_stream_configuration_t *stream_list);
int (*register_stream_buffers)(const struct camera3_device *,
const camera3_stream_buffer_set_t *buffer_set);
const camera_metadata_t *(*construct_default_request_settings)(
const struct camera3_device *, int type);
int (*process_capture_request)(const struct camera3_device *,
camera3_capture_request_t *request);
void (*dump)(const struct camera3_device *, int fd);
int (*flush)(const struct camera3_device *);
void (*signal_stream_flush)(const struct camera3_device *,
uint32_t num_streams,
const camera3_stream_t *const *streams);
int (*is_reconfiguration_required)(const struct camera3_device *,
const camera_metadata_t *old_session_params,
const camera_metadata_t *new_session_params);
} camera3_device_ops_t;
这里我重点讲三个:
- initialize:初始化设备,注册回调。Framework 会传进来
camera3_callback_ops_t,HAL 用它来通知 Framework 各种事件。 - configure_streams:配置数据流。说白了就是告诉 HAL:「我要三个流:预览、拍照、录像,你准备好。」
- process_capture_request:处理拍照请求。这是最核心的函数,每次拍照、预览帧都通过它下发。
我的经验:我在项目中遇到过 configure_streams 被反复调用导致性能问题。后来发现是 Framework 在某些场景下会重新配置流。建议在实现时做好缓存,避免不必要的重配置。
open/close 流程
好,咱们看看设备是怎么打开和关闭的。这个流程我画过很多次,今天用文字讲清楚。
打开流程
- Framework 调用
hw_get_module()加载 HAL 库 - 调用
camera3_module_t->common.methods->open() - HAL 实现中分配
camera3_device_t结构体 - 填充
common字段(tag、version、close 函数指针等) - 填充
ops字段,指向实际的函数实现 - 设置
priv指向私有数据(比如硬件句柄、状态机等) - 返回设备句柄给 Framework
// 典型的 open 实现片段
static int camera_device_open(const hw_module_t* module,
const char* id,
hw_device_t** device) {
camera3_device_t *camera_dev = malloc(sizeof(*camera_dev));
memset(camera_dev, 0, sizeof(*camera_dev));
// 填充 common
camera_dev->common.tag = HARDWARE_DEVICE_TAG;
camera_dev->common.version = CAMERA_DEVICE_API_VERSION_3_5;
camera_dev->common.module = (hw_module_t*)module;
camera_dev->common.close = camera_device_close;
// 填充 ops
camera_dev->ops = &g_camera3_ops;
// 设置私有数据
camera_dev->priv = init_private_data();
*device = &camera_dev->common;
return 0;
}
注意:common.close 必须实现!我曾经见过有人忘了设置这个指针,结果 Framework 调用 close 时直接崩溃。嗯,这种低级错误排查起来特别痛苦。
关闭流程
- Framework 调用
camera3_device_t->common.close() - HAL 实现中释放所有资源(停止硬件、释放内存、关闭文件描述符等)
- 释放
camera3_device_t结构体本身
static int camera_device_close(hw_device_t* device) {
camera3_device_t *camera_dev = (camera3_device_t*)device;
// 停止所有正在处理的请求
camera_dev->ops->flush(camera_dev);
// 释放私有数据
release_private_data(camera_dev->priv);
// 释放设备结构体
free(camera_dev);
return 0;
}
避坑指南
我做了这么多年 Camera HAL,总结几个常见坑:
- 线程安全:
process_capture_request可能被多个线程同时调用。你的实现必须是线程安全的。 - 内存管理:
priv指向的内存必须在 close 时释放。别漏了。 - 版本兼容:
common.version要填对。填低了 Framework 可能不支持某些功能,填高了可能不兼容。 - 回调注册:
initialize中拿到的callback_ops要保存好,后续所有事件通知都靠它。
总结一下:camera3_device_t 是 HAL3 设备接口的基石。它通过 ops 函数指针表暴露所有操作,通过 common 融入 Android HAL 框架,通过 priv 保持灵活性。理解了这个结构体,你就掌握了 HAL3 设备层的核心。
下一章我会讲 camera3_stream_t 和流配置,那是数据通路的关键。咱们到时候见。