相机扩展

设备制造商可以通过 OEM 供应商库提供的相机扩展接口,向第三方开发者公开散景、夜间模式和 HDR 等扩展功能。开发者可以使用 Camera2 Extensions APICameraX Extensions API 访问 OEM 供应商库中实现的扩展功能。

有关 Camera2 和 CameraX 均支持的扩展功能列表,请参阅 CameraX Extensions API。如果您想添加扩展功能,请在 问题跟踪器 中提交错误报告。

本页介绍了如何在设备上实现和启用 OEM 供应商库。

架构

下图描述了相机扩展接口或 extensions-interface 的架构: Architecture

图 1. 相机扩展架构图

如图所示,要支持 Camera Extensions,您需要实现 OEM 供应商库提供的 extensions-interface。您的 OEM 供应商库启用两个 API:CameraX Extensions APICamera2 Extensions API。CameraX 和 Camera2 应用分别使用这两个 API 来访问供应商扩展程序。

实现 OEM 供应商库

要实现 OEM 供应商库,请将 camera-extensions-stub 文件复制到系统库项目中。这些文件定义了 Camera Extensions 接口。

camera-extensions-stub 文件分为以下几类

基本接口文件(请勿修改)

  • PreviewExtenderImpl.java
  • ImageCaptureExtenderImpl.java
  • ExtenderStateListener.java
  • ProcessorImpl.java
  • PreviewImageProcessorImpl.java
  • CaptureProcessorImpl.java
  • CaptureStageImpl.java
  • RequestUpdateProcessorImpl.java
  • ProcessResultImpl.java
  • advanced/AdvancedExtenderImpl.java
  • advanced/Camera2OutputConfigImpl.java
  • advanced/Camera2SessionConfigImpl.java
  • advanced/ImageProcessorImpl.java
  • advanced/ImageReaderOutputConfigImpl.java
  • advanced/ImageReferenceImpl.java
  • advanced/MultiResolutionImageReaderOutputConfigImpl.java
  • advanced/OutputSurfaceImpl.java
  • advanced/RequestProcessorImpl.java
  • advanced/SessionProcessorImpl.java
  • advanced/SurfaceOutputConfigImpl.java

强制性实现(添加您的实现)

  • ExtensionVersionImpl.java
  • InitializerImpl.java

背景虚化扩展程序类(如果支持背景虚化扩展程序,请实现)

  • BokehImageCaptureExtenderImpl.java
  • BokehPreviewExtenderImpl.java
  • advanced/BokehAdvancedExtenderImpl.java

夜间扩展程序类(如果支持夜间扩展程序,请实现)

  • NightImageCaptureExtenderImpl.java
  • NightPreviewExtenderImpl.java
  • advanced/NightAdvancedExtenderImpl.java

自动扩展程序类(如果支持自动扩展程序,请实现)

  • AutoImageCaptureExtenderImpl.java
  • AutoPreviewExtenderImpl.java
  • advanced/AutoAdvancedExtenderImpl.java

HDR 扩展程序类(如果支持 HDR 扩展程序,请实现)

  • HdrImageCaptureExtenderImpl.java
  • HdrPreviewExtenderImpl.java
  • advanced/HdrAdvancedExtenderImpl.java

人像美颜扩展程序类(如果支持人像美颜扩展程序,请实现)

  • BeautyImageCaptureExtenderImpl.java
  • BeautyPreviewExtenderImpl.java
  • advanced/BeautyAdvancedExtenderImpl.java

实用程序(可选,可以删除)

  • advanced/Camera2OutputConfigImplBuilder.java
  • advanced/Camera2SessionConfigImplBuilder.java

您无需为每个扩展程序都提供实现。如果您不实现某个扩展程序,请将 isExtensionAvailable() 设置为返回 false,或者移除相应的 Extender 类。Camera2 和 CameraX Extensions API 会向应用报告该扩展程序不可用。

下面我们来了解一下 Camera2 和 CameraX Extensions API 如何与供应商库交互以启用扩展程序。下图说明了以夜间模式扩展程序为例的端到端流程

Mainflow

图 2. 夜间模式扩展程序实现

  1. 版本验证

    Camera2/X 调用 ExtensionVersionImpl.checkApiVersion(),以确保 OEM 实现的 extensions-interface 版本与 Camera2/X 支持的版本兼容。

  2. 供应商库初始化

    InitializerImpl 有一个方法 init(),用于初始化供应商库。Camera2/X 会先完成初始化,然后再访问 Extender 类。

  3. 实例化 Extender 类

    实例化扩展程序的 Extender 类。Extender 类型有两种:Basic Extender 和 Advanced Extender。您必须为所有扩展程序实现一种 Extender 类型。如需了解详情,请参阅 Basic Extender 与 Advanced Extender 的对比

    Camera2/X 会实例化 Extender 类并与之交互,以检索信息并启用扩展程序。对于给定的扩展程序,Camera2/X 可以多次实例化 Extender 类。因此,请勿在构造函数或 init() 调用中执行繁重的初始化操作。仅当相机会话即将开始时才执行繁重操作,例如在 Basic Extender 中调用 onInit() 或在 Advanced Extender 中调用 initSession() 时。

    对于夜间模式扩展程序,以下 Extender 类针对 Basic Extender 类型实例化

    • NightImageCaptureExtenderImpl.java
    • NightPreviewExtenderImpl.java

    对于 Advanced Extender 类型,则实例化以下 Extender 类

    • NightAdvancedExtenderImpl.java
  4. 检查扩展程序是否可用

    在启用扩展程序之前,isExtensionAvailable() 会检查指定的相机 ID 上是否可通过 Extender 实例使用该扩展程序。

  5. 使用相机信息初始化 Extender

    Camera2/X 在 Extender 实例上调用 init(),并将相机 ID 和 CameraCharacteristics 传递给它。

  6. 查询信息

    调用 Extender 类以检索信息,例如支持的分辨率、静态照片拍摄的估计延迟时间以及来自 Extender 的拍摄请求键,以便为启用扩展程序做准备。

  7. 在 Extender 上启用扩展程序

    Extender 类提供启用该类所需的所有接口。它提供了一种将 OEM 实现挂钩到 Camera2 管道的机制,例如注入拍摄请求参数或启用后处理器。

    对于 Advanced Extender 类型,Camera2/X 与 SessionProcessorImpl 交互以启用扩展程序。Camera2/X 通过在 Extender 上调用 createSessionProcessor() 来检索 SessionProcessorImpl 实例。

