產品新訊

超越單一功能:使用 CameraX 1.5 確保功能組合

閱讀時間:6 分鐘
Tahsin Masrur
軟體工程師

現代相機應用程式的特色在於功能強大且重疊。使用者希望錄製 HDR 影片、以 60 FPS 捕捉流暢動作,並透過預覽穩定功能取得流暢的影片,而且通常希望同時達成這些目標。

身為開發人員,我們知道實際情況更加複雜。如何確保特定裝置實際支援特定組合?啟用多項功能往往是碰運氣,你可以檢查個別功能是否支援,但如果將這些功能合併使用,可能會導致未定義的行為,或更糟的情況,就是攝影機工作階段失敗。這種不確定性會迫使開發人員採取保守做法,導致使用者無法在效能充足的裝置上獲得最佳體驗。

舉例來說,只有極少數高階裝置能同時穩定支援 HDR 和 60 FPS 影片。因此,大多數應用程式都會避免同時啟用這兩項功能,以免在大多數手機上造成不良的使用者體驗。

為解決這個問題,我們推出了 CameraX 中的功能群組,這項新 API 的設計宗旨是消除這類猜測。現在您可以在設定相機,查詢是否支援特定功能組合,也可以直接告知 CameraX 您的優先順序,讓 CameraX 為您啟用最適合的組合。

CameraX 新手

在深入瞭解新的 Feature Group API 之前,我們先快速回顧 CameraX。CameraX 是 Jetpack 支援資料庫,可協助您輕鬆開發相機應用程式。並提供一致且易於使用的 API 介面,適用於大多數 Android 裝置,具備 Android 6.0 (API 級別 23) 的回溯相容性。如果您是 CameraX 新手,建議先查看官方說明文件,並嘗試程式碼研究室

您可以使用特徵群組 API 建構的項目

您不必再冒險組合功能,可以放心地提供最佳的相機體驗,例如在支援的硬體 (例如 Pixel 10 Pro) 上同時使用 HDR 和 60 FPS 影片,並在無法支援組合的裝置上順利避免錯誤。

unnamed.png

Pixel 10 Pro 同時啟用 HDR 和 60 FPS

unnamed (1).png

如果裝置較舊,無法同時執行 HDR 和 60 FPS,系統只會啟用 HDR,並停用 60 FPS 選項。

透過 Feature Group API,您可以:

  • 建構更智慧的動態 UI:根據即時硬體支援情況,在 UI 中智慧地啟用或停用設定。舉例來說,如果使用者啟用 HDR,但裝置不支援 HDR 和 60 FPS 的組合,您可以立即將 60 FPS 選項設為灰色並停用。
unsupported-features-disabled.gif
  • 提供可靠的「高畫質」模式: 設定攝影機時,請優先列出所需功能。CameraX 會自動找出並啟用任何裝置最支援的組合,確保產生優質結果,不必使用複雜的裝置專屬邏輯。
  • 避免相機工作階段失敗:預先驗證支援情形,可防止相機嘗試設定不支援的組合,消除常見的當機原因,提供流暢的使用者體驗。

運作方式:核心元件

新版 API 的核心是 SessionConfigCameraInfo 的重要新增項目。

  1. GroupableFeature:這項 API 導入一組預先定義的可分組功能,例如 HDR_HLG10FPS_60PREVIEW_STABILIZATION 和 IMAGE_ULTRA_HDR。由於運算限制,只有特定功能組合才能以這個 API 提供的高可靠度分組。我們正積極擴充這份清單,並會在日後推出的版本中支援更多功能。
  2. SessionConfig 參數:這個類別用於啟動攝影機工作階段,現在接受兩個新參數:
    • requiredFeatureGroup:用於必須支援的功能,才能成功設定,非常適合使用者明確啟用的功能,例如切換「HDR」開關。為確保體驗具有決定性且一致,如果系統不支援所要求的組合,bindToLifecycle 呼叫會擲回 IllegalArgumentException,而不是默默忽略功能要求。請先使用 CameraInfo#isFeatureGroupSupported API (詳情請見下文) 查詢這項結果。
    • preferredFeatureGroup:用於可有可無但很實用的功能,例如您想實作預設的「高畫質」模式。您提供依優先順序排序的所需功能清單,CameraX 會自動啟用裝置支援的最高優先順序組合。
  3. CameraInfo#isFeatureGroupSupported():這是用於明確檢查是否支援功能群組的核心查詢方法,非常適合在應用程式 UI 中僅向使用者提供支援的功能選項。您會將 SessionConfig 傳遞給這個函式,而函式會傳回布林值,指出是否支援該組合。如果您打算繫結具有必要功能的 SessionConfig,請先使用這個 API 確保該功能受到支援。

實際導入

讓我們看看如何使用這些元件,打造更優質的相機體驗。

情境 1:「盡量」高畫質模式

