カメラのキャプチャ セッションとリクエスト

注: このページでは、Camera2 パッケージについて説明します。アプリで Camera2 の特定の低レベルの機能を必要とする場合を除き、CameraX を使用することをおすすめします。CameraX と Camera2 は、どちらも Android 5.0(API レベル 21)以降に対応しています。

1 台の Android 搭載デバイスに複数のカメラを搭載できます。カメラはそれぞれ CameraDevice CameraDevice は複数のストリームを同時に出力できます。

これを行う理由の一つは、1 つのストリームで連続したカメラフレームが CameraDevice からのもので、特定のタスク(表示など)用に最適化されています。 ビューファインダーなど、写真の撮影や動画の撮影に使われることもあります。 ストリームは RAW フレームを処理する並列パイプラインとして機能します 一度に 1 フレームずつ出てくるような処理です。

図 1. ユニバーサル カメラ アプリの作成(Google I/O ‘18)のイラスト

並列処理では、デプロイ環境によっては、 CPU、GPU、その他のプロセッサで利用可能な処理能力。もし パイプラインが受信フレームに追いつけないと ドロップし始めます

各パイプラインには独自の出力形式があります。入ってくる元データは 適切なモデルに自動的に変換され、 出力形式 各パイプラインに関連する指標ですこのページの全体を通して使用される CameraDevice コードサンプルは固有ではないため、最初に列挙 すべての利用可能なカメラを確認してください。

CameraDevice を使用すると、 CameraCaptureSession, その CameraDevice に固有のコードです。CameraDevice は 各 RAW フレームのフレーム構成を CameraCaptureSession を使用してプロットします。「 設定では、オートフォーカス、絞り、効果、効果などのカメラ属性が リスクですハードウェアの制約により、1 つの構成にしか 常にカメラセンサーに残っています。これはいわゆる アクティブ構成を使用します。

ストリーミングのユースケースでは、CameraDevice のこれまでの使用方法が強化、拡張されます。 キャプチャ セッションをストリーミングできます。これにより、環境に合わせてカメラ ストリームを最適化できます。 判断できますたとえば、バッテリーを長持ちさせるために、 ビデオ通話を行えます。

CameraCaptureSession は、バインドされる可能性のあるすべてのパイプラインを表します。 CameraDevice。セッションの作成時にパイプラインを追加または削除することはできません。 CameraCaptureSession は、 CaptureRequest それがアクティブな構成になります

CaptureRequest は、キューに構成を追加し、1 つ以上の構成を選択します。 1 つ、またはすべての利用可能なパイプラインのいずれか、またはすべてに CameraDevice。キャプチャの実行中に多数のキャプチャ リクエストを送信できる あります。各リクエストにより、有効な構成と出力のセットを変更できる 未処理の画像を受け取るパイプライン

ストリームのユースケースを使用してパフォーマンスを向上させる

ストリームのユースケースは、Camera2 のキャプチャのパフォーマンスを向上させる方法である あります。パラメータを調整するための追加情報をハードウェア デバイスに提供し、 特定のタスクを行う際のカメラ エクスペリエンスが向上します。

この カメラデバイスでカメラのハードウェアとソフトウェアのパイプラインを最適化できる ユーザーシナリオに基づいて選択されますストリームの使用についての詳細 ケースについては、setStreamUseCase をご覧ください。

ストリーミングのユースケースでは、特定のカメラ ストリームをストリーミングで使用する方法を指定できます。 より詳細な構成を CameraDevice.createCaptureRequest()。これにより、カメラのハードウェアは パラメータ(調整、センサーモード、カメラセンサー設定など)は、 レイテンシのトレードオフを考慮する必要があります。

