ARCore による共有カメラアクセス

このデベロッパー ガイドでは、アプリの移行を有効にする手順について説明します。 カメラの排他制御をシームレスに切り替えられます Android Camera2 API ARCore によるカメラアクセスの共有などです。

このトピックは、次のことを前提としています。

サンプルアプリをビルドして実行する

Shared Camera Java サンプルアプリをビルドして実行すると、 共有カメラアクセスをサポートする ARCore セッション。アプリが AR 以外で起動する モードを終了しました。

アプリが非 AR モードで動作する場合、カメラビューアがセピアカラーになる できます。AR モードに切り替えると、アプリに応じてセピア効果がオフになり、 一時停止したセッションを再開して、カメラ コントロールを ARCore に返します。

アプリの AR スイッチを使用してモードを変更できます。プレビュー中は Camera2 によってキャプチャされた連続フレームの数を表示します。

Shared Camera Java サンプルアプリをビルドして実行するには:

  1. ファイルをダウンロードして解凍 Android 向け Google ARCore SDK

  2. アプリ samples/shared_camera_java プロジェクト。

  3. Android デバイスが開発マシンに接続されていることを確認する 接続します。ARCore の対応デバイスをご覧ください。 をご覧ください。

  4. Android Studio で Run)をクリックします。

  5. デプロイ ターゲットとしてデバイスを選択し、[OK] をクリックして サンプルアプリに進みます。

  6. デバイスで、このアプリに写真の撮影を許可することを確認します。 動画を撮影できます。

  7. 更新を求めるメッセージが表示された場合は、ARCore の最新バージョンを更新するか、インストールします。

  8. 非 AR モードと AR モードを切り替えるには、AR スイッチを使用します。

アプリが ARCore とカメラアクセスを共有できるようにする方法の概要

ARCore を使用して共有カメラへのアクセスをアプリに実装する手順は次のとおりです。 すべてのコード スニペットは、 SharedCameraActivity.java shared_camera_java 内 表示されます。

CAMERA 権限をリクエストする

デバイスのカメラを使用できるようにするには、 アプリに CAMERA 権限を付与する必要があります。 ARCore のサンプルには、CameraPermissionHelper、 には、アプリの正しい権限をリクエストするためのユーティリティが用意されています。

Java

protected void onResume() {
  // Request the camera permission, if necessary.
  if (!CameraPermissionHelper.hasCameraPermission(this)) {
      CameraPermissionHelper.requestCameraPermission(this);
  }
}

Kotlin

override fun onResume() {
  // Request the camera permission, if necessary.
  if (!CameraPermissionHelper.hasCameraPermission(this)) {
    CameraPermissionHelper.requestCameraPermission(this)
  }
}

ARCore がインストールされ、最新の状態であることを確認する

ARCore を使用するには、インストールして最新の状態である必要があります。 次のスニペットは、ARCore がまだデバイスにインストールされていない場合に、インストールをリクエストする方法を示しています。

Java

boolean isARCoreSupportedAndUpToDate() {
  // Make sure that ARCore is installed and supported on this device.
  ArCoreApk.Availability availability = ArCoreApk.getInstance().checkAvailability(this);
  switch (availability) {
    case SUPPORTED_INSTALLED:
      return true;

    case SUPPORTED_APK_TOO_OLD:
    case SUPPORTED_NOT_INSTALLED:
        // Requests an ARCore installation or updates ARCore if needed.
        ArCoreApk.InstallStatus installStatus = ArCoreApk.getInstance().requestInstall(this, userRequestedInstall);
        switch (installStatus) {
          case INSTALL_REQUESTED:
            return false;
          case INSTALLED:
            return true;
        }
      return false;

    default:
      // Handle the error. For example, show the user a snackbar that tells them
      // ARCore is not supported on their device.
      return false;
  }
}

Kotlin

// Determine ARCore installation status.
// Requests an ARCore installation or updates ARCore if needed.
fun isARCoreSupportedAndUpToDate(): Boolean {
  when (ArCoreApk.getInstance().checkAvailability(this)) {
    Availability.SUPPORTED_INSTALLED -> return true

    Availability.SUPPORTED_APK_TOO_OLD,
    Availability.SUPPORTED_NOT_INSTALLED -> {
      when(ArCoreApk.getInstance().requestInstall(this, userRequestedInstall)) {
        InstallStatus.INSTALLED -> return true
        else -> return false
      }
    }

    else -> {
      // Handle the error. For example, show the user a snackbar that tells them
      // ARCore is not supported on their device.
      return false
    }
  }
}

カメラの共有をサポートする ARCore セッションを作成する

これには、セッションの作成と、ARCore の参照と ID の保存が含まれます。 共有カメラ:

Java

// Create an ARCore session that supports camera sharing.
sharedSession = new Session(this, EnumSet.of(Session.Feature.SHARED_CAMERA))

// Store the ARCore shared camera reference.
sharedCamera = sharedSession.getSharedCamera();

// Store the ID of the camera that ARCore uses.
cameraId = sharedSession.getCameraConfig().getCameraId();

