1. Einführung
Die Möglichkeit, eine AR-Erfahrung in einer MP4-Datei zu speichern und aus der MP4-Datei wiederzugeben, kann sowohl für App-Entwickler als auch für Endnutzer nützlich sein.
Neue Funktionen am Schreibtisch debuggen und testen
Die ARCore Record & Playback API ist am einfachsten für Entwickler zu verwenden. Früher mussten Sie die App auf einem Testgerät erstellen und ausführen, das USB-Kabel trennen und herumlaufen, um eine kleine Codeänderung zu testen. Jetzt müssen Sie nur noch ein MP4 in der Testumgebung mit erwarteten Smartphone-Bewegungen aufzeichnen und können den Test direkt an Ihrem Schreibtisch durchführen.
Auf verschiedenen Geräten aufnehmen und wiedergeben
Mit den APIs für Aufzeichnung und Wiedergabe kann ein Nutzer eine Sitzung auf einem Gerät aufzeichnen und ein anderer Nutzer dieselbe Sitzung auf einem anderen Gerät wiedergeben. Sie können eine AR-Erfahrung für einen anderen Nutzer freigeben. Es gibt viele Möglichkeiten.
Erstellen Sie zum ersten Mal eine ARCore-App?
Wie werden Sie dieses Codelab verwenden?
Aufgaben
In diesem Codelab verwenden Sie die Recording & Playback API, um eine App zu erstellen, die sowohl eine AR-Erfahrung in einer MP4-Datei aufzeichnet als auch die Erfahrung aus derselben Datei wiedergibt. Lerninhalte:
- So speichern Sie eine AR-Sitzung mit der Recording API in einer MP4-Datei.
- So verwenden Sie die Playback API, um eine AR-Sitzung aus einer MP4-Datei wiederzugeben.
- So zeichnen Sie eine AR-Sitzung auf einem Gerät auf und geben sie auf einem anderen wieder.
Voraussetzungen
In diesem Codelab werden Sie die App Hello AR Java ändern, die mit dem ARCore Android SDK erstellt wurde. Sie benötigen bestimmte Hardware und Software, um die Anleitung nachzuvollziehen.
Hardwareanforderungen
- Ein von ARCore unterstütztes Gerät mit Entwickleroptionen aktiviert und USB-Debugging aktiviert, das über ein USB-Kabel mit Ihrem Entwicklercomputer verbunden ist.
- Ein Entwicklungscomputer, auf dem Sie Android Studio ausführen.
- Internetzugang zum Herunterladen von Bibliotheken während der Entwicklung.
Softwareanforderungen
- Google Play-Dienste für AR (ARCore) 1.24 oder höher auf Ihrem ARCore-Entwicklungsgerät. Dieser Dienst wird normalerweise automatisch über den Play Store auf dem Gerät installiert. Sie können es auch manuell auf einem Gerät mit ARCore-Unterstützung installieren.
- Android Studio (Version 3.1 oder höher) auf dem Entwicklungscomputer.
Für optimale Ergebnisse sollten Sie auch grundlegende Kenntnisse von ARCore haben.
2. Entwicklungsumgebung einrichten
Richten Sie zuerst Ihre Entwicklungsumgebung ein.
ARCore Android SDK herunterladen
Klicken Sie auf , um das SDK herunterzuladen.
ARCore Android SDK entpacken
Nachdem Sie das Android SDK auf Ihren Computer heruntergeladen haben, entpacken Sie die Datei und rufen Sie das Verzeichnis arcore-android-sdk-1.24/samples/hello_ar_java auf. Dies ist das Stammverzeichnis der App, mit der Sie arbeiten werden.

„Hello AR Java“ in Android Studio laden
Starten Sie Android Studio und klicken Sie auf Open an existing Android Studio project (Vorhandenes Android Studio-Projekt öffnen).

Wählen Sie im angezeigten Dialogfeld arcore-android-sdk-1.24/samples/hello_ar_java aus und klicken Sie auf Öffnen.
Warten Sie, bis Android Studio das Projekt synchronisiert hat. Wenn Komponenten fehlen, kann der Import des Projekts mit Fehlermeldungen fehlschlagen. Beheben Sie diese Probleme, bevor Sie fortfahren.
Beispiel-App ausführen
- Verbinden Sie ein ARCore-kompatibles Gerät mit Ihrem Entwicklungscomputer.
- Wenn das Gerät richtig erkannt wird, sollte der Gerätename in Android Studio angezeigt werden.

- Klicken Sie auf die Schaltfläche „Ausführen“ oder wählen Sie Ausführen > „App“ ausführen aus, damit Android Studio die App auf dem Gerät installiert und startet.

- Sie werden um die Berechtigung gebeten, Fotos und Videos aufzunehmen. Wählen Sie Beim Verwenden der App aus, um der App die Berechtigung für die Kamera zu erteilen. Auf dem Display des Geräts wird dann Ihre reale Umgebung angezeigt.

- Bewegen Sie das Gerät horizontal, um nach Flugzeugen zu suchen.
- Wenn die App eine Ebene erkennt, wird ein weißes Raster angezeigt. Tippen Sie darauf, um eine Markierung auf dieser Ebene zu platzieren.

