多摄像头支持

Android 9 通过一个新的逻辑摄像头设备(由两个或更多个指向同一方向的物理摄像头设备组成)引入了对多摄像头设备的 API 支持。该逻辑摄像头设备以单个 CameraDevice/CaptureSession 的形式提供给应用,从而允许与集成了 HAL 的多摄像头功能互动。应用可以选择访问和控制底层物理摄像头信息流、元数据和控件。

多摄像头支持

图 1. 多摄像头支持

在此图中,不同的摄像头 ID 用不同颜色标识。应用可以从每个物理摄像头同时流式传输 RAW 缓冲区,也可以设置单独的控件并从不同的物理摄像头单独接收元数据。

示例和源代码

多摄像头设备必须通过逻辑多摄像头功能播发。

摄像头客户端可以通过调用 getPhysicalCameraIds(),查询构成特定逻辑摄像头的物理设备的摄像头 ID。随结果返回的 ID 之后会用于通过 setPhysicalCameraId() 单独控制物理设备。此类单个请求的结果可以通过调用 getPhysicalCameraResults() 从完整结果中查询。

单个物理摄像头请求可能仅支持有限的部分参数。为了接收受支持参数的列表,开发者可以调用 getAvailablePhysicalCameraRequestKeys()

只有非重新处理请求以及单色和 Bayer 传感器支持物理摄像头数据流。

实现

支持核对清单

如需在 HAL 端添加逻辑多摄像头设备,请执行以下操作:

对于搭载 Android 9 的设备,摄像头设备必须支持将一个逻辑 YUV/RAW 信息流替换为来自两个物理摄像头的大小(不适用于 RAW 信息流)和格式相同的物理信息流。这并不适用于搭载 Android 10 的设备。

对于搭载 Android 10(其中摄像头 HAL 设备版本为 3.5或更高版本)的设备,摄像头设备必须支持 isStreamCombinationSupported 来查询应用是否支持包含物理信息流的特定信息流组合。

信息流配置映射

对于逻辑摄像头,特定硬件级别的摄像头设备的强制性数据流组合与 CameraDevice.createCaptureSession 中所需的数据流组合相同。信息流配置映射中的所有信息流都必须是逻辑信息流。

对于支持 RAW 功能且物理子摄像头大小不同的逻辑摄像头设备,如果应用配置了逻辑 RAW 信息流,逻辑摄像头设备就不得切换到传感器大小不同的物理子摄像头。这样可以确保现有 RAW 捕获应用不会中断。

为了在 RAW 捕获期间通过在物理子摄像头之间进行切换来利用 HAL 实现的光学变焦,应用必须配置物理子摄像头信息流(而不是逻辑 RAW 信息流)。

有保证的信息流组合

逻辑摄像头及其底层物理摄像头都必须保证其设备级别所需的强制性信息流组合

逻辑摄像头设备的运行方式应该与物理摄像头设备相同,具体取决于其硬件级别和功能。建议将其特征集设为单个物理摄像头的特征集的超集。

在搭载 Android 9 的设备上,对于每个有保证的信息流组合,逻辑摄像头必须支持:

  • 将一个逻辑 YUV_420_888 或 RAW 信息流替换为两个相同大小和格式的物理信息流(每个信息流来自不同的物理摄像头),只要物理摄像头支持这种大小和格式就可以。

  • 添加两个原始数据流(在每个物理摄像头中各添加一个),条件是逻辑摄像头不播发 RAW 功能,但底层物理摄像头播发该功能。当两个物理摄像头具有不同的传感器尺寸时,通常会出现这种情况。

  • 使用物理数据流代替大小和格式相同的逻辑数据流。当物理信息流和逻辑信息流的最小帧时长相同时,这么做必须不能减慢捕获的帧速率。

性能和功率考虑因素

  • 性能:

    • 由于资源限制,配置和流式传输物理信息流可能会降低逻辑摄像头的捕获速率。
    • 如果将底层摄像头设为不同的帧速率,则应用物理摄像头设置可能会降低捕获速率。
  • 功率:

    • HAL 的功率优化在默认情况下继续有效。
    • 配置或请求物理信息流可能会替换 HAL 的内部功率优化并消耗更多电量。

自定义

您可以通过以下方式自定义设备实现。

  • 逻辑摄像头设备的融合输出完全取决于 HAL 实现。关于如何从物理摄像头派生融合逻辑信息流,该决定对于应用和 Android 相机框架是透明的。
  • 可以选择支持单个物理请求和结果。此类请求中的可用参数集也完全取决于特定的 HAL 实现。
  • 从 Android 10 开始,HAL 可以选择不在 getCameraIdList 中播发部分或所有 PHYSICAL_ID,从而减少应用能够直接打开的摄像头数量。调用 getPhysicalCameraCharacteristics 必须返回物理摄像头的特性。

验证

逻辑多摄像头设备必须像任何其他普通摄像头一样通过摄像头 CTS。可以在 LogicalCameraDeviceTest 模块中找到针对此类设备的测试用例。

