Kamerazugriff mit ARCore geteilt

In diesem Entwicklerleitfaden erfahren Sie, wie Sie den Wechsel Ihrer App aktivieren. zwischen der exklusiven Steuerung der Kamera über die Android Camera2 API und den Zugriff auf die Kamera mit ARCore.

In diesem Thema wird davon ausgegangen, dass Sie:

Beispielanwendung erstellen und ausführen

Wenn Sie die Beispiel-App Shared Camera Java erstellen und ausführen, wird ein ARCore-Sitzung, die den Zugriff auf die gemeinsame Kamera unterstützt. Die App startet nicht im AR-Modus mit pausiertem ARCore-Modus.

Wenn die App im Nicht-AR-Modus betrieben wird, zeigt das Gerät der Kamera eine Sepiafarbe an. Effekts. Wenn du in den AR-Modus wechselst, schaltet sich der Sepia-Effekt aus, da die App gibt die Kamerasteuerung an ARCore zurück, indem die pausierte Sitzung fortgesetzt wird.

Mit dem AR-Schalter in der App kannst du den Modus ändern. Während der Vorschau werden beide Modi die Anzahl der aufeinanderfolgenden Frames, die von Camera2 aufgenommen wurden, anzuzeigen.

So erstellen Sie die Java-Beispiel-App für freigegebene Kamera und führen sie aus:

  1. Laden Sie die Datei Google ARCore SDK for Android

  2. Öffnen Sie das samples/shared_camera_java-Projekt

  3. Achten Sie darauf, dass Ihr Android-Gerät mit dem Entwicklungscomputer verbunden ist USB-Kabel. Weitere Informationen zu unterstützten Geräten für ARCore .

  4. Klicken Sie in Android Studio auf Run .

  5. Wählen Sie Ihr Gerät als Bereitstellungsziel aus und klicken Sie auf OK, um die Beispiel-App auf Ihrem Gerät.

  6. Bestätigen Sie auf dem Gerät, dass Sie der App erlauben möchten, Fotos und Video aufnehmen.

  7. Wenn du dazu aufgefordert wirst, aktualisiere oder installiere die neueste Version von ARCore.

  8. Mit dem Schalter AR können Sie zwischen dem Nicht-AR- und dem AR-Modus wechseln.

App für die Freigabe des Kamerazugriffs mit ARCore aktivieren

Folge dieser Anleitung, um den Zugriff auf die gemeinsame Kamera mit ARCore in deiner App zu implementieren. Alle Code-Snippets sind in der SharedCameraActivity.java in der shared_camera_java Stichprobe.

Berechtigung „CAMERA“ anfordern

Damit Nutzer die Kamera des Geräts verwenden können, muss deiner App die Berechtigung CAMERA erteilen. Zu den ARCore-Beispielen gehören CameraPermissionHelper, womit Dienstprogramme die richtige Berechtigung für Ihre App anfordern können.

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 muss installiert und auf dem neuesten Stand sein

ARCore muss installiert und auf dem neuesten Stand sein, damit du es verwenden kannst. Das folgende Snippet zeigt, wie Sie die Installation von ARCore anfordern, wenn ARCore noch nicht auf dem Gerät installiert ist.

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-Sitzung erstellen, die die Kamerafreigabe unterstützt

Dazu gehört das Erstellen der Sitzung und das Speichern der Referenz und der ID von ARCore Gemeinsame Kamera:

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

Optional: ARCore über benutzerdefinierte Oberflächen informieren

Wenn zusätzliche benutzerdefinierte Oberflächen angefordert werden, erhöht sich die Leistungsanforderungen der . Testen Sie Ihre App auf den Geräten, die die Nutzenden nutzen.

ARCore fordert standardmäßig zwei Streams an:

  1. 1x YUV-CPU-Stream, aktuell immer 640x480.
    ARCore verwendet diesen Stream für die Bewegungserkennung.
  2. Ein 1x GPU-Stream, normalerweise 1920x1080
    Session#getCameraConfig() verwenden um die aktuelle Auflösung des GPU-Streams zu ermitteln.

Du kannst die Auflösung des GPU-Streams auf unterstützten Geräten mit dem folgenden Befehl ändern: getSupportedCameraConfigs() und setCameraConfig()

Als grober Indikator können Sie Folgendes erwarten:

Gerätetyp Gleichzeitige Streams werden unterstützt
High-End-Smartphones
  • 2 x YUV-CPU-Streams, z.B. 640x480 und 1920x1080
  • 1 GPU-Stream, z.B. 1920x1080
  • Gelegentliches Standbild mit hoher Auflösung (JPEG), z.B. 12MP
Smartphones der mittleren Preisklasse
  • 2 x YUV-CPU-Streams, z.B. 640x480 und 1920x1080
  • 1 GPU-Stream, z.B. 1920x1080
–oder– <ph type="x-smartling-placeholder">
    </ph>
  • 1 YUV-CPU-Streams, z.B. 640x480 –oder– 1920x1080
  • 1 GPU-Stream, z.B. 1920x1080
  • Gelegentliches Standbild mit hoher Auflösung (JPEG), z.B. 12MP

Wenn Sie benutzerdefinierte Oberflächen verwenden möchten, z. B. eine CPU-Bildleseoberfläche, müssen Sie diese hinzufügen in der Liste der zu aktualisierenden Oberflächen. z. B. ImageReader.

Java

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

Kotlin

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

Kamera öffnen

Öffne die Kamera mit einem mit ARCore verpackten Callback:

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)

Callback für den Gerätestatus der Kamera verwenden

Im Kameragerätestatus wird ein Verweis auf das Kameragerät gespeichert. eine neue Aufnahme starten.

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()
}

Neue Aufnahmesitzung erstellen

Erstellen Sie eine neue Erfassungsanfrage. TEMPLATE_RECORD verwenden um sicherzustellen, dass die Aufnahmeanfrage mit ARCore kompatibel ist und eine nahtlose während der Laufzeit zwischen Nicht-AR- und AR-Modus wechseln.

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)
  }
}

Im Nicht-AR- oder AR-Modus starten

Rufen Sie captureSession.setRepeatingRequest() auf, um mit der Aufnahme von Frames zu beginnen. aus dem onConfigured()-Statusrückruf für Kameraaufnahmesitzungen. Setze die ARCore-Sitzung innerhalb des onActive()-Callbacks fort, um im AR-Modus zu starten.

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)
}

Nahtlos zwischen Nicht-AR- und AR-Modus während der Laufzeit wechseln

So wechseln Sie vom Nicht-AR-Modus in den AR-Modus und setzen eine pausierte ARCore-Sitzung fort:

Java

// Resume the ARCore session.
resumeARCore();

Kotlin

// Resume the ARCore session.
resumeARCore()

So wechseln Sie vom AR- in den Nicht-AR-Modus:

Java

// Pause ARCore.
sharedSession.pause();

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

Kotlin

// Pause ARCore.
sharedSession.pause()

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