Was Sie in diesem Schritt getan haben
- Hello AR-Java-Projekt einrichten
- Sie haben die Beispiel-App auf einem ARCore-kompatiblen Gerät erstellt und ausgeführt.
Als Nächstes nehmen Sie eine AR-Sitzung in einer MP4-Datei auf.
3. ARCore-Sitzung in einer MP4-Datei aufzeichnen
In diesem Schritt fügen wir die Aufnahmefunktion hinzu. Sie setzt sich aus folgenden Komponenten zusammen:
- Eine Schaltfläche zum Starten oder Beenden der Aufnahme.
- Speicherfunktionen zum Speichern der MP4-Datei auf dem Gerät.
- Aufrufe zum Starten oder Beenden der Aufzeichnung von ARCore-Sitzungen.
Benutzeroberfläche für die Schaltfläche „Aufzeichnen“ hinzufügen
Bevor Sie die Aufzeichnung implementieren, fügen Sie der Benutzeroberfläche eine Schaltfläche hinzu, damit der Nutzer ARCore mitteilen kann, wann die Aufzeichnung gestartet oder beendet werden soll.
Öffnen Sie im Projektfenster die Datei app/res/layout/activity_main.xml.

Standardmäßig wird in Android Studio die Designansicht verwendet, nachdem Sie die Datei app/res/layout/activity_main.xml geöffnet haben. Klicken Sie oben rechts auf dem Tab auf die Schaltfläche Code, um zur Codeansicht zu wechseln.

Fügen Sie in activity_main.xml vor dem schließenden Tag den folgenden Code ein, um die neue Schaltfläche Record zu erstellen und ihren Event-Handler auf eine Methode namens onClickRecord() festzulegen:
<!--
Add a new "Record" button with those attributes:
text is "Record",
onClick event handler is "onClickRecord",
text color is "red".
-->
<Button
android:id="@+id/record_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@id/surfaceview"
android:layout_alignBottom="@id/surfaceview"
android:layout_marginBottom="100dp"
android:onClick="onClickRecord"
android:text="Record"
android:textColor="@android:color/holo_red_light" />
Nachdem Sie den oben genannten Code hinzugefügt haben, wird möglicherweise vorübergehend der Fehler Corresponding method handler 'public void onClickRecord(android.view.View)' not found" angezeigt. Dies ist zu erwarten. In den nächsten Schritten beheben Sie den Fehler, indem Sie die Funktion onClickRecord() erstellen.
Text auf Schaltfläche basierend auf dem Status ändern
Mit der Schaltfläche Aufzeichnen können Sie die Aufnahme starten und beenden. Wenn die App keine Daten aufzeichnet, sollte das Wort „Aufzeichnen“ angezeigt werden. Wenn die App Daten aufzeichnet, sollte auf der Schaltfläche „Stopp“ angezeigt werden.
Damit der Button diese Funktion ausführen kann, muss die App seinen aktuellen Status kennen. Mit dem folgenden Code wird ein neues Enum namens AppState erstellt, um den Arbeitsstatus der App darzustellen. Bestimmte Statusänderungen werden über eine private Member-Variable namens appState erfasst. Fügen Sie sie HelloArActivity.java am Anfang der Klasse HelloArActivity hinzu.
// Represents the app's working state.
public enum AppState {
Idle,
Recording
}
// Tracks app's specific state changes.
private AppState appState = AppState.Idle;
Nachdem Sie den internen Status der App verfolgen können, erstellen Sie eine Funktion namens updateRecordButton(), die den Text der Schaltfläche basierend auf dem aktuellen Status der App ändert. Fügen Sie den folgenden Code in die Klasse HelloArActivity in HelloArActivity.java ein.
// Add imports to the beginning of the file.
import android.widget.Button;
// Update the "Record" button based on app's internal state.
private void updateRecordButton() {
View buttonView = findViewById(R.id.record_button);
Button button = (Button) buttonView;
switch (appState) {
case Idle:
button.setText("Record");
break;
case Recording:
button.setText("Stop");
break;
}
}
Erstellen Sie als Nächstes die Methode onClickRecord(), die den Status der App prüft, ihn in den nächsten Status ändert und updateRecordButton() aufruft, um die Benutzeroberfläche der Schaltfläche zu ändern. Fügen Sie den folgenden Code in die Klasse HelloArActivity in HelloArActivity.java ein.
// Handle the "Record" button click event.
public void onClickRecord(View view) {
Log.d(TAG, "onClickRecord");
// Check the app's internal state and switch to the new state if needed.
switch (appState) {
// If the app is not recording, begin recording.
case Idle: {
boolean hasStarted = startRecording();
Log.d(TAG, String.format("onClickRecord start: hasStarted %b", hasStarted));
if (hasStarted)
appState = AppState.Recording;
break;
}
// If the app is recording, stop recording.
case Recording: {
boolean hasStopped = stopRecording();
Log.d(TAG, String.format("onClickRecord stop: hasStopped %b", hasStopped));
if (hasStopped)
appState = AppState.Idle;
break;
}
default:
// Do nothing.
break;
}
updateRecordButton();
}
App zum Starten der Aufnahme aktivieren
Sie müssen nur zwei Dinge tun, um die Aufnahme in ARCore zu starten:
- Geben Sie den URI der Aufzeichnungsdatei in einem
RecordingConfig-Objekt an. session.startRecordingmit demRecordingConfig-Objekt aufrufen
Der Rest ist nur Boilerplate-Code: Konfiguration, Protokollierung und Überprüfung auf Richtigkeit.
Erstellen Sie eine neue Funktion namens startRecording(), die Daten aufzeichnet und in einem MP4-URI speichert. Fügen Sie den folgenden Code in die Klasse HelloArActivity in HelloArActivity.java ein.
// Add imports to the beginning of the file.
import android.net.Uri;
import com.google.ar.core.RecordingConfig;
import com.google.ar.core.RecordingStatus;
import com.google.ar.core.exceptions.RecordingFailedException;
private boolean startRecording() {
Uri mp4FileUri = createMp4File();
if (mp4FileUri == null)
return false;
Log.d(TAG, "startRecording at: " + mp4FileUri);
pauseARCoreSession();
// Configure the ARCore session to start recording.
RecordingConfig recordingConfig = new RecordingConfig(session)
.setMp4DatasetUri(mp4FileUri)
.setAutoStopOnPause(true);
try {
// Prepare the session for recording, but do not start recording yet.
session.startRecording(recordingConfig);
} catch (RecordingFailedException e) {
Log.e(TAG, "startRecording - Failed to prepare to start recording", e);
return false;
}
boolean canResume = resumeARCoreSession();
if (!canResume)
return false;
// Correctness checking: check the ARCore session's RecordingState.
RecordingStatus recordingStatus = session.getRecordingStatus();
Log.d(TAG, String.format("startRecording - recordingStatus %s", recordingStatus));
return recordingStatus == RecordingStatus.OK;
}
Wenn Sie eine ARCore-Sitzung sicher pausieren und fortsetzen möchten, erstellen Sie pauseARCoreSession() und resumeARCoreSession() in HelloArActivity.java.
private void pauseARCoreSession() {
// Pause the GLSurfaceView so that it doesn't update the ARCore session.
// Pause the ARCore session so that we can update its configuration.
// If the GLSurfaceView is not paused,
// onDrawFrame() will try to update the ARCore session
// while it's paused, resulting in a crash.
surfaceView.onPause();
session.pause();
}
private boolean resumeARCoreSession() {
// We must resume the ARCore session before the GLSurfaceView.
// Otherwise, the GLSurfaceView will try to update the ARCore session.
try {
session.resume();
} catch (CameraNotAvailableException e) {
Log.e(TAG, "CameraNotAvailableException in resumeARCoreSession", e);
return false;
}
surfaceView.onResume();
return true;
}
App erlauben, die Aufnahme zu beenden
Erstellen Sie in HelloArActivity.java eine Funktion namens stopRecording(), um zu verhindern, dass Ihre App neue Daten aufzeichnet. Diese Funktion ruft session.stopRecording() auf und sendet einen Fehler an das Konsolenprotokoll, wenn die App die Aufzeichnung nicht beenden kann.
private boolean stopRecording() {
try {
session.stopRecording();
} catch (RecordingFailedException e) {
Log.e(TAG, "stopRecording - Failed to stop recording", e);
return false;
}
// Correctness checking: check if the session stopped recording.
return session.getRecordingStatus() == RecordingStatus.NONE;
}
Dateispeicher mit dem begrenzten Speicher von Android 11 entwerfen
Die speicherbezogenen Funktionen in diesem Codelab wurden gemäß den neuen Anforderungen für den eingeschränkten Speicherzugriff in Android 11 entwickelt.
Nehmen Sie einige kleine Änderungen an der Datei app/build.gradle vor, um Android 11 als Ziel zu verwenden. Im Bereich „Projekt“ von Android Studio befindet sich diese Datei unter dem Knoten Gradle Scripts, der dem Modul app zugeordnet ist.