Kotlin

// Create an ARCore session that supports camera sharing.
sharedSession = Session(this, EnumSet.of(Session.Feature.SHARED_CAMERA))

// Store the ARCore shared camera reference.
sharedCamera = sharedSession.sharedCamera

// Store the ID of the camera that ARCore uses.
cameraId = sharedSession.cameraConfig.cameraId

(省略可)ARCore にカスタム サーフェスを通知する

追加のカスタム サーフェスをリクエストすると、 ダウンロードします適切に機能することを確認するには、 説明します。

ARCore はデフォルトで 2 つのストリームをリクエストします。

  1. 1x YUV CPU ストリーム。現在は常に 640x480 です。
    ARCore は、このストリームをモーション トラッキングに使用します。
  2. 1x GPU ストリーム(通常は 1920x1080
    Session#getCameraConfig() を使用してください。 現在の GPU ストリームの解像度を判断します。

サポートされているデバイスの GPU ストリームの解像度を変更するには、次のコマンドを使用します。 getSupportedCameraConfigs() および setCameraConfig()

大まかな目安として、次のことが予想されます。

デバイスの種類 同時ストリーミングに対応
ハイエンド スマートフォン
  • 2x YUV CPU ストリーム(例:640x4801920x1080
  • 1x GPU ストリーム。例:1920x1080
  • 時折高解像度の静止画像 1 枚(JPEG)。例:12MP
ミッドティアのスマートフォン
  • 2x YUV CPU ストリーム(例:640x4801920x1080
  • 1x GPU ストリーム。例:1920x1080
で確認できます。 または <ph type="x-smartling-placeholder">
    </ph>
  • 1x YUV CPU ストリーム(例:640x480 または 1920x1080
  • 1x GPU ストリーム。例:1920x1080
  • 時折高解像度の静止画像 1 枚(JPEG)。例:12MP

CPU イメージリーダー サーフェスなどのカスタム サーフェスを使用するには、必ず追加してください 更新が必要なサーフェスのリストに追加されます (例: ImageReader)。

Java

sharedCamera.setAppSurfaces(this.cameraId, Arrays.asList(imageReader.getSurface()));

Kotlin

sharedCamera.setAppSurfaces(this.cameraId, listOf(imageReader.surface))

カメラを起動します

ARCore でラップされたコールバックを使用してカメラを開きます。

Java

// Wrap the callback in a shared camera callback.
CameraDevice.StateCallback wrappedCallback =
    sharedCamera.createARDeviceStateCallback(cameraDeviceCallback, backgroundHandler);

// Store a reference to the camera system service.
cameraManager = (CameraManager) this.getSystemService(Context.CAMERA_SERVICE);

// Open the camera device using the ARCore wrapped callback.
cameraManager.openCamera(cameraId, wrappedCallback, backgroundHandler);

Kotlin

// Wrap the callback in a shared camera callback.
val wrappedCallback = sharedCamera.createARDeviceStateCallback(cameraDeviceCallback, backgroundHandler)

// Store a reference to the camera system service.
val cameraManager = this.getSystemService(Context.CAMERA_SERVICE) as CameraManager

// Open the camera device using the ARCore wrapped callback.
cameraManager.openCamera(cameraId, wrappedCallback, backgroundHandler)

カメラデバイス状態のコールバックを使用する

カメラデバイス状態のコールバックに、カメラデバイスへの参照を保存します。 新しいキャプチャ セッションを開始します。

Java

public void onOpened(@NonNull CameraDevice cameraDevice) {
    Log.d(TAG, "Camera device ID " + cameraDevice.getId() + " opened.");
    SharedCameraActivity.this.cameraDevice = cameraDevice;
    createCameraPreviewSession();
}

Kotlin

fun onOpened(cameraDevice: CameraDevice) {
  Log.d(TAG, "Camera device ID " + cameraDevice.id + " opened.")
  this.cameraDevice = cameraDevice
  createCameraPreviewSession()
}

新しいキャプチャ セッションを作成する

新しい回収リクエストを作成します。TEMPLATE_RECORD を使用する キャプチャ リクエストが ARCore と互換性があることを確認し、 非 AR モードと AR モードを実行時に切り替えられるようになりました。

Java

void createCameraPreviewSession() {
  try {
    // Create an ARCore-compatible capture request using `TEMPLATE_RECORD`.
    previewCaptureRequestBuilder =
        cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);

    // Build a list of surfaces, starting with ARCore provided surfaces.
    List<Surface> surfaceList = sharedCamera.getArCoreSurfaces();

    // (Optional) Add a CPU image reader surface.
    surfaceList.add(cpuImageReader.getSurface());

    // The list should now contain three surfaces:
    // 0. sharedCamera.getSurfaceTexture()
    // 1. …
    // 2. cpuImageReader.getSurface()

    // Add ARCore surfaces and CPU image surface targets.
    for (Surface surface : surfaceList) {
      previewCaptureRequestBuilder.addTarget(surface);
    }

    // Wrap our callback in a shared camera callback.
    CameraCaptureSession.StateCallback wrappedCallback =
        sharedCamera.createARSessionStateCallback(cameraSessionStateCallback, backgroundHandler);

    // Create a camera capture session for camera preview using an ARCore wrapped callback.
    cameraDevice.createCaptureSession(surfaceList, wrappedCallback, backgroundHandler);
  } catch (CameraAccessException e) {
    Log.e(TAG, "CameraAccessException", e);
  }
}

Kotlin

fun createCameraPreviewSession() {
  try {
    // Create an ARCore-compatible capture request using `TEMPLATE_RECORD`.
    previewCaptureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD)

    // Build a list of surfaces, starting with ARCore provided surfaces.
    val surfaceList: MutableList<Surface> = sharedCamera.arCoreSurfaces

    // (Optional) Add a CPU image reader surface.
    surfaceList.add(cpuImageReader.getSurface())

    // The list should now contain three surfaces:
    // 0. sharedCamera.getSurfaceTexture()
    // 1. …
    // 2. cpuImageReader.getSurface()

    // Add ARCore surfaces and CPU image surface targets.
    for (surface in surfaceList) {
      previewCaptureRequestBuilder.addTarget(surface)
    }

    // Wrap the callback in a shared camera callback.
    val wrappedCallback = sharedCamera.createARSessionStateCallback(cameraSessionStateCallback, backgroundHandler)

    // Create a camera capture session for camera preview using an ARCore wrapped callback.
    cameraDevice.createCaptureSession(surfaceList, wrappedCallback, backgroundHandler)
  } catch (e: CameraAccessException) {
    Log.e(TAG, "CameraAccessException", e)
  }
}

非 AR モードまたは AR モードで開始する

フレームのキャプチャを開始するには、captureSession.setRepeatingRequest() を呼び出します。 カメラ キャプチャ セッション onConfigured() 状態コールバックから取得されます。 onActive() コールバック内で ARCore セッションを再開して、AR モードで開始します。

Java

// Repeating camera capture session state callback.
CameraCaptureSession.StateCallback cameraSessionStateCallback =
    new CameraCaptureSession.StateCallback() {

      // Called when ARCore first configures the camera capture session after
      // initializing the app, and again each time the activity resumes.
      @Override
      public void onConfigured(@NonNull CameraCaptureSession session) {
        captureSession = session;
        setRepeatingCaptureRequest();
      }

      @Override
      public void onActive(@NonNull CameraCaptureSession session) {
        if (arMode && !arcoreActive) {
          resumeARCore();
        }
      }
    };

// A repeating camera capture session capture callback.
CameraCaptureSession.CaptureCallback cameraCaptureCallback =
    new CameraCaptureSession.CaptureCallback() {
      @Override
      public void onCaptureCompleted(…) {
        shouldUpdateSurfaceTexture.set(true);
      }
    };

void setRepeatingCaptureRequest() {
    captureSession.setRepeatingRequest(
        previewCaptureRequestBuilder.build(), cameraCaptureCallback, backgroundHandler);
}

void resumeARCore() {
    // Resume ARCore.
    sharedSession.resume();
    arcoreActive = true;

    // Set the capture session callback while in AR mode.
    sharedCamera.setCaptureCallback(cameraCaptureCallback, backgroundHandler);
}

Kotlin

val cameraSessionStateCallback = object : CameraCaptureSession.StateCallback() {
      // Called when ARCore first configures the camera capture session after
      // initializing the app, and again each time the activity resumes.
  override fun onConfigured(session: CameraCaptureSession) {
    captureSession = session
    setRepeatingCaptureRequest()
  }

  override fun onActive(session: CameraCaptureSession) {
    if (arMode && !arcoreActive) {
      resumeARCore()
    }
  }
}

val cameraCaptureCallback = object : CameraCaptureSession.CaptureCallback() {
  override fun onCaptureCompleted(
    session: CameraCaptureSession,
    request: CaptureRequest,
    result: TotalCaptureResult
  ) {
    shouldUpdateSurfaceTexture.set(true);
  }
}

fun setRepeatingCaptureRequest() {
  captureSession.setRepeatingRequest(
    previewCaptureRequestBuilder.build(), cameraCaptureCallback, backgroundHandler
  )
}

fun resumeARCore() {
    // Resume ARCore.
    sharedSession.resume()
    arcoreActive = true

    // Set the capture session callback while in AR mode.
    sharedCamera.setCaptureCallback(cameraCaptureCallback, backgroundHandler)
}

非 AR モードと AR モードを実行時にシームレスに切り替え可能

非 AR モードから AR モードに切り替えて、一時停止した ARCore セッションを再開するには:

Java

// Resume the ARCore session.
resumeARCore();

Kotlin

// Resume the ARCore session.
resumeARCore()

AR モードから非 AR モードに切り替えるには:

Java

// Pause ARCore.
sharedSession.pause();

// Create the Camera2 repeating capture request.
setRepeatingCaptureRequest();

Kotlin

// Pause ARCore.
sharedSession.pause()

// Create the Camera2 repeating capture request.
setRepeatingCaptureRequest()