HALBufferManager -- 相机 HAL3 缓冲区管理 API

Android 10 引入了可选的相机 HAL3 缓冲区管理 API,使您能够实现缓冲区管理逻辑,以便在相机 HAL 实现中达成不同的内存和拍摄延迟折衷权衡。

相机 HAL 需要 N 个请求(其中 N 等于管道深度)在其管道中排队,但通常不需要同时使用所有 N 组输出缓冲区。

例如,在 HAL 管道中排队的请求可能有 8 个,但 HAL 只需使用管道最后阶段的 2 个请求的输出缓冲区。在搭载 Android 9 及更低版本的设备上,当请求在 HAL 中排队时,相机框架会分配缓冲区,从而使 HAL 中有 6 组未使用的缓冲区。在 Android 10 中,相机 HAL3 缓冲区管理 API 允许分离输出缓冲区,从而释放 6 组缓冲区的空间。就高端设备而言,这样可以节省数百兆的内存,而对于低内存设备来说,这也非常有用。

图 1 为搭载 Android 9 及更低版本的设备的相机 HAL 接口示意图。图 2 显示的是已实现相机 HAL3 缓冲区管理 API 的 Android 10 中的相机 HAL 接口。

图 1. Android 9 及更低版本中的相机 HAL 接口

图 2. 使用缓冲区管理 API 的 Android 10 中的相机 HAL 接口

实现缓冲区管理 API

要实现缓冲区管理 API,相机 HAL 必须执行以下操作:

相机 HAL 使用 ICameraDeviceCallback.hal 中的 requestStreamBuffers 和 returnStreamBuffers 方法来请求并返回缓冲区。该 HAL 还必须实现 ICameraDeviceSession.hal 中的 signalStreamFlush 方法来指示相机 HAL 返回缓冲区。

注意:如果相机 HAL 在搭载 Android 9 及更低版本的设备上实现这些缓冲区管理 API,那么要支持图 1 所示的 API 协定,必须使用该 HAL。

requestStreamBuffers

使用 requestStreamBuffers 方法从相机框架请求缓冲区。使用相机 HAL3 缓冲区管理 API 时,相机框架中的拍摄请求不包含输出缓冲区,也就是说,StreamBuffer 中的 bufferId 字段为 0。因此,相机 HAL 必须使用 requestStreamBuffers 从相机框架请求缓冲区。

通过 requestStreamBuffers 方法,调用方可以在一次调用中从多个输出流请求多个缓冲区,从而减少 HIDL IPC 调用的次数。不过,如果同时请求的缓冲区增加,调用所需的时间也会增加,这可能会导致从请求到结果的总延迟时间增加。此外,由于 requestStreamBuffers 调用已在相机服务中序列化,因此建议相机 HAL 使用专用的高优先级线程来请求缓冲区。

如果缓冲区请求失败,相机 HAL 必须能够妥善处理非严重错误。下表介绍了缓冲区请求失败的常见原因以及相机 HAL 应如何处理这些失败。

  • 应用与输出流断开连接:这种情况属于非严重错误。相机 HAL 应针对任何以已断开连接的输出流为目标的拍摄请求发送 ERROR_REQUEST,并做好正常处理后续请求的准备。
  • 超时:如果应用在忙于执行密集型处理操作,同时保留某些缓冲区,则可能会发生超时情况。相机 HAL 应针对因超时错误而无法完成的拍摄请求发送 ERROR_REQUEST,并做好正常处理后续请求的准备。
  • 相机框架正在准备新的输出流配置:相机 HAL 应等到下一次 configureStreams 调用完成后,再重新调用 requestStreamBuffers
  • 相机 HAL 已达到其缓冲区限制maxBuffers 字段):相机 HAL 应等到返回输出流的至少一个缓冲区后,再重新调用 requestStreamBuffers

returnStreamBuffers

使用 returnStreamBuffers 方法将额外的缓冲区返回到相机框架。相机 HAL 通常会通过 processCaptureResult 方法将缓冲区返回到相机框架,但是它只能考虑已发送至相机 HAL 的拍摄请求。通过 requestStreamBuffers 方法,相机 HAL 实现保留的缓冲区数可能会超过相机框架所请求的缓冲区数。这时应使用 returnStreamBuffers 方法。如果 HAL 实现保留的缓冲区数从未超过请求的缓冲区数,则相机 HAL 实现无需调用 returnStreamBuffers 方法。

signalStreamFlush

signalStreamFlush 方法由相机框架调用,用于通知相机 HAL 返回当前可用的所有缓冲区。通常在以下情况下调用此方法:相机框架即将调用 configureStreams 且必须排空相机拍摄管道。与 returnStreamBuffers 方法类似,如果相机 HAL 实现保留的缓冲区数不超过请求的缓冲区数,则可以不实现此方法。

