Android Camera(12)HAL3 Buffer Management APIs
HAL3 Buffer Management APIs
目录
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 接口。
实现缓冲区管理 API
要实现缓冲区管理 API,相机 HAL 必须执行以下操作:
- 实现 HIDL
[email protected]
。 - 将摄像头特征**
android.info.supportedBufferManagementVersion
设置为HIDL_DEVICE_3_5
。
相机 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 通常会通过 proce*tureResult
方法将缓冲区返回到摄像头传输框架,但是它只能考虑已发送至相机 HAL 的捕获请求。通过 requestStreamBuffers
方法,相机 HAL 实现保留的缓冲区数可能会超过摄像头传输框架所请求的缓冲区数。这时应使用 returnStreamBuffers
方法。如果 HAL 实现保留的缓冲区数从未超过请求的缓冲区数,则相机 HAL 实现无需调用 returnStreamBuffers
方法。
signalStreamFlush
signalStreamFlush
方法由摄像头传输框架调用,用于通知相机 HAL 返回当前可用的所有缓冲区。通常在以下情况下调用此方法:摄像头传输框架即将调用 configureStreams
且必须排空相机捕获管道。与 returnStreamBuffers
方法类似,如果相机 HAL 实现保留的缓冲区数不超过请求的缓冲区数,则可以不实现此方法。
摄像头传输框架调用 signalStreamFlush
后,该框架会停止向相机 HAL 发送新的捕获请求,直到所有缓冲区均已返回到摄像头传输框架为止。返回所有缓冲区时,requestStreamBuffers
方法调用会失败,并且摄像头传输框架会在整洁状态下继续工作。然后摄像头传输框架会调用 configureStreams
或 proce*tureRequest
方法。如果摄像头传输框架调用 configureStreams
方法,相机 HAL 可以在 configureStreams
调用成功返回后重新开始请求缓冲区。如果摄像头传输框架调用 proce*tureRequest
方法,相机 HAL 可在 proce*tureRequest
调用期间开始请求缓冲区。
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。
实现缓冲区管理 API 时发生的行为变更
使用缓冲区管理 API 实现缓冲区管理逻辑时,请考虑相机和相机 HAL 实现可能会发生的行为变更:
-
捕获请求更快且更频繁地到达相机 HAL:如果不使用缓冲区管理 API,摄像头传输框架会针对每个捕获请求请求输出缓冲区,然后再向相机 HAL 发送捕获请求。如果使用缓冲区管理 API,则摄像头传输框架不再需要等待缓冲区请求完成,因此可以更早向相机 HAL 发送捕获请求。
此外,如果不使用缓冲区管理 API,当捕获请求的其中一个输出流达到 HAL 一次可容纳的最大缓冲区数(此值由相机 HAL 在
configureStreams
调用的返回值中的HalStream::maxBuffers
字段中指定)时,摄像头传输框架会停止发送捕获请求。如果使用缓冲区管理 API,此限制行为不再存在,而且如果 HAL 中排队的捕获请求过多,相机 HAL 实现不得接受proce*tureRequest
调用。 -
requestStreamBuffers
调用延迟变化显著:requestStreamBuffers
调用所需时间超过平均时间的原因有很多。例如:- 对于新建输出流的前几个缓冲区,调用所需时间可能更长,因为设备需要分配内存。
- 预期延迟时间会按每次调用时请求的缓冲区数的比例增加。
- 该应用正在保留缓冲区并忙于处理操作。这可能会导致缓冲区请求因缓冲区不足或 CPU 繁忙而降速或超时。
缓冲区管理策略
缓冲区管理 API 支持实现各种类型的缓冲区管理策略。以下是一些示例:
-
向后兼容:调用
proce*tureRequest
期间,HAL 会针对捕获请求请求缓冲区。此策略不会节省任何内存,但可用作缓冲区管理 API 的第一个实现,几乎不需要更改现有相机 HAL 的代码。 - 最大限度地节省内存:相机 HAL 仅在需要填充缓冲区之前立即请求输出缓冲区。此策略可最大限度地节省内存。此策略的潜在弊端是,当完成缓冲区请求所需时间过长时,相机管道会出现更多卡顿。
- 已缓存:相机 HAL 会缓存少许缓冲区,以降低缓冲区请求速度偶尔较慢时受到影响的可能性。
相机 HAL 可针对特定使用情形采用不同的策略,例如,对于使用大量内存的使用情形采用“最大限度地节省内存”策略,对于其他使用情形则采用“向后兼容”策略。
外部相机 HAL 中的实现示例
外部相机 HAL 是在 Android 9 中引入的,可在 hardware/interfaces/camera/device/3.5/
上的源代码树中找到。在 Android 10 中,此外部相机 HAL 已进行更新,其中新增了 ExternalCameraDeviceSession.cpp
,这是缓冲区管理 API 的一种实现。此外部相机 HAL 使用几百行 C++ 代码实现缓冲区管理策略中介绍的“最大限度地节省内存”策略。
转自:https://source.android.google.cn/devices/camera/buffer-management-api?hl=en#requeststreambuffers