4. Camera HAL3 核心数据结构:camera3_device_t、camera3_callback_ops_t、camera3_stream_t 等关键结构体解析
好,咱们今天来啃一块硬骨头——HAL3 的核心数据结构。
说实话,我刚接触 HAL3 的时候,看着这些结构体也是一头雾水。什么 camera3_device_t、camera3_callback_ops_t、camera3_stream_t……名字长得差不多,功能却天差地别。后来在项目里踩了几次坑,才慢慢摸清楚它们的脾气。
这一章,我就带你把这些结构体一个一个拆开看。你搞懂了它们,HAL3 的框架也就通了七七八八。
4.1 camera3_device_t:HAL 层的“门面”
先看最顶层的结构体——camera3_device_t。
你可以把它理解成 HAL 层的“门面”。上层 Framework 要操作相机设备,第一步就是拿到这个结构体。它定义在 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:这是 Android 硬件抽象层的通用头。里面包含了设备打开、关闭、版本号等基础信息。说白了,这是 Android 硬件框架的“身份证”。
- ops:操作函数指针表。这是核心中的核心。所有上层调用的接口——比如
initialize()、configure_streams()、process_capture_request()——都挂在这个指针表上。 - priv:私有数据指针。你可以在这里挂你自己的 HAL 实现上下文。我习惯在这里放一个指向我自己定义的
CameraDevice类的指针。
重点:ops 指针绝对不能为 NULL。否则上层一调用就崩。我曾经在移植一个老平台时,忘了初始化 ops,结果一打开相机就 segfault。查了半天才发现是这里的问题。
4.2 camera3_callback_ops_t:反向通知的“桥梁”
接下来是 camera3_callback_ops_t。这个结构体是干什么用的?
你想想看,HAL 处理完一帧数据,怎么通知 Framework 来取?总不能轮询吧。所以 Android 设计了一套回调机制。
camera3_callback_ops_t 就是这套回调机制的“接口契约”。它由 Framework 实现,然后通过 initialize() 传给 HAL。
typedef struct camera3_callback_ops {
void (*process_capture_result)(const struct camera3_callback_ops *,
const camera3_capture_result_t *result);
void (*notify)(const struct camera3_callback_ops *,
const camera3_notify_msg_t *msg);
} camera3_callback_ops_t;
两个回调函数:
- process_capture_result:HAL 处理完一帧后,调用这个函数把结果送回 Framework。结果里包含图像 buffer、metadata 等。
- notify:用于发送异步事件通知,比如快门事件、错误事件等。
我的经验:回调函数里不要做耗时操作。我曾经在回调里直接做图像后处理,结果导致 UI 卡顿。正确的做法是:回调里只做数据传递,真正的处理放到工作线程里。
4.3 camera3_stream_t:数据流的“管道”
再来说 camera3_stream_t。这个结构体描述了一条数据流——比如预览流、拍照流、录像流。
typedef struct camera3_stream {
int stream_type;
uint32_t width;
uint32_t height;
int format;
uint32_t usage;
uint32_t max_buffers;
void *priv;
android_dataspace_t data_space;
int rotation;
int id;
camera3_stream_configuration_t *configuration;
} camera3_stream_t;
字段很多,我挑几个关键的讲:
- stream_type:流类型。有
CAMERA3_STREAM_OUTPUT(输出流,比如预览)、CAMERA3_STREAM_INPUT(输入流,比如 reprocessing)等。 - width / height:图像分辨率。这个由 Framework 根据应用需求决定。
- format:像素格式。常见的有
HAL_PIXEL_FORMAT_YCbCr_420_888、HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED等。 - usage:buffer 的使用标记。比如
GRALLOC_USAGE_HW_TEXTURE表示 buffer 会被用于 GPU 纹理。 - max_buffers:HAL 请求的最大 buffer 数量。这个值不能乱填,要根据硬件能力来。
注意:format 字段很容易踩坑。我记得有一次,Framework 请求的是 IMPLEMENTATION_DEFINED 格式,我直接返回了 NV12。结果预览画面颜色完全不对。后来才发现,IMPLEMENTATION_DEFINED 需要根据 usage 来协商实际格式。
4.4 camera3_stream_configuration_t:流的“集合”
单个流不够,多个流怎么管理?这就轮到 camera3_stream_configuration_t 了。
typedef struct camera3_stream_configuration {
uint32_t num_streams;
camera3_stream_t **streams;
uint32_t operation_mode;
const camera3_stream_buffer_set_t *input_buffers;
} camera3_stream_configuration_t;
- num_streams:流的数量。
- streams:指向流指针数组的指针。每个元素是一个
camera3_stream_t *。 - operation_mode:操作模式。比如
CAMERA3_STREAM_CONFIGURATION_NORMAL_MODE或CAMERA3_STREAM_CONFIGURATION_CONSTRAINED_HIGH_SPEED_MODE。
这个结构体在 configure_streams() 调用中传入。HAL 需要根据这个配置来分配硬件资源。
4.5 camera3_capture_request_t 与 camera3_capture_result_t:请求与结果
最后看两个“成对”的结构体——请求和结果。
camera3_capture_request_t
typedef struct camera3_capture_request {
uint32_t frame_number;
const camera3_stream_buffer_t *input_buffer;
uint32_t num_output_buffers;
const camera3_stream_buffer_t *output_buffers;
const camera_metadata_t *settings;
} camera3_capture_request_t;
- frame_number:帧序号。每个请求唯一。
- input_buffer:输入 buffer(用于 reprocessing 场景)。
- output_buffers:输出 buffer 数组。每个 buffer 对应一个 stream。
- settings:请求的 metadata。包含 AE/AWB/AF 等参数。
camera3_capture_result_t
typedef struct camera3_capture_result {
uint32_t frame_number;
const camera3_stream_buffer_t *input_buffer;
uint32_t num_output_buffers;
const camera3_stream_buffer_t *output_buffers;
const camera_metadata_t *result;
int32_t partial_result;
} camera3_capture_result_t;
结构和请求很像,但多了 partial_result 字段。这个字段用于支持“部分结果”——比如先返回 metadata,再返回 buffer。
我的建议:尽量使用 partial_result 机制。这样 Framework 可以先拿到 metadata 做预览参数更新,不用等 buffer 处理完。用户体验会好很多。
4.6 结构体之间的关系
这些结构体不是孤立的。它们之间有一条清晰的调用链:
- Framework 通过
camera3_device_t.ops->initialize()传入camera3_callback_ops_t。 - Framework 调用
camera3_device_t.ops->configure_streams()传入camera3_stream_configuration_t。 - Framework 调用
camera3_device_t.ops->process_capture_request()传入camera3_capture_request_t。 - HAL 处理完成后,通过
camera3_callback_ops_t.process_capture_result()返回camera3_capture_result_t。
嗯,这就是 HAL3 的数据流全貌。你把这些结构体串起来,整个 HAL3 的骨架就清晰了。
4.7 避坑指南
最后,分享几个我踩过的坑:
- stream 的 max_buffers 不要设太大。设大了浪费内存,设小了可能丢帧。我一般根据硬件 pipeline 深度来定,比如 ISP 有 4 个 buffer 槽,我就设 4。
- frame_number 必须严格递增。Framework 依赖这个序号来匹配请求和结果。我曾经在某个分支里忘了递增,结果导致 Framework 报错。
- settings 不能为 NULL。即使没有参数变化,也要传一个空的 metadata。否则 Framework 会认为 HAL 不支持参数控制。
好了,这一章的内容就到这里。下一章我们会深入 configure_streams() 的实现细节——那才是真正考验 HAL 功底的地方。