設備製造商可以透過 OEM 供應商庫提供的相機擴充介面向第三方開發者公開散景、夜間模式和 HDR 等擴充。開發人員可以使用Camera2 擴充 API和CameraX 擴充 API來存取 OEM 供應商庫中實現的擴充。
有關支援的擴充功能清單(Camera2 和 CameraX 中的擴充功能相同),請參閱CameraX 擴充 API 。如果您想新增擴展,請使用問題追蹤器提交錯誤。
本頁介紹如何在裝置上實施和啟用 OEM 供應商庫。
建築學
下圖描述了相機擴充介面或extensions-interface
的架構:
圖 1. Camera Extensions 架構圖
如圖所示,要支援Camera Extensions,您需要實作OEM供應商庫提供的extensions-interface
。您的 OEM 供應商庫啟用兩個 API: CameraX Extensions API和Camera2 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擴充類別(如果支援Face Retouch擴充則實作它)
-
BeautyImageCaptureExtenderImpl.java
-
BeautyPreviewExtenderImpl.java
-
advanced/BeautyAdvancedExtenderImpl.java
實用程式(可選,可刪除)
-
advanced/Camera2OutputConfigImplBuilder.java
-
advanced/Camera2SessionConfigImplBuilder.java
您不需要為每個擴充功能提供實作。如果您沒有實作擴展,請將isExtensionAvailable()
設定為傳回false
或刪除對應的 Extender 類別。 Camera2 和 CameraX 擴充 API 向應用程式報告擴充功能不可用。
讓我們了解一下 Camera2 和 CameraX 擴充 API 如何與供應商庫互動以啟用擴充功能。下圖以夜間擴展為例說明了端到端流程:
圖 2.夜間擴展實施
版本驗證:
Camera2/X 呼叫
ExtensionVersionImpl.checkApiVersion()
以確保 OEM 實作的extensions-interface
版本與 Camera2/X 支援的版本相容。供應商庫初始化:
InitializerImpl
有一個init()
方法,用來初始化供應商函式庫。 Camera2/X 在存取 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
-
檢查擴充可用性:
在啟用擴充之前,
isExtensionAvailable()
透過 Extender 實例檢查該擴充功能是否在指定攝影機 ID 上可用。使用相機資訊初始化擴展器:
Camera2/X 在 Extender 實例上呼叫
init()
並向其傳遞相機 ID 和CameraCharacteristics
。查詢資訊:
呼叫 Extender 類別來檢索支援的分辨率等信息,仍然捕獲估計的延遲,並從 Extender 捕獲請求密鑰以準備啟用擴展。
在擴充器上啟用擴充:
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 庫報告的版本來確定是否可以啟用擴充功能以及應呼叫哪些功能。
主要版本相容性
如果 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 起就支援Advanced Extender。
實作基本擴充器以進行擴展處理相機 HAL 中的影像或使用能夠處理 YUV 流的後處理器。
為需要自訂 Camera2 流配置並根據需要發送捕獲請求的擴充實作進階擴充器。
對比見下表:
基本擴充器 | 進階擴充器 | |
---|---|---|
串流配置 | 固定的 預覽: PRIVATE 或YUV_420_888 (如果處理器存在)靜態捕獲: JPEG 或YUV_420_888 (如果處理器存在) | 可按 OEM 定制。 |
發送捕獲請求 | 只有 Camera2/X 可以發送捕獲請求。您可以為這些請求設定參數。當處理器提供影像擷取時,Camera2/X 可以發送多個擷取請求,並將所有影像和擷取結果傳送到處理器。 | 為您提供了一個RequestProcessorImpl 實例來執行camera2擷取請求並取得結果和影像。 Camera2/X 呼叫 |
相機管道中的掛鉤 |
|
|
適合於 | 在相機 HAL 或處理 YUV 影像的處理器中實現的擴展。 |
|
支援的API版本 | Camera2 擴充:Android 13 或更高版本 CameraX 擴充: camera-extensions 1.1.0 或更高版本 | Camera2 擴充:Android 12L 或更高版本 CameraX 擴充: camera-extensions 1.2.0-alpha03 或更高版本 |
應用程式流程
下表顯示了三種類型的應用程式流程及其對應的相機擴充 API 呼叫。雖然 Camera2/X 提供這些 API,但您必須正確實作供應商庫來支援這些流程,我們將在後面的部分中更詳細地描述這些流程。
相機2擴充 | CameraX 擴充 | |
---|---|---|
查詢擴充可用性 | CameraExtensionCharacteristics . getSupportedExtensions | ExtensionsManager. isExtensionAvailable |
查詢資訊 | CameraExtensionCharacteristics. getExtensionSupportedSizes CameraExtensionCharacteristics. getEstimatedCaptureLatencyRangeMillis CameraExtensionCharacteristics. getAvailableCaptureRequestKeys CameraExtensionCharacteristics. getAvailableCaptureResultKeys | ExtensionsManager. getEstimatedCaptureLatencyRange CameraX 處理庫中的其餘資訊。 |
啟用擴展後預覽和靜態捕獲 | CameraDevice. createExtensionSession | val cameraSelector = ExtensionsManager. getExtensionEnabledCameraSelector bindToLifecycle(lifecycleOwner,cameraSelector,預覽,...) |
基本擴充器
Basic Extender 介面提供了與相機管道中多個位置的掛鉤。每個擴充類型都有 OEM 需要實作的對應 Extender 類別。
下表列出了 OEM 需要為每個擴展實現的擴展器類別:
要實現的擴展類 | |
---|---|
夜晚 | NightPreviewExtenderImpl.java |
高動態範圍 | HdrPreviewExtenderImpl.java |
汽車 | AutoPreviewExtenderImpl.java |
散景 | BokehPreviewExtenderImpl.java |
臉部修飾 | BeautyPreviewExtenderImpl.java |
在下列範例中,我們使用PreviewExtenderImpl
和ImageCaptureExtenderImpl
作為佔位符。將它們替換為您正在實現的實際文件的名稱。
基本擴充器具有以下功能:
- 配置
CameraCaptureSession
(onPresetSession
) 時注入會話參數。 - 通知您捕獲會話開始和關閉事件,並發送單一請求以使用傳回的參數(
onEnableSession
、onDisableSession
)通知 HAL。 - 為請求注入捕獲參數(
PreviewExtenderImpl.getCaptureStage
、ImageCaptureExtenderImpl.getCaptureStages
)。 - 新增能夠處理
YUV_420_888
流的預覽和靜態捕獲處理器。
讓我們看看Camera2/X如何呼叫extensions-interface
來實作上述三個應用程式流程。
應用流程 1:檢查擴充可用性
圖 3. Basic Extender 上的應用程式流程 1
在此流程中,Camera2/X 直接呼叫PreviewExtenderImpl
和ImageCaptureExtenderImpl
的isExtensionAvailable()
方法,而不呼叫init()
。兩個 Extender 類別都必須回傳true
才能啟用擴充。
這通常是應用程式在啟用擴充功能之前檢查給定相機 ID 是否支援給定擴充類型的第一步。這是因為某些擴充功能僅在某些相機 ID 上支援。
應用流程2:查詢訊息
圖 4. Basic Extender 上的應用程式流程 2
在確定擴充功能是否可用後,應用程式應在啟用擴充功能之前查詢以下資訊。
仍然會擷取延遲範圍:
ImageCaptureExtenderImpl.getEstimatedCaptureLatencyRange
傳回應用程式的擷取延遲範圍,以評估是否適合為目前場景啟用擴充。預覽和捕獲表面支援的尺寸:
ImageCaptureExtenderImpl.getSupportedResolutions
和PreviewExtenderImpl.getSupportedResolutions
傳回表面格式和尺寸支援的影像格式和尺寸清單。支援的請求和結果鍵: Camera2/X 呼叫以下方法從您的實作中擷取支援的擷取請求鍵和結果鍵:
-
ImageCaptureExtenderImpl.getAvailableCaptureRequestKeys
-
ImageCaptureExtenderImpl.getAvailableCapturetResultKeys
-
在查詢更多資訊之前,Camera2/X 總是先在這些 Extender 類別上呼叫init()
。
應用程式流程 3:啟用擴充的預覽/靜態捕捉(HAL 實作)
圖 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
進行預覽。流程見下圖:
圖 6.使用PreviewImageProcessorImpl
進行預覽流程
PreviewImageProcessorImpl
介面擴充了ProcessImpl
並且有三個重要方法:
onOutputSurface(Surface surface, int imageFormat)
設定處理器的輸出表面。對於PreviewImageProcessorImpl
,imageFormat
是像素格式,例如PixelFormat.RGBA_8888
。onResolutionUpdate(Size size)
設定輸入影像的大小。onImageFormatUpdate(int imageFormat)
設定輸入影像的影像格式。目前只能是YUV_420_888
。
影像捕捉處理器
對於靜態捕獲,您可以透過使用ImageCaptureExtenderImpl.getCaptureProcessor
返回CaptureProcessorImpl
實例來實現處理器。處理器負責處理捕獲的YUV_420_888
影像和TotalCaptureResult
實例的列表,並將輸出寫入YUV_420_888
表面。
您可以放心地假設在發送靜態捕獲請求之前預覽已啟用並正在運行。
流程見下圖:
圖 7.使用CaptureProcessorImpl
進行靜態擷取流程
Camera2/X 使用
YUV_420_888
格式表面進行靜態捕捉來設定捕捉工作階段。 Camera2/X 透過呼叫以下方式來準備CaptureProcessorImpl
:-
CaptureProcessorImpl.onImageFormatUpdate()
與YUV_420_888
。 -
CaptureProcessorImpl.onResolutionUpdate()
與輸入影像大小。 -
CaptureProcessorImpl.onOutputSurface()
具有輸出YUV_420_888
表面。
-
ImageCaptureExtenderImpl.getCaptureStages
傳回CaptureStageImpl
的列表,其中每個元素對應到帶有由 Camera2/X 發送的捕獲參數的CaptureRequest
實例。例如,如果它傳回三個CaptureStageImpl
實例的列表,則 Camera2/X 使用captureBurst
API 發送三個帶有相應捕獲參數的捕獲請求。接收到的映像和
TotalCaptureResult
實例捆綁在一起並傳送到CaptureProcessorImpl
進行處理。CaptureProcessorImpl
將結果影像(YUV_420_888
格式)寫入onOutputSurface()
呼叫指定的輸出表面。如果需要,Camera2/X 會將其轉換為 JPEG 影像。
支援捕獲請求key和結果
除了相機預覽和拍攝之外,應用程式還可以設定變焦、閃光參數或觸發點擊對焦。這些參數可能與您的擴充實作不相容。
以下方法已新增至extensions-interface
1.3.0 中,以允許您公開您的實作支援的參數:
-
ImageCaptureExtenderImpl.getAvailableCaptureRequestKeys()
傳回您的實作支援的擷取請求金鑰。 -
ImageCaptureExtenderImpl.getAvailableCaptureResultKeys()
傳回擷取結果中包含的擷取結果鍵。
如果相機 HAL 處理擴展,Camera2/X 將在CameraCaptureSession.CaptureCallback
中擷取擷取結果。但是,如果實作了處理器,則 Camera2/X 會在ProcessResultImpl
中檢索擷取結果,並將其傳遞給PreviewImageProcessorImpl
和CaptureProcessorImpl
中的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 或先前版本的基本擴充器,CameraX 擴充 API 明確支援上述所有鍵。對於extensions-interface
1.3.0,CameraX 和 Camera2 均遵循傳回的列表,並且僅支援其中包含的鍵。例如,如果您決定在 1.3.0 實作中僅傳回CaptureRequest#CONTROL_ZOOM_RATIO
和CaptureRequest#SCALER_CROP_REGION
,則表示應用程式僅支援縮放,而不允許點擊對焦、閃光和曝光補償。
進階擴充器
Advanced Extender 是一種基於 Camera2 API 的供應商實作。此擴展器類型是在extensions-interface
1.2.0 中新增的。根據設備製造商的不同,擴展可能會在應用層實現,這取決於以下因素:
自訂串流配置:配置自訂串流(如 RAW 串流)或為不同的實體攝影機 ID 提供多個串流。
發送Camera2請求的能力:支援複雜的交互邏輯,可以根據先前請求的結果發送帶有參數的捕獲請求。
Advanced Extender 提供了一個包裝器或中間層,因此您可以自訂流程配置並按需發送擷取請求。
實施文件
要切換到 Advanced Extender 實現, ExtensionVersionImpl
中的isAdvancedExtenderImplemented()
方法必須傳回true
。對於每種擴充類型,OEM 必須實作對應的 Extender 類別。 Advanced Extender 實作檔案位於進階包中。
要實現的擴展類 | |
---|---|
夜晚 | advanced/NightAdvancedExtenderImpl.java |
高動態範圍 | advanced/HdrAdvancedExtenderImpl.java |
汽車 | advanced/AutoAdvancedExtenderImpl.java |
散景 | advanced/BokehAdvancedExtenderImpl.java |
臉部修飾 | advanced/BeautyAdvancedExtenderImpl.java |
在以下範例中,我們使用AdvancedExtenderImpl
作為佔位符。將其替換為您正在實現的擴充功能的擴充功能檔案的名稱。
讓我們看看Camera2/X如何呼叫extensions-interface
來實作三個應用程式流程。
應用流程 1:檢查擴充可用性
圖 8. Advanced Extender 上的應用程式流程 1
首先,應用程式檢查是否支援給定的擴充。
應用流程2:查詢訊息
圖 9. Advanced Extender 上的應用程式流程 2
呼叫AdvancedExtenderImpl.init()
後,應用程式可以查詢AdvancedExtenderImpl
的以下資訊:
估計的靜態擷取延遲:
AdvancedExtenderImpl.getEstimatedCaptureLatencyRange()
傳回擷取延遲的範圍,以便應用程式評估是否適合為目前場景啟用擴充。支援的預覽和靜態捕捉解析度:
AdvancedExtenderImpl.getSupportedPreviewOutputResolutions()
將影像格式對應回到預覽表面格式和尺寸支援的尺寸清單。 OEM 必須至少支援PRIVATE
格式。AdvancedExtenderImpl.getSupportedCaptureOutputResolutions()
傳回靜態擷取表面支援的格式和大小。 OEM 必須支援JPEG
和YUV_420_888
格式輸出。AdvancedExtenderImpl.getSupportedYuvAnalysisResolutions()
傳回用於影像分析的額外YUV_420_888
流支援的大小。如果不支援影像分析 YUV 表面,則getSupportedYuvAnalysisResolutions()
應傳回null
或空列表。
可用的擷取請求鍵/結果(在
extensions-interface
1.3.0 中新增):Camera2/X 呼叫下列方法從您的實作中擷取支援的擷取請求鍵和結果鍵:-
AdvancedExtenderImpl.getAvailableCaptureRequestKeys
-
AdvancedExtenderImpl.getAvailableCaptureResultKeys
-
有關詳細信息,請參閱支援捕獲請求鍵和結果。
應用程式流程 3:在啟用擴充的情況下預覽/靜態捕捉
圖 10. Advanced Extender 上的應用程式流程 3
上圖顯示了高階擴展器類型的啟動預覽和靜態捕獲的主要流程。讓我們逐步完成每個步驟。
SessionProcessorImpl
實例Advanced Extender 的核心實作位於
SessionProcessorImpl
中,它負責提供自訂會話配置並傳送擷取請求以發起預覽和靜態擷取要求。呼叫AdvancedExtenderImpl.createSessionProcessor()
以傳回SessionProcessorImpl
實例。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 實例的Camera2OutputConfigImpl
getSurfaceSharingOutputConfigs()
方法來與另一個表面共用表面。表面格式和尺寸必須相同。
所有
Camera2OutputConfigImpl
包含SurfaceOutputConfigImpl
和ImageReaderOutputConfigImpl
都必須有一個唯一的 ID (getId()
),用於指定目標表面並從ImageReaderOutputConfigImpl
檢索影像。-
onCaptureSessionStart
和RequestProcessorImpl
當
CameraCaptureSession
啟動且 Camera 框架呼叫onConfigured()
時,Camera2/X 使用 Camera2 要求包裝器RequestProcessImpl
呼叫SessionProcessorImpl.onCaptureSessionStart()
。 Camera2/X 實作了RequestProcessImpl
,它使您能夠執行擷取要求,並在使用ImageReaderOutputConfigImpl
時檢索影像。在執行請求方面,
RequestProcessImpl
API 與 Camera2CameraCaptureSession
API 類似。差異是:- 目標表面由
Camera2OutputConfigImpl
實例的 ID 指定。 - 檢索
ImageReader
影像的能力。
您可以使用指定的
Camera2OutputConfigImpl
ID呼叫RequestProcessorImpl.setImageProcessor()
來註冊ImageProcessorImpl
實例來接收映像。Camera2/X 呼叫
SessionProcessorImpl.onCaptureSessionEnd()
後,RequestProcessImpl
實例將失效。- 目標表面由
開始預覽並拍照
在Advanced Extender實作中,您可以透過
RequestProcessorImpl
介面發送捕獲請求。 Camera2/X 分別透過呼叫SessionProcessorImpl#startRepeating
和SessionProcessorImpl#startCapture
通知您開始重複要求預覽或靜態擷取序列。您應該發送捕獲請求來滿足這些預覽和靜態捕獲請求。Camera2/X 也透過
SessionProcessorImpl#setParameters
設定擷取請求參數。您必須在重複請求和單一請求上設定這些請求參數(如果支援參數)。您必須至少支援
CaptureRequest.JPEG_ORIENTATION
和CaptureRequest.JPEG_QUALITY
。extensions-interface
1.3.0 支援請求和結果鍵,透過以下方法公開:-
AdvancedExtenderImpl.getAvailableCaptureRequestKeys()
-
AdvancedExtenderImpl.getAvailableCaptureResultKeys()
開發者在設定
getAvailableCaptureRequestKeys
清單中的key時,必須啟用該參數,並確保擷取結果包含getAvailableCaptureResultKeys
清單中的key。-
startTrigger
呼叫
SessionProcessorImpl.startTrigger()
來啟動觸發器,例如CaptureRequest.CONTROL_AF_TRIGGER
和CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER
。您可以忽略AdvancedExtenderImpl.getAvailableCaptureRequestKeys()
中未公佈的任何捕獲請求密鑰。自
extensions-interface
1.3.0 起就支援startTrigger()
。它使應用程式能夠透過擴充實現點擊對焦和閃光。清理
完成擷取工作階段時,會在關閉
CameraCaptureSession
之前呼叫SessionProcessorImpl.onCaptureSessionEnd()
。捕獲會話關閉後,deInitSession()
執行清理工作。
支援預覽、靜態捕捉和影像分析
您應該為預覽和靜態捕獲用例應用該擴充功能。但是,如果延遲太高而無法流暢地顯示預覽,您可以僅針對靜態擷取應用程式擴充。
對於 Basic Extender 類型,無論是否啟用預覽擴展,您都必須同時為給定擴展實現ImageCaptureExtenderImpl
和PreviewExtenderImpl
。通常,應用程式也會使用 YUV 流來分析圖像內容,例如尋找 QR 程式碼或文字。為了更好地支援此用例,您應該支援預覽,仍然捕獲的流組合,以及用於配置CameraCaptureSession
的YUV_420_888
流。這意味著,如果您實作處理器,則必須支援三個YUV_420_888
流的流組合。
對於高階擴充器,Camera2/X將三個輸出表面傳遞到SessionProcessorImpl.initSession()
呼叫。這些輸出表面分別用於預覽,仍然捕獲和影像分析。您必須確保預覽並仍然捕獲輸出表面顯示有效的輸出。但是,對於影像分析輸出表面,僅當其非零狀時才能正常工作。如果您的實作無法支援影像分析流,則可以傳回AdvancedExtenderImpl.getSupportedYuvAnalysisResolutions()
中的空列表。這樣可以確保影像分析輸出表面在SessionProcessorImpl.initSession()
中始終為null。
支援影片拍攝
目前的相機擴展架構僅支援預覽,但仍會擷取用例。我們不支援在MediaCodec
或MediaRecorder
表面上啟用擴展,以錄製影片。但是,應用程式可能會記錄預覽輸出。
正在研究支援MediaCodec
和MediaRecorder
表面。
特定於擴展的元數據
對於Android 14及更高版本,特定於擴展特定的元資料可讓攝影機擴展用戶端設定並接收擴展特定的擷取請求設定和結果。具體來說,攝影機擴充用戶端可以使用EXTENSION_STRENGTH
擷取請求參數來控制擴展強度,而EXTENSION_CURRENT_TYPE
擷取結果表示啟用的擴充類型。
捕獲請求
EXTENSION_STRENGTH
擷取請求參數控制擴展後處理效果的強度。如果用戶端未明確設定此參數,則相應的擷取結果包括預設強度值。此參數可套用以下以下內容:這些擴充類型:
-
BOKEH
:控制模糊的數量。 -
HDR
和NIGHT
:控制融合的影像量和最終影像的亮度。 -
FACE_RETOUCH
:控制化妝品增強和皮膚平滑的量。
EXTENSION_STRENGTH
參數的支援範圍在0
到100
之間,其中0
表示沒有擴展處理或簡單的傳遞, 100
表示處理效果的最大擴展強度。
若要新增對EXTENSION_STRENGTH
的支持,請使用擴充庫介面1.3.0中引入的供應商特定參數API。有關更多信息,請參見getAvailableCaptureRequestKeys()
。
捕獲結果
EXTENSION_CURRENT_TYPE
擷取結果使擴充實作會通知客戶端有關活動擴充類型。
由於使用AUTO
類型的擴展量會根據場景條件動態切換,例如HDR
和NIGHT
的擴展類型,因此相機擴展應用程式可以使用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();
為了支援即時仍然捕獲延遲估計,請實施以下內容:
- 基本擴充:
ImageCaptureExtenderImpl.getRealtimeCaptureLatency()
- 進階擴充:
SessionProcessorImpl.getRealtimeCaptureLatency
捕獲處理進度回調
對於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
}
}
…
}
為了支援捕獲處理進度回調,您的擴充供應商實作必須呼叫以下回調,並具有當前進度值:
- 基本擴充:
ProcessResultImpl.onCaptureProcessProgressed()
- 進階擴充:
CaptureCallback.onCaptureProcessProgressed()
PostView仍然捕獲
對於Android 14及更高版本,相機擴充功能可以使用setPostviewOutputConfiguration
提供PostView(預覽映像)。為了改善用戶體驗,當擴充功能經歷增加處理延遲時,應用程式可以顯示佔位符,並在最終圖像可用時替換圖像。應用程式可以使用以下參考碼配置和發行PostView捕獲請求:
{
…
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();
…
}
為了支援PostView仍在捕獲,您的供應商實施必須實現以下內容:
支援SurfaceView輸出
對於Android 14及更高版本,相機擴充用戶端可以透過註冊SurfaceView
實例進行預覽輸出來使用電源和效能最佳化的預覽路徑。
為了支援SurfaceView
輸出,您的供應商擴充實作必須能夠將預覽流和輸出預覽為SurfaceView
實例。要驗證這是支援的,請執行SurfaceViewExtensionPreviewTest.java
CTS模組。
供應商特定會話類型
此功能使供應商擴展實作能夠選擇一個供應商特定的會話類型,該類型將在內部攝影機擷取工作階段中而不是預設值中設定。
該功能完全在框架和供應商堆疊中起作用,並且沒有客戶/公共可見API影響。
若要選擇特定於供應商的會話類型,請為您的擴充程式庫實作以下內容: *基本副檔名 * ExtenderStateListener.onSessionType()
Camera2SessionConfigImpl.getSessionType()
用於進階擴充
擴充介面版本歷史
下表顯示了相機擴充介面版本歷史記錄。您應該始終使用最新版本實作供應商庫。
版本 | 新增功能 |
---|---|
1.0.0 |
|
1.1.0 |
|
1.2.0 |
|
1.3.0 |
|
1.4.0 |
|
參考實現
以下參考OEM供應商庫實作可在frameworks/ex
中取得。
advancedSample
:高級擴展器的基本實作。sample
:基本擴展器的基本實作。service_based_sample
:實作如何在Service
中託管相機擴充功能。此實作包含以下元件:oem_library
:相機擴充功能camera2和camerax擴充API的相機OEM庫,該API實作了Extensions-Interface
。這是一個傳遞,可以從Extensions-Interface
到服務的呼叫。該庫還提供AIDL文件和包裝類別以與服務通訊。預設情況下啟用了高級擴展器。若要啟用基本的擴充器,請變更
ExtensionsVersionImpl#isAdvancedExtenderImplemented
以傳回false
。extensions_service
:擴充服務的範例實作。在此處新增您的實作。在服務中實作的介面類似於Extensions-Interface
。例如,實作IAdvancedExtenderImpl.Stub
執行與AdvancedExtenderImpl
相同的操作。需要ImageWrapper
和TotalCaptureResultWrapper
製作Image
和TotalCaptureResult
parcelcelable。
在設備上設定供應商庫
OEM供應商庫未內建在應用程式中;它是在運行時通過camera2/x從設備加載的。在Camerax中, <uses-library>
tag聲明androidx.camera.extensions.impl
庫,該庫是在camera-extensions
庫的AndroidManifest.xml
文件中定義的,是攝影庫的依賴性,必須在運行時加載。在Camera2中,該框架加載了擴展服務,該服務還聲明了<uses-library>
在運行時加載相同的androidx.camera.extensions.impl
庫。
這允許使用擴展名的第三方應用程式自動載入OEM供應商庫。 OEM庫被標記為可選的,因此應用程式可以在裝置上沒有庫的裝置上運行。只要應用程式製造商將OEM庫放置在裝置上,因此Camera2/X會自動處理此行為。
若要在裝置上設定OEM庫,請執行下列操作:
- 新增一個
<uses-library>
文件,該文件使用以下格式:/etc/permissions/ ANY_FILENAME .xml
所要求的。例如,/etc/permissions/camera_extensions.xml
。該目錄中的檔案提供了<uses-library>
中命名的庫的映射到設備上的實際檔案路徑。 使用下面的範例將所需資訊新增到文件中。
-
name
必須為androidx.camera.extensions.impl
,因為那是camerax搜尋的函式庫。 -
file
是包含擴展實現的文件的絕對路徑(例如,/system/framework/androidx.camera.extensions.impl.jar
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/
中使用範例應用程序,該應用程式透過各種供應商擴充功能運行。
完成實施後,請使用攝影機擴充驗證工具來執行自動化和手動測試,以驗證供應商庫是否正確實現。
擴展場景模式與相機擴展
對於散景擴展,除了使用攝影機副檔名將其暴露外,您還可以使用擴展場景模式公開擴展,該模式可以透過CONTROL_EXTENDED_SCENE_MODE
鍵啟用。有關更多實施詳細信息,請參見相機散景。
與Camera2應用程式的相機擴充相比,擴展場景模式的限制較少。例如,您可以在常規的CameraCaptureSession
實例中啟用擴展場景模式,該實例支援靈活的流組合併擷取請求參數。相比之下,相機擴充僅支援一組固定的流類型,並且對捕獲請求參數的支援有限。
擴展場景模式的一個缺點是您只能在相機HAL中實現它,這意味著必須對其進行驗證才能在應用程式開發人員使用的所有正交控制中工作。
我們建議使用擴充場景模式和攝影機擴充功能同時展示散景,因為應用程式可能偏好使用特定的API啟用散景。我們建議先使用擴展場景模式,因為這是應用程式啟用Bokeh擴充的最靈活的方式。然後,您可以基於擴充場景模式實作相機擴充介面。例如,如果在相機HAL中實現散景非常困難,因為它需要在應用程式層中運行的後處理器來處理影像,因此我們建議使用相機擴展介面實現散佈擴展。
常見問題 (FAQ)
API等級有任何限制嗎?
是的。這取決於OEM供應商庫實作所需的Android API功能集。例如, ExtenderStateListener.onPresetSession()
使用SessionConfiguration.setSessionParameters()
呼叫來設定基線標籤集。此通話僅在API等級28及更高等級上可用。有關特定介面方法的詳細信息,請參閱API參考文件。