Ändern Sie compileSdkVersion und targetSdkVersion in 30.
compileSdkVersion 30
defaultConfig {
targetSdkVersion 30
}
Verwenden Sie für die Aufzeichnung die Android MediaStore API, um die MP4-Datei im freigegebenen Filmverzeichnis zu erstellen.
Erstellen Sie in HelloArActivity.java eine Funktion mit dem Namen createMp4File():
// Add imports to the beginning of the file.
import java.text.SimpleDateFormat;
import android.content.ContentResolver;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;
import android.content.ContentValues;
import java.io.File;
import android.content.CursorLoader;
import android.database.Cursor;
import java.util.Date;
private final String MP4_VIDEO_MIME_TYPE = "video/mp4";
private Uri createMp4File() {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
String mp4FileName = "arcore-" + dateFormat.format(new Date()) + ".mp4";
ContentResolver resolver = this.getContentResolver();
Uri videoCollection = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
videoCollection = MediaStore.Video.Media.getContentUri(
MediaStore.VOLUME_EXTERNAL_PRIMARY);
} else {
videoCollection = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
}
// Create a new Media file record.
ContentValues newMp4FileDetails = new ContentValues();
newMp4FileDetails.put(MediaStore.Video.Media.DISPLAY_NAME, mp4FileName);
newMp4FileDetails.put(MediaStore.Video.Media.MIME_TYPE, MP4_VIDEO_MIME_TYPE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// The Relative_Path column is only available since API Level 29.
newMp4FileDetails.put(MediaStore.Video.Media.RELATIVE_PATH, Environment.DIRECTORY_MOVIES);
} else {
// Use the Data column to set path for API Level <= 28.
File mp4FileDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES);
String absoluteMp4FilePath = new File(mp4FileDir, mp4FileName).getAbsolutePath();
newMp4FileDetails.put(MediaStore.Video.Media.DATA, absoluteMp4FilePath);
}
Uri newMp4FileUri = resolver.insert(videoCollection, newMp4FileDetails);
// Ensure that this file exists and can be written.
if (newMp4FileUri == null) {
Log.e(TAG, String.format("Failed to insert Video entity in MediaStore. API Level = %d", Build.VERSION.SDK_INT));
return null;
}
// This call ensures the file exist before we pass it to the ARCore API.
if (!testFileWriteAccess(newMp4FileUri)) {
return null;
}
Log.d(TAG, String.format("createMp4File = %s, API Level = %d", newMp4FileUri, Build.VERSION.SDK_INT));
return newMp4FileUri;
}
// Test if the file represented by the content Uri can be open with write access.
private boolean testFileWriteAccess(Uri contentUri) {
try (java.io.OutputStream mp4File = this.getContentResolver().openOutputStream(contentUri)) {
Log.d(TAG, String.format("Success in testFileWriteAccess %s", contentUri.toString()));
return true;
} catch (java.io.FileNotFoundException e) {
Log.e(TAG, String.format("FileNotFoundException in testFileWriteAccess %s", contentUri.toString()), e);
} catch (java.io.IOException e) {
Log.e(TAG, String.format("IOException in testFileWriteAccess %s", contentUri.toString()), e);
}
return false;
}
Speicherberechtigungen verarbeiten
Wenn Sie ein Gerät mit Android 11 verwenden, können Sie mit dem Testen des Codes beginnen. Um Geräte mit Android 10 oder niedriger zu unterstützen, müssen Sie der App Speicherberechtigungen erteilen, damit Daten im Dateisystem des Zielgeräts gespeichert werden können.
Deklarieren Sie in AndroidManifest.xml, dass die App vor Android 11 (API-Level 30) Lese- und Schreibberechtigungen für den Speicher benötigt.
<!-- Inside the <manifest> tag, below the existing Camera permission -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="29" />
Fügen Sie in HelloArActivity.java eine Hilfsfunktion namens checkAndRequestStoragePermission() hinzu, um die WRITE_EXTERNAL_STORAGE-Berechtigungen während der Laufzeit anzufordern.
// Add imports to the beginning of the file.
import android.Manifest;
import android.content.pm.PackageManager;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
private final int REQUEST_WRITE_EXTERNAL_STORAGE = 1;
public boolean checkAndRequestStoragePermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
REQUEST_WRITE_EXTERNAL_STORAGE);
return false;
}
return true;
}
Wenn Sie API-Level 29 oder niedriger verwenden, fügen Sie oben in createMp4File() eine Prüfung auf Speicherberechtigungen ein und beenden Sie die Funktion frühzeitig, wenn die App nicht die richtigen Berechtigungen hat. Für den Zugriff auf Dateien in MediaStore ist bei API-Level 30 (Android 11) keine Speicherberechtigung erforderlich.
private Uri createMp4File() {
// Since we use legacy external storage for Android 10,
// we still need to request for storage permission on Android 10.
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
if (!checkAndRequestStoragePermission()) {
Log.i(TAG, String.format(
"Didn't createMp4File. No storage permission, API Level = %d",
Build.VERSION.SDK_INT));
return null;
}
}
// ... omitted code ...
}
Auf dem Zielgerät aufzeichnen
Sehen wir uns an, was Sie bisher erstellt haben. Verbinden Sie Ihr Mobilgerät mit Ihrem Entwicklercomputer und klicken Sie in Android Studio auf Run (Ausführen).
Unten links auf dem Bildschirm sollte eine rote Schaltfläche Aufzeichnen angezeigt werden. Wenn Sie darauf tippen, sollte sich der Text in Beenden ändern. Bewegen Sie Ihr Gerät, um eine Sitzung aufzuzeichnen, und klicken Sie auf die Schaltfläche Beenden, wenn Sie die Aufzeichnung abschließen möchten. Dadurch sollte eine neue Datei mit dem Namen arcore-xxxxxx_xxxxxx.mp4 auf dem externen Speicher Ihres Geräts gespeichert werden.