以下部分更详细地描述了扩展程序流程。

版本验证

当在运行时从设备加载 OEM 供应商库时,Camera2/X 会验证该库是否与 extensions-interface 版本兼容。extensions-interface 使用语义化版本控制(即 MAJOR.MINOR.PATCH),例如 1.1.0 或 1.2.0。但是,版本验证期间仅使用主版本号和次版本号。

要验证版本,Camera2/X 会使用支持的 extensions-interface 版本调用 ExtensionVersionImpl.checkApiVersion()。然后,Camera2/X 使用 OEM 库报告的版本来确定是否可以启用扩展程序以及应调用哪些功能。

主版本兼容性

如果 Camera2/X 和供应商库之间的扩展程序接口的主版本不同,则会被视为不兼容,并且会停用扩展程序。

向后兼容性

只要主版本相同,Camera2/X 就能确保与使用早期 extensions-interface 版本构建的 OEM 供应商库向后兼容。例如,如果 Camera2/X 支持 extensions-interface 1.3.0,则已实现 1.0.0、1.1.0 和 1.2.0 的 OEM 供应商库仍然兼容。这也意味着,在您实现供应商库的特定版本后,Camera2/X 会确保该库与即将推出的 extension-interface 版本向后兼容。

向前兼容性

与较新 extensions-interface 版本的供应商库的向前兼容性取决于您(OEM)。如果您需要某些功能来实现扩展程序,则可能希望从某个版本开始启用扩展程序。在这种情况下,当 Camera2/X 库版本满足要求时,您可以返回支持的 extensions-interface 版本。如果不支持 Camera2/X 版本,您可以返回不兼容的版本(例如 99.0.0)以停用扩展程序。

供应商库初始化

在验证 OEM 库实现的 extensions-interface 版本后,Camera2/X 会启动初始化过程。InitializerImpl.init() 方法向 OEM 库发出信号,表明应用正在尝试使用扩展程序。

在 OEM 供应商库调用 OnExtensionsInitializedCallback.onSuccess() 以通知初始化完成之前,Camera2/X 不会对 OEM 库进行其他调用(版本检查除外)。

extensions-interface 1.1.0 开始,您必须实现 InitializerImpl。如果 OEM 供应商库实现 extensions-interface 1.0.0,Camera2/X 会跳过库初始化步骤。

Basic Extender 与 Advanced Extender 的对比

extensions-interface 实现有两种类型:Basic Extender 和 Advanced Extender。自 extensions-interface 1.2.0 起,Advanced Extender 受到支持。

对于在相机 HAL 中处理图像或使用能够处理 YUV 流的后处理器的扩展程序,请实现 Basic Extender。

对于需要自定义 Camera2 流配置并根据需要发送拍摄请求的扩展程序,请实现 Advanced Extender。

请参阅下表了解二者的对比

Basic Extender Advanced Extender
流配置 固定
预览:PRIVATEYUV_420_888(如果存在处理器)
静态照片拍摄:JPEGYUV_420_888(如果存在处理器)
可由 OEM 自定义。
发送拍摄请求 只有 Camera2/X 可以发送拍摄请求。您可以设置这些请求的参数。当为照片拍摄提供处理器时,Camera2/X 可以发送多个拍摄请求,并将所有图像和拍摄结果发送到处理器。 系统会为您提供一个 RequestProcessorImpl 实例,用于执行 camera2 拍摄请求并获取结果和 Image。

Camera2/X 调用 startRepeatingstartCapture(在 SessionProcessorImpl 上),以发出信号,指示 OEM 启动预览的重复请求并启动静态照片拍摄序列。

相机管道中的挂钩
  • onPresetSession 提供会话参数。
  • onEnableSession 在配置 CameraCaptureSession 后立即发送单个请求。
  • onDisableSessionCameraCaptureSession 关闭之前发送单个请求。
  • initSession 初始化并返回自定义的 camera2 会话配置,以创建拍摄会话。
  • onCaptureSessionStart 在配置 CameraCaptureSession 后立即调用。
  • onCaptureSessionEndCameraCaptureSession 关闭之前调用。
适用场景 在相机 HAL 中或在处理 YUV 图像的处理器中实现的扩展程序。
  • 针对扩展程序具有基于 Camera2 的实现。
  • 需要自定义流配置,例如 RAW 流。
  • 需要交互式拍摄序列。
支持的 API 版本 Camera2 Extensions:Android 13 或更高版本
CameraX Extensions:camera-extensions 1.1.0 或更高版本
Camera2 Extensions:Android 12L 或更高版本
CameraX Extensions:camera-extensions 1.2.0-alpha03 或更高版本

应用流程

下表显示了三种类型的应用流程及其对应的 Camera Extensions API 调用。虽然 Camera2/X 提供这些 API,但您必须正确实现供应商库才能支持这些流程,我们将在后面的部分中详细介绍。

