ARCore Kayıt ve Oynatma API'sine Giriş

1. Giriş

AR deneyimini MP4 dosyasına kaydedip MP4 dosyasından oynatma imkanı, hem uygulama geliştiriciler hem de son kullanıcılar için faydalı olabilir.

Masanızda hata ayıklayın ve yeni özellikleri test edin

ARCore Kaydı ve Oynatma API'si geliştiriciler içindir. Uygulamayı bir test cihazında oluşturup çalıştırmanız, USB kablosunu çıkarmanız ve yalnızca küçük bir kod değişikliğini test etmek için etrafta dolaşmanız gereken günler geride kaldı. Artık bir MP4 dosyasını test ortamında beklenen telefon hareketiyle kaydedip doğrudan masanızdan test etmeniz gerekiyor.

İçerikleri farklı cihazlardan kaydedip oynatın

Kayıt ve Oynatma API'leriyle, bir kullanıcı bir oturumu bir cihazı kullanarak kaydedebilir ve başka bir kullanıcı aynı oturumu farklı bir cihazda oynatabilir. Artırılmış gerçeklik (AR) deneyimini başka bir kullanıcıyla paylaşmak mümkündür. Çok sayıda olasılık var.

İlk kez bir ARCore uygulaması mı geliştiriyorsunuz?

Hayır. Evet.

Bu codelab'i nasıl kullanacaksınız?

Yalnızca baştan sona oku Okuyun ve alıştırmaları tamamlayın

Neler oluşturacaksınız?

Bu codelab'de Kayıt ve Hem AR deneyimini MP4 dosyasına kaydeden hem de deneyimi aynı dosyadan oynatan bir uygulama oluşturmak için Playback API'sini kullanın. Öğrenecekleriniz:

  • AR oturumunu MP4 dosyasına kaydetmek için kayıt API'sini kullanma.
  • Bir MP4 dosyasından AR oturumunu tekrar oynatmak için Playback API'sini kullanma.
  • AR oturumunu bir cihazda kaydedip başka bir cihazda tekrar oynatma.

Gerekenler

Bu codelab'de, ARCore Android SDK ile oluşturulan Hello AR Java uygulamasında değişiklik yapacaksınız. Çalışmak için belirli donanım ve yazılımlara ihtiyacınız olacaktır.

Donanım gereksinimleri

Yazılım gereksinimleri

Ayrıca en iyi sonuçlar için ARCore hakkında temel bilgilere sahip olmanız gerekir.

2. Geliştirme ortamınızı ayarlama

Geliştirme ortamınızı kurarak başlayın.

ARCore Android SDK'sını indirin

SDK'yı indirmek için öğesini tıklayın.

ARCore Android SDK'sının sıkıştırmasını açın

Android SDK'yı makinenize indirdikten sonra, sıkıştırılmış dosyayı açın ve arcore-android-sdk-1.24/samples/hello_ar_java dizinine gidin. Bu, üzerinde çalışacağınız uygulamanın kök dizinidir.

hello-ar-java-extracted

Hello AR Java'yı Android Studio'ya yükleme

Android Studio'yu başlatın ve Mevcut bir Android Studio projesini aç'ı tıklayın.

android-studio-open-projects

Açılan iletişim penceresinde arcore-android-sdk-1.24/samples/hello_ar_java'i seçin ve 'ı tıklayın.

Android Studio'nun proje senkronizasyonunu tamamlamasını bekleyin. Eksik bileşen varsa projenin içe aktarılması hata mesajları vererek başarısız olabilir. Devam etmeden önce bu sorunları düzeltin.

Örnek uygulamayı çalıştırma

  1. Geliştirme makinenize ARCore destekli bir cihaz bağlayın.
  2. Cihaz düzgün şekilde tanınırsa Android Studio'da cihazın adı gösterilir. android-studio-pixel-5.png.
  3. Çalıştır düğmesini tıklayın veya Çalıştır > Android Studio'nun cihaza yüklenmesini ve uygulamayı çalıştırmasını sağlamak için "uygulamayı" çalıştırın. android-studio-run-button.png
  4. Resim çekmek ve video kaydetmek için izin isteyen bir istem görürsünüz. Uygulamaya Kamera izinleri vermek için Bu uygulamayı kullanırken'i seçin. Daha sonra, gerçek dünyadaki ortamınızı cihazın ekranında görürsünüz. hello-ar-java-permission.
  5. Uçakları taramak için cihazı yatay olarak hareket ettirin.
  6. Uygulama bir uçak algıladığında beyaz bir ızgara görünür. Uçağa işaretçi yerleştirmek için bu filtreye dokunun. Merhaba AR yerleşimi.