Jetzt sollte sich eine neue arcore-xxxxxx_xxxxxx.mp4-Datei auf dem externen Speicher Ihres Geräts befinden. Auf Pixel 5-Geräten lautet der Pfad /storage/emulated/0/Movies/. Der Pfad wird nach dem Starten einer Aufzeichnung im Logcat-Fenster angezeigt.
com.google.ar.core.examples.java.helloar D/HelloArActivity: startRecording at:/storage/emulated/0/Movies/arcore-xxxxxxxx_xxxxxx.mp4 com.google.ar.core.examples.java.helloar D/HelloArActivity: startRecording - RecordingStatus OK
Aufzeichnung ansehen
Sie können sich die Aufzeichnung in einer Dateisystem-App wie Files by Google ansehen oder sie auf Ihren Entwicklungscomputer kopieren. Im Folgenden finden Sie die beiden adb-Befehle zum Auflisten und Abrufen von Dateien vom Android-Gerät:
adb shell ls '$EXTERNAL_STORAGE/Movies/*', um die Dateien im Verzeichnis „Filme“ im externen Speicher auf dem Gerät anzuzeigenadb pull /absolute_path_from_previous_adb_shell_ls/arcore-xxxxxxxx_xxxxxx.mp4, um die Datei vom Gerät auf den Entwicklungscomputer zu kopieren
Hier sehen Sie ein Beispiel für die Ausgabe nach der Verwendung dieser beiden Befehle (unter macOS):
$ adb shell ls '$EXTERNAL_STORAGE/Movies/*' /sdcard/Movies/arcore-xxxxxxxx_xxxxxx.mp4 $ adb pull /sdcard/Movies/arcore-xxxxxxxx_xxxxxx.mp4 /sdcard/Movies/arcore-xxxxxxxx_xxxxxx.mp4: ... pulled
Was Sie in diesem Schritt getan haben
- Es wurde eine Schaltfläche zum Starten und Beenden der Aufnahme hinzugefügt.
- Funktionen zum Starten und Beenden der Aufnahme implementiert
- App auf dem Gerät getestet
- Die aufgezeichnete MP4-Datei wurde auf Ihren Computer kopiert und überprüft.
Als Nächstes spielen Sie eine AR-Sitzung aus einer MP4-Datei ab.
4. ARCore-Sitzung aus einer MP4-Datei wiedergeben
Sie haben jetzt die Schaltfläche Aufzeichnen und einige MP4-Dateien mit aufgezeichneten Sitzungen. Jetzt werden sie mit der ARCore Playback API wiedergegeben.
Benutzeroberfläche für die Schaltfläche „Wiedergabe“ hinzufügen
Bevor Sie die Wiedergabe implementieren, fügen Sie der Benutzeroberfläche eine Schaltfläche hinzu, damit der Nutzer ARCore mitteilen kann, wann die Wiedergabe der Sitzung beginnen und enden soll.
Öffnen Sie im Bereich Projekt die Datei app/res/layout/activity_main.xml.