Camera2 扩展程序 CameraX 扩展程序
查询扩展程序是否可用 CameraExtensionCharacteristics。getSupportedExtensions ExtensionsManager。isExtensionAvailable
查询信息 CameraExtensionCharacteristics. getExtensionSupportedSizes CameraExtensionCharacteristics. getEstimatedCaptureLatencyRangeMillis CameraExtensionCharacteristics. getAvailableCaptureRequestKeys CameraExtensionCharacteristics. getAvailableCaptureResultKeys ExtensionsManager。getEstimatedCaptureLatencyRange

CameraX 在库中处理其余信息。

启用扩展程序后的预览和静态照片拍摄 CameraDevice。createExtensionSession

cameraExtensionsSession。setRepeatingRequest

cameraExtensionsSession。capture

val cameraSelector = ExtensionsManager。getExtensionEnabledCameraSelector

bindToLifecycle(lifecycleOwner, cameraSelector, preview, ...)

Basic Extender

Basic Extender 接口在相机管道的多个位置提供挂钩。每种扩展程序类型都有 OEM 需要实现的相应 Extender 类。

下表列出了 OEM 需要为每种扩展程序实现的 Extender 类

要实现的 Extender 类
夜间模式 NightPreviewExtenderImpl.java

NightImageCaptureExtenderImpl.java

HDR HdrPreviewExtenderImpl.java

HdrImageCaptureExtenderImpl.java

自动 AutoPreviewExtenderImpl.java

AutoImageCaptureExtenderImpl.java

背景虚化 BokehPreviewExtenderImpl.java

BokehImageCaptureExtenderImpl.java

人像美颜 BeautyPreviewExtenderImpl.java

BeautyImageCaptureExtenderImpl.java

在以下示例中,我们使用 PreviewExtenderImplImageCaptureExtenderImpl 作为占位符。请将这些占位符替换为您正在实现的实际文件名。

Basic Extender 具有以下功能

  • 在配置 CameraCaptureSession 时注入会话参数 (onPresetSession)。
  • 通知您拍摄会话开始和关闭事件,并发送单个请求以使用返回的参数通知 HAL (onEnableSessiononDisableSession)。
  • 为请求注入拍摄参数 (PreviewExtenderImpl.getCaptureStageImageCaptureExtenderImpl.getCaptureStages)。
  • 为预览和静态照片拍摄添加能够处理 YUV_420_888 流的处理器。

下面我们来看看 Camera2/X 如何调用 extensions-interface 来实现上述三种应用流程。

应用流程 1:检查扩展程序是否可用

BasicExtenderAppFlow1

图 3. Basic Extender 上的应用流程 1

在此流程中,Camera2/X 直接调用 PreviewExtenderImplImageCaptureExtenderImplisExtensionAvailable() 方法,而无需调用 init()。两个 Extender 类都必须返回 true 才能启用扩展程序。

这通常是应用检查给定相机 ID 是否支持给定扩展程序类型的第一个步骤,然后再启用该扩展程序。这是因为某些扩展程序仅在特定相机 ID 上受支持。

应用流程 2:查询信息

BasicExtenderAppFlow2

图 4. Basic Extender 上的应用流程 2

在确定扩展程序是否可用后,应用应在启用扩展程序之前查询以下信息。

  • 静态照片拍摄延迟时间范围: ImageCaptureExtenderImpl.getEstimatedCaptureLatencyRange 返回拍摄延迟时间范围,供应用评估是否适合在当前场景中启用扩展程序。

  • 预览和拍摄图面的支持尺寸: ImageCaptureExtenderImpl.getSupportedResolutionsPreviewExtenderImpl.getSupportedResolutions 返回图像格式列表以及图面格式和尺寸支持的尺寸。

  • 支持的请求键和结果键: Camera2/X 调用以下方法,从您的实现中检索支持的拍摄请求键和结果键

    • ImageCaptureExtenderImpl.getAvailableCaptureRequestKeys
    • ImageCaptureExtenderImpl.getAvailableCapturetResultKeys

Camera2/X 始终先在这些 Extender 类上调用 init(),然后再查询更多信息。

应用流程 3:启用扩展程序后的预览/静态照片拍摄(HAL 实现)

BasicExtenderAppFlow3

图 5. Basic Extender 上的应用流程 3

上图说明了在没有任何处理器的情况下启用扩展程序后的预览和静态照片拍摄的主流程。这意味着相机 HAL 处理扩展程序。

在此流程中,Camera2/X 首先调用 init(),然后调用 onInit,以通知您相机会话即将使用指定的扩展程序启动。您可以在 onInit() 中执行繁重的初始化操作。

在配置 CameraCaptureSession 时,Camera2/X 调用 onPresetSession 以获取会话参数。成功配置拍摄会话后,Camera2/X 调用 onEnableSession,返回包含拍摄参数的 CaptureStageImpl 实例。Camera2/X 立即使用这些拍摄参数发送单个请求以通知 HAL。同样,在拍摄会话关闭之前,Camera2/X 调用 onDisableSession,然后使用返回的拍摄参数发送单个请求。

由 Camera2/X 触发的重复请求包含 PreviewExtenderImpl.getCaptureStage() 返回的请求参数。此外,静态照片拍摄请求包含 ImageCaptureExtenderImpl.getCaptureStages() 返回的参数。

最后,Camera2/X 在相机会话结束后调用 onDeInit()。您可以在 onDeinit() 中释放资源。

预览处理器

除了相机 HAL 之外,您还可以在处理器中实现扩展程序。