如要預設啟用最佳功能,可以向 preferredFeatureGroup 提供優先順序清單。在本範例中,我們告知 CameraX 優先處理 HDR,然後是 60 FPS,最後是預覽穩定功能。CameraX 會處理檢查所有可能組合的複雜作業,並選擇裝置支援的最佳組合。

舉例來說,如果裝置可以同時處理 HDR 和 60 FPS,但無法處理預覽畫面穩定功能,CameraX 就會啟用前兩者,並捨棄第三者。這樣一來,您就能獲得最佳體驗,不必編寫複雜的裝置專用檢查。

cameraProvider.bindToLifecycle(

    lifecycleOwner,

    cameraSelector,

    SessionConfig(

        useCases = listOf(preview, videoCapture),

        // The order of features in this list determines their priority. 

        // CameraX will enable the best-supported combination based on these

        // priorities: HDR_HLG10 > FPS_60 > Preview Stabilization.  

        preferredFeatureGroup =

           listOf(HDR_HLG10, FPS_60, PREVIEW_STABILIZATION),

    ).apply {

        // (Optional) Get a callback with the enabled features

        // to update your UI. 

        setFeatureSelectionListener { selectedFeatures ->

            updateUiIndicators(selectedFeatures)

        }

    }

)

對於這個程式碼片段,CameraX 會嘗試依下列優先順序啟用功能組合,並選取裝置完全支援的第一個組合:

  1. HDR + 60 FPS + 預覽防震功能
  2. HDR + 60 FPS
  3. HDR + 預覽防震功能
  4. 高動態範圍
  5. 60 FPS + 預覽防震功能
  6. 每秒 60 個影格
  7. 預覽防震功能
  8. 以上皆非

情境 2:建構反應式 UI

如要建立可回應使用者選取內容的 UI,並防止使用者選取不支援的功能組合,您可以直接查詢支援項目。以下函式會檢查哪些功能與使用者的目前選項不相容,方便您停用對應的 UI 元素。

/**

 * Returns a list of features that are NOT supported in combination

 * with the currently selected features.

 */

fun getUnsupportedFeatures(

    currentFeatures: Set<GroupableFeature>

): Set<GroupableFeature> {

    val unsupportedFeatures = mutableSetOf<GroupableFeature>()

    val appFeatureOptions = setOf(HDR_HLG10, FPS_60, PREVIEW_STABILIZATION)


    // Iterate over every available feature option in your app. 

    appFeatureOptions.forEach { featureOption ->

        // Skip features the user has already selected. 

        if (currentFeatures.contains(featureOption)) return@forEach


        // Check if adding this new feature is supported. 

        val isSupported = cameraInfo.isFeatureGroupSupported(

            SessionConfig(

                useCases = useCases,

                // Check the new feature on top of existing ones.

                requiredFeatureGroup = currentFeatures + featureOption

            )

        )


        if (!isSupported) {

            unsupportedFeatures.add(featureOption)

        }

    }


    return unsupportedFeatures

}

接著,您可以將這項邏輯連線至 ViewModel 或 UI 控制器,以便對使用者輸入內容做出反應,並使用保證可運作的設定重新繫結攝影機。

// Invoked when user turns some feature on/off.

fun onFeatureChange(currentFeatures: Set<GroupableFeature>) {

    // Identify features that are unsupported with the current selection.

    val unsupportedFeatures = getUnsupportedFeatures(currentFeatures)



    // Update app UI so that users can't enable them.

    updateDisabledFeatures(unsupportedFeatures)



    // Since the UI now only allows selecting supported feature combinations, 

    // `currentFeatures` is always valid. This allows setting

    // `requiredFeatureGroup` directly, without needing to re-check for

    // support or set a feature selection listener.  

    cameraProvider.bindToLifecycle(

        lifecycleOwner,

        cameraSelector,

        SessionConfig(

            useCases = listOf(preview, videoCapture),

            requiredFeatureGroup = currentFeatures,

        )

    )

}

如要在實際運作的應用程式中查看這些概念,可以探索我們的內部測試應用程式。這個應用程式完整實作了上述「盡力而為」和「反應式 UI」情境。

請注意:這是測試應用程式,並非官方支援的範例。雖然這份文件是 Feature Group API 的絕佳參考資料,但尚未經過潤飾,不適合用於正式環境。

立即開始使用

Feature Group API 可消除使用進階相機功能時的模糊地帶。透過提供查詢功能支援的確定性方式,您可以放心地建構更強大且可靠的相機應用程式。

這項 API 在 CameraX 1.5 中為實驗功能,預計在 1.6 版中全面穩定推出,並持續提供更多支援和改善項目。

詳情請參閱官方說明文件。我們很期待看到你的作品,也歡迎提供意見回饋。歡迎透過以下管道分享你的想法或回報任何問題:

繼續閱讀