Fügen Sie in activity_main.xml den folgenden Code vor dem schließenden Tag ein, um die neue Schaltfläche Wiedergabe zu erstellen und ihren Ereignishandler auf eine Methode namens onClickPlayback() festzulegen. Diese Schaltfläche ähnelt der Schaltfläche Aufzeichnen und wird auf der rechten Seite des Bildschirms angezeigt.
<!--
Add a new "Playback" button with those attributes:
text is "Playback",
onClick event handler is "onClickPlayback",
text color is "green".
-->
<Button
android:id="@+id/playback_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignEnd="@id/surfaceview"
android:layout_alignBottom="@id/surfaceview"
android:layout_marginBottom="100dp"
android:onClick="onClickPlayback"
android:text="Playback"
android:textColor="@android:color/holo_green_light" />
Schaltflächen während der Wiedergabe aktualisieren
Die App hat jetzt einen neuen Status namens Playingback. Aktualisieren Sie das AppState-Enum und alle vorhandenen Funktionen, die appState als Argument verwenden, um dies zu berücksichtigen.
Fügen Sie Playingback dem Enum AppState in HelloArActivity.java hinzu:
public enum AppState {
Idle,
Recording,
Playingback // New enum value.
}
Wenn die Schaltfläche Aufzeichnen während der Wiedergabe weiterhin auf dem Bildschirm angezeigt wird, kann es passieren, dass der Nutzer versehentlich darauf klickt. Um das zu vermeiden, können Sie die Schaltfläche Aufzeichnen während der Wiedergabe ausblenden. So müssen Sie den Status für Playingback nicht in onClickRecord() verarbeiten.
Ändern Sie die updateRecordButton()-Funktion in HelloArActivity.java, um die Schaltfläche Aufzeichnen auszublenden, wenn sich die App im Status Playingback befindet.
// Update the "Record" button based on app's internal state.
private void updateRecordButton() {
View buttonView = findViewById(R.id.record_button);
Button button = (Button)buttonView;
switch (appState) {
// The app is neither recording nor playing back. The "Record" button is visible.
case Idle:
button.setText("Record");
button.setVisibility(View.VISIBLE);
break;
// While recording, the "Record" button is visible and says "Stop".
case Recording:
button.setText("Stop");
button.setVisibility(View.VISIBLE);
break;
// During playback, the "Record" button is not visible.
case Playingback:
button.setVisibility(View.INVISIBLE);
break;
}
}
Blende die Schaltfläche Wiedergabe aus, wenn der Nutzer eine Sitzung aufzeichnet, und ändere die Beschriftung in „Stopp“, wenn der Nutzer eine Sitzung aktiv wiedergibt. So können sie die Wiedergabe beenden, ohne warten zu müssen, bis sie von selbst abgeschlossen ist.
updatePlaybackButton()-Funktion in HelloArActivity.java hinzufügen:
// Update the "Playback" button based on app's internal state.
private void updatePlaybackButton() {
View buttonView = findViewById(R.id.playback_button);
Button button = (Button)buttonView;
switch (appState) {
// The app is neither recording nor playing back. The "Playback" button is visible.
case Idle:
button.setText("Playback");
button.setVisibility(View.VISIBLE);
break;
// While playing back, the "Playback" button is visible and says "Stop".
case Playingback:
button.setText("Stop");
button.setVisibility(View.VISIBLE);
break;
// During recording, the "Playback" button is not visible.
case Recording:
button.setVisibility(View.INVISIBLE);
break;
}
}
Aktualisieren Sie schließlich onClickRecord(), um updatePlaybackButton() aufzurufen. Fügen Sie HelloArActivity.java die folgende Zeile hinzu:
public void onClickRecord(View view) {
// ... omitted code ...
updatePlaybackButton(); // Add this line to the end of the function.
}
Datei mit der Schaltfläche „Wiedergabe“ auswählen
Wenn der Nutzer auf die Schaltfläche Wiedergabe tippt, sollte er eine Datei zur Wiedergabe auswählen können. Unter Android erfolgt die Dateiauswahl in der Systemdateiauswahl in einer anderen Aktivität. Dies erfolgt über das Storage Access Framework (SAF). Sobald der Nutzer eine Datei auswählt, erhält die App einen Callback namens onActivityResult(). Die eigentliche Wiedergabe wird in dieser Callback-Funktion gestartet.
Erstellen Sie in HelloArActivity.java eine onClickPlayback()-Funktion, um die Dateiauswahl zu treffen und die Wiedergabe zu beenden.
// Handle the click event of the "Playback" button.
public void onClickPlayback(View view) {
Log.d(TAG, "onClickPlayback");
switch (appState) {
// If the app is not playing back, open the file picker.
case Idle: {
boolean hasStarted = selectFileToPlayback();
Log.d(TAG, String.format("onClickPlayback start: selectFileToPlayback %b", hasStarted));
break;
}
// If the app is playing back, stop playing back.
case Playingback: {
boolean hasStopped = stopPlayingback();
Log.d(TAG, String.format("onClickPlayback stop: hasStopped %b", hasStopped));
break;
}
default:
// Recording - do nothing.
break;
}
// Update the UI for the "Record" and "Playback" buttons.
updateRecordButton();
updatePlaybackButton();
}
Erstellen Sie in HelloArActivity.java eine selectFileToPlayback()-Funktion, die eine Datei auf dem Gerät auswählt. Wenn Sie eine Datei aus dem Android-Dateisystem auswählen möchten, verwenden Sie einen ACTION_OPEN_DOCUMENT-Intent.
// Add imports to the beginning of the file.
import android.content.Intent;
import android.provider.DocumentsContract;
private boolean selectFileToPlayback() {
// Start file selection from Movies directory.
// Android 10 and above requires VOLUME_EXTERNAL_PRIMARY to write to MediaStore.
Uri videoCollection;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
videoCollection = MediaStore.Video.Media.getContentUri(
MediaStore.VOLUME_EXTERNAL_PRIMARY);
} else {
videoCollection = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
}
// Create an Intent to select a file.
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
// Add file filters such as the MIME type, the default directory and the file category.
intent.setType(MP4_VIDEO_MIME_TYPE); // Only select *.mp4 files
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, videoCollection); // Set default directory
intent.addCategory(Intent.CATEGORY_OPENABLE); // Must be files that can be opened
this.startActivityForResult(intent, REQUEST_MP4_SELECTOR);
return true;
}
REQUEST_MP4_SELECTOR ist eine Konstante zur Identifizierung dieser Anfrage. Sie können sie mit einem beliebigen Platzhalterwert in HelloArActivity in HelloArActivity.java definieren:
private int REQUEST_MP4_SELECTOR = 1;
Überschreiben Sie die Funktion onActivityResult() in HelloArActivity.java, um den Callback von der Dateiauswahl zu verarbeiten.
// Begin playback once the user has selected the file.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// Check request status. Log an error if the selection fails.
if (resultCode != android.app.Activity.RESULT_OK || requestCode != REQUEST_MP4_SELECTOR) {
Log.e(TAG, "onActivityResult select file failed");
return;
}
Uri mp4FileUri = data.getData();
Log.d(TAG, String.format("onActivityResult result is %s", mp4FileUri));
// Begin playback.
startPlayingback(mp4FileUri);
}
Wiedergabe in der App aktivieren
Für die Wiedergabe einer MP4-Datei in einer ARCore-Sitzung sind drei API-Aufrufe erforderlich:
session.pause()session.setPlaybackDataset()session.resume()
Erstellen Sie in HelloArActivity.java die Funktion startPlayingback().
// Add imports to the beginning of the file.
import com.google.ar.core.PlaybackStatus;
import com.google.ar.core.exceptions.PlaybackFailedException;
private boolean startPlayingback(Uri mp4FileUri) {
if (mp4FileUri == null)
return false;
Log.d(TAG, "startPlayingback at:" + mp4FileUri);
pauseARCoreSession();
try {
session.setPlaybackDatasetUri(mp4FileUri);
} catch (PlaybackFailedException e) {
Log.e(TAG, "startPlayingback - setPlaybackDataset failed", e);
}
// The session's camera texture name becomes invalid when the
// ARCore session is set to play back.
// Workaround: Reset the Texture to start Playback
// so it doesn't crashes with AR_ERROR_TEXTURE_NOT_SET.
hasSetTextureNames = false;
boolean canResume = resumeARCoreSession();
if (!canResume)
return false;
PlaybackStatus playbackStatus = session.getPlaybackStatus();
Log.d(TAG, String.format("startPlayingback - playbackStatus %s", playbackStatus));
if (playbackStatus != PlaybackStatus.OK) { // Correctness check
return false;
}
appState = AppState.Playingback;
updateRecordButton();
updatePlaybackButton();
return true;
}
App zum Beenden der Wiedergabe aktivieren
Erstellen Sie in HelloArActivity.java eine Funktion mit dem Namen stopPlayingback(), um die Änderungen am App-Status nach folgenden Ereignissen zu verarbeiten:
- Die MP4-Wiedergabe wurde vom Nutzer beendet
- Die MP4-Wiedergabe wurde automatisch beendet.
Wenn der Nutzer die Wiedergabe beendet hat, sollte die App in den Zustand zurückkehren, in dem sie sich befand, als der Nutzer sie zum ersten Mal gestartet hat.
// Stop the current playback, and restore app status to Idle.
private boolean stopPlayingback() {
// Correctness check, only stop playing back when the app is playing back.
if (appState != AppState.Playingback)
return false;
pauseARCoreSession();
// Close the current session and create a new session.
session.close();
try {
session = new Session(this);
} catch (UnavailableArcoreNotInstalledException
|UnavailableApkTooOldException
|UnavailableSdkTooOldException
|UnavailableDeviceNotCompatibleException e) {
Log.e(TAG, "Error in return to Idle state. Cannot create new ARCore session", e);
return false;
}
configureSession();
boolean canResume = resumeARCoreSession();
if (!canResume)
return false;
// A new session will not have a camera texture name.
// Manually set hasSetTextureNames to false to trigger a reset.
hasSetTextureNames = false;
// Reset appState to Idle, and update the "Record" and "Playback" buttons.
appState = AppState.Idle;
updateRecordButton();
updatePlaybackButton();
return true;
}
Die Wiedergabe kann auch automatisch beendet werden, wenn der Player das Ende der MP4-Datei erreicht hat. In diesem Fall sollte stopPlayingback() den Status der App wieder auf Idle zurücksetzen. Prüfen Sie in onDrawFrame() die PlaybackStatus. Wenn es FINISHED ist, rufen Sie die Funktion stopPlayingback() im UI-Thread auf.
public void onDrawFrame(SampleRender render) {
// ... omitted code ...
// Insert before this line:
// frame = session.update();
// Check the playback status and return early if playback reaches the end.
if (appState == AppState.Playingback
&& session.getPlaybackStatus() == PlaybackStatus.FINISHED) {
this.runOnUiThread(this::stopPlayingback);
return;
}
// ... omitted code ...
}
Wiedergabe auf dem Zielgerät
Sehen wir uns an, was Sie bisher erstellt haben. Verbinden Sie Ihr Mobilgerät mit Ihrem Entwicklercomputer und klicken Sie in Android Studio auf Run (Ausführen).
Wenn die App gestartet wird, sollte ein Bildschirm mit einer roten Schaltfläche Aufzeichnen auf der linken Seite und einer grünen Schaltfläche Wiedergabe auf der rechten Seite angezeigt werden.