实现 PreviewExtenderImpl.getProcessorType 以指定处理器类型,如下所述

  • PROCESSOR_TYPE_NONE无处理器。图像在相机 HAL 中处理。

  • PROCESSOR_TYPE_REQUEST_UPDATE_ONLY处理器类型允许您使用新的拍摄请求参数根据最新的 TotalCaptureResult 更新重复请求。

    PreviewExtenderImpl.getProcessor 必须返回一个 RequestUpdateProcessorImpl 实例,该实例处理 TotalCaptureResult 实例并返回一个 CaptureStageImpl 实例以更新重复请求。PreviewExtenderImpl.getCaptureStage() 也应反映处理结果,并返回最新的 CaptureStageImpl

  • PROCESSOR_TYPE_IMAGE_PROCESSOR此类型允许您实现一个处理器来处理 YUV_420_888 图像,并将输出写入 PRIVATE 图面。

    您需要在 PreviewExtenderImpl.getProcessor 中实现并返回 PreviewImageProcessorImpl 实例。处理器负责处理 YUV_420_888 输入图像。它应将输出写入预览的 PRIVATE 格式。Camera2/X 使用 YUV_420_888 图面而不是 PRIVATE 来配置预览的 CameraCaptureSession

    请参见下图中的流程

PreviewProcessor

图 6. 使用 PreviewImageProcessorImpl 的预览流程

PreviewImageProcessorImpl 接口扩展了 ProcessImpl,并具有三个重要方法

  • onOutputSurface(Surface surface, int imageFormat) 设置处理器的输出图面。对于 PreviewImageProcessorImplimageFormat 是一种像素格式,例如 PixelFormat.RGBA_8888

  • onResolutionUpdate(Size size) 设置输入图像的尺寸。

  • onImageFormatUpdate(int imageFormat) 设置输入图像的图像格式。目前,它只能是 YUV_420_888

照片拍摄处理器

对于静态照片拍摄,您可以通过使用 ImageCaptureExtenderImpl.getCaptureProcessor 返回 CaptureProcessorImpl 实例来实现处理器。处理器负责处理捕获的 YUV_420_888 图像列表和 TotalCaptureResult 实例,并将输出写入 YUV_420_888 图面。

您可以安全地假设,在发送静态照片拍摄请求之前,预览已启用并正在运行。

请参见下图中的流程

CaptureProcessor

图 7. 使用 CaptureProcessorImpl 的静态照片拍摄流程

  1. Camera2/X 使用 YUV_420_888 格式图面进行静态照片拍摄,以配置拍摄会话。Camera2/X 通过调用以下方法来准备 CaptureProcessorImpl

    • CaptureProcessorImpl.onImageFormatUpdate(),其中 YUV_420_888
    • CaptureProcessorImpl.onResolutionUpdate(),其中包含输入图像尺寸。
    • CaptureProcessorImpl.onOutputSurface(),其中包含输出 YUV_420_888 图面。
  2. ImageCaptureExtenderImpl.getCaptureStages 返回 CaptureStageImpl 列表,其中每个元素都映射到一个 CaptureRequest 实例,该实例带有由 Camera2/X 发送的拍摄参数。例如,如果它返回三个 CaptureStageImpl 实例的列表,则 Camera2/X 会使用 captureBurst API 发送三个带有相应拍摄参数的拍摄请求。

  3. 收到的图像和 TotalCaptureResult 实例捆绑在一起,并发送到 CaptureProcessorImpl 进行处理。

  4. CaptureProcessorImpl 将结果 Image(YUV_420_888 格式)写入 onOutputSurface() 调用指定的输出图面。如有必要,Camera2/X 会将其转换为 JPEG 图像。

支持拍摄请求键和结果

除了相机预览和拍摄之外,应用还可以设置变焦、闪光灯参数或触发点按对焦。这些参数可能与您的扩展程序实现不兼容。

已在 extensions-interface 1.3.0 中添加以下方法,以便您公开您的实现支持的参数

  • ImageCaptureExtenderImpl.getAvailableCaptureRequestKeys() 返回您的实现支持的拍摄请求键。
  • ImageCaptureExtenderImpl.getAvailableCaptureResultKeys() 返回拍摄结果中包含的拍摄结果键。

如果相机 HAL 处理扩展程序,则 Camera2/X 会在 CameraCaptureSession.CaptureCallback 中检索拍摄结果。但是,如果实现了处理器,则 Camera2/X 会在 ProcessResultImpl 中检索拍摄结果,该结果会传递到 PreviewImageProcessorImplCaptureProcessorImpl 中的 process() 方法。您负责通过 ProcessResultImpl 向 Camera2/X 报告拍摄结果。

请参见下面的 CaptureProcessorImpl 接口的定义示例。在 extensions-interface 1.3.0 或更高版本中,会调用第二个 process() 调用

Interface CaptureProcessorImpl extends ProcessorImpl {
    // invoked when extensions-interface version < 1.3.0
    void process(Map<Integer, Pair<Image, TotalCaptureResult>> results);
    // invoked when extensions-interface version >= 1.3.0
    void process(Map<Integer, Pair<Image, TotalCaptureResult>> results,
            ProcessResultImpl resultCallback, Executor executor);
}

对于变焦、点按对焦、闪光灯和曝光补偿等常见相机操作,我们建议同时支持以下拍摄请求键和拍摄结果键

  • 变焦
    • CaptureRequest#CONTROL_ZOOM_RATIO
    • CaptureRequest#SCALER_CROP_REGION
  • 点按对焦
    • CaptureRequest#CONTROL_AF_MODE
    • CaptureRequest#CONTROL_AF_TRIGGER
    • CaptureRequest#CONTROL_AF_REGIONS
    • CaptureRequest#CONTROL_AE_REGIONS
    • CaptureRequest#CONTROL_AWB_REGIONS
  • 闪光灯
    • CaptureRequest#CONTROL_AE_MODE
    • CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
    • CaptureRequest#FLASH_MODE
  • 曝光补偿
    • CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION

对于实现 1.2.0 或更早版本的 Basic Extender,CameraX Extensions API 显式支持上述所有键。对于 extensions-interface 1.3.0,CameraX 和 Camera2 都遵循返回的列表,并且仅支持其中包含的键。例如,如果您决定在 1.3.0 实现中仅返回 CaptureRequest#CONTROL_ZOOM_RATIOCaptureRequest#SCALER_CROP_REGION,则意味着仅支持应用的变焦,而不允许点按对焦、闪光灯和曝光补偿。

Advanced Extender

Advanced Extender 是一种基于 Camera2 API 的供应商实现类型。此 Extender 类型在 extensions-interface 1.2.0 中添加。根据设备制造商的不同,扩展程序可能在应用层实现,这取决于以下因素

  • 自定义流配置:配置自定义流(如 RAW 流)或为不同的物理相机 ID 配置多个流。

  • 发送 Camera2 请求的功能:支持复杂的交互逻辑,该逻辑可以根据先前请求的结果发送带有参数的拍摄请求。

Advanced Extender 提供了一个封装容器或中间层,因此您可以自定义流配置并按需发送拍摄请求。

要实现的文件

要切换到 Advanced Extender 实现,ExtensionVersionImpl 中的 isAdvancedExtenderImplemented() 方法必须返回 true。对于每种扩展程序类型,OEM 都必须实现相应的 Extender 类。Advanced Extender 实现文件位于 advanced 包中。

要实现的 Extender 类
夜间模式 advanced/NightAdvancedExtenderImpl.java
HDR advanced/HdrAdvancedExtenderImpl.java
自动 advanced/AutoAdvancedExtenderImpl.java
背景虚化 advanced/BokehAdvancedExtenderImpl.java
人像美颜 advanced/BeautyAdvancedExtenderImpl.java

在以下示例中,我们使用 AdvancedExtenderImpl 作为占位符。请将其替换为您要实现的扩展程序的 Extender 文件名。

下面我们来看看 Camera2/X 如何调用 extensions-interface 来实现这三种应用流程。

应用流程 1:检查扩展程序是否可用

AdvancedAppFlow1

图 8. Advanced Extender 上的应用流程 1

首先,应用检查是否支持给定的扩展程序。

应用流程 2:查询信息

AdvancedAppFlow2

图 9. Advanced Extender 上的应用流程 2

在调用 AdvancedExtenderImpl.init() 后,应用可以在 AdvancedExtenderImpl 上查询以下信息

  • 估计的静态照片拍摄延迟时间: AdvancedExtenderImpl.getEstimatedCaptureLatencyRange() 返回拍摄延迟时间范围,供应用评估是否适合在当前场景中启用扩展程序。

  • 预览和静态照片拍摄的支持分辨率

    • AdvancedExtenderImpl.getSupportedPreviewOutputResolutions() 返回图像格式到预览图面格式和尺寸支持的尺寸列表的映射。OEM 必须至少支持 PRIVATE 格式。

    • AdvancedExtenderImpl.getSupportedCaptureOutputResolutions() 返回静态照片拍摄图面支持的格式和尺寸。OEM 必须同时支持 JPEGYUV_420_888 格式输出。

    • AdvancedExtenderImpl.getSupportedYuvAnalysisResolutions() 返回用于图像分析的额外 YUV_420_888 流的支持尺寸。如果不支持图像分析 YUV 图面,则 getSupportedYuvAnalysisResolutions() 应返回 null 或空列表。

  • 可用的拍摄请求键/结果(在 extensions-interface 1.3.0 中添加):Camera2/X 调用以下方法,从您的实现中检索支持的拍摄请求键和结果键

    • AdvancedExtenderImpl.getAvailableCaptureRequestKeys
    • AdvancedExtenderImpl.getAvailableCaptureResultKeys

如需了解详情,请参阅 支持拍摄请求键和结果

应用流程 3:启用扩展程序后的预览/静态照片拍摄

AdvancedAppFlow3

图 10. Advanced Extender 上的应用流程 3

