3. HAL3 核心数据结构详解

好,咱们进入正题。HAL3 的这几个核心数据结构,说白了就是 Camera HAL 的骨架。你如果不把它们吃透,后面写代码肯定会踩坑。我当年刚接触 HAL3 时,就被 camera3_stream_t 的 usage 字段坑过一回,后面我会讲到。

咱们一个一个来看。

3.1 camera3_device_t:你的 HAL 设备句柄

这个结构体,是 Framework 和 HAL 沟通的入口。每个 Camera 设备,对应一个 camera3_device_t 实例。

它的定义大概长这样:

typedef struct camera3_device {
    hw_device_t common;
    camera3_device_ops_t *ops;
    void *priv;
} camera3_device_t;

三个字段,各司其职:

  • common:标准的 Android HAL 设备头。里面包含了 openclose 这些基础操作。说白了,就是让上层能统一管理所有 HAL 设备。
  • ops:这个最重要。它是一个函数指针表,指向你实现的 initializeconfigure_streamsprocess_capture_request 等核心方法。Framework 调用你的 HAL,就是通过这个 ops。
  • priv:私有数据指针。你可以把任何你想存的东西挂在这里。我个人习惯把设备上下文、状态机、调试信息都塞进去。

重点ops 里的函数,必须全部实现。少一个,Framework 就会 crash。我见过有人漏了 flush,结果在 CTS 测试时直接挂掉。

3.2 camera3_callback_ops_t:你给 Framework 的回调

这个结构体,是 HAL 用来通知 Framework 的。比如:

  • 拍照完成了,把结果 buffer 送回去
  • 出错了,报告错误码
  • Metadata 更新了,通知上层

它的定义:

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:每次 capture 完成后,你必须调用它。把 camera3_capture_result_t 传回去。里面包含了 output buffers、metadata、partial result 等信息。
  • notify:用于发送异步通知。比如快门事件、错误事件。嗯,这里要注意:错误通知一定要及时发,否则 Framework 会一直等你的 buffer,导致 ANR。

我的经验:我曾经在调试时,忘了在出错时调用 notify 发送 CAMERA3_MSG_ERROR_REQUEST。结果上层一直卡在等待状态,整个 Camera 服务都僵住了。后来查了三天才找到原因。

3.3 camera3_stream_t:数据流的描述

这个结构体,描述了 Camera 输出的数据流。比如预览流、拍照流、视频流。每个流都有自己的配置。

关键字段:

字段 说明
stream_type CAMERA3_STREAM_OUTPUT(输出)或 CAMERA3_STREAM_INPUT(输入,用于 reprocess)
width / height 图像分辨率。注意:必须是 configure_streams 时协商好的尺寸
format 像素格式。比如 HAL_PIXEL_FORMAT_YCbCr_420_888、HAL_PIXEL_FORMAT_BLOB(用于 JPEG)
usage Gralloc 的使用标记。比如 GRALLOC_USAGE_SW_READ_OFTEN、GRALLOC_USAGE_HW_TEXTURE
max_buffers HAL 建议的 buffer 数量。Framework 会参考这个值来分配
priv HAL 私有数据。你可以把每个流的上下文挂在这里

避坑指南usage 字段一定要和你的硬件匹配。我曾经在某个平台上,把预览流的 usage 设成了 GRALLOC_USAGE_HW_TEXTURE,但硬件实际上只支持 GRALLOC_USAGE_SW_READ_OFTEN。结果预览画面全是花屏,查了两天才发现是 usage 不匹配。

另外,format 的选择也很关键。比如:

  • 预览流:一般用 YCbCr_420_888,兼容性好
  • 拍照流:用 BLOB,因为 JPEG 编码后的数据是压缩的
  • 视频流:用 IMPLEMENTATION_DEFINED,让硬件自己选最优格式

3.4 camera3_stream_buffer_t:单个 buffer 的描述

这个结构体,描述了一个具体的 buffer。它是在 process_capture_requestprocess_capture_result 之间传递的。

定义:

typedef struct camera3_stream_buffer {
    camera3_stream_t *stream;
    buffer_handle_t *buffer;
    int status;
    int acquire_fence;
    int release_fence;
} camera3_stream_buffer_t;

字段含义:

  • stream:指向所属的 camera3_stream_t。这样你就知道这个 buffer 是给哪个流用的。
  • buffer:实际的 buffer handle。通过它,你可以拿到图像数据。
  • status:buffer 的状态。比如 CAMERA3_BUFFER_STATUS_OK 表示成功,CAMERA3_BUFFER_STATUS_ERROR 表示出错。
  • acquire_fence / release_fence:同步 fence。用于协调不同硬件模块之间的访问顺序。比如 ISP 写完了,GPU 才能读。

关键点:fence 的处理一定要小心。如果你不正确地等待 acquire_fence,可能会读到不完整的数据。如果你不正确地设置 release_fence,可能会造成死锁。我见过一个 case,release_fence 一直没 signal,结果整个 pipeline 都卡住了。

3.5 它们之间的关系

这几个结构体,不是孤立的。它们一起构成了 HAL3 的数据流模型:

  1. camera3_device_t 是入口,通过 ops 接收 Framework 的请求。
  2. Framework 调用 configure_streams 时,传进来一组 camera3_stream_t,描述了你需要输出哪些流。
  3. 每次 capture 请求,Framework 会传进来一个 camera3_capture_request_t,里面包含了 output buffers(即 camera3_stream_buffer_t 数组)。
  4. 你处理完数据后,通过 camera3_callback_ops_tprocess_capture_result 回调,把填充好的 camera3_stream_buffer_t 返回给 Framework。

说白了,就是一条流水线:请求进来 → 你处理 → 结果回去。而上面这四个结构体,就是这条流水线上的关键节点。

我的建议:刚开始写 HAL3 时,先把这几个结构体的生命周期理清楚。比如 camera3_stream_t 是在 configure_streams 时创建的,在 flush 或设备关闭时销毁。而 camera3_stream_buffer_t 是每次 capture 时临时分配的,用完就还回去。搞清楚了这些,后面写代码就顺了。

3.6 小结

嗯,这一章的内容就这些。四个核心结构体,每个都有自己的职责。你想想看,它们就像乐高积木,拼在一起就是完整的 HAL3 数据流。

下一章,我们会深入 configure_streams 的实现细节。到时候我会分享一些我在实际项目中遇到的坑,比如如何协商分辨率、如何处理 format 转换。敬请期待。