Bu adımda yaptıklarınız

  • Hello AR Java projesini ayarlama
  • Örnek uygulamayı ARCore destekli bir cihazda derleyip çalıştırma

Şimdi, bir MP4 dosyasına bir AR oturumu kaydedeceksiniz.

3. ARCore oturumunu MP4 dosyasına kaydetme

Bu adımda kayıt özelliğini ekleyeceğiz. Şunlardan oluşur:

  • Kaydı başlatmak veya durdurmak için kullanılan düğme.
  • Depolama işlevleri, MP4 dosyasını cihaza kaydetmek için kullanılır.
  • ARCore oturum kaydını başlatmak veya durdurmak için çağrılar.

Add UI for Record (Kayıt Kullanıcı Arayüzü Ekle) düğmesi

Kaydı uygulamadan önce kullanıcı arayüzüne bir düğme ekleyin. Böylece, kullanıcının kaydı ne zaman başlatacağı veya durduracağı konusunda ARCore'u bilgilendirmesi gerekir.

Proje panelinde app/res/layout/activity_main.xml dosyasını açın.

activity_main-xml-location-in-project

Varsayılan olarak, Android Studio app/res/layout/activity_main.xml dosyasını açtıktan sonra tasarım görünümünü kullanır. Kod görünümüne geçmek için sekmenin sağ üst köşesindeki Kod düğmesini tıklayın.

swith-to-the-code-view.png

activity_main.xml ürününde, yeni Record düğmesini oluşturmak ve etkinlik işleyicisini onClickRecord() adlı yönteme ayarlamak için kapanış etiketinin önüne aşağıdaki kodu ekleyin:

  <!--
    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" />

Yukarıdaki kodu ekledikten sonra geçici olarak bir hata gösterilebilir: Corresponding method handler 'public void onClickRecord(android.view.View)' not found". Bu beklenen bir durumdur. Bu hatayı sonraki birkaç adımda onClickRecord() işlevini oluşturarak çözeceksiniz.

Düğmedeki metni duruma göre değiştir

Kaydet düğmesi aslında hem kaydetme hem de durdurma işlemlerini gerçekleştirir. Uygulama veri kaydetmiyorken "Record" (Kaydet) kelimesi görünmelidir. Uygulama veri kaydederken düğme, "Durdur" kelimesini gösterecek şekilde değişmelidir.

Uygulamanın, düğmeye bu işlevi sağlaması için mevcut durumunu bilmesi gerekir. Aşağıdaki kod, uygulamanın çalışma durumunu temsil eden AppState adlı yeni bir sıralama oluşturur ve belirli durum değişikliklerini appState adlı gizli üye değişkeni aracılığıyla izler. Bunu HelloArActivity dersinin başındaki HelloArActivity.java klasörüne ekleyin.

  // Represents the app's working state.
  public enum AppState {
    Idle,
    Recording
  }

  // Tracks app's specific state changes.
  private AppState appState = AppState.Idle;

Artık uygulamanın dahili durumunu takip edebileceğinize göre updateRecordButton() adlı bir işlev oluşturabilirsiniz. Bu işlev, düğmenin metnini uygulamanın mevcut durumuna göre değiştirir. Aşağıdaki kodu HelloArActivity.java uygulamasındaki HelloArActivity sınıfına ekleyin.

// 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;
    }
  }

Ardından, uygulamanın durumunu kontrol eden, bir sonrakiyle değiştiren ve düğmenin kullanıcı arayüzünü değiştirmek için updateRecordButton() çağrısı yapan onClickRecord() yöntemini oluşturun. Aşağıdaki kodu HelloArActivity.java uygulamasındaki HelloArActivity sınıfına ekleyin.

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

