3. CaptureResult 与 CaptureRequest 的对应关系:result metadata、partial result、shutter callback、buffer status
在 Android Camera HAL3 架构中,每一个 CaptureRequest 的提交都会触发一个或多个 CaptureResult 的回调。理解这两者之间的对应关系,是定位 HAL 链路异常、校验参数传递正确性的核心基础。本章将深入剖析 result metadata、partial result、shutter callback 以及 buffer status 四个关键概念,并阐明它们如何共同构成一次完整的 capture 生命周期。
3.1 核心对应关系总览
一个 CaptureRequest 从提交到完成,HAL 会按顺序产生以下三类回调:
- shutter callback:通知框架曝光开始的时间戳。
- partial result:中间状态的 metadata 片段,允许框架提前处理部分数据。
- final result:包含完整 metadata 和所有 buffer 的最终结果。
下表总结了每个回调与原始 Request 的对应关系:
| 回调类型 | 触发时机 | 包含内容 | 与 Request 的对应关系 |
|---|---|---|---|
| shutter callback | 传感器开始曝光时 | 曝光开始时间戳 (timestamp) | 一对一,每个 Request 最多一次 |
| partial result | HAL 处理过程中 | 部分 metadata keys(如 sensor 状态、3A 结果) | 零到多次,按 partial result count 配置 |
| final result | 所有处理完成时 | 完整 metadata + 所有 buffer 状态 | 一对一,每个 Request 最终一次 |
requestId 将 result 与原始 request 绑定。在调试时,务必检查 result 中的 android.request.id 是否与预期一致。
3.2 result metadata:从 Request 到 Result 的传递链
CaptureResult 中的 metadata 是 HAL 对 CaptureRequest 中参数的响应。并非所有 request 中的 key 都会出现在 result 中,只有 HAL 实际使用的 key 才会被回传。下图展示了 metadata 的传递与校验链路:
3.3 partial result:中间状态的分段交付
HAL3 允许通过 android.request.partialResultCount 配置 partial result 的数量。每个 partial result 包含一部分 metadata,框架可以在收到所有 partial result 之前就开始处理某些数据(如预览帧的 3A 状态)。
partialResultCount,框架会一直等待,导致 result timeout。这是常见的 HAL 实现 bug。
partial result 的典型使用场景:
- 第 1 个 partial result:通常包含 sensor 时间戳、曝光参数。
- 第 2 个 partial result:包含 3A 状态(AE/AWB/AF)。
- 第 3 个 partial result:包含统计信息或后处理参数。
- final result:包含所有 metadata + buffer 状态。
3.4 shutter callback:曝光时间戳的精确锚点
shutter callback 是 HAL 通知框架传感器开始曝光的关键事件。它携带一个 timestamp,该时间戳必须与 result metadata 中的 android.sensor.timestamp 一致。
| 属性 | 说明 | 常见异常 |
|---|---|---|
| 触发时机 | 传感器开始积分(曝光)时 | HAL 在曝光前或曝光后很久才调用 |
| 时间戳来源 | 通常来自 sensor 的硬件时间戳 | 使用系统时间而非硬件时间,导致同步偏差 |
| 与 result 的关系 | 必须早于 final result 的 timestamp | shutter 时间戳晚于 result 时间戳(时序颠倒) |
| 多帧场景 | 每个 request 独立触发一次 | 漏触发或重复触发 |
android.sensor.timestamp 不一致,会导致 AE/AF 收敛算法 和 视频稳像 出现不可预测的偏差。务必在 HAL 实现中保证两者使用同一个时钟源。
3.5 buffer status:输出图像的交付状态
每个 CaptureRequest 可以包含多个输出 buffer(如 preview、still capture、video)。HAL 通过 CaptureResult 中的 android.request.outputStreams 和对应的 bufferStatus 来报告每个 buffer 的处理结果。
buffer status 的常见取值:
- OK (0):buffer 已成功填充数据。
- ERROR (1):buffer 处理失败,数据无效。
- ERROR_REQUEST (2):整个 request 失败,所有 buffer 均无效。
下图展示了 buffer 从 request 到 result 的完整生命周期:
3.6 异常定位实战:result 与 request 不匹配的典型场景
在实际调试中,以下问题最为常见:
- result 中缺少 request 中设置的 key:HAL 未实现该 key 的处理,或未在 result 中回传。
- partial result 数量不足:HAL 返回的 partial result 少于
partialResultCount,导致框架超时。 - shutter callback 时间戳与 result 不一致:时钟源不同或时间戳传递错误。
- buffer status 为 ERROR 但 metadata 正常:HAL 在填充 buffer 时发生错误,但未正确上报。
- final result 中 buffer 数量与 request 中 output streams 数量不匹配:HAL 漏处理了某个 stream。
adb shell dumpsys media.camera | grep -A 20 "CaptureRequest"
adb shell dumpsys media.camera | grep -A 20 "CaptureResult"
通过对比 requestId 和 timestamp,可以快速定位丢失的 result。
3.7 总结:对应关系检查清单
在 HAL 实现或调试过程中,请逐项核对以下清单:
| 检查项 | 预期行为 | 异常后果 |
|---|---|---|
| shutter callback 触发次数 | 每个 request 一次 | 框架等待超时 |
| partial result 数量 | 等于 partialResultCount | result 不完整或超时 |
| final result 中的 metadata | 包含所有 mandatory keys | 上层应用获取不到必要参数 |
| buffer status | 所有 buffer 为 OK | 图像数据丢失或黑帧 |
| 时间戳一致性 | shutter < partial < final | 3A 算法异常 |