ライブ配信のユースケース:

  • DEFAULT: 既存のすべてのアプリケーション動作をカバーします。not と同等です。 ストリーミングのユースケースを設定できます。

  • PREVIEW: ビューファインダーやアプリ内の画像分析に推奨されます。

  • STILL_CAPTURE: 高画質の高解像度キャプチャ向けに最適化されています。 プレビューのようなフレームレートを維持します

  • VIDEO_RECORD: 高画質を含む高画質動画キャプチャ向けに最適化されています 手ぶれ補正(デバイスがサポートしており、アプリで有効になっている場合)。 このオプションでは、リアルタイムからかなり遅れた出力フレームが生成される可能性があります。 高品質な手ぶれ補正やその他の処理が可能になります。

  • VIDEO_CALL: バッテリーの消耗が早い環境でカメラを長時間使用する場合に推奨 懸念事項です。

  • PREVIEW_VIDEO_STILL: ソーシャル メディア アプリまたはシングル ストリームでの使用に推奨 対応できます多目的ストリームです

  • VENDOR_START: OEM 定義のユースケースに使用されます。

CameraCaptureSession を作成する

カメラ セッションを作成するには、1 つ以上の出力バッファを指定します 出力フレームを書き込むことができます。各バッファはパイプラインを表します。必要なこと フレームワークが構成できるように、カメラの使用を開始する前にこの操作を行います。 デバイスの内部パイプラインを割り当て、フレームを送信するためのメモリバッファを割り当てます。 必要があります。

次のコード スニペットは、2 つのセッションがあるカメラ セッションを準備する方法を示しています。 1 つは出力バッファであり、1 つは SurfaceViewImageReaderPREVIEW ストリームのユースケースを previewSurface に追加し、 STILL_CAPTURE ストリームの使用 imReaderSurface の場合、デバイスのハードウェアはこれらのストリームも最適化します。 説明します。

Kotlin


// Retrieve the target surfaces, which might be coming from a number of places:
// 1. SurfaceView, if you want to display the image directly to the user
// 2. ImageReader, if you want to read each frame or perform frame-by-frame
// analysis
// 3. OpenGL Texture or TextureView, although discouraged for maintainability
      reasons
// 4. RenderScript.Allocation, if you want to do parallel processing
val surfaceView = findViewById<SurfaceView>(...)
val imageReader = ImageReader.newInstance(...)

// Remember to call this only *after* SurfaceHolder.Callback.surfaceCreated()
val previewSurface = surfaceView.holder.surface
val imReaderSurface = imageReader.surface
val targets = listOf(previewSurface, imReaderSurface)

// Create a capture session using the predefined targets; this also involves
// defining the session state callback to be notified of when the session is
// ready
// Setup Stream Use Case while setting up your Output Configuration.
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
fun configureSession(device: CameraDevice, targets: List<Surface>){
    val configs = mutableListOf<OutputConfiguration>()
    val streamUseCase = CameraMetadata
        .SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL

    targets.forEach {
        val config = OutputConfiguration(it)
        config.streamUseCase = streamUseCase.toLong()
        configs.add(config)
    }
    ...
    device.createCaptureSession(session)
}

Java


// Retrieve the target surfaces, which might be coming from a number of places:
// 1. SurfaceView, if you want to display the image directly to the user
// 2. ImageReader, if you want to read each frame or perform frame-by-frame
      analysis
// 3. RenderScript.Allocation, if you want to do parallel processing
// 4. OpenGL Texture or TextureView, although discouraged for maintainability
      reasons
Surface surfaceView = findViewById<SurfaceView>(...);
ImageReader imageReader = ImageReader.newInstance(...);

// Remember to call this only *after* SurfaceHolder.Callback.surfaceCreated()
Surface previewSurface = surfaceView.getHolder().getSurface();
Surface imageSurface = imageReader.getSurface();
List<Surface> targets = Arrays.asList(previewSurface, imageSurface);

// Create a capture session using the predefined targets; this also involves defining the
// session state callback to be notified of when the session is ready
private void configureSession(CameraDevice device, List<Surface> targets){
    ArrayList<OutputConfiguration> configs= new ArrayList()
    String streamUseCase=  CameraMetadata
        .SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL

    for(Surface s : targets){
        OutputConfiguration config = new OutputConfiguration(s)
        config.setStreamUseCase(String.toLong(streamUseCase))
        configs.add(config)
}

device.createCaptureSession(session)
}