Kaydetmeye başlamak için uygulamayı etkinleştirin

ARCore'da kayda başlamak için yalnızca iki şey yapmanız gerekir:

  1. RecordingConfig nesnesinde kayıt dosyası URI'sini belirtin.
  2. RecordingConfig nesnesiyle session.startRecording öğesini çağır

Gerisi sadece standart kodlardır: yapılandırma, günlük kaydı ve doğruluk kontrolü.

Verileri kaydeden ve bir MP4 URI'sına kaydeden startRecording() adlı yeni bir işlev oluşturun. Aşağıdaki kodu HelloArActivity.java uygulamasındaki HelloArActivity sınıfına ekleyin.

// 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;
  }

ARCore oturumunu güvenli bir şekilde duraklatmak ve devam ettirmek için HelloArActivity.java uygulamasında pauseARCoreSession() ve resumeARCoreSession() oluşturun.

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

Kaydı durdurmak için uygulamayı etkinleştirin

Uygulamanızın yeni veri kaydetmesini durdurmak için HelloArActivity.java ürününde stopRecording() adlı bir işlev oluşturun. Bu işlev, uygulamanın kaydı durduramaması durumunda session.stopRecording() öğesini çağırır ve konsol günlüğüne bir hata gönderir.

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

Android 11 kapsamlı depolama alanını kullanarak dosya depolama tasarlama

Bu codelab'deki depolama alanıyla ilgili işlevler, Android 11 kapsamlı depolama alanı gereksinimlerine göre tasarlanmıştır.

Android 11'i hedeflemek için app/build.gradle dosyasında bazı küçük değişiklikler yapın. Android Studio Proje panelinde bu dosya, app modülüyle ilişkilendirilmiş Gradle Komut Dosyaları düğümünün altındadır.

app-build.gradle.png

compileSdkVersion ve targetSdkVersion değerlerini 30 olarak değiştirin.

    compileSdkVersion 30
    defaultConfig {
      targetSdkVersion 30
    }

Kayıt için, paylaşılan Movie dizininde MP4 dosyasını oluşturmak üzere Android MediaStore API'yi kullanın.

HelloArActivity.java içinde createMp4File() adlı bir işlev oluşturun:

// 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;
  }

Depolama izinlerini işleme

Android 11 cihaz kullanıyorsanız kodu test etmeye başlayabilirsiniz. Android 10 veya önceki sürümlerin yüklü olduğu cihazları desteklemek için uygulamanın, hedef cihazın dosya sistemine veri kaydetmesi için depolama alanı izinleri vermeniz gerekir.

AndroidManifest.xml bölümünde, Android 11'den (API düzeyi 30) önce uygulamanın depolama alanında okuma ve yazma izinlerine ihtiyacı olduğunu beyan edin.

  <!-- 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" />

Çalışma zamanı sırasında WRITE_EXTERNAL_STORAGE izinlerini istemek için HelloArActivity.java koduna checkAndRequestStoragePermission() adlı yardımcı bir işlev ekleyin.

// 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;
  }

API düzeyi 29 veya önceki sürümlerden birini kullanıyorsanız createMp4File() öğesinin üst kısmına depolama izinleri için bir kontrol ekleyin ve uygulama doğru izinlere sahip değilse işlevden erken çıkın. API düzeyi 30 (Android 11), MediaStore'daki dosyalara erişmek için depolama alanı izni gerektirmez.

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

Hedef cihazdan kaydedin

Şimdiye kadar neler geliştirdiğinizi görme zamanı. Mobil cihazınızı geliştirme makinenize bağlayın ve Android Studio'da Çalıştır'ı tıklayın.

Ekranın sol alt tarafında kırmızı bir Kayıt düğmesi görürsünüz. Düğmeye dokunduğunuzda metin Durdur olarak değişir. Bir oturum kaydetmek için cihazınızı hareket ettirin ve kaydı tamamlamak istediğiniz zaman Durdur düğmesini tıklayın. Bu işlemle cihazınızın harici depolama alanına arcore-xxxxxx_xxxxxx.mp4 adlı yeni bir dosya kaydedilir.

