相機擴充功能

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

如需支援的擴充功能清單 (在 Camera2 和 CameraX 中相同),請參閱 CameraX Extensions API。如要新增擴充功能,請透過 Issue Tracker 回報錯誤。

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

建築

下圖說明相機擴充功能介面或 extensions-interface 的架構:建築

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

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

導入原始設備製造商 (OEM) 供應商程式庫

如要實作 OEM 供應商程式庫,請將 camera-extensions-stub 檔案複製到系統程式庫專案中。這些檔案會定義相機擴充功能介面。

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

Bokeh 擴充工具類別 (如果支援 Bokeh 擴充功能,即可實作)

  • 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

修容擴充功能類別 (如果支援 Face Retouch 擴充功能,即可實作)

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

公用程式 (選用,可刪除)

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

您不需要為每個擴充功能提供實作項目。如果您未實作擴充功能,請將 isExtensionAvailable() 設為傳回 false,或移除對應的 Extender 類別。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 類別。擴充功能有兩種類型:基本擴充功能和進階擴充功能。您必須為所有擴充功能實作一個擴充功能類型。詳情請參閱「基本擴充功能與進階擴充功能」。

    Camera2/X 會將 Extender 類別例項化並與其互動,以便擷取資訊並啟用擴充功能。針對特定擴充功能,Camera2/X 可以多次將 Extender 類別例項化。因此,請勿在建構函式或 init() 呼叫中執行繁重的工作初始化作業。只有在相機工作階段即將開始時才執行繁重的工作,例如在基本擴充功能中呼叫 onInit(),或在進階擴充功能中呼叫 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。不過,驗證版本時只會使用主要和次要版本。

如要驗證版本,Camera2/X 會使用支援的 extensions-interface 版本呼叫 ExtensionVersionImpl.checkApiVersion()。接著,Camera2/X 會使用 OEM 程式庫回報的版本,判斷是否可以啟用擴充功能,以及該擴充功能應叫用哪些功能。

主要版本相容性

如果 extension-interface 的主要版本在 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 會略過程式庫初始化步驟。

基本延伸功能與進階延伸功能

extensions-interface 實作方式分為兩種:基本擴充功能和進階擴充功能。extensions-interface 1.2.0 以上版本支援進階延伸功能。

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

針對需要自訂 Camera2 串流設定及傳送擷取要求的擴充功能,實作進階擴充程式。

請參閱下表的比較結果:

基本延伸器 進階延伸功能
串流設定 已修正
預覽: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 工作階段設定,用於建立擷取工作階段。
  • 系統會在設定 CameraCaptureSession 後立即叫用 onCaptureSessionStart
  • onCaptureSessionEnd 會在 CameraCaptureSession 關閉前呼叫。
適合 在相機 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, ...)

基本延長線

基本擴充介面會在相機管道中的多個位置提供鉤子。每個擴充功能類型都有對應原始設備製造商 (OEM) 需實作的擴充工具類別。

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

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

NightImageCaptureExtenderImpl.java

HDR HdrPreviewExtenderImpl.java

HdrImageCaptureExtenderImpl.java

自動 AutoPreviewExtenderImpl.java

AutoImageCaptureExtenderImpl.java

Bokeh BokehPreviewExtenderImpl.java

BokehImageCaptureExtenderImpl.java

修容 BeautyPreviewExtenderImpl.java

BeautyImageCaptureExtenderImpl.java

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

基本擴充功能提供下列功能:

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

讓我們看看 Camera2/X 如何叫用 extensions-interface,以實現上述三個應用程式流程。

應用程式流程 1:檢查擴充功能的可用性

BasicExtenderAppFlow1

圖 3. 在 Basic Extender 上執行應用程式流程 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. 在 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 必須傳回處理 TotalCaptureResult 例項的 RequestUpdateProcessorImpl 執行個體,並傳回 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 介面。

您可以在傳送仍在擷取要求之前,放心假設預覽已經啟用並執行。

請參閱下圖中的流程:

擷取處理器

圖 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);
}

針對縮放、輕觸對焦、閃光燈和曝光補償等常見的相機作業,建議您同時支援以下按鍵來擷取要求和拍攝結果:

  • Zoom:
    • 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 以上版本的基本擴充功能,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 要求的能力:支援複雜的互動邏輯,可根據先前要求的結果傳送帶有參數的擷取要求。

進階延伸元件會提供包裝函式或中介層,讓您自訂串流設定,並視需要傳送擷取要求。

要實作的檔案

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

要實作的擴充類別
夜晚 advanced/NightAdvancedExtenderImpl.java
HDR advanced/HdrAdvancedExtenderImpl.java
自動 advanced/AutoAdvancedExtenderImpl.java
Bokeh advanced/BokehAdvancedExtenderImpl.java
修容 advanced/BeautyAdvancedExtenderImpl.java

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

現在來看看 Camera2/X 如何叫用 extensions-interface 來完成三個應用程式流程。

應用程式流程 1:檢查擴充功能的可用性

AdvancedAppFlow1

圖 8. 進階擴展器上的應用程式流程 1

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

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

AdvancedAppFlow2