この時点では、カメラのアクティブな構成は定義されていません。 セッションの設定が済んだら、キャプチャを作成してディスパッチできます。 できます。

入力がバッファに書き込まれる際に入力に適用される変換は、 各ターゲットのタイプによって決まります。 Surface。Android フレームワークは、 アクティブな構成の未加工の画像を、アプリケーションに適した 作成されます。変換は、ピクセル形式とピクセルのサイズによって制御されます。 (特定の Surface)。

フレームワークは最善を尽くそうとするが、一部の Surface 構成の組み合わせが機能しない場合があり、その場合はセッションや 作成されていない場合、リクエストのディスパッチ時にランタイム エラーがスローされる、または パフォーマンスの低下につながりますこのフレームワークでは、インフラストラクチャの device、Surface、Request の各パラメータの組み合わせ。「 createCaptureSession() より詳しい情報をご確認ください。

単一の CaptureRequest

各フレームに使用される構成は、CaptureRequest でエンコードされます。 カメラに送信されます回収リクエストを作成するには、 事前定義 テンプレート または、TEMPLATE_MANUAL を使用して完全に制御できます。「新規顧客の獲得」目標を 使用する出力バッファを 1 つ以上用意し、 表示されます。キャプチャ時にすでに定義されているバッファのみを使用できる 選択します。

キャプチャ リクエストでは、 ビルダー パターン デベロッパーがさまざまな オプション 自動露出オートフォーカス、 および レンズ絞り。 フィールドを設定する前に、対象のフィールドで Google Chat に電話をかけて CameraCharacteristics.getAvailableCaptureRequestKeys() 適切なカメラをチェックして、指定した値がサポートされていることを確認します。 利用可能な自動露出などの モードをご覧ください。

テンプレートを使用して SurfaceView のキャプチャ リクエストを作成する 変更せずにプレビュー用に設計されているため、 CameraDevice.TEMPLATE_PREVIEW:

Kotlin

val session: CameraCaptureSession = ...  // from CameraCaptureSession.StateCallback
val captureRequest = session.device.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
captureRequest.addTarget(previewSurface)

Java

CameraCaptureSession session = ...;  // from CameraCaptureSession.StateCallback
CaptureRequest.Builder captureRequest =
    session.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
captureRequest.addTarget(previewSurface);

キャプチャ リクエストを定義したら、次はディスパッチ カメラ セッションに追加します。

Kotlin

val session: CameraCaptureSession = ...  // from CameraCaptureSession.StateCallback
val captureRequest: CaptureRequest = ...  // from CameraDevice.createCaptureRequest()

// The first null argument corresponds to the capture callback, which you
// provide if you want to retrieve frame metadata or keep track of failed capture
// requests that can indicate dropped frames; the second null argument
// corresponds to the Handler used by the asynchronous callback, which falls
// back to the current thread's looper if null
session.capture(captureRequest.build(), null, null)

Java

CameraCaptureSession session = ...;  // from CameraCaptureSession.StateCallback
CaptureRequest captureRequest = ...;  // from CameraDevice.createCaptureRequest()

// The first null argument corresponds to the capture callback, which you
// provide if you want to retrieve frame metadata or keep track of failed
// capture
// requests that can indicate dropped frames; the second null argument
// corresponds to the Handler used by the asynchronous callback, which falls
// back to the current thread's looper if null
session.capture(captureRequest.build(), null, null);

