プレビューを実装する

アプリにプレビューを追加する場合は、PreviewView を使用します。これは適切な表示に合わせて切り抜き、サイズ変更、回転ができる View です。

画像プレビューは、カメラがアクティブになったときに PreviewView 内のサーフェスにストリーミングされます。

PreviewView を使用する

PreviewView を使用して CameraX のプレビューを実装するには、以下の手順(後のセクションで説明)を行います。

  1. 必要に応じて CameraXConfig.Provider を設定します。
  2. レイアウトに PreviewView を追加します。
  3. ProcessCameraProvider をリクエストします。
  4. View を作成するときは、ProcessCameraProvider を確認します。
  5. カメラを選択してライフサイクルとユースケースをバインドします。

PreviewView の使用には、いくつかの制限事項があります。PreviewView を使用する場合、次のいずれの操作も実行できません。

  • SurfaceTexture を作成し、TextureViewPreview.SurfaceProvider に設定する。
  • TextureView から SurfaceTexture を取得し、Preview.SurfaceProvider に設定する。
  • SurfaceView から Surface を取得し、Preview.SurfaceProvider に設定する。

これらのうちいずれかの操作が行われた場合、PreviewPreviewView へのフレームのストリーミングを停止します。

PreviewView をレイアウトに追加する

次のサンプルは、レイアウト内の PreviewView を示しています。

<FrameLayout
    android:id="@+id/container">
        <androidx.camera.view.PreviewView
            android:id="@+id/previewView" />
</FrameLayout>

CameraProvider をリクエストする

次のコードは、CameraProvider をリクエストする方法を示しています。

Kotlin

import androidx.camera.lifecycle.ProcessCameraProvider
import com.google.common.util.concurrent.ListenableFuture

class MainActivity : AppCompatActivity() {
    private lateinit var cameraProviderFuture : ListenableFuture<ProcessCameraProvider>
    override fun onCreate(savedInstanceState: Bundle?) {
        cameraProviderFuture = ProcessCameraProvider.getInstance(this)
    }
}

Java

import androidx.camera.lifecycle.ProcessCameraProvider
import com.google.common.util.concurrent.ListenableFuture

public class MainActivity extends AppCompatActivity {
    private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        cameraProviderFuture = ProcessCameraProvider.getInstance(this);
    }
}

CameraProvider が利用可能かどうかを確認する

CameraProvider をリクエストした後、ビューの作成時に初期化が成功したことを確認します。次のコードに、その方法を示します。

Kotlin

cameraProviderFuture.addListener(Runnable {
    val cameraProvider = cameraProviderFuture.get()
    bindPreview(cameraProvider)
}, ContextCompat.getMainExecutor(this))

Java

cameraProviderFuture.addListener(() -> {
    try {
        ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
        bindPreview(cameraProvider);
    } catch (ExecutionException | InterruptedException e) {
        // No errors need to be handled for this Future.
        // This should never be reached.
    }
}, ContextCompat.getMainExecutor(this));

たとえば、このサンプルで使用されている bindPreview 関数については、次のセクションに示されているコードをご覧ください。

カメラを選択してライフサイクルとユースケースをバインドする

CameraProvider を作成して確認したら、次のようにします。

  1. Preview を作成します。
  2. 希望のカメラの LensFacing オプションを指定します。
  3. 選択したカメラとユースケースをライフサイクルにバインドします。
  4. PreviewPreviewView に接続します。

次のコードに、例を示します。

Kotlin

fun bindPreview(cameraProvider : ProcessCameraProvider) {
    var preview : Preview = Preview.Builder()
            .build()

    var cameraSelector : CameraSelector = CameraSelector.Builder()
          .requireLensFacing(CameraSelector.LENS_FACING_BACK)
          .build()

    preview.setSurfaceProvider(previewView.getSurfaceProvider())

    var camera = cameraProvider.bindToLifecycle(this as LifecycleOwner, cameraSelector, preview)
}

Java

void bindPreview(@NonNull ProcessCameraProvider cameraProvider) {
    Preview preview = new Preview.Builder()
            .build();

    CameraSelector cameraSelector = new CameraSelector.Builder()
            .requireLensFacing(CameraSelector.LENS_FACING_BACK)
            .build();

    preview.setSurfaceProvider(previewView.getSurfaceProvider());

    Camera camera = cameraProvider.bindToLifecycle((LifecycleOwner)this, cameraSelector, preview);
}

bindToLifecycle()Camera オブジェクトを返します。ズームや露出など、カメラ出力の制御について詳しくは、カメラ出力をご覧ください。

これでカメラ プレビューの実装は完了です。アプリをビルドし、プレビューがアプリに表示され、意図したとおりに動作することを確認します。

PreviewView の追加コントロール

CameraX PreviewView には、次のようなプロパティを設定するための追加 API が用意されています。

実装モード

PreviewView は、以下のいずれかのモードを使用して、プレビュー ストリームをターゲット View にレンダリングできます。

  • PERFORMANCE モード(デフォルト モード): PreviewViewSurfaceView を使用して動画ストリームを表示しますが、特定のケースでは TextureView にフォールバックします。SurfaceView には専用の描画サーフェスがあり、特にプレビュー動画上に他の UI 要素(ボタンなど)がない場合、内部ハードウェア コンポジターによりハードウェア オーバーレイで実装される可能性が高くなります。ハードウェア オーバーレイでレンダリングすると、動画フレームが GPU パスを回避するので、プラットフォームの電力消費とレイテンシを削減できます。

  • COMPATIBLE モード: PreviewViewTextureView を使用しますが、SurfaceView とは異なり、専用の描画サーフェスはありません。その結果、動画を表示するにはブレンディングでレンダリングされます。このステップでは、動画を制限なしで拡大縮小したり回転させたりするなど、アプリケーションで追加の処理を実行できます。