上面的图表显示了高级扩展器类型的启动预览和静止图像捕获的主流程。让我们逐步了解每个步骤。

  1. SessionProcessorImpl 实例

    核心高级扩展器实现在 SessionProcessorImpl 中,它负责提供自定义会话配置并发送捕获请求以启动预览和静止图像捕获请求。AdvancedExtenderImpl.createSessionProcessor() 被调用以返回 SessionProcessorImpl 实例。

  2. initSession

    SessionProcessorImpl.initSession() 初始化扩展的会话。您可以在此处分配资源并返回会话配置,以准备 CameraCaptureSession

    对于输入参数,Camera2/X 指定了预览、静止图像捕获和可选 YUV 图像分析的输出图面配置。此输出图面配置 (OutputSurfaceImpl) 包含通过以下 AdvancedExtenderImpl 中的方法检索的图面、大小和图像格式

    • getSupportedPreviewOutputResolutions()
    • getSupportedCaptureOutputResolutions()
    • getSupportedYuvAnalysisResolutions()

    您必须返回一个 Camera2SessionConfigImpl 实例,该实例由 Camera2OutputConfigImpl 实例列表和用于配置 CameraCaptureSession 的会话参数组成。您负责将正确的相机图像输出到 Camera2/X 传入的输出图面。以下是一些启用输出的选项

    • 在相机 HAL 中处理: 您可以使用 SurfaceOutputConfigImpl 实现直接将输出图面添加到 CameraCaptureSession。这将提供的输出图面配置到相机管道,并允许相机 HAL 处理图像。
    • 处理中间 ImageReader 图面(RAW、YUV 等): 使用 ImageReaderOutputConfigImpl 实例将中间 ImageReader 图面添加到 CameraCaptureSession

      您需要处理中间图像并将结果图像写入输出图面。

    • 使用 Camera2 图面共享: 通过将任何 Camera2OutputConfigImpl 实例添加到另一个 Camera2OutputConfigImpl 实例的 getSurfaceSharingOutputConfigs() 方法,使用与其他图面共享的图面。图面格式和大小必须相同。

    所有 Camera2OutputConfigImpl,包括 SurfaceOutputConfigImplImageReaderOutputConfigImpl,都必须具有唯一的 ID (getId()),该 ID 用于指定目标图面并从 ImageReaderOutputConfigImpl 检索图像。

  3. onCaptureSessionStartRequestProcessorImpl

    CameraCaptureSession 启动并且 Camera 框架调用 onConfigured() 时,Camera2/X 会使用 Camera2 请求包装器 RequestProcessImpl 调用 SessionProcessorImpl.onCaptureSessionStart()。Camera2/X 实现 RequestProcessImpl,这使您能够执行捕获请求,并在使用 ImageReaderOutputConfigImpl检索图像

    RequestProcessImpl API 在执行请求方面与 Camera2 CameraCaptureSession API 类似。不同之处在于

    • 目标图面由 Camera2OutputConfigImpl 实例的 ID 指定。
    • 检索 ImageReader 图像的功能。

    您可以调用 RequestProcessorImpl.setImageProcessor() 并指定 Camera2OutputConfigImpl ID,以注册 ImageProcessorImpl 实例来接收图像。

    在 Camera2/X 调用 SessionProcessorImpl.onCaptureSessionEnd() 后,RequestProcessImpl 实例将变为无效。

  4. 启动预览并拍照

    在高级扩展器实现中,您可以通过 RequestProcessorImpl 接口发送捕获请求。Camera2/X 通过分别调用 SessionProcessorImpl#startRepeatingSessionProcessorImpl#startCapture 通知您启动用于预览的重复请求或静止图像捕获序列。您应发送捕获请求以满足这些预览和静止图像捕获请求。

    Camera2/X 还会通过 SessionProcessorImpl#setParameters 设置捕获请求参数。您必须在重复请求和单次请求上都设置这些请求参数(如果支持参数)。

    您必须至少支持 CaptureRequest.JPEG_ORIENTATIONCaptureRequest.JPEG_QUALITYextensions-interface 1.3.0 支持请求和结果键,这些键通过以下方法公开

    • AdvancedExtenderImpl.getAvailableCaptureRequestKeys()
    • AdvancedExtenderImpl.getAvailableCaptureResultKeys()

    当开发人员在 getAvailableCaptureRequestKeys 列表中设置键时,您必须启用参数并确保捕获结果包含 getAvailableCaptureResultKeys 列表中的键。

  5. startTrigger

    调用 SessionProcessorImpl.startTrigger() 以启动触发器,例如 CaptureRequest.CONTROL_AF_TRIGGERCaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER。您可以忽略 AdvancedExtenderImpl.getAvailableCaptureRequestKeys() 中未声明的任何捕获请求键。

    extensions-interface 1.3.0 起,便已支持 startTrigger()。它使应用能够通过扩展实现点击对焦和闪光灯。

  6. 清理

    完成捕获会话后,会在关闭 CameraCaptureSession 之前调用 SessionProcessorImpl.onCaptureSessionEnd()。捕获会话关闭后,deInitSession() 会执行清理。

支持预览、静止图像捕获和图像分析

您应该将扩展应用于预览和静止图像捕获用例。但是,如果延迟太高而无法流畅地显示预览,则可以仅将扩展应用于静止图像捕获。

对于基本扩展器类型,无论是否为预览启用扩展,您都必须为给定的扩展实现 ImageCaptureExtenderImplPreviewExtenderImpl。通常,应用还会使用 YUV 流来分析图像内容,例如查找 QR 码或文本。为了更好地支持此用例,您应该支持预览、静止图像捕获和 YUV_420_888 流的流组合,以配置 CameraCaptureSession。这意味着,如果您实现处理器,则必须支持三个 YUV_420_888 流的流组合。

对于高级扩展器,Camera2/X 将三个输出图面传递给 SessionProcessorImpl.initSession() 调用。这些输出图面分别用于预览、静止图像捕获和图像分析。您必须确保预览和静止图像捕获输出图面显示有效的输出。但是,对于图像分析输出图面,请确保仅当它为非空时才工作。如果您的实现不支持图像分析流,则可以在 AdvancedExtenderImpl.getSupportedYuvAnalysisResolutions() 中返回一个空列表。这可确保图像分析输出图面在 SessionProcessorImpl.initSession() 中始终为空。

支持视频捕获

当前的相机扩展架构仅支持预览和静止图像捕获用例。我们不支持在 MediaCodecMediaRecorder 图面上启用扩展以录制视频。但是,应用可以录制预览输出。

MediaCodecMediaRecorder 图面的支持正在调查中。

特定于扩展的元数据

对于 Android 14 及更高版本,特定于扩展的元数据允许相机扩展客户端设置和接收特定于扩展的捕获请求设置和结果。具体来说,相机扩展客户端可以使用 EXTENSION_STRENGTH 捕获请求参数来控制扩展强度,并使用 EXTENSION_CURRENT_TYPE 捕获结果来指示启用的扩展类型。

捕获请求

EXTENSION_STRENGTH 捕获请求参数控制扩展后处理效果的强度。如果客户端未显式设置此参数,则相应的捕获结果包括默认强度值。此参数可以按如下方式应用于这些扩展类型

  • BOKEH:控制模糊量。
  • HDRNIGHT:控制融合的图像数量和最终图像的亮度。
  • FACE_RETOUCH:控制美颜和皮肤平滑的程度。