相机框架调用 signalStreamFlush 后,该框架会停止向相机 HAL 发送新的拍摄请求,直到所有缓冲区均已返回到相机框架为止。返回所有缓冲区后,requestStreamBuffers 方法调用会失败,并且相机框架会在干净状态下继续工作。然后相机框架会调用 configureStreams 或 processCaptureRequest 方法。如果相机框架调用 configureStreams 方法,相机 HAL 可以在 configureStreams 调用成功返回后重新开始请求缓冲区。如果相机框架调用 processCaptureRequest 方法,相机 HAL 可以在 processCaptureRequest 调用期间开始请求缓冲区。

signalStreamFlush 方法和 flush 方法的语义有所不同。调用 flush 方法时,HAL 会终止待处理的拍摄请求并显示 ERROR_REQUEST,以尽快排空管道。调用 signalStreamFlush 方法时,HAL 必须正常完成所有待处理的拍摄请求,并将所有缓冲区返回到相机框架。

signalStreamFlush 方法与其他方法之间的另一个差异在于 signalStreamFlush 是单向 HIDL 方法,也就是说,相机框架可能会先调用其他屏蔽 API,然后 HAL 再接收 signalStreamFlush 调用。这意味着,signalStreamFlush 方法和其他方法(特别是 configureStreams 方法)到达相机 HAL 的顺序,可能与它们在相机框架中调用的顺序不同。为解决此异步问题,streamConfigCounter 字段已添加到 StreamConfiguration 并作为参数添加到 signalStreamFlush 方法。相机 HAL 实现应使用 streamConfigCounter 参数来确定 signalStreamFlush 调用的到达时间是否晚于其相应的 configureStreams 调用的到达时间。如需查看示例,请参阅图 3。

图 3. 相机 HAL 应如何检测和处理迟到的 signalStreamFlush 调用

实现缓冲区管理 API 时发生的行为变更

在使用缓冲区管理 API 去实现缓冲区管理逻辑时,请考虑相机和相机 HAL 实现可能会发生的行为变更:

  • 拍摄请求到达相机 HAL 的速度更快、频率更高:如果不使用缓冲区管理 API,相机框架会先为每个拍摄请求请求输出缓冲区,然后再向相机 HAL 发送拍摄请求。而使用缓冲区管理 API 后,相机框架无需再等待缓冲区请求完成,因此可以更早地向相机 HAL 发送拍摄请求。

    此外,如果不使用缓冲区管理 API,当拍摄请求的其中一个输出流达到 HAL 一次可容纳的最大缓冲区数(此值由相机 HAL 在 configureStreams 调用的返回值中的 HalStream::maxBuffers 字段中指定)时,相机框架会停止发送拍摄请求。如果使用缓冲区管理 API,此限制行为不再存在,而且如果 HAL 中排队的拍摄请求过多,相机 HAL 实现不得接受 processCaptureRequest 调用。

  • requestStreamBuffers 调用延迟变化显著:导致 requestStreamBuffers 调用所需时间超过平均时间的原因有很多。例如:

    • 对于新建输出流的前几个缓冲区而言,调用所需时间可能较长,因为设备需要分配内存。
    • 预期延迟时间会按每次调用时请求的缓冲区数成比例增加。
    • 应用正在保留缓冲区并忙于处理操作。这可能会导致缓冲区请求因缓冲区不足或 CPU 繁忙而降速或超时。

缓冲区管理策略

缓冲区管理 API 支持实现各种类型的缓冲区管理策略。以下是一些示例:

  • 向后兼容:HAL 在调用 processCaptureRequest 期间为拍摄请求请求缓冲区。此策略不会节省任何内存,但可用作缓冲区管理 API 的第一个实现,几乎不需要更改现有相机 HAL 的代码。
  • 最大限度地节省内存:相机 HAL 仅在需要填充缓冲区之前立即请求输出缓冲区。此策略可最大限度地节省内存。此策略的潜在弊端是,当完成缓冲区请求所需的时间过长时,相机管道会出现更多卡顿。
  • 已缓存:相机 HAL 缓存少许缓冲区,以降低缓冲区请求速度偶尔较慢时受到影响的可能性。

相机 HAL 可针对特定使用情形采用不同的策略,例如,对于使用大量内存的使用情形采用“最大限度地节省内存”策略,对于其他使用情形则采用“向后兼容”策略。

外部相机 HAL 中的实现示例

外部相机 HAL 是在 Android 9 中引入的,可在 hardware/interfaces/camera/device/3.5/ 上的源代码树中找到。在 Android 10 中,此外部相机 HAL 已进行更新,其中新增了 ExternalCameraDeviceSession.cpp,这是缓冲区管理 API 的一种实现。此外部相机 HAL 使用几百行 C++ 代码实现缓冲区管理策略中介绍的“最大限度地节省内存”策略。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值