出力フレームが特定のバッファに入ると、キャプチャは コールバック トリガーされます多くの場合、追加のコールバック( ImageReader.OnImageAvailableListener 含まれるフレームの処理時にトリガーされます。場所: このポイントは、指定されたバッファから画像データを取得できます。

CaptureRequest を繰り返す

1 つのカメラへのリクエストは簡単に実行できますが、ライブ あまり役に立ちませんその場合は、 連続したフレームのストリームを表現できます。次のコード スニペット 追加する方法を リクエストの繰り返し 追加します。

Kotlin

val session: CameraCaptureSession = ...  // from CameraCaptureSession.StateCallback
val captureRequest: CaptureRequest = ...  // from CameraDevice.createCaptureRequest()

// This keeps sending the capture request as frequently as possible until
// the
// session is torn down or session.stopRepeating() is called
// session.setRepeatingRequest(captureRequest.build(), null, null)

Java

CameraCaptureSession session = ...;  // from CameraCaptureSession.StateCallback
CaptureRequest captureRequest = ...;  // from CameraDevice.createCaptureRequest()

// This keeps sending the capture request as frequently as possible until the
// session is torn down or session.stopRepeating() is called
// session.setRepeatingRequest(captureRequest.build(), null, null);

キャプチャ リクエストが繰り返されると、カメラデバイスは継続的にキャプチャを行います 指定された CaptureRequest の設定を使用します。Camera2 API カメラから動画を撮影するには 以下の例のように、CaptureRequests を反復しています。 Camera2 のサンプル リポジトリをご覧ください。また、撮影した映像をキャプチャして、スローモーション動画をレンダリングすることもできます。 連続再生を使用した高速(スローモーション)動画 CaptureRequests Camera2 のスローモーション動画サンプルアプリに記載のもの ご覧ください。

CaptureRequest をインターリーブする

キャプチャの繰り返しリクエストが有効な間に 2 つ目のキャプチャ リクエストを送信するには、 たとえば、ビューファインダーを表示してユーザーが写真を撮影できるようにする場合、 停止します。代わりに、非繰り返しキャプチャを発行します。 リクエストが継続して実行されている間 再試行されます

使用する出力バッファはすべて、カメラ セッションの一部として構成する必要がある 設定されます。繰り返しリクエストの優先度は、優先度が 単一フレーム リクエストまたはバースト リクエストを使用すると、次のサンプルが機能します。

Kotlin

val session: CameraCaptureSession = ...  // from CameraCaptureSession.StateCallback

// Create the repeating request and dispatch it
val repeatingRequest = session.device.createCaptureRequest(
CameraDevice.TEMPLATE_PREVIEW)
repeatingRequest.addTarget(previewSurface)
session.setRepeatingRequest(repeatingRequest.build(), null, null)

// Some time later...

// Create the single request and dispatch it
// NOTE: This can disrupt the ongoing repeating request momentarily
val singleRequest = session.device.createCaptureRequest(
CameraDevice.TEMPLATE_STILL_CAPTURE)
singleRequest.addTarget(imReaderSurface)
session.capture(singleRequest.build(), null, null)

Java

CameraCaptureSession session = ...;  // from CameraCaptureSession.StateCallback

// Create the repeating request and dispatch it
CaptureRequest.Builder repeatingRequest =
session.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
repeatingRequest.addTarget(previewSurface);
session.setRepeatingRequest(repeatingRequest.build(), null, null);

// Some time later...

// Create the single request and dispatch it
// NOTE: This can disrupt the ongoing repeating request momentarily
CaptureRequest.Builder singleRequest =
session.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
singleRequest.addTarget(imReaderSurface);
session.capture(singleRequest.build(), null, null);

ただし、この方法には欠点があります。 発生します。次の図では、A が繰り返しフィールドである場合、 B は単一フレームのキャプチャ リクエストです。 次のようにリクエスト キューを処理します。

図 2. 進行中のカメラ セッションのリクエスト キューのイラスト

最後の繰り返しリクエスト間のレイテンシは保証されません。 A(リクエスト B が有効)、次に A が使用される その場合、フレームがスキップされる可能性があります。Google では、 する方法をいくつか紹介します。

  • リクエスト A の出力ターゲットをリクエスト B に追加します。そうすれば、 B のフレームの準備ができると、A の出力ターゲットにコピーされます。 たとえば、動画のスナップショットを作成して、 示します。上記のコードでは、次のコードを追加します。 singleRequest.addTarget(previewSurface) を返します。

  • この特定のシナリオで動作するように設計されたテンプレートを組み合わせて使用します。 設計することができます。