EXTENSION_STRENGTH 参数的受支持范围介于 0100 之间,其中 0 表示没有扩展处理或简单的直通,100 表示处理效果的最大扩展强度。

要添加对 EXTENSION_STRENGTH 的支持,请使用扩展库接口 1.3.0 版本中引入的供应商特定参数 API。有关详细信息,请参阅 getAvailableCaptureRequestKeys()

捕获结果

EXTENSION_CURRENT_TYPE 捕获结果使扩展实现能够向客户端通知活动扩展类型。

由于使用 AUTO 类型的扩展会在 HDRNIGHT 等扩展类型之间动态切换,具体取决于场景条件,因此相机扩展应用可以使用 EXTENSION_CURRENT_TYPE 来显示有关 AUTO 扩展选择的当前扩展类型的信息。

实时静止图像捕获延迟估计

对于 Android 14 及更高版本,相机扩展客户端可以使用 getRealtimeStillCaptureLatency() 查询基于场景和环境条件的实时静止图像捕获延迟估计。此方法提供的估计比静态 getEstimatedCaptureLatencyRangeMillis() 方法更准确。根据延迟估计,应用可以决定跳过扩展处理,或者显示指示以通知用户长时间运行的操作。

CameraExtensionSession.StillCaptureLatency latency;

latency = extensionSession.getRealtimeStillCaptureLatency();

// The capture latency from ExtensionCaptureCallback#onCaptureStarted() until ExtensionCaptureCallback#onCaptureProcessStarted().

latency.getCaptureLatency();

// The processing latency from  ExtensionCaptureCallback#onCaptureProcessStarted() until  the processed frame returns to the client.

latency.getProcessingLatency();

要支持实时静止图像捕获延迟估计,请实现以下内容

捕获处理进度回调

对于 Android 14 及更高版本,相机扩展客户端可以接收长时间运行的静止图像捕获处理操作进度的回调。应用可以向用户显示当前进度,以改善整体用户体验。

应用可以使用以下代码来集成此功能

import android.hardware.camera2.CameraExtensionSession.
ExtensionCaptureCallback;

{

  class AppCallbackImpl extends ExtensionCaptureCallback {

    @Override
    public void onCaptureProcessProgressed(
      @NonNull CameraExtensionSession session,
      @NonNull CaptureRequest request,
      @IntRange(from = 0, to = 100) int progress) {
      // Update app UI with current progress
    }
  }

}

要支持捕获处理进度回调,您的扩展供应商实现必须使用当前进度值调用以下回调

Postview 静止图像捕获

对于 Android 14 及更高版本,相机扩展可以使用 setPostviewOutputConfiguration 提供预览后图像(预览图像)。为了改善用户体验,当扩展的 processing latency 增加时,应用可以显示预览后图像作为占位符,并在最终图像可用时替换该图像。应用可以使用以下参考代码配置和发出预览后捕获请求

{

if (!CameraExtensionCharacteristics.isPostviewAvailable()) {
    continue;
}

ExtensionSessionConfiguration extensionConfiguration = new
        ExtensionSessionConfiguration(
                CameraExtensionCharacteristics.EXTENSION_NIGHT,
                outputConfig,
                backgroundExecutor,
                extensionSessionStateCallback
    );

extensionConfiguration.setPostviewOutputConfiguration(
    postviewImageOutput);

CaptureRequest.Builder captureRequestBuilder =
    cameraDevice.createCaptureRequest(
        CameraDevice.TEMPLATE_STILL_CAPTURE);
captureRequestBuilder.addTarget(stillImageReader.getSurface());
captureRequestBuilder.addTarget(postviewImageSurface);

CaptureRequest captureRequest = captureRequestBuilder.build();

}

要支持预览后静止图像捕获,您的供应商实现必须实现以下内容

支持 SurfaceView 输出

对于 Android 14 及更高版本,相机扩展客户端可以通过为重复请求的预览输出注册 SurfaceView 实例来使用功耗和性能优化的预览渲染路径。

要支持 SurfaceView 输出,您的供应商扩展实现必须能够将预览流式传输并输出到 SurfaceView 实例。要验证是否支持此功能,请运行 SurfaceViewExtensionPreviewTest.java CTS 模块。

供应商特定会话类型

此功能使供应商扩展实现能够选择供应商特定的会话类型,该类型将在内部相机捕获会话中设置,而不是默认值。

此功能完全在框架和供应商堆栈中工作,并且对客户端/公共可见的 API 没有影响。

要选择供应商特定的会话类型,请为您的扩展库实现以下内容:* 基本扩展的 ExtenderStateListener.onSessionType() * 高级扩展的 Camera2SessionConfigImpl.getSessionType()

扩展接口版本历史记录

下表显示了相机扩展接口版本历史记录。您应始终使用最新版本实现供应商库。

版本 添加的功能
1.0.0
  • 版本验证
    • ExtensionVersionImpl
  • Basic Extender
    • PreviewExtenderImpl
    • ImageCaptureExtenderImpl
    • 处理器
      • PreviewImageProcessorImpl
      • CaptureProcessorImpl
      • RequestUpdateProcessorImpl
1.1.0
  • 库初始化
    • InitializerImpl
  • 公开支持的分辨率
    • PreviewExtenderImpl.getSupportedResolutions
    • ImageCaptureExtenderImpl.getSupportedResolutions
1.2.0
  • AdvancedExtender
    • AdvancedExtenderImpl
    • SessionProcessorImpl
  • 获取估计的捕获延迟
    • ImageCaptureExtenderImpl.getEstimatedCaptureLatencyRange