PreviewView.setImplementationMode() を使用して、アプリケーションに適した実装モードを選択します。デフォルトの PERFORMANCE モードがアプリケーションに適していない場合のために、次のコードサンプルで COMPATIBLE モードの設定方法を示します。

Kotlin

// viewFinder is a PreviewView instance
viewFinder.implementationMode = PreviewView.ImplementationMode.COMPATIBLE

スケールタイプ

プレビュー動画の解像度がターゲット PreviewView のサイズと異なる場合は、動画コンテンツを切り抜くかレターボックス表示にするかして、ビューに合わせる必要があります(アスペクト比は変えないでください)。PreviewView には、この目的のために次の ScaleTypes が用意されています。

  • FIT_CENTERFIT_STARTFIT_END(レターボックス表示用): 動画コンテンツ全体が、ターゲット PreviewView で表示できる最大サイズに拡大縮小されます。ただし、動画フレーム全体が表示されても、画面の一部が空白になることがあります。選択した 3 つのスケールタイプに応じて、ターゲット ビューの中央、始点、または終点に合わせて動画フレームが配置されます。

  • FILL_CENTERFILL_STARTFILL_END(切り抜き用): 動画が PreviewView のアスペクト比と一致しない場合、コンテンツは一部しか表示されませんが、動画は PreviewView 全体に表示されます。

CameraX が使用するデフォルトのスケールタイプは FILL_CENTER です。PreviewView.setScaleType() を使用して、アプリケーションに最適なスケールタイプを設定してください。次のコードサンプルでは、FIT_CENTER スケールタイプを設定しています。

Kotlin

// viewFinder is a PreviewView instance
viewFinder.scaleType = PreviewView.ScaleType.FIT_CENTER

動画の表示は、以下のステップから処理されます。

  1. 動画を拡大縮小します。
    • FIT_* スケールタイプの場合、min(dst.width/src.width, dst.height/src.height) で動画を拡大縮小します。
    • FILL_* スケールタイプの場合、max(dst.width/src.width, dst.height/src.height) で動画を拡大縮小します。
  2. 拡大縮小された動画を表示先 PreviewView に合わせます。
    • FIT_CENTER/FILL_CENTER の場合、拡大縮小された動画と表示先 PreviewView を、それぞれの中央を合わせて配置します。
    • FIT_START/FILL_START の場合、拡大縮小された動画と表示先 PreviewView を、それぞれの左上端を合わせて配置します。
    • FIT_END/FILL_END の場合、拡大縮小された動画と表示先 PreviewView を、それぞれの右下端を合わせて配置します。

たとえば、元になる動画が 640x480 で、表示先の PreviewView が 1920x1080 だとします。

640x480 の動画と 1920x1080 のプレビューを対比する画像

次の図は、FIT_START / FIT_CENTER / FIT_END の拡大縮小処理を示しています。

FIT_START、FIT_CENTER、FIT_END の拡大縮小処理を示す画像

この処理は次のように行われます。

  1. 動画フレームを(アスペクト比を変えずに)min(1920/640, 1080/480) = 2.25 倍に拡大して、1440x1080 の中間動画フレームを生成します。
  2. 1440x1080 の動画フレームを 1920x1080 の PreviewView に合わせます。
    • FIT_CENTER の場合、動画フレームを PreviewView ウィンドウの中央に合わせます。PreviewView の始点側と終点側の 240 ピクセルの列は空白です。
    • FIT_START の場合、動画フレームを PreviewView ウィンドウの始点(左上端)に合わせます。PreviewView の終点側の 480 ピクセルの列は空白です。
    • FIT_END の場合、動画フレームを PreviewView ウィンドウの終点(右下端)に合わせます。PreviewView の始点側の 480 ピクセルの列は空白です。

次の図は、FILL_START / FILL_CENTER / FILL_END の拡大縮小処理を示しています。

FILL_START、FILL_CENTER、FILL_END の拡大縮小処理を示す画像

この処理は次のように行われます。

  1. 動画フレームを max(1920/640, 1080/480) = 3 倍に拡大して、1920x1440 の中間動画フレーム(PreviewView より大きい)を生成します。
  2. 1920x1440 の動画フレームを 1920x1080 の PreviewView ウィンドウに合うよう切り抜きます。
    • FILL_CENTER の場合、拡大済みの 1920x1440 の動画の中央から 1920x1080 を切り抜きます。動画の上下 180 行は表示されません。
    • FILL_START の場合、拡大済みの 1920x1440 の動画の始点から 1920x1080 を切り抜きます。動画の下側の 360 行は表示されません。
    • FILL_END の場合、拡大済みの 1920x1440 の動画の終点から 1920x1080 を切り抜きます。動画の上側 360 行は表示されません。

参考情報

CameraX について詳しくは、以下の参考情報をご確認ください。

Codelab

  • CameraX のスタートガイド
  • コードサンプル

  • CameraX のサンプルアプリ