プロダクト ニュース

単一の機能を超えて: CameraX 1.5 で機能の組み合わせを保証する

6 分で読了
Tahsin Masrur
ソフトウェア エンジニア

最新のカメラアプリは、強力で重複する機能によって定義されます。ユーザーは、美しい HDR で動画を録画し、60 FPS で滑らかなモーションを撮影し、プレビューの手ぶれ補正でスムーズな映像を撮影することを期待しています。多くの場合、これらを同時に行います。

デベロッパーとして、現実はもっと複雑であることを知っています。特定のデバイスが特定の組み合わせを実際にサポートしていることをどのように保証できますか?これまで、複数の機能を有効にすることは多くの場合、賭けでした。個々の機能のサポートを確認することはできましたが、それらを組み合わせると、未定義の動作が発生したり、最悪の場合、カメラ セッションが失敗したりする可能性がありました。 この不確実性により、デベロッパーは慎重にならざるを得ず、高性能デバイスのユーザーは可能な限り最高の体験を得ることができませんでした。

たとえば、HDR と 60 FPS の動画を同時に確実にサポートしているプレミアム デバイスはごくわずかです。そのため、ほとんどのアプリでは、大半のスマートフォンでユーザー エクスペリエンスが低下するのを防ぐため、両方を同時に有効にすることを避けています。

この問題に対処するため、CameraX に機能グループ を導入します。これは、この推測を排除するように設計された新しい API です。カメラを構成する前に、特定の機能の組み合わせがサポートされているかどうかをクエリできるようになりました。また、CameraX に優先順位を伝えるだけで、サポートされている最適な組み合わせを有効にすることもできます。

CameraX を初めて使用する場合

新しい機能グループ API について詳しく説明する前に、CameraX について簡単に説明します。CameraX は、カメラアプリの開発を容易にすることを目的とした Jetpack サポート ライブラリです。ほとんどの Android デバイスで機能する、使いやすく一貫性のある API サーフェスを提供するほか、Android 6.0(API レベル 23)への下位互換性も備えています。CameraX を初めて使用する場合は、公式ドキュメントを確認し、Codelab を試して始めることをおすすめします。

機能グループ API で構築できるもの

機能の組み合わせに賭ける必要がなくなり、高性能ハードウェア(Google Pixel 10 Pro など)で HDR と 60 FPS の動画を同時に撮影するなど、可能な限り最高のカメラ エクスペリエンスを自信を持って提供できます。また、組み合わせをサポートできないデバイスではエラーを回避できます。

unnamed.png

Google Pixel 10 Pro で HDR と 60 FPS の両方を同時に有効にする

無題(1).png

古いデバイスでは HDR と 60 FPS を同時に実行できないため、HDR のみが有効になり、60 FPS オプションは無効になります。

機能グループ API を使用すると、次のことができます。

  • よりスマートで動的な UI を構築する: リアルタイムのハードウェア サポートに基づいて、UI の設定をインテリジェントに有効または無効にします。たとえば、ユーザーが HDR を有効にした場合、そのデバイスで組み合わせがサポートされていない場合は、60 FPS オプションをすぐにグレー表示にして無効にできます。
unsupported-features-disabled.gif
  • 信頼性の高い [高画質] モードを提供する:  必要な機能の優先順位付きリストでカメラを構成します。CameraX は、特定のデバイスでサポートされている最適な組み合わせを自動的に検索して有効にします。複雑なデバイス固有のロジックを使用せずに、優れた結果を得ることができます。
  • カメラ セッションの失敗を防ぐ: サポートを事前に確認することで、カメラがサポートされていない組み合わせを構成しようとするのを防ぎ、クラッシュの一般的な原因を排除して、スムーズなユーザー エクスペリエンスを提供します。

仕組み: コア コンポーネント

新しい API は、SessionConfigCameraInfo への重要な追加を中心にしています。

  1. GroupableFeature: この API では、HDR_HLG10FPS_60PREVIEW_STABILIZATIONIMAGE_ULTRA_HDR など、事前定義されたグループ化可能な機能のセットが導入されています。計算上の制限により、この API が提供する高い信頼性でグループ化できるのは、特定の機能セットのみです。 Google はこのリストの拡大に積極的に取り組んでおり、今後のリリースでより多くの機能のサポートを導入する予定です。
  2. 新しい SessionConfig パラメータ: カメラ セッションの開始に使用されるこのクラスで、次の 2 つの新しいパラメータを受け入れるようになりました:
    • requiredFeatureGroup: 構成を成功させるためにサポートする必要がある機能に使用します。たとえば、ユーザーが明示的に有効にする機能([HDR] スイッチの切り替えなど)に最適です。決定論的で一貫したエクスペリエンスを確保するため、リクエストされた組み合わせが対象外の場合、bindToLifecycle 呼び出しは機能リクエストを無視するのではなく、IllegalArgumentException をスローします。この結果を事前にクエリするには、CameraInfo#isFeatureGroupSupported API(詳細は下記)を使用する必要があります。
    • preferredFeatureGroup: 望ましいが省略可能な機能に使用します。たとえば、デフォルトの [高画質] モードを実装する場合などです。必要な機能のリストを優先順位順に 指定すると、CameraX はデバイスがサポートする優先順位が最も高い組み合わせを自動的に有効にします。
  3. CameraInfo#isFeatureGroupSupported(): これは、機能グループがサポートされているかどうかを明示的に確認するためのコアクエリ メソッドです。アプリの UI でサポートされている機能オプションのみをユーザーに提供するのに適しています。SessionConfig を渡すと、組み合わせがサポートされているかどうかを示すブール値が返されます。必要な機能を含む SessionConfig をバインドする場合は、まずこの API を使用してサポートされていることを確認する必要があります。

実際の実装

これらのコンポーネントを使用して、より優れたカメラ エクスペリエンスを構築する方法を見てみましょう。

シナリオ 1: [ベスト エフォート] 高画質モード

可能な限り最高の機能をデフォルトで有効にする場合は、優先順位付きリストを preferredFeatureGroup に指定します。この例では、HDR、60 FPS、プレビューの手ぶれ補正の順に優先順位を付けるよう CameraX に指示します。CameraX は、考えられるすべての組み合わせを確認し、デバイスがサポートする最適な組み合わせを選択する複雑さを処理します。

たとえば、デバイスが HDR と 60 FPS を同時に処理できるが、プレビューの手ぶれ補正はできない場合、CameraX は最初の 2 つを有効にし、3 つ目を破棄します。このようにして、複雑なデバイス固有のチェックを記述せずに、可能な限り最高の体験を得ることができます。

  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. HDR
  5. 60 FPS + プレビューの手ぶれ補正
  6. 60 FPS
  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」シナリオの両方の完全な実装が提供されています。

注: これはテストアプリであり、公式にサポートされているサンプルではありません。機能グループ API の優れたリファレンスですが、本番環境での使用向けに調整されていません。

今すぐ始めましょう

機能グループ API を使用すると、高度なカメラ機能の操作の曖昧さが解消されます。機能のサポートをクエリする決定論的な方法を提供することで、より強力で信頼性の高いカメラアプリを自信を持って構築できます。

この API は CameraX 1.5 で試験運用版として提供されており、1.6 リリースで完全に安定する予定です。今後、サポートと改善が予定されています。

詳しくは、公式ドキュメントをご覧ください。皆様がどのようなものを作成されるか楽しみにしています。フィードバックをお待ちしております。ご意見や問題点がありましたら、次のチャネルからお寄せください。

作成者:

続きを読む