1.3.0
  • 公开支持的捕获请求键/结果键
    • ImageCaptureExtenderImpl.getAvailableCaptureRequestKeysgetAvailableCaptureResultKeys
    • AdvancedExtenderImpl.getAvailableCaptureRequestKeysgetAvailableCaptureResultKeys
    • 新的 process() 调用,它在 PreviewImageProcessorImplCaptureProcessorImpl 中采用 ProcessResultImpl
    • 支持触发器类型请求
      • AdvancedExtenderImpl.startTrigger
1.4.0
  • 特定于扩展的元数据
  • 动态静止图像捕获延迟估计
  • 捕获处理进度回调
  • Postview 静止图像捕获
  • 支持 SurfaceView 输出
  • 供应商特定会话类型

参考实现

以下参考 OEM 供应商库实现在 frameworks/ex 中提供。

  • advancedSample:高级扩展器的基本实现。

  • sample:基本扩展器的基本实现。

  • service_based_sample:演示如何在 Service 中托管相机扩展的实现。此实现包含以下组件

    • oem_library:用于 Camera2 和 CameraX Extensions API 的相机扩展 OEM 库,它实现了 Extensions-Interface。这充当传递器,将来自 Extensions-Interface 的调用转发到服务。此库还提供 AIDL 文件和包装器类,以与服务通信。

      默认情况下启用高级扩展器。要启用基本扩展器,请更改 ExtensionsVersionImpl#isAdvancedExtenderImplemented 以返回 false

    • extensions_service:扩展服务的示例实现。在此处添加您的实现。要在服务中实现的接口类似于 Extensions-Interface。例如,实现 IAdvancedExtenderImpl.Stub 执行与 AdvancedExtenderImpl 相同的操作。ImageWrapperTotalCaptureResultWrapper 是使 ImageTotalCaptureResult 可打包所必需的。

在设备上设置供应商库

OEM 供应商库未内置到应用中;它在运行时由 Camera2/X 从设备加载。在 CameraX 中,<uses-library> 标记声明 androidx.camera.extensions.impl 库(在 AndroidManifest.xml 文件的 camera-extensions 库中定义)是 CameraX 的依赖项,必须在运行时加载。在 Camera2 中,框架加载一个扩展服务,该服务也声明 <uses-library> 在运行时加载相同的 androidx.camera.extensions.impl 库。

这允许使用扩展的第三方应用自动加载 OEM 供应商库。OEM 库标记为可选,以便应用可以在设备上没有该库的设备上运行。当应用尝试使用相机扩展时,只要设备制造商将 OEM 库放置在设备上,以便应用可以发现它,Camera2/X 就会自动处理此行为。

要在设备上设置 OEM 库,请执行以下操作

  1. 使用以下格式添加 <uses-library> 标记所需的权限文件:/etc/permissions/ANY_FILENAME.xml。例如,/etc/permissions/camera_extensions.xml。此目录中的文件提供 <uses-library> 中命名的库到设备上实际文件路径的映射。
  2. 使用以下示例将所需信息添加到文件中。

    • name 必须为 androidx.camera.extensions.impl,因为这是 CameraX 搜索的库。
    • file 是包含扩展实现的文件的绝对路径(例如,/system/framework/androidx.camera.extensions.impl.jar)。
    <?xml version="1.0" encoding="utf-8"?>
    <permissions>
        <library name="androidx.camera.extensions.impl"
                 file="OEM_IMPLEMENTED_JAR" />
    </permissions>

在 Android 12 或更高版本中,支持 CameraX 扩展的设备必须将 ro.camerax.extensions.enabled 属性设置为 true,这允许查询设备是否支持扩展。为此,请在设备 make 文件中添加以下行

PRODUCT_VENDOR_PROPERTIES += \
    ro.camerax.extensions.enabled=true \

验证

要在开发阶段测试 OEM 供应商库的实现,请使用 androidx-main/camera/integration-tests/extensionstestapp/ 中的示例应用,该应用会运行各种供应商扩展。

完成实现后,使用 相机扩展验证工具 运行自动化和手动测试,以验证供应商库是否已正确实现。

扩展场景模式与相机扩展

对于散景扩展,除了使用相机扩展公开它之外,您还可以使用扩展场景模式公开该扩展,该模式通过 CONTROL_EXTENDED_SCENE_MODE 键启用。有关更多实现详细信息,请参阅 相机散景

与相机扩展相比,扩展场景模式对 camera2 应用的限制更少。例如,您可以在常规 CameraCaptureSession 实例中启用扩展场景模式,该实例支持灵活的流组合和捕获请求参数。相比之下,相机扩展仅支持一组固定的流类型,并且对捕获请求参数的支持有限。

扩展场景模式的一个缺点是,您只能在相机 HAL 中实现它,这意味着必须验证它是否适用于应用开发者可用的所有正交控件。

我们建议同时使用扩展场景模式和相机扩展来公开散景,因为应用可能更喜欢使用特定的 API 来启用散景。我们建议首先使用扩展场景模式,因为这是应用启用散景扩展的最灵活方式。然后,您可以基于扩展场景模式实现相机扩展接口。如果难以在相机 HAL 中实现散景(例如,因为它需要应用层中运行的后处理器来处理图像),我们建议使用相机扩展接口实现散景扩展。

常见问题解答 (FAQ)

API 级别是否有任何限制?

是。这取决于 OEM 供应商库实现所需的 Android API 功能集。例如,ExtenderStateListener.onPresetSession() 使用 SessionConfiguration.setSessionParameters() 调用来设置基线标记集。此调用仅在 API 级别 28 及更高版本上可用。有关特定接口方法的详细信息,请参阅 API 参考文档