相機擴充功能

裝置製造商可透過 OEM 廠商程式庫提供的 Camera Extensions 介面,向第三方開發人員公開散景、夜視模式和 HDR 等擴充功能。開發人員可以使用 Camera2 Extensions APICameraX Extensions API,存取 OEM 供應商程式庫中實作的擴充功能。

如需支援的擴充功能清單 (Camera2 和 CameraX 支援的擴充功能相同),請參閱「CameraX Extensions API」。如要新增擴充功能,請使用問題追蹤工具回報錯誤。

本頁說明如何在裝置上實作及啟用 OEM 供應商程式庫。

建築

下圖說明 Camera Extensions 介面或 extensions-interface 的架構: 建築

圖 1. 相機擴充功能架構圖

如圖所示,如要支援相機擴充功能,您需要實作 OEM 廠商程式庫提供的 extensions-interface。OEM 供應商程式庫會啟用兩個 API:CameraX Extensions APICamera2 Extensions API,分別供 CameraX 和 Camera2 應用程式存取供應商擴充功能。

實作 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,或移除對應的擴充器類別。Camera2 和 CameraX Extensions API 會向應用程式回報擴充功能無法使用。

接下來,我們將逐步說明 Camera2 和 CameraX Extensions API 如何與供應商程式庫互動,以啟用擴充功能。下圖以 Night 擴充功能為例,說明端對端流程:

Mainflow

圖 2. 夜間擴充功能導入

  1. 版本驗證:

    Camera2/X 會呼叫 ExtensionVersionImpl.checkApiVersion(),確保 OEM 實作的 extensions-interface 版本與 Camera2/X 支援的版本相容。

  2. 供應商程式庫初始化:

    InitializerImpl 具有可初始化供應商程式庫的方法 init()。Camera2/X 會先完成初始化,再存取擴充器類別。

  3. 例項化 Extender 類別:

    為擴充功能例項化 Extender 類別。擴充器有兩種:基本擴充器和進階擴充器。您必須為所有擴充功能實作一個 Extender 型別。詳情請參閱「基本擴充器與進階擴充器」。

    Camera2/X 會例項化 Extender 類別並與之互動,以擷取資訊及啟用擴充功能。針對特定擴充功能,Camera2/X 可多次例項化 Extender 類別。因此,請勿在建構函式或 init() 呼叫中執行大量初始化作業。只有在攝影機工作階段即將開始時,才執行大量工作,例如在 Basic Extender 中呼叫 onInit(),或在 Advanced Extender 中呼叫 initSession()

    如果是 Night 擴充功能,系統會針對 Basic Extender 類型例項化下列 Extender 類別:

    • NightImageCaptureExtenderImpl.java
    • NightPreviewExtenderImpl.java

    如果是進階擴充器類型:

    • NightAdvancedExtenderImpl.java
  4. 檢查擴充功能是否適用:

    啟用擴充功能前,isExtensionAvailable() 會透過 Extender 例項檢查擴充功能是否適用於指定的攝影機 ID。

  5. 使用攝影機資訊初始化擴充器:

    Camera2/X 會在 Extender 例項上呼叫 init(),並傳遞相機 ID 和 CameraCharacteristics

  6. 查詢資訊:

    呼叫 Extender 類別,擷取支援的解析度等資訊、擷取靜態影像、擷取預估延遲時間,以及從 Extender 擷取要求鍵,準備啟用擴充功能。

  7. 在擴充器上啟用擴充功能:

    Extender 類別提供啟用類別所需的所有介面。這項機制可將 OEM 實作項目掛接到 Camera2 管道,例如插入擷取要求參數或啟用後處理器。

    如果是「進階延伸器」類型,Camera2/X 會與 SessionProcessorImpl 互動,以啟用擴充功能。Camera2/X 會呼叫 Extender 上的 createSessionProcessor(),擷取 SessionProcessorImpl 例項。

以下各節將詳細說明擴充功能流程。

版本驗證

從裝置載入 OEM 供應商程式庫時,Camera2/X 會驗證程式庫是否與 extensions-interface 版本相容。extensions-interface 使用語意化版本,或 MAJOR.MINOR.PATCH,例如 1.1.0 或 1.2.0。不過,版本驗證期間只會使用主要和次要版本。