Tippen Sie auf die Schaltfläche Wiedergabe und wählen Sie eine der MP4-Dateien aus, die Sie gerade aufgenommen haben. Wenn Sie keine Dateinamen sehen, die mit arcore- beginnen, wird auf Ihrem Gerät möglicherweise der Ordner Filme nicht angezeigt. Rufen Sie in diesem Fall über das Menü oben links den Ordner Smartphone-Modell > Filme auf. Möglicherweise müssen Sie auch die Option Internen Speicher anzeigen aktivieren, damit der Ordner des Smartphone-Modells angezeigt wird.


Tippen Sie auf einen Dateinamen auf dem Bildschirm, um die MP4-Datei auszuwählen. Die App sollte die MP4-Datei abspielen.

Ein Unterschied zwischen der Wiedergabe einer Sitzung und der Wiedergabe eines normalen Videos besteht darin, dass Sie mit der aufgezeichneten Sitzung interagieren können. Tippe auf eine erkannte Ebene, um Markierungen auf dem Bildschirm zu platzieren.

Was Sie in diesem Schritt getan haben
- Schaltfläche zum Starten und Beenden der Wiedergabe hinzugefügt
- Eine Funktion zum Starten und Beenden der Aufnahme durch die App wurde implementiert.
- Eine zuvor auf dem Gerät aufgezeichnete ARCore-Sitzung wurde wiedergegeben.
5. Zusätzliche Daten in der MP4-Datei aufzeichnen
Mit ARCore 1.24 ist es möglich, zusätzliche Informationen in der MP4-Datei aufzuzeichnen. Sie können die Pose von AR-Objektplatzierungen aufzeichnen und die AR-Objekte dann bei der Wiedergabe an derselben Stelle erstellen.
Neuen Track für die Aufzeichnung konfigurieren
Definieren Sie einen neuen Track mit einer UUID und einem MIME-Tag in HelloArActivity.java.
// Add imports to the beginning of the file.
import java.util.UUID;
import com.google.ar.core.Track;
// Inside the HelloArActiity class.
private static final UUID ANCHOR_TRACK_ID = UUID.fromString("53069eb5-21ef-4946-b71c-6ac4979216a6");;
private static final String ANCHOR_TRACK_MIME_TYPE = "application/recording-playback-anchor";
private boolean startRecording() {
// ... omitted code ...
// Insert after line:
// pauseARCoreSession();
// Create a new Track, with an ID and MIME tag.
Track anchorTrack = new Track(session)
.setId(ANCHOR_TRACK_ID).
.setMimeType(ANCHOR_TRACK_MIME_TYPE);
// ... omitted code ...
}
Aktualisieren Sie den vorhandenen Code, um das RecordingConfig-Objekt mit einem Aufruf von addTrack() zu erstellen.
private boolean startRecording() {
// ... omitted code ...
// Update the lines below with a call to the addTrack() function:
// RecordingConfig recordingConfig = new RecordingConfig(session)
// .setMp4DatasetUri(mp4FileUri)
// .setAutoStopOnPause(true);
RecordingConfig recordingConfig = new RecordingConfig(session)
.setMp4DatasetUri(mp4FileUri)
.setAutoStopOnPause(true)
.addTrack(anchorTrack); // add the new track onto the recordingConfig
// ... omitted code ...
}
Ankerpose während der Aufnahme speichern
Jedes Mal, wenn der Nutzer auf eine erkannte Ebene tippt, wird eine AR-Markierung auf einem Anchor platziert, dessen Position von ARCore aktualisiert wird.
Die Position eines Anchor wird im Frame aufgezeichnet, in dem es erstellt wird, sofern die ARCore-Sitzung noch aufgezeichnet wird.
Ändern Sie die Funktion handleTap() in HelloArActivity.java.
// Add imports to the beginning of the file.
import com.google.ar.core.Pose;
import java.nio.FloatBuffer;
private void handleTap(Frame frame, Camera camera) {
// ... omitted code ...
// Insert after line:
// anchors.add(hit.createAnchor());
// If the app is recording a session,
// save the new Anchor pose (relative to the camera)
// into the ANCHOR_TRACK_ID track.
if (appState == AppState.Recording) {
// Get the pose relative to the camera pose.
Pose cameraRelativePose = camera.getPose().inverse().compose(hit.getHitPose());
float[] translation = cameraRelativePose.getTranslation();
float[] quaternion = cameraRelativePose.getRotationQuaternion();
ByteBuffer payload = ByteBuffer.allocate(4 * (translation.length + quaternion.length));
FloatBuffer floatBuffer = payload.asFloatBuffer();
floatBuffer.put(translation);
floatBuffer.put(quaternion);
try {
frame.recordTrackData(ANCHOR_TRACK_ID, payload);
} catch (IllegalStateException e) {
Log.e(TAG, "Error in recording anchor into external data track.", e);
}
}
// ... omitted code ...
}
Wir speichern die kamerabezogene Pose und nicht die weltbezogene Pose, weil der Weltursprung einer Aufzeichnungssitzung und der Weltursprung einer Wiedergabesitzung nicht identisch sind. Der Weltursprung einer Aufzeichnungssitzung wird beim ersten Fortsetzen der Sitzung festgelegt, wenn Session.resume() zum ersten Mal aufgerufen wird. Der Ursprung der Welt einer Wiedergabesitzung beginnt, wenn der erste Frame aufgezeichnet wird, wenn Session.resume() zum ersten Mal nach Session.startRecording() aufgerufen wird.
Wiedergabeanker erstellen
Das Erstellen einer neuen Anchor ist ganz einfach. Fügen Sie in HelloArActivity.java eine Funktion namens createRecordedAnchors() hinzu.
// Add imports to the beginning of the file.
import com.google.ar.core.TrackData;
// Extract poses from the ANCHOR_TRACK_ID track, and create new anchors.
private void createRecordedAnchors(Frame frame, Camera camera) {
// Get all `ANCHOR_TRACK_ID` TrackData from the frame.
for (TrackData trackData : frame.getUpdatedTrackData(ANCHOR_TRACK_ID)) {
ByteBuffer payload = trackData.getData();
FloatBuffer floatBuffer = payload.asFloatBuffer();
// Extract translation and quaternion from TrackData payload.
float[] translation = new float[3];
float[] quaternion = new float[4];
floatBuffer.get(translation);
floatBuffer.get(quaternion);
// Transform the recorded anchor pose
// from the camera coordinate
// into world coordinates.
Pose worldPose = camera.getPose().compose(new Pose(translation, quaternion));
// Re-create an anchor at the recorded pose.
Anchor recordedAnchor = session.createAnchor(worldPose);
// Add the new anchor into the list of anchors so that
// the AR marker can be displayed on top.
anchors.add(recordedAnchor);
}
}
Rufen Sie createRecordedAnchors() in der Funktion onDrawFrame() in HelloArActivity.java auf.
public void onDrawFrame(SampleRender render) {
// ... omitted code ...
// Insert after this line:
// handleTap(frame, camera);
// If the app is currently playing back a session, create recorded anchors.
if (appState == AppState.Playingback) {
createRecordedAnchors(frame, camera);
}
// ... omitted code ...
}
Auf dem Zielgerät testen
Verbinden Sie Ihr Mobilgerät mit Ihrem Entwicklercomputer und klicken Sie in Android Studio auf Run (Ausführen).
Tippe zuerst auf die Schaltfläche Aufzeichnen, um eine Trainingseinheit aufzuzeichnen. Tippen Sie während der Aufnahme auf erkannte Flugzeuge, um einige AR-Markierungen zu platzieren.
Tippe nach dem Beenden der Aufnahme auf die Schaltfläche Wiedergabe und wähle die Datei aus, die du gerade aufgenommen hast. Die Wiedergabe sollte beginnen. Beachten Sie, dass die vorherigen Platzierungen von AR-Markern genau so angezeigt werden, wie Sie auf die App getippt haben.
Das ist der gesamte Code, den Sie für dieses Codelab schreiben müssen.
6. Glückwunsch
Herzlichen Glückwunsch, Sie haben das Codelab abgeschlossen. Sehen wir uns an, was Sie in diesem Codelab gemacht haben:
- Sie haben das ARCore-Beispiel Hello AR Java erstellt und ausgeführt.
- Der App wurde eine Schaltfläche zum Aufzeichnen hinzugefügt, mit der eine AR-Sitzung in einer MP4-Datei gespeichert werden kann.
- Der App wurde eine Wiedergabetaste hinzugefügt, mit der eine AR-Sitzung aus einer MP4-Datei wiedergegeben werden kann.
- Es wurde eine neue Funktion hinzugefügt, mit der vom Nutzer erstellte Anker in der MP4-Datei für die Wiedergabe gespeichert werden können.