record-button.png

Artık cihazınızın harici depolama alanında yeni bir arcore-xxxxxx_xxxxxx.mp4 dosyası olmalıdır. Pixel 5 cihazlarda yol /storage/emulated/0/Movies/ şeklindedir. Yol, kayıt başlatıldıktan sonra Logcat penceresinde bulunabilir.

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

Kaydı görüntüleme

Kaydı görüntülemek için Google Files gibi bir dosya sistemi uygulaması kullanabilir veya kaydı geliştirme makinenize kopyalayabilirsiniz. Aşağıda, Android cihazdaki dosyaları listelemek ve getirmek için kullanılan iki adb komutu verilmiştir:

  • Filmler dizinindeki dosyaları cihazdaki harici depolama alanında göstermek için adb shell ls '$EXTERNAL_STORAGE/Movies/*'
  • Dosyayı cihazdan geliştirme makinesine kopyalamak için adb pull /absolute_path_from_previous_adb_shell_ls/arcore-xxxxxxxx_xxxxxx.mp4

Bu, aşağıdaki iki komutu kullandıktan sonra örnek bir çıkıştır (macOS'ten):

$ 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

Bu adımda yaptıklarınız

  • Kaydı başlatmak ve durdurmak için düğme eklendi
  • Kaydı başlatmak ve durdurmak için işlevler uygulandı
  • Uygulamayı cihazda test etme
  • Kaydedilen MP4'ü makinenize kopyalandı ve doğruladı

Ardından, bir MP4 dosyasından bir AR oturumunu oynatırsınız.

4. MP4 dosyasından ARCore oturumunu oynatma

Artık bir Record düğmeniz ve kaydedilmiş oturumları içeren bazı MP4 dosyalarınız var. Şimdi bunları ARCore Playback API'sini kullanarak oynatacaksınız.

Oynat düğmesi için kullanıcı arayüzü ekle

Oynatmayı uygulamadan önce, kullanıcı arayüzüne bir düğme ekleyin. Böylece kullanıcı, ARCore'a oturumun ne zaman başlayacağını ve oynatmayı ne zaman durduracağını bildirebilir.

Proje panelinde app/res/layout/activity_main.xml dosyasını açın.

activity_main-xml-location-in-project

activity_main.xml ürününde, yeni Oynatma düğmesini oluşturmak ve etkinlik işleyicisini onClickPlayback() adlı bir yönteme ayarlamak için kapanış etiketinin önüne aşağıdaki kodu ekleyin. Bu düğme, Kaydet düğmesine benzer ve ekranın sağ tarafında gösterilir.

  <!--
    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" />

Oynatma Sırasında Düğmeleri Güncelle

Uygulamanın artık Playingback adında yeni bir durumu var. Bunu işlemek için AppState listesini ve appState öğesini bağımsız değişken olarak alan tüm mevcut işlevleri güncelleyin.

HelloArActivity.java içindeki AppState sıralamasına Playingback ekleyin:

  public enum AppState {
    Idle,
    Recording,
    Playingback // New enum value.
  }

Oynatma sırasında Kaydet düğmesi ekranda hâlâ açıksa kullanıcı yanlışlıkla bu düğmeyi tıklayabilir. Bunu önlemek için Oynatma sırasında Kaydet düğmesini gizleyin. Bu şekilde, onClickRecord() içindeki Playingback durumunu işlemeniz gerekmez.

Uygulama Playingback durumundayken HelloArActivity.java işlevinde Kaydet düğmesini gizlemek için updateRecordButton() işlevini değiştirin.

  // 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;
    }
  }

Benzer şekilde, kullanıcı oturum kaydederken Oynatma düğmesini gizle ve "Durdur" olarak değiştirin. Kullanıcı bir oturumu aktif olarak oynattığında. Bu sayede, kendiliğinden tamamlanmasını beklemek zorunda kalmadan oynatmayı durdurabilirler.

HelloArActivity.java içine updatePlaybackButton() işlevi ekleyin:

  // 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;
    }
  }

