In diesem Entwicklerleitfaden erfährst du, wie du mit deiner App nahtlos zwischen der exklusiven Steuerung der Kamera über die Android Camera2 API und der Freigabe des Kamerazugriffs mit ARCore hin- und herwechseln kannst.
In diesem Thema wird Folgendes vorausgesetzt:
Sie haben den ARCore-Schnellstart abgeschlossen.
Sie sind mit der Android Camera2 API vertraut. Weitere Informationen finden Sie im Android-spezifischen Camera2-Beispiel.
Beispielanwendung erstellen und ausführen
Wenn Sie die Beispiel-App Shared Camera Java erstellen und ausführen, wird eine ARCore-Sitzung erstellt, die den gemeinsamen Kamerazugriff unterstützt. Die App wird im Nicht-AR-Modus gestartet, ARCore ist pausiert.
Wenn die App im Nicht-AR-Modus ausgeführt wird, zeigt die Kamera einen Sepia-Farbeffekt an. Wenn Sie in den AR-Modus wechseln, schaltet sich der Sepia-Effekt ab, da die pausierte Sitzung fortgesetzt wird, sobald die Kamerasteuerung auf ARCore zurückgesetzt wird.
Mit dem AR-Schalter in der App können Sie den Modus wechseln. In der Vorschau wird in beiden Modi die Anzahl der zusammenhängenden Frames angezeigt, die von Camera2 aufgenommen wurden.
So erstellen Sie die Java-Beispiel-App für freigegebene Kamera und führen sie aus:
Laden Sie das Google ARCore SDK for Android herunter und extrahieren Sie es.
Öffnen Sie das Projekt
samples/shared_camera_java
.Prüfen Sie, ob Ihr Android-Gerät über USB mit dem Entwicklungscomputer verbunden ist. Weitere Informationen finden Sie unter Unterstützte Geräte für ARCore.
Klicke in Android Studio auf Run .
Wählen Sie Ihr Gerät als Bereitstellungsziel aus und klicken Sie auf OK, um die Beispiel-App auf Ihrem Gerät zu starten.
Bestätigen Sie auf dem Gerät, dass die App Fotos und Videos aufnehmen darf.
Wenn du dazu aufgefordert wirst, aktualisiere oder installiere die neueste Version von ARCore.
Mit dem Schalter AR können Sie zwischen dem Nicht-AR- und dem AR-Modus wechseln.
Freigabe des Kamerazugriffs durch Apps mit ARCore
Führe die folgenden Schritte aus, um den gemeinsamen Kamerazugriff mit ARCore in deiner App zu implementieren.
Alle Code-Snippets sind in der SharedCameraActivity.java
im Beispiel shared_camera_java
verfügbar.
Berechtigung „CAMERA
“ anfordern
Um die Kamera des Geräts verwenden zu können, muss der Nutzer deiner App die Berechtigung CAMERA
erteilen.
Die ARCore-Beispiele enthalten ein CameraPermissionHelper
, das Dienstprogramme zum Anfordern der richtigen Berechtigung für Ihre App bereitstellt.
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, bevor es verwendet werden kann. Das folgende Snippet zeigt, wie eine Installation von ARCore angefordert wird, falls sie noch nicht auf dem Gerät installiert wurde.
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 wird die Sitzung erstellt und die Referenz und die ID der gemeinsam genutzten ARCore-Kamera gespeichert:
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 Leistung des Geräts. Testen Sie Ihre App auf den Geräten, die Ihre Nutzer verwenden werden, um sicherzustellen, dass sie gut funktioniert.
ARCore fordert standardmäßig zwei Streams an:
- 1x YUV-CPU-Stream, aktuell immer
640x480
.
ARCore verwendet diesen Stream für die Bewegungserkennung. - Ein 1x-GPU-Stream, in der Regel
1920x1080
.
Verwenden SieSession#getCameraConfig()
, um die aktuelle GPU-Stream-Auflösung zu ermitteln.
Sie können die Auflösung des GPU-Streams auf unterstützten Geräten mit getSupportedCameraConfigs()
und setCameraConfig()
ändern.
Als groben Indikator können Sie Folgendes erwarten:
Gerätetyp | Unterstützung gleichzeitiger Streams |
---|---|
High-End-Smartphones |
|
Smartphones der mittleren Preisklasse |
|
Wenn Sie benutzerdefinierte Oberflächen verwenden möchten, z. B. eine CPU-Bildleseoberfläche, müssen Sie sie der Liste der zu aktualisierenden Oberflächen hinzufügen (z. B. ImageReader
).
Java
sharedCamera.setAppSurfaces(this.cameraId, Arrays.asList(imageReader.getSurface()));
Kotlin
sharedCamera.setAppSurfaces(this.cameraId, listOf(imageReader.surface))
Kamera öffnen
Öffnen Sie die Kamera mithilfe eines mit ARCore verpackten Callbacks:
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)
Gerätestatus-Callback der Kamera verwenden
Im Callback zum Kameragerätestatus wird ein Verweis auf das Kameragerät gespeichert und eine neue Aufnahmesitzung gestartet.
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. Verwenden Sie TEMPLATE_RECORD
, damit die Aufnahmeanfrage mit ARCore kompatibel ist und während der Laufzeit ein nahtloser Wechsel zwischen dem Nicht-AR- und dem AR-Modus möglich ist.
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
Um mit der Aufnahme von Bildern zu beginnen, rufen Sie captureSession.setRepeatingRequest()
über den Callback onConfigured()
-Status der Kamerasitzung auf.
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)
}
Während der Laufzeit nahtlos zwischen AR- und AR-Modus 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-Modus 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()