圖 9.進階擴展器的應用程式流程 2

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

  • 預估仍會擷取延遲時間: AdvancedExtenderImpl.getEstimatedCaptureLatencyRange() 會傳回擷取延遲時間的範圍,讓應用程式評估是否能在目前情境中啟用擴充功能。

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

    • AdvancedExtenderImpl.getSupportedPreviewOutputResolutions() 會將圖片格式對應至預覽途徑格式和大小的支援大小清單。原始設備製造商 (OEM) 至少必須支援 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:啟用擴充功能的預覽/靜態影像擷取

進階應用程式 Flow3

圖 10. 進階擴展器的應用程式流程 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() 方法,即可使用途徑共用功能與其他途徑。表面格式和大小必須相同。

    包括 SurfaceOutputConfigImplImageReaderOutputConfigImpl 等所有 Camera2OutputConfigImpl 都必須有專屬 ID (getId()),用於指定目標介面並從 ImageReaderOutputConfigImpl 擷取圖片。

  3. onCaptureSessionStartRequestProcessorImpl

    CameraCaptureSession 啟動且相機架構叫用 onConfigured() 時,Camera2/X 就會使用 Camera2 要求包裝函式 RequestProcessImpl 叫用 SessionProcessorImpl.onCaptureSessionStart()。Camera2/X 會實作 RequestProcessImpl,讓您執行擷取要求,並在使用 ImageReaderOutputConfigImpl擷取圖片

    RequestProcessImpl API 在執行要求方面與 Camera2 CameraCaptureSession API 類似。兩者之間的差異如下:

    • 目標途徑會透過 Camera2OutputConfigImpl 例項的 ID 指定。
    • 可擷取 ImageReader 的圖片。

    您可以使用指定的 Camera2OutputConfigImpl ID 呼叫 RequestProcessorImpl.setImageProcessor(),以便註冊 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 code 或文字。為進一步支援此用途,您應支援預覽、靜態影像擷取和 YUV_420_888 串流的串流組合,以便設定 CameraCaptureSession。也就是說,如果您實作處理器,就必須支援三個 YUV_420_888 串流的串流組合。

對於進階擴充功能,Camera2/X 會將三個輸出途徑傳遞至 SessionProcessorImpl.initSession() 呼叫。這些輸出介面分別用於預覽、靜態擷取和圖片分析。您必須確保預覽且仍可擷取輸出介面,顯示有效的輸出內容。但是,如果是圖片分析輸出介面,請確保只有非空值時才能正常運作。如果您的實作不支援圖片分析串流,您可以在 AdvancedExtenderImpl.getSupportedYuvAnalysisResolutions() 中傳回空白清單。這可確保圖片分析輸出介面在 SessionProcessorImpl.initSession() 中一律為空值。

支援錄影

目前的 CameraX 擴充功能架構僅支援預覽和靜態影像拍攝用途。我們不支援在 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()

擴充功能介面版本記錄

下表顯示相機擴充功能介面版本記錄。您應一律使用最新版本的供應商程式庫。

版本 新增功能
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 中託管相機擴充功能的實作。這個實作包含下列元件:

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

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

    • extensions_service:Extensions Service 的範例實作。請在此處新增實作內容。在服務中實作的介面類似於 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,才能查詢裝置是否支援擴充功能。如要這麼做,請在裝置製造檔案中加入下列一行:

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

驗證

如要在開發階段測試 OEM 供應商程式庫的導入方式,請使用 androidx-main/camera/integration-tests/extensionstestapp/ 中的範例應用程式,該應用程式會透過各種供應商擴充功能執行。

完成導入後,請使用相機擴充功能驗證工具執行自動化和手動測試,驗證供應商程式庫是否正確導入。

擴充場景模式與相機擴充功能

針對 Bokeh 擴充功能,除了使用相機擴充功能外,您還可以使用擴充場景模式來公開該擴充功能,這項模式可透過 CONTROL_EXTENDED_SCENE_MODE 鍵啟用。如要進一步瞭解實作方式,請參閱「相機散景效果」。

與相機 2 應用程式的相機擴充功能相比,擴充場景模式的限制較少。舉例來說,您可以在支援彈性串流組合和擷取要求參數的一般 CameraCaptureSession 執行個體中啟用擴充場景模式。相較之下,相機擴充功能只支援固定的串流類型,且對擷取要求參數的支援有限。

擴充場景模式的缺點是,您只能在相機 HAL 中實作這項模式,也就是說,您必須驗證這項模式是否可在應用程式開發人員可用的所有直角控制項中運作。

建議您同時使用延伸場景模式和相機擴充功能公開散景,因為應用程式可能偏好使用特定 API 啟用散景。我們建議您先使用擴充場景模式,因為這是應用程式啟用 bokeh 擴充功能最具彈性的做法。然後,您可以根據延伸場景模式實作相機擴充功能介面。如果在相機 HAL 中實作散景效果很困難,例如因為需要在應用程式層級執行後置處理器來處理圖片,建議您使用相機擴充功能介面實作散景效果擴充功能。

常見問題 (FAQ)

API 級別是否有任何限制?

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