Sonunda, onClickRecord() uygulamasını updatePlaybackButton() araması yapacak şekilde güncelleyin. Aşağıdaki satırı HelloArActivity.java öğesine ekleyin:

  public void onClickRecord(View view) {
    // ... omitted code ...
    updatePlaybackButton(); // Add this line to the end of the function.
  }

Oynat düğmesini kullanarak bir dosya seçin

Kullanıcı bu düğmeye dokunulduğunda Oynatma düğmesine dokunarak oynatılacak bir dosya seçebilir. Android'de, dosya seçimi başka bir Etkinlik'teki sistem dosya seçiciyle işlenir. Bunun için Depolama Erişim Çerçevesi (SAF) kullanılır. Kullanıcı bir dosya seçtiğinde, uygulama onActivityResult() adlı bir geri çağırma alır. Asıl oynatmayı bu geri çağırma işlevinin içinde başlatırsınız.

HelloArActivity.java içinde, dosya seçimi yapmak ve oynatmayı durdurmak için bir onClickPlayback() işlevi oluşturun.

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

HelloArActivity.java ürününde, cihazdan dosya seçen bir selectFileToPlayback() işlevi oluşturun. Android Dosya Sistemi'nden dosya seçmek için bir ACTION_OPEN_DOCUMENT Amacı kullanın.

// 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, bu isteği tanımlamak için sabit değerdir. Bunu, HelloArActivity.java içinde HelloArActivity içindeki herhangi bir yer tutucu değeri kullanarak tanımlayabilirsiniz:

  private int REQUEST_MP4_SELECTOR = 1;

Dosya seçiciden geri çağırma işlemini gerçekleştirmek için HelloArActivity.java içindeki onActivityResult() işlevini geçersiz kılın.

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

Oynatmaya başlamak için uygulamayı etkinleştirin

Bir ARCore oturumunda, MP4 dosyasını çalmak için üç API çağrısı gerekir:

  1. session.pause()
  2. session.setPlaybackDataset()
  3. session.resume()

HelloArActivity.java içinde startPlayingback() işlevini oluşturun.

// 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;
  }

Oynatmayı durdurmak için uygulamayı etkinleştirin

Aşağıdaki uygulama durumu değişikliklerini işlemek için HelloArActivity.java içinde stopPlayingback() adında bir işlev oluşturun:

  1. MP4 çalma, kullanıcı tarafından durduruldu
  2. MP4 çalma kendi kendine tamamlandı

Kullanıcı oynatmayı durdurduysa uygulama, ilk kez başlattığında olduğu duruma geri dönmelidir.

  // 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;
  }

Oynatma işlemi, oynatıcı MP4 dosyasının sonuna ulaştıktan sonra da doğal olarak durabilir. Bu durumda stopPlayingback(), uygulamanın durumunu tekrar Idle olarak değiştirmelidir. onDrawFrame() uygulamasında PlaybackStatus özelliğini kontrol edin. FINISHED ise kullanıcı arayüzü iş parçacığında stopPlayingback() işlevini çağırın.

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

Hedef cihazdan oynatma

Şimdiye kadar neler geliştirdiğinizi görme zamanı. Mobil cihazınızı geliştirme makinenize bağlayın ve Android Studio'da Çalıştır'ı tıklayın.

Uygulama başlatıldığında, sol tarafında kırmızı bir Kaydet ve sağ tarafında yeşil bir Oynatma düğmesi bulunan bir ekran görürsünüz.

playback-button.png

Çal düğmesine dokunun ve az önce kaydettiğiniz MP4 dosyalarından birini seçin. arcore- ile başlayan bir dosya adı görmüyorsanız cihazınız Filmler klasörünü göstermiyor olabilir. Bu durumda, Telefon modeli > Filmler klasörüne sol üst köşedeki menüyü kullanarak dokunun. Telefon modeli klasörünün görünmesi için Dahili depolamayı göster seçeneğini de etkinleştirmeniz gerekebilir.

show-internal-storage-button.png

nativate-to-movies-file-picker.jpg

MP4 dosyasını seçmek için ekranda bir dosya adına dokunun. Uygulama MP4 dosyasını oynatır.

playback-stop-button.png

Bir oturumu oynatma ile sıradan bir videoyu oynatma arasındaki fark, kaydedilen oturumla etkileşimde bulunabilmenizdir. İşaretçileri ekrana yerleştirmek için algılanan bir uçağa dokunun.

oynatma yerleşimi

Bu adımda yaptıklarınız

  • Oynatmayı başlatmak ve durdurmak için düğme eklendi
  • Uygulamanın kaydı başlatmasını ve durdurmasını sağlayan bir işlev uygulandı
  • Cihazda daha önce kaydedilmiş bir ARCore oturumunun oynatılması

5. MP4'e ek veri kaydedin

ARCore 1.24 ile MP4 dosyasına ek bilgiler kaydetmek mümkündür. AR nesne yerleşimlerinin Pose kadarını kaydedebilir ve ardından oynatma sırasında AR nesnelerini aynı konumda oluşturabilirsiniz.

Kaydedilecek yeni parçayı yapılandırın

HelloArActivity.java ürününde UUID ve MIME etiketine sahip yeni bir kanal tanımlayın.

// 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 ...
  }

addTrack() çağrısıyla RecordingConfig nesnesini oluşturmak için mevcut kodu güncelleyin.

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

Kayıt sırasında sabit duruşu kaydet

Kullanıcı algılanan bir uçağa her dokunduğunda, pozu ARCore tarafından güncellenecek bir Anchor üzerine AR işaretçisi yerleştirilir.

ARCore oturumunu hâlâ kaydediyorsanız Anchor etkinliğinin oluşturulduğu karede pozunuzu kaydedin.

HelloArActivity.java içinde handleTap() işlevini değiştirin.

// 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 ...
  }

Dünyaya göre Pose yerine kamera göreli Pose ayarını sürdürmemizin nedeni, kayıt oturumunun dünya başlangıç noktası ile oynatma oturumunun dünya başlangıç noktasının aynı olmamasıdır. Bir kayıt oturumunun dünya genelinde kaynağı, oturum ilk kez devam ettirildiğinde, Session.resume() ilk çağrıldığında başlar. Bir oynatma oturumunun dünya kaynağı, ilk kare kaydedildiğinde başlar, Session.resume() ise Session.startRecording() sonra ilk kez çağrılır.

Oynatma bağlantısı oluşturma

Anchor hesabını yeniden oluşturmak oldukça kolaydır. HelloArActivity.java işlevine createRecordedAnchors() adlı bir işlev ekleyin.

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

HelloArActivity.java içindeki onDrawFrame() işlevinde createRecordedAnchors() yöntemini çağırın.

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

Hedef cihazda test edin

Mobil cihazınızı geliştirme makinenize bağlayın ve Android Studio'da Çalıştır'ı tıklayın.

Öncelikle Kaydet düğmesine dokunarak oturum kaydedin. Kayıt sırasında, birkaç AR işaretçisi yerleştirmek için algılanan düzlemlere dokunun.

Kayıt durduktan sonra Oynatma düğmesine dokunun ve az önce kaydettiğiniz dosyayı seçin. Oynatma işlemi başlar. Önceki AR işaretçisi yerleşimlerinizin, tam uygulamaya dokunurken nasıl göründüğüne dikkat edin.

Bu codelab'de yapmanız gereken tüm kodlama işlemleri bu kadar.

6. Tebrikler

Tebrikler, bu codelab'in sonuna ulaştınız. Bu codelab'de yaptıklarınıza tekrar bakalım:

  • ARCore Hello AR Java örneğini derleyip çalıştırın.
  • AR oturumunu MP4 dosyasına kaydetmek için uygulamaya Kaydet düğmesi eklendi
  • MP4 dosyasından AR oturumunu oynatmak için uygulamaya bir Oynat düğmesi eklendi
  • Kullanıcı tarafından oluşturulan çapaları MP4'te oynatma için kaydetmek üzere yeni bir özellik eklendi

Bu codelab'i yaparken eğlendiniz mi?

Evet Hayır

Bu codelab'i yaparken faydalı bir şeyler öğrendiniz mi?

Evet Hayır

Uygulamayı oluşturma işlemini bu codelab'de tamamladınız mı?

Evet Hayır