以下三个 ITS 测试针对多摄像头系统,以便于正确融合图像:

scene1 和 scene4 测试使用ITS-in-a-box 测试装置运行。当两个摄像头都启用时,test_multi_camera_match 测试会声明图像中心的亮度匹配。test_multi_camera_alignment 测试会声明摄像头间距、方向和失真参数已正确加载。如果多摄像头系统包含广视野摄像头(大于 90o),则需要 rev2 版 ITS 包装盒。

Sensor_fusion 是另一个测试装置,它可以实现规定的重复手机动作,并声明陀螺仪和图像传感器时间戳匹配以及多摄像头帧保持同步。

所有测试盒均由 AcuSpec, Inc. (www.acuspecinc.com,fred@acuspecinc.com) 和 MYWAY Manufacturing (www.myway.tw,sales@myway.tw) 提供。此外,rev1 ITS 测试盒可从 West-Mark (www.west-mark.com,dgoodman@west-mark.com) 购买。

最佳做法

如需在保持应用兼容性的同时充分利用多摄像头支持的功能,请在实现逻辑多摄像头设备时遵循这些最佳实践。

  • (Android 10 或更高版本)从 getCameraIdList 中隐藏物理子摄像头。这样可以减少应用能够直接打开的摄像头数量,使得应用不需要采用复杂的摄像头选择逻辑。
  • (Android 11 或更高版本)对于支持光学变焦的逻辑多摄像头设备,请实现 ANDROID_CONTROL_ZOOM_RATIO API,并将 ANDROID_SCALER_CROP_REGION 仅用于裁剪宽高比。ANDROID_CONTROL_ZOOM_RATIO 使设备可以缩小并保持更高精确率。在这种情况下,HAL 必须调整 ANDROID_SCALER_CROP_REGIONANDROID_CONTROL_AE_REGIONSANDROID_CONTROL_AWB_REGIONSANDROID_CONTROL_AF_REGIONSANDROID_STATISTICS_FACE_RECTANGLESANDROID_STATISTICS_FACE_LANDMARKS 的坐标系,将缩放后视野范围视为传感器活动数组。如需详细了解 ANDROID_SCALER_CROP_REGION 如何与 ANDROID_CONTROL_ZOOM_RATIO 结合使用,请参阅 camera3_crop_reprocess#cropping
  • 对于配备具有不同功能的物理摄像头的多摄像头设备,请确保仅当整个缩放范围支持控件的某个值或范围时,设备才会播发对该值或范围的支持。例如,如果逻辑摄像头由超广角、广角和远距摄像头组成,请执行以下操作:
    • 如果物理摄像头的活跃数组大小不同,摄像头 HAL 必须为 ANDROID_SCALER_CROP_REGIONANDROID_CONTROL_AE_REGIONSANDROID_CONTROL_AWB_REGIONSANDROID_CONTROL_AF_REGIONSANDROID_STATISTICS_FACE_RECTANGLESANDROID_STATISTICS_FACE_LANDMARKS 执行从物理摄像头的活跃数组到逻辑摄像头的活跃数组的映射操作,因此从应用的角度来看,坐标系是逻辑摄像头的活跃数组大小。
    • 如果广角和远距摄像头支持自动对焦,但超广角摄像头支持固定焦距,请确保逻辑摄像头播发自动对焦支持。HAL 必须模拟超广角摄像头的自动对焦状态机,以便在应用缩小到超广角镜头时,底层物理摄像头支持固定焦距且对应用透明,并且受支持的 AF 模式的自动对焦状态机可以按预期运行。
    • 如果广角摄像头和远距摄像头支持 4K 60 fps,并且超广角摄像头仅支持 4K 30 fps 或 1080p 60 fps 但不支持 4K 60 fps,请确保逻辑摄像头不会在其支持的信息流配置中播发 4k 60 fps。这样可以保证逻辑摄像头功能的完整性,从而确保应用在 ANDROID_CONTROL_ZOOM_RATIO 值小于 1 的情况下不会发生达不到 4k 60 fps 的问题。
  • 从 Android 10 开始,不需要使用逻辑多摄像头来支持包含物理信息流的信息流组合。如果 HAL 支持与物理信息流组合,请执行以下操作:
    • (Android 11 或更高版本)为了更好地处理双目立体视觉和动作跟踪等用例,请使物理信息流输出的视野范围尽可能大(可通过硬件实现)。但是,如果物理信息流和逻辑信息流源自同一物理摄像头,硬件限制可能会强制使物理信息流的视野范围与逻辑信息流相同。
    • 为了解决由多个物理信息流引发的内存压力,请确保应用使用 discardFreeBuffers 来释放空闲缓冲区(使用方已释放但生产方尚未使其退出队列的缓冲区),前提是物理信息流预期在一段时间后处于空闲状态。
    • 如果来自不同物理摄像头的物理信息流通常不会附加到同一请求中,请确保应用使用 surface group,以便将一个缓冲区队列用于支持两个面向应用的途径,从而减少内存消耗。