如要驗證版本,請使用支援的 extensions-interface 版本呼叫 Camera2/X 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如要使用某些功能來實作擴充功能,建議從特定版本開始啟用擴充功能。在這種情況下,當 Camera2/X 程式庫版本符合需求時,您可以傳回支援的 extensions-interface 版本。如果系統不支援 Camera2/X 版本,您可以傳回不相容的版本 (例如 99.0.0) 來停用擴充功能。

供應商程式庫初始化

驗證 OEM 程式庫實作的 extensions-interface 版本後,Camera2/X 就會啟動初始化程序。InitializerImpl.init() 方法會向 OEM 程式庫發出信號,表示應用程式嘗試使用擴充功能。

在 OEM 供應商程式庫呼叫 OnExtensionsInitializedCallback.onSuccess() 通知初始化完成前,Camera2/X 不會呼叫 OEM 程式庫 (版本檢查除外)。

您必須實作 InitializerImpl (自 extensions-interface 1.1.0 起)。如果 OEM 供應商程式庫實作 extensions-interface 1.0.0,Camera2/X 會略過程式庫初始化步驟。

基本延伸護欄與進階延伸護欄

extensions-interface 導入方式有兩種:基本擴充器和進階擴充器。自 extensions-interface 1.2.0 起,系統支援進階擴充器。

針對在相機 HAL 中處理圖片的擴充功能,或使用可處理 YUV 串流的後續處理器,實作基本擴充功能。

針對需要自訂 Camera2 串流設定,並視需要傳送擷取要求的擴充功能,實作 Advanced Extender。

比較結果如下表所示:

基本延伸護欄 進階延長線
串流設定 固定
預覽:PRIVATEYUV_420_888 (如有處理器)
仍會擷取:JPEGYUV_420_888 (如有處理器)
原始設備製造商 (OEM) 可自訂。
傳送擷取要求 只有 Camera2/X 可以傳送擷取要求。您可以為這些要求設定參數。如果提供影像擷取處理器,Camera2/X 可以傳送多個擷取要求,並將所有圖片和擷取結果傳送至處理器。 系統會提供 RequestProcessorImpl 執行個體,供您執行 Camera2 擷取要求,並取得結果和圖片。

Camera2/X 會在 SessionProcessorImpl 上叫用 startRepeatingstartCapture,分別向 OEM 發出信號,要求開始重複預覽要求,以及啟動靜態影像擷取序列。

攝影機管道中的掛鉤
  • onPresetSession 提供工作階段參數。
  • onEnableSession 會在設定 CameraCaptureSession 後立即傳送單一要求。
  • onDisableSession 會在 CameraCaptureSession 關閉前傳送單一要求。
  • initSession 會初始化並傳回自訂的 camera2 工作階段設定,用於建立擷取工作階段。
  • onCaptureSessionStart 會在設定 CameraCaptureSession 後立即叫用。
  • onCaptureSessionEnd 會在 CameraCaptureSession 關閉前叫用。
適用於 在相機 HAL 或處理 YUV 圖片的處理器中導入的擴充功能。
  • 提供以 Camera2 為基礎的擴充功能實作項目。
  • 需要自訂串流設定,例如原始串流。
  • 需要互動式擷取序列。
支援的 API 版本 Camera2 擴充功能:Android 13 以上版本
CameraX 擴充功能: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 介面提供多個相機管道的掛鉤。每種擴充功能類型都有對應的擴充器類別,OEM 必須實作這些類別。

下表列出 OEM 必須為每個擴充功能實作的擴充器類別:

要實作的擴充程式類別
夜晚 NightPreviewExtenderImpl.java

NightImageCaptureExtenderImpl.java

HDR HdrPreviewExtenderImpl.java

HdrImageCaptureExtenderImpl.java

自動 AutoPreviewExtenderImpl.java

AutoImageCaptureExtenderImpl.java

散景 BokehPreviewExtenderImpl.java

BokehImageCaptureExtenderImpl.java

修容 BeautyPreviewExtenderImpl.java

BeautyImageCaptureExtenderImpl.java

在以下範例中,我們使用 PreviewExtenderImplImageCaptureExtenderImpl 做為預留位置。請將這些名稱換成您要實作的實際檔案名稱。

基本擴充器具備下列功能:

  • 設定 CameraCaptureSession (onPresetSession) 時,請插入工作階段參數。
  • 通知您擷取工作階段的開始和關閉事件,並傳送單一要求,將傳回的參數 (onEnableSessiononDisableSession) 通知 HAL。
  • 為要求插入擷取參數 (PreviewExtenderImpl.getCaptureStageImageCaptureExtenderImpl.getCaptureStages)。
  • 新增預覽和靜態影像擷取的處理器,這些處理器可處理 YUV_420_888 串流。

我們來看看 Camera2/X 如何叫用 extensions-interface,以達成上述三種應用程式流程。

應用程式流程 1:檢查擴充功能是否可用

BasicExtenderAppFlow1

圖 3. 基本擴充器上的應用程式流程 1

在此流程中,Camera2/X 會直接呼叫 PreviewExtenderImplImageCaptureExtenderImplisExtensionAvailable() 方法,而不會呼叫 init()。兩個擴充器類別都必須傳回 true,才能啟用擴充功能。

應用程式通常會先執行這個步驟,檢查指定相機 ID 是否支援指定擴充功能類型,再啟用擴充功能。這是因為部分擴充功能僅支援特定攝影機 ID。

應用程式流程 2:查詢資訊

BasicExtenderAppFlow2

圖 4. 基本擴充器上的應用程式流程 2

判斷擴充功能是否可用後,應用程式應先查詢下列資訊,再啟用擴充功能。

  • 仍會擷取延遲範圍: ImageCaptureExtenderImpl.getEstimatedCaptureLatencyRange 會傳回應用程式的擷取延遲範圍,以評估是否適合為目前情境啟用擴充功能。

  • 預覽和擷取介面支援的大小: ImageCaptureExtenderImpl.getSupportedResolutionsPreviewExtenderImpl.getSupportedResolutions 會傳回圖片格式清單,以及介面格式和大小支援的大小。

  • 支援的要求和結果鍵: Camera2/X 會呼叫下列方法,從實作項目中擷取支援的擷取要求鍵和結果鍵:

    • ImageCaptureExtenderImpl.getAvailableCaptureRequestKeys
    • ImageCaptureExtenderImpl.getAvailableCapturetResultKeys

Camera2/X 一律會先在這些擴充程式類別上呼叫 init(),再查詢更多資訊。

應用程式流程 3:啟用擴充功能後預覽/拍攝靜態相片 (HAL 實作)

BasicExtenderAppFlow3

圖 5. 基本擴充器上的應用程式流程 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 會將結果圖像 (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
  • Flash:
    • 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,表示應用程式只支援縮放功能,不允許輕觸對焦、閃光燈和曝光補償。

進階延伸護欄

進階擴充器是根據 Camera2 API 實作的供應商類型。這個擴充器類型是在 extensions-interface 1.2.0 中新增。視裝置製造商而定,擴充功能可能會在應用程式層級實作,這取決於下列因素:

  • 自訂串流設定:設定 RAW 串流等自訂串流,或為不同實體攝影機 ID 設定多個串流。

  • 傳送 Camera2 要求的機能:支援複雜的互動邏輯,可根據先前要求的結果傳送含有參數的擷取要求。

Advanced Extender 提供封裝或中介層,方便您自訂串流設定,並視需要傳送擷取要求。

要導入的檔案

如要切換至進階擴充程式實作,ExtensionVersionImpl 中的 isAdvancedExtenderImplemented() 方法必須傳回 true。針對每種擴充功能類型,原始設備製造商必須實作對應的擴充器類別。進階擴充器導入檔案位於 advanced 套件中。

要實作的擴充程式類別
夜晚 advanced/NightAdvancedExtenderImpl.java
HDR advanced/HdrAdvancedExtenderImpl.java
自動 advanced/AutoAdvancedExtenderImpl.java
散景 advanced/BokehAdvancedExtenderImpl.java
臉部潤飾 advanced/BeautyAdvancedExtenderImpl.java

在以下範例中,我們使用 AdvancedExtenderImpl 做為預留位置。請將其替換為您要實作的擴充功能適用的擴充程式檔案名稱。

我們來看看 Camera2/X 如何叫用 extensions-interface,實現三種應用程式流程。

應用程式流程 1:檢查擴充功能是否可用

AdvancedAppFlow1

圖 8. Advanced Extender 上的應用程式流程 1

首先,應用程式會檢查是否支援指定的擴充功能。

應用程式流程 2:查詢資訊

AdvancedAppFlow2

圖 9.Advanced Extender 上的應用程式流程 2

呼叫 AdvancedExtenderImpl.init() 後,應用程式可以查詢 AdvancedExtenderImpl 上的下列資訊:

  • 預估靜態擷取延遲時間: AdvancedExtenderImpl.getEstimatedCaptureLatencyRange() 會傳回應用程式的擷取延遲時間範圍,以評估是否適合為目前情境啟用擴充功能。

  • 預覽和靜態影像擷取支援的解析度:

    • AdvancedExtenderImpl.getSupportedPreviewOutputResolutions() 會傳回圖片格式對應的尺寸清單,這些尺寸支援預覽畫面格式和大小。原始設備製造商必須至少支援 PRIVATE 格式。

    • AdvancedExtenderImpl.getSupportedCaptureOutputResolutions() 會傳回靜態擷取介面支援的格式和大小。原始設備製造商必須支援 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. 進階擴充器上的應用程式流程 3

上圖顯示啟動預覽和擷取進階擴充器類型靜態影像的主要流程。接下來逐一說明各個步驟。

  1. SessionProcessorImpl 執行個體

    核心的 Advanced Extender 實作項目位於 SessionProcessorImpl,負責提供自訂工作階段設定,並傳送擷取要求,以啟動預覽和靜態擷取要求。AdvancedExtenderImpl.createSessionProcessor() 會叫用來傳回 SessionProcessorImpl 例項。

  2. initSession

    SessionProcessorImpl.initSession() 會初始化擴充功能的會期。您可以在這裡分配資源,並傳回工作階段設定,以準備 CameraCaptureSession

    就輸入參數而言,Camera2/X 會指定預覽、靜態擷取和選用 YUV 圖片分析的輸出介面設定。這個輸出內容介面設定 (OutputSurfaceImpl) 包含透過 AdvancedExtenderImpl 中的下列方法擷取的介面、大小和圖片格式:

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

    您必須傳回 Camera2SessionConfigImpl 執行個體,其中包含 Camera2OutputConfigImpl 執行個體清單,以及用於設定 CameraCaptureSession 的工作階段參數。您有責任將正確的攝影機圖像輸出至 Camera2/X 傳入的輸出介面。以下提供幾種啟用輸出內容的方式:

    • 在攝影機 HAL 中處理:您可以直接將輸出介面新增至 CameraCaptureSession,並實作 SurfaceOutputConfigImpl。這會將提供的輸出介面設定為攝影機管道,並允許攝影機 HAL 處理圖片。
    • 處理中繼 ImageReader 表面 (RAW、YUV 等):將中繼 ImageReader 表面新增至 CameraCaptureSession,並使用 ImageReaderOutputConfigImpl 執行個體。

      您需要處理中間圖片,並將結果圖片寫入輸出介面。

    • 使用 Camera2 Surface 分享功能:將任何 Camera2OutputConfigImpl 執行個體新增至另一個 Camera2OutputConfigImpl 執行個體的 getSurfaceSharingOutputConfigs() 方法,即可與其他 Surface 分享 Surface。表面格式和大小必須相同。

    所有 Camera2OutputConfigImpl (包括 SurfaceOutputConfigImplImageReaderOutputConfigImpl) 都必須有專屬 ID (getId()),用於指定目標介面,並從 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() 中未宣傳的任何擷取要求金鑰。

    startTrigger()extensions-interface 1.3.0 版起提供支援。應用程式可透過擴充功能實作輕觸對焦和閃光燈功能。

  6. 清理

    結束擷取工作階段時,系統會先叫用 SessionProcessorImpl.onCaptureSessionEnd(),再關閉 CameraCaptureSession。擷取工作階段關閉後,deInitSession() 會執行清除作業。

支援預覽、靜態影像擷取和圖像分析

您應該將擴充功能套用至預覽和靜態影像擷取用途。不過,如果延遲時間過長,無法順暢顯示預覽畫面,您可以只對靜態擷取套用擴充功能。

如果是「基本擴充器」類型,無論是否啟用擴充器預覽功能,您都必須為指定擴充器實作 ImageCaptureExtenderImplPreviewExtenderImpl。應用程式通常也會使用 YUV 串流分析圖片內容,例如尋找 QR code 或文字。為進一步支援這個用途,您應支援預覽、靜態影像擷取和 YUV_420_888 串流的組合,以設定 CameraCaptureSession。也就是說,如果您實作處理器,就必須支援三種 YUV_420_888 串流的串流組合。

如果是 Advanced Extender,Camera2/X 會將三個輸出介面傳遞至 SessionProcessorImpl.initSession() 呼叫。這些輸出介面分別用於預覽、靜態影像擷取和圖像分析。請務必確保預覽畫面和靜態影像擷取輸出介面顯示有效輸出內容。不過,如果是圖片分析輸出介面,請確保只有在非空值時才運作。如果實作項目無法支援圖像分析串流,您可以在 AdvancedExtenderImpl.getSupportedYuvAnalysisResolutions() 中傳回空白清單。這可確保 SessionProcessorImpl.initSession() 中的圖像分析輸出介面一律為空值。

支援錄影

目前的 Camera Extension 架構僅支援預覽和靜態影像擷取的使用情境。我們不支援在 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
    }
  }

}

如要支援擷取處理進度回呼,擴充功能廠商的實作方式必須使用目前進度值呼叫下列回呼:

瀏覽後仍擷取

在 Android 14 以上版本,相機擴充功能可以使用 setPostviewOutputConfiguration 提供後視畫面 (預覽圖片)。為提升使用者體驗,當擴充功能處理延遲時間增加時,應用程式可以顯示後視圖片做為預留位置,並在最終圖片可用時替換該圖片。應用程式可使用下列參考程式碼,設定及發出後續瀏覽擷取要求:

{

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()

擴充功能介面版本記錄

下表顯示 Camera Extension 介面版本記錄。請務必導入最新版本的供應商程式庫。

版本 新增功能
1.0.0
  • 版本驗證
    • ExtensionVersionImpl
  • 基本擴充器
    • PreviewExtenderImpl
    • ImageCaptureExtenderImpl
    • Processor
      • 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
  • 擴充功能專屬中繼資料
  • 動態靜態影像擷取延遲時間估計值
  • 擷取處理進度回呼
  • 瀏覽後仍擷取
  • 支援 SurfaceView 輸出
  • 供應商專屬工作階段類型

參考實作

frameworks/ex 提供下列參考 OEM 供應商程式庫實作。

  • advancedSample:進階擴充器的基本實作方式。

  • sample:基本擴充程式的基本實作。

  • service_based_sample:實作範例,說明如何在 Service 中代管 Camera Extensions。這項實作包含下列元件:

    • oem_library: 適用於 Camera2 和 CameraX Extensions API 的 Camera Extensions OEM 程式庫,可實作 Extensions-Interface。這會做為傳遞機制,將來自 Extensions-Interface 的呼叫轉送至服務。這個程式庫也提供 AIDL 檔案和包裝函式類別,可與服務通訊。

      進階擴充器預設為啟用。如要啟用基本擴充器,請將 ExtensionsVersionImpl#isAdvancedExtenderImplemented 變更為回傳 false

    • extensions_service: Extensions 服務的實作範例。在此處新增實作項目。服務中實作的介面與 Extensions-Interface 類似。舉例來說,實作 IAdvancedExtenderImpl.Stub 會執行與 AdvancedExtenderImpl 相同的作業。ImageWrapperTotalCaptureResultWrapper 是讓 ImageTotalCaptureResult 可封送的必要條件。

在裝置上設定供應商程式庫

OEM 供應商程式庫不會內建於應用程式中,而是由 Camera2/X 在執行階段從裝置載入。在 CameraX 中,<uses-library> 標記會宣告 androidx.camera.extensions.impl 程式庫 (定義於 camera-extensions 程式庫的 AndroidManifest.xml 檔案中) 是 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 中實作,因此必須驗證是否適用於應用程式開發人員可用的所有正交控制項。

建議同時使用擴充場景模式和 CameraExtensions 公開散景,因為應用程式可能會偏好使用特定 API 啟用散景。建議您先使用擴充場景模式,因為這是應用程式啟用散景擴充功能時,最彈性的方式。然後,您就可以根據擴充的場景模式實作攝影機擴充功能介面。如果難以在相機 HAL 中實作散景效果 (例如需要應用程式層執行的後續處理器來處理圖片),建議使用 Camera Extensions 介面實作散景擴充功能。

常見問題 (FAQ)

API 級別是否有任何限制?

可以。這取決於 OEM 供應商程式庫實作項目所需的 Android API 功能集。舉例來說,ExtenderStateListener.onPresetSession() 會使用 SessionConfiguration.setSessionParameters() 呼叫設定一組基準代碼。這項呼叫僅適用於 API 級別 28 以上的版本。如要瞭解特定介面方法,請參閱 API 參考說明文件