ARCore রেকর্ডিং এবং প্লেব্যাক API এর ভূমিকা

১. ভূমিকা

কোনো AR অভিজ্ঞতাকে MP4 ফাইলে সংরক্ষণ করে সেই ফাইল থেকে তা প্লেব্যাক করার সুবিধাটি অ্যাপ ডেভেলপার এবং ব্যবহারকারী উভয়ের জন্যই উপকারী হতে পারে।

আপনার ডেস্ক থেকেই নতুন ফিচারগুলো ডিবাগ ও পরীক্ষা করুন

ARCore রেকর্ড ও প্লেব্যাক এপিআই-এর সবচেয়ে সহজ ব্যবহার হলো ডেভেলপারদের জন্য। সেই দিন আর নেই যখন শুধু একটি ছোট কোড পরিবর্তন পরীক্ষা করার জন্য আপনাকে একটি টেস্ট ডিভাইসে অ্যাপটি বিল্ড ও রান করে, ইউএসবি কেবল সংযোগ বিচ্ছিন্ন করে এদিক-ওদিক ঘুরতে হতো। এখন আপনাকে শুধু টেস্ট এনভায়রনমেন্টে ফোনের স্বাভাবিক নড়াচড়া সহ একটি MP4 রেকর্ড করতে হবে এবং আপনার ডেস্ক থেকেই তা পরীক্ষা করতে পারবেন।

বিভিন্ন ডিভাইস থেকে রেকর্ড এবং প্লেব্যাক করুন

রেকর্ডিং এবং প্লেব্যাক এপিআই-এর মাধ্যমে, একজন ব্যবহারকারী একটি ডিভাইসে একটি সেশন রেকর্ড করতে পারেন এবং অন্য একজন ব্যবহারকারী ভিন্ন একটি ডিভাইসে সেই একই সেশনটি প্লেব্যাক করতে পারেন। অন্য ব্যবহারকারীর সাথে একটি এআর অভিজ্ঞতা শেয়ার করাও সম্ভব। এর সম্ভাবনা অনেক!

আপনি কি প্রথমবারের মতো ARCore অ্যাপ তৈরি করছেন?

না। হ্যাঁ।

আপনি এই কোডল্যাবটি কীভাবে ব্যবহার করবেন?

শুধু একবার পড়ে দেখুন এটি পড়ুন এবং অনুশীলনগুলো সম্পূর্ণ করুন।

আপনি যা তৈরি করবেন

এই কোডল্যাবে, আপনি রেকর্ডিং ও প্লেব্যাক এপিআই ব্যবহার করে এমন একটি অ্যাপ তৈরি করবেন যা একটি এআর অভিজ্ঞতাকে MP4 ফাইলে রেকর্ড করে এবং একই ফাইল থেকে সেই অভিজ্ঞতাটি প্লেব্যাক করে। আপনি শিখবেন:

  • রেকর্ডিং এপিআই ব্যবহার করে কীভাবে একটি এআর সেশনকে MP4 ফাইলে সংরক্ষণ করবেন।
  • MP4 ফাইল থেকে AR সেশন পুনরায় চালানোর জন্য প্লেব্যাক API কীভাবে ব্যবহার করবেন
  • কীভাবে একটি ডিভাইসে এআর সেশন রেকর্ড করে অন্য ডিভাইসে তা পুনরায় চালানো যায়।

আপনার যা যা লাগবে

এই কোডল্যাবে, আপনি Hello AR Java অ্যাপটি পরিবর্তন করবেন, যেটি ARCore Android SDK দিয়ে তৈরি। এটি অনুসরণ করার জন্য আপনার নির্দিষ্ট হার্ডওয়্যার এবং সফ্টওয়্যার প্রয়োজন হবে।

হার্ডওয়্যারের প্রয়োজনীয়তা

  • ডেভেলপার অপশন চালু এবং ইউএসবি ডিবাগিং সক্রিয় করা একটি ARCore সমর্থিত ডিভাইস , যা একটি ইউএসবি কেবলের মাধ্যমে আপনার ডেভেলপমেন্ট মেশিনের সাথে সংযুক্ত।
  • একটি ডেভেলপমেন্ট মেশিন যেখানে আপনি অ্যান্ড্রয়েড স্টুডিও চালান।
  • উন্নয়নের সময় লাইব্রেরি ডাউনলোড করার জন্য ইন্টারনেট ব্যবহারের সুযোগ।

সফটওয়্যার প্রয়োজনীয়তা

সর্বোত্তম ফলাফলের জন্য আপনার ARCore সম্পর্কেও প্রাথমিক ধারণা থাকা উচিত।

২. আপনার ডেভেলপমেন্ট এনভায়রনমেন্ট সেট আপ করুন।

প্রথমে আপনার ডেভেলপমেন্ট এনভায়রনমেন্ট সেট আপ করে নিন।

ARCore অ্যান্ড্রয়েড SDK ডাউনলোড করুন

SDK ডাউনলোড করতে ক্লিক করুন।

ARCore অ্যান্ড্রয়েড SDK আনজিপ করুন

আপনার মেশিনে অ্যান্ড্রয়েড এসডিকে ডাউনলোড করার পর, ফাইলটি আনজিপ করুন এবং arcore-android-sdk-1.24/samples/hello_ar_java ডিরেক্টরিতে যান। এটিই সেই অ্যাপের রুট ডিরেক্টরি, যা নিয়ে আপনি কাজ করবেন।

হ্যালো-এআর-জাভা-এক্সট্র্যাক্টেড

অ্যান্ড্রয়েড স্টুডিওতে হ্যালো এআর জাভা লোড করুন

অ্যান্ড্রয়েড স্টুডিও চালু করুন এবং একটি বিদ্যমান অ্যান্ড্রয়েড স্টুডিও প্রজেক্ট খুলুন-এ ক্লিক করুন।

অ্যান্ড্রয়েড-স্টুডিও-ওপেন-প্রজেক্ট

প্রদর্শিত ডায়ালগ উইন্ডোতে, arcore-android-sdk-1.24/samples/hello_ar_java নির্বাচন করুন এবং Open-এ ক্লিক করুন।

অ্যান্ড্রয়েড স্টুডিওর প্রজেক্ট সিঙ্ক করা শেষ হওয়া পর্যন্ত অপেক্ষা করুন। কোনো কম্পোনেন্ট অনুপস্থিত থাকলে, প্রজেক্ট ইম্পোর্ট করার সময় এরর মেসেজসহ ব্যর্থ হতে পারে। কাজ চালিয়ে যাওয়ার আগে এই সমস্যাগুলো সমাধান করুন।

নমুনা অ্যাপটি চালান

  1. আপনার ডেভেলপমেন্ট মেশিনের সাথে একটি ARCore সমর্থিত ডিভাইস সংযুক্ত করুন।
  2. ডিভাইসটি সঠিকভাবে শনাক্ত হলে, আপনি অ্যান্ড্রয়েড স্টুডিওতে ডিভাইসের নামটি দেখতে পাবেন। android-studio-pixel-5.png
  3. ডিভাইসে অ্যান্ড্রয়েড স্টুডিও দিয়ে অ্যাপটি ইনস্টল ও চালু করতে রান বাটনে ক্লিক করুন অথবা রান > রান 'অ্যাপ' নির্বাচন করুন। android-studio-run-button.png
  4. আপনি ছবি তোলা এবং ভিডিও রেকর্ড করার অনুমতি চেয়ে একটি প্রম্পট দেখতে পাবেন। অ্যাপটিকে ক্যামেরার অনুমতি দেওয়ার জন্য ‘এই অ্যাপটি ব্যবহার করার সময়’ (While using this app) বিকল্পটি নির্বাচন করুন। এরপর আপনি ডিভাইসের স্ক্রিনে আপনার বাস্তব পরিবেশ দেখতে পাবেন। হ্যালো-এআর-জাভা-অনুমতি
  5. প্লেন স্ক্যান করার জন্য ডিভাইসটিকে আনুভূমিকভাবে সরান।
  6. অ্যাপটি কোনো তল শনাক্ত করলে একটি সাদা গ্রিড দেখা যায়। সেই তলে একটি মার্কার স্থাপন করতে সেটির উপর ট্যাপ করুন। হ্যালো এআর প্লেসমেন্ট

এই ধাপে আপনি যা করেছেন

  • হ্যালো এআর জাভা প্রজেক্টটি সেট আপ করুন
  • ARCore সমর্থিত একটি ডিভাইসে নমুনা অ্যাপটি তৈরি ও চালানো হয়েছে।

এরপর, আপনি একটি AR সেশন রেকর্ড করে একটি MP4 ফাইল তৈরি করবেন।

৩. একটি ARCore সেশনকে MP4 ফাইলে রেকর্ড করুন।

আমরা এই ধাপে রেকর্ডিং বৈশিষ্ট্যটি যুক্ত করব। এটি নিম্নলিখিত বিষয়গুলো নিয়ে গঠিত:

  • রেকর্ডিং শুরু বা বন্ধ করার জন্য একটি বাটন।
  • ডিভাইসে MP4 ফাইলটি সংরক্ষণ করার জন্য স্টোরেজ ফাংশন।
  • ARCore সেশন রেকর্ডিং শুরু বা বন্ধ করার কল।

রেকর্ড বাটনের জন্য UI যোগ করুন

রেকর্ডিং চালু করার আগে, ইউজার ইন্টারফেসে (UI) একটি বাটন যোগ করুন, যাতে ব্যবহারকারী ARCore-কে রেকর্ডিং শুরু বা বন্ধ করার কথা জানাতে পারেন।

প্রজেক্ট প্যানেলে app/res/layout/activity_main.xml ফাইলটি খুলুন।

প্রজেক্টে অ্যাক্টিভিটি_মেইন-এক্সএমএল-লোকেশন

ডিফল্টরূপে, আপনি app/res/layout/activity_main.xml ফাইলটি খোলার পর অ্যান্ড্রয়েড স্টুডিও ডিজাইন ভিউ ব্যবহার করবে। কোড ভিউতে যাওয়ার জন্য ট্যাবের উপরের ডান কোণায় থাকা কোড বাটনে ক্লিক করুন।

switch-to-the-code-view.png

activity_main.xml ফাইলে, নতুন রেকর্ড বাটন তৈরি করতে এবং এর ইভেন্ট হ্যান্ডলারকে onClickRecord() নামক একটি মেথডে সেট করতে, ক্লোজিং ট্যাগের আগে নিম্নলিখিত কোডটি যোগ করুন:

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

উপরের কোডটি যোগ করার পর, সাময়িকভাবে একটি ত্রুটি প্রদর্শিত হতে পারে: Corresponding method handler 'public void onClickRecord(android.view.View)' not found" । এটি স্বাভাবিক। পরবর্তী কয়েকটি ধাপে onClickRecord() ফাংশনটি তৈরি করার মাধ্যমে আপনি এই ত্রুটিটি সমাধান করবেন।

অবস্থার উপর ভিত্তি করে বাটনের টেক্সট পরিবর্তন করুন

রেকর্ড বাটনটি আসলে রেকর্ডিং এবং বন্ধ করা, উভয় কাজই করে। যখন অ্যাপটি কোনো ডেটা রেকর্ড করবে না, তখন এতে "Record" শব্দটি প্রদর্শিত হওয়া উচিত। আর যখন অ্যাপটি ডেটা রেকর্ড করবে, তখন বাটনটিতে "Stop" শব্দটি প্রদর্শিত হওয়া উচিত।

বাটনটিকে এই কার্যকারিতা দেওয়ার জন্য, অ্যাপটিকে তার বর্তমান অবস্থা জানতে হবে। নিচের কোডটি অ্যাপের কার্যরত অবস্থা বোঝানোর জন্য AppState নামে একটি নতুন enum তৈরি করে এবং appState নামক একটি প্রাইভেট মেম্বার ভেরিয়েবলের মাধ্যমে নির্দিষ্ট অবস্থার পরিবর্তন ট্র্যাক করে। এটি HelloArActivity.java ফাইলের HelloArActivity ক্লাসের শুরুতে যোগ করুন।

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

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

এখন যেহেতু আপনি অ্যাপের অভ্যন্তরীণ অবস্থা ট্র্যাক করতে পারেন, তাই updateRecordButton() নামে একটি ফাংশন তৈরি করুন যা অ্যাপের বর্তমান অবস্থার উপর ভিত্তি করে বাটনের টেক্সট পরিবর্তন করবে। HelloArActivity.java ফাইলের HelloArActivity ক্লাসের ভিতরে নিম্নলিখিত কোডটি যোগ করুন।

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

এরপরে, onClickRecord() মেথডটি তৈরি করুন যা অ্যাপের স্টেট চেক করে, সেটিকে পরবর্তী স্টেটে পরিবর্তন করে এবং বাটনের UI পরিবর্তন করার জন্য updateRecordButton() মেথডকে কল করে। HelloArActivity.java ফাইলের HelloArActivity ক্লাসের ভিতরে নিম্নলিখিত কোডটি যোগ করুন।

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

রেকর্ডিং শুরু করতে অ্যাপটি সক্ষম করুন।

ARCore-এ রেকর্ডিং শুরু করতে আপনাকে মাত্র দুটি কাজ করতে হবে:

  1. একটি RecordingConfig অবজেক্টে রেকর্ডিং ফাইলের URI উল্লেখ করুন।
  2. RecordingConfig অবজেক্ট ব্যবহার করে session.startRecording কল করুন।

বাকিটা হলো গতানুগতিক কোড: কনফিগারেশন, লগিং এবং সঠিকতা যাচাই।

startRecording() নামে একটি নতুন ফাংশন তৈরি করুন যা ডেটা রেকর্ড করে এবং একটি MP4 URI-তে সংরক্ষণ করে। HelloArActivity.java ফাইলের HelloArActivity ক্লাসের ভিতরে নিম্নলিখিত কোডটি যোগ করুন।

// 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 সেশন নিরাপদে পজ ও রিজুম করার জন্য, HelloArActivity.java ফাইলে pauseARCoreSession() এবং resumeARCoreSession() ফাংশন তৈরি করুন।

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

রেকর্ডিং বন্ধ করতে অ্যাপটি সক্ষম করুন।

আপনার অ্যাপকে নতুন ডেটা রেকর্ড করা থেকে বিরত রাখতে HelloArActivity.java তে stopRecording() নামে একটি ফাংশন তৈরি করুন। এই ফাংশনটি session.stopRecording() কে কল করে এবং অ্যাপটি রেকর্ডিং বন্ধ করতে না পারলে কনসোল লগে একটি এরর পাঠায়।

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

অ্যান্ড্রয়েড ১১ স্কোপড স্টোরেজ ব্যবহার করে ডিজাইন ফাইল সংরক্ষণ

এই কোডল্যাবের স্টোরেজ-সম্পর্কিত ফাংশনগুলো নতুন অ্যান্ড্রয়েড ১১-এর স্কোপড স্টোরেজ রিকোয়ারমেন্টস অনুসরণ করে ডিজাইন করা হয়েছে।

অ্যান্ড্রয়েড ১১-কে টার্গেট করার জন্য app/build.gradle ফাইলে কিছু ছোটখাটো পরিবর্তন করুন। অ্যান্ড্রয়েড স্টুডিও প্রজেক্ট প্যানেলে, এই ফাইলটি `app` মডিউলের সাথে যুক্ত `Gradle Scripts` নোডের অধীনে থাকে।

app-build.gradle.png

compileSdkVersion এবং targetSdkVersion পরিবর্তন করে 30 করুন।

    compileSdkVersion 30
    defaultConfig {
      targetSdkVersion 30
    }

রেকর্ডিংয়ের জন্য, অ্যান্ড্রয়েড মিডিয়াস্টোর এপিআই ব্যবহার করে শেয়ার করা মুভি ডিরেক্টরিতে MP4 ফাইলটি তৈরি করুন।

HelloArActivity.java তে 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;
  }

স্টোরেজ অনুমতি পরিচালনা করুন

আপনি যদি অ্যান্ড্রয়েড ১১ ডিভাইস ব্যবহার করেন, তবে কোডটি পরীক্ষা করা শুরু করতে পারেন। অ্যান্ড্রয়েড ১০ বা তার চেয়ে নিম্ন সংস্করণের ডিভাইস সমর্থন করার জন্য, আপনাকে অ্যাপটিকে টার্গেট ডিভাইসের ফাইল সিস্টেমে ডেটা সংরক্ষণের জন্য স্টোরেজ পারমিশন দিতে হবে।

AndroidManifest.xml ফাইলে ঘোষণা করুন যে Android 11 (API লেভেল 30)-এর আগে অ্যাপটির স্টোরেজ রিড এবং রাইট পারমিশন প্রয়োজন।

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

রানটাইমে WRITE_EXTERNAL_STORAGE পারমিশন অনুরোধ করার জন্য HelloArActivity.java তে checkAndRequestStoragePermission() নামে একটি হেল্পার ফাংশন যোগ করুন।

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

আপনি যদি এপিআই লেভেল ২৯ বা তার আগের সংস্করণ ব্যবহার করেন, createMp4File() ফাংশনের শুরুতে স্টোরেজ পারমিশন যাচাই করার জন্য একটি অপশন যোগ করুন এবং অ্যাপটির সঠিক পারমিশন না থাকলে ফাংশনটি থেকে বেরিয়ে যান। এপিআই লেভেল ৩০ (অ্যান্ড্রয়েড ১১)-এ MediaStore-এর ফাইল অ্যাক্সেস করার জন্য স্টোরেজ পারমিশনের প্রয়োজন হয় না।

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

টার্গেট ডিভাইস থেকে রেকর্ড করুন

এখন পর্যন্ত আপনি যা তৈরি করেছেন তা দেখার সময় হয়েছে। আপনার মোবাইল ডিভাইসটিকে আপনার ডেভেলপমেন্ট মেশিনের সাথে সংযুক্ত করুন এবং অ্যান্ড্রয়েড স্টুডিওতে ' রান' (Run) বোতামে ক্লিক করুন।

আপনি স্ক্রিনের নিচের বাম দিকে একটি লাল রেকর্ড বাটন দেখতে পাবেন। এটিতে ট্যাপ করলে লেখাটি ‘স্টপ’ হয়ে যাবে। একটি সেশন রেকর্ড করার জন্য আপনার ডিভাইসটি নাড়াচাড়া করুন এবং রেকর্ডিং শেষ করতে চাইলে স্টপ বাটনে ক্লিক করুন। এটি আপনার ডিভাইসের এক্সটার্নাল স্টোরেজে arcore-xxxxxx_xxxxxx.mp4 নামের একটি নতুন ফাইল সেভ করবে।

রেকর্ড-বোতাম.png

এখন, আপনার ডিভাইসের এক্সটার্নাল স্টোরেজে একটি নতুন arcore-xxxxxx_xxxxxx.mp4 ফাইল থাকার কথা। পিক্সেল ৫ ডিভাইসগুলোতে, পাথটি হলো /storage/emulated/0/Movies/ । রেকর্ডিং শুরু করার পর Logcat উইন্ডোতে পাথটি খুঁজে পাওয়া যাবে।

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

রেকর্ডিংটি দেখুন

আপনি রেকর্ডিংটি দেখার জন্য Files by Google-এর মতো একটি ফাইল সিস্টেম অ্যাপ ব্যবহার করতে পারেন, অথবা এটি আপনার ডেভেলপমেন্ট মেশিনে কপি করতে পারেন। অ্যান্ড্রয়েড ডিভাইস থেকে ফাইল তালিকাভুক্ত করতে এবং আনতে নিচের দুটি adb কমান্ড ব্যবহার করা হলো:

  • ডিভাইসের এক্সটার্নাল স্টোরেজের Movies ডিরেক্টরিতে থাকা ফাইলগুলো দেখতে adb shell ls '$EXTERNAL_STORAGE/Movies/*' ব্যবহার করুন।
  • ডিভাইস থেকে ডেভেলপমেন্ট মেশিনে ফাইলটি কপি করতে adb pull /absolute_path_from_previous_adb_shell_ls/arcore-xxxxxxxx_xxxxxx.mp4

এই দুটি কমান্ড ব্যবহার করার পর প্রাপ্ত আউটপুটের একটি উদাহরণ নিচে দেওয়া হলো (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

এই ধাপে আপনি যা করেছেন

  • রেকর্ডিং শুরু ও বন্ধ করার জন্য একটি বাটন যোগ করা হয়েছে।
  • রেকর্ডিং শুরু এবং বন্ধ করার ফাংশনগুলো বাস্তবায়ন করা হয়েছে।
  • ডিভাইসে অ্যাপটি পরীক্ষা করা হয়েছে
  • রেকর্ড করা MP4 ফাইলটি আপনার মেশিনে কপি করে যাচাই করা হয়েছে।

এরপর, আপনি একটি MP4 ফাইল থেকে একটি AR সেশন প্লে করবেন।

৪. একটি MP4 ফাইল থেকে ARCore সেশন প্লেব্যাক করুন

এখন আপনার কাছে একটি রেকর্ড বাটন এবং রেকর্ড করা সেশন সম্বলিত কিছু MP4 ফাইল আছে। এখন, আপনি ARCore প্লেব্যাক API ব্যবহার করে সেগুলো প্লে করবেন।

প্লেব্যাক বাটনের জন্য UI যোগ করুন

প্লেব্যাক চালু করার আগে, UI-তে একটি বাটন যোগ করুন যাতে ব্যবহারকারী ARCore-কে জানাতে পারেন কখন সেশনটির প্লেব্যাক শুরু এবং বন্ধ করতে হবে।

প্রজেক্ট প্যানেলে app/res/layout/activity_main.xml ফাইলটি খুলুন।

প্রজেক্টে অ্যাক্টিভিটি_মেইন-এক্সএমএল-লোকেশন

activity_main.xml ফাইলে, নতুন প্লেব্যাক বাটন তৈরি করতে এবং এর ইভেন্ট হ্যান্ডলারকে onClickPlayback() নামক একটি মেথডে সেট করতে ক্লোজিং ট্যাগের আগে নিচের কোডটি যোগ করুন। এই বাটনটি রেকর্ড বাটনের মতোই হবে এবং স্ক্রিনের ডানদিকে প্রদর্শিত হবে।

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

প্লেব্যাকের সময় বাটন আপডেট করুন

অ্যাপটিতে এখন Playingback নামে একটি নতুন স্টেট রয়েছে। এটি পরিচালনা করার জন্য AppState enum এবং appState আর্গুমেন্ট হিসেবে গ্রহণকারী সমস্ত বিদ্যমান ফাংশন আপডেট করুন।

HelloArActivity.java তে AppState enum-এ Playingback যোগ করুন:

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

প্লেব্যাকের সময় যদি রেকর্ড বাটনটি স্ক্রিনে থেকে যায়, তাহলে ব্যবহারকারী ভুলবশত এটিতে ক্লিক করে ফেলতে পারেন। এটি এড়ানোর জন্য, প্লেব্যাকের সময় রেকর্ড বাটনটি লুকিয়ে রাখুন। এর ফলে, onClickRecord() ফাংশনে Playingback স্টেট হ্যান্ডেল করার প্রয়োজন হবে না।

অ্যাপটি Playingback অবস্থায় থাকলে রেকর্ড বাটনটি লুকানোর জন্য HelloArActivity.java এর updateRecordButton() ফাংশনটি পরিবর্তন করুন।

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

একইভাবে, ব্যবহারকারী যখন কোনো সেশন রেকর্ড করছেন, তখন প্লেব্যাক বাটনটি লুকিয়ে ফেলুন এবং যখন তিনি সক্রিয়ভাবে কোনো সেশন প্লেব্যাক করছেন, তখন বাটনটিতে "স্টপ" লেখাটি যুক্ত করুন। এর ফলে, প্লেব্যাকটি নিজে থেকে সম্পূর্ণ হওয়ার জন্য অপেক্ষা না করেই তারা তা থামাতে পারবেন।

HelloArActivity.java তে একটি updatePlaybackButton() ফাংশন যোগ করুন:

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

অবশেষে, onClickRecord() updatePlaybackButton() কল করার জন্য আপডেট করুন। HelloArActivity.java ফাইলে নিম্নলিখিত লাইনটি যোগ করুন:

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

প্লেব্যাক বোতাম দিয়ে একটি ফাইল নির্বাচন করুন

প্লেব্যাক বাটনটি ট্যাপ করলে, ব্যবহারকারী প্লেব্যাক করার জন্য একটি ফাইল বেছে নিতে পারবেন। অ্যান্ড্রয়েডে, ফাইল নির্বাচনের কাজটি অন্য একটি অ্যাক্টিভিটির সিস্টেম ফাইল পিকারের মাধ্যমে করা হয়। এটি স্টোরেজ অ্যাক্সেস ফ্রেমওয়ার্ক ( SAF ) দ্বারা সম্পন্ন হয়। ব্যবহারকারী একটি ফাইল বেছে নিলে, অ্যাপটি onActivityResult() নামে একটি কলব্যাক গ্রহণ করে। আপনি এই কলব্যাক ফাংশনের ভেতরেই প্রকৃত প্লেব্যাক শুরু করবেন।

HelloArActivity.java তে, ফাইল নির্বাচন এবং প্লেব্যাক বন্ধ করার জন্য একটি onClickPlayback() ফাংশন তৈরি করুন।

  // 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 তে, একটি selectFileToPlayback() ফাংশন তৈরি করুন যা ডিভাইস থেকে একটি ফাইল নির্বাচন করবে। অ্যান্ড্রয়েড ফাইল সিস্টেম থেকে ফাইল নির্বাচন করতে, একটি 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 হলো এই অনুরোধটি শনাক্ত করার জন্য একটি ধ্রুবক। আপনি HelloArActivity.java এর মধ্যে HelloArActivity তে যেকোনো প্লেসহোল্ডার মান ব্যবহার করে এটি নির্ধারণ করতে পারেন:

  private int REQUEST_MP4_SELECTOR = 1;

ফাইল পিকার থেকে আসা কলব্যাকটি হ্যান্ডেল করার জন্য HelloArActivity.java তে onActivityResult() ফাংশনটি ওভাররাইড করুন।

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

প্লেব্যাক শুরু করতে অ্যাপটি সক্ষম করুন।

একটি MP4 ফাইল প্লেব্যাক করার জন্য ARCore সেশনে তিনটি API কলের প্রয়োজন হয়:

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

HelloArActivity.java তে 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;
  }

প্লেব্যাক বন্ধ করতে অ্যাপটি সক্ষম করুন।

HelloArActivity.java তে stopPlayingback() নামে একটি ফাংশন তৈরি করুন যা নিম্নলিখিত ঘটনার পরে অ্যাপের অবস্থার পরিবর্তনগুলি পরিচালনা করবে:

  1. ব্যবহারকারী MP4 প্লেব্যাক বন্ধ করে দিয়েছেন।
  2. MP4 প্লেব্যাকটি নিজে থেকেই সম্পন্ন হয়েছে।

যদি ব্যবহারকারী প্লেব্যাক বন্ধ করে দেন, তাহলে অ্যাপটি সেই অবস্থায় ফিরে আসা উচিত, যে অবস্থায় এটি প্রথমবার চালু করা হয়েছিল।

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

MP4 ফাইলের শেষে পৌঁছানোর পর প্লেব্যাক স্বাভাবিকভাবেই বন্ধ হয়ে যেতে পারে। এমনটা হলে, stopPlayingback() অ্যাপের স্টেটকে আবার Idle অবস্থায় ফিরিয়ে দেবে। onDrawFrame() ফাংশনে PlaybackStatus চেক করুন। যদি এটি FINISHED হয়, তাহলে UI থ্রেডে stopPlayingback() ফাংশনটি কল করুন।

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

টার্গেট ডিভাইস থেকে প্লেব্যাক করুন

এখন পর্যন্ত আপনি যা তৈরি করেছেন তা দেখার সময় হয়েছে। আপনার মোবাইল ডিভাইসটিকে আপনার ডেভেলপমেন্ট মেশিনের সাথে সংযুক্ত করুন এবং অ্যান্ড্রয়েড স্টুডিওতে ' রান' (Run) বোতামে ক্লিক করুন।

অ্যাপটি চালু হলে, আপনি এমন একটি স্ক্রিন দেখতে পাবেন যার বাম দিকে একটি লাল রঙের রেকর্ড বাটন এবং ডান দিকে একটি সবুজ রঙের প্লেব্যাক বাটন থাকবে।

প্লেব্যাক-বাটন.png

প্লেব্যাক বোতামে ট্যাপ করুন এবং আপনার এইমাত্র রেকর্ড করা MP4 ফাইলগুলোর মধ্যে একটি বেছে নিন। যদি আপনি arcore- দিয়ে শুরু হওয়া কোনো ফাইলের নাম দেখতে না পান, তাহলে সম্ভবত আপনার ডিভাইসটি মুভিজ ফোল্ডারটি দেখাচ্ছে না। এই ক্ষেত্রে, উপরের বাম কোণার মেনু ব্যবহার করে ফোন মডেল > মুভিজ ফোল্ডারে যান। ফোন মডেল ফোল্ডারটি দেখানোর জন্য আপনাকে ‘শো ইন্টারনাল স্টোরেজ’ অপশনটি চালু করতে হতে পারে।

show-internal-storage-button.png

nativate-to-movies-file-picker.jpg

MP4 ফাইলটি নির্বাচন করতে স্ক্রিনে থাকা ফাইলের নামে ট্যাপ করুন। অ্যাপটি MP4 ফাইলটি প্লে করবে।

প্লেব্যাক-স্টপ-বাটন.png

একটি সেশন প্লেব্যাক করা এবং একটি সাধারণ ভিডিও প্লেব্যাক করার মধ্যে পার্থক্য হলো, আপনি রেকর্ড করা সেশনটির সাথে ইন্টারঅ্যাক্ট করতে পারেন। স্ক্রিনে মার্কার স্থাপন করতে শনাক্ত করা কোনো প্লেনে ট্যাপ করুন।

প্লেব্যাক-প্লেসমেন্ট

এই ধাপে আপনি যা করেছেন

  • প্লেব্যাক শুরু ও বন্ধ করার জন্য একটি বাটন যোগ করা হয়েছে।
  • অ্যাপে রেকর্ডিং শুরু ও বন্ধ করার জন্য একটি ফাংশন যুক্ত করা হয়েছে।
  • ডিভাইসটিতে পূর্বে রেকর্ড করা একটি ARCore সেশন প্লেব্যাক করা হলো।

৫. MP4-এ অতিরিক্ত তথ্য রেকর্ড করুন।

ARCore 1.24-এর সাহায্যে MP4 ফাইলে অতিরিক্ত তথ্য রেকর্ড করা সম্ভব। আপনি AR অবজেক্ট স্থাপনের Pose রেকর্ড করতে পারেন, এবং তারপর প্লেব্যাকের সময় একই স্থানে AR অবজেক্টগুলো তৈরি করতে পারেন।

রেকর্ড করার জন্য নতুন ট্র্যাকটি কনফিগার করুন

HelloArActivity.java তে একটি UUID এবং একটি MIME ট্যাগ সহ একটি নতুন ট্র্যাক সংজ্ঞায়িত করুন।

// 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() কল করার মাধ্যমে RecordingConfig অবজেক্টটি তৈরি করতে বিদ্যমান কোডটি আপডেট করুন।

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

রেকর্ডিং চলাকালীন অ্যাঙ্কর পোজ সংরক্ষণ করুন

প্রতিবার ব্যবহারকারী কোনো শনাক্তকৃত প্লেনে ট্যাপ করলে, একটি Anchor উপর একটি এআর মার্কার স্থাপন করা হবে, যার পোজ এআরকোর দ্বারা আপডেট করা হবে।

আপনি যদি তখনও ARCore সেশনটি রেকর্ড করতে থাকেন, তাহলে একটি Anchor তৈরি হওয়ার ফ্রেমে সেটির পোজ রেকর্ড করুন।

HelloArActivity.java তে handleTap() ফাংশনটি পরিবর্তন করুন।

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

ওয়ার্ল্ড রিলেটিভ Pose পরিবর্তে ক্যামেরা রিলেটিভ Pose ধরে রাখার কারণ হলো, একটি রেকর্ডিং সেশনের ওয়ার্ল্ড অরিজিন এবং একটি প্লেব্যাক সেশনের ওয়ার্ল্ড অরিজিন এক নয়। একটি রেকর্ডিং সেশনের ওয়ার্ল্ড অরিজিন শুরু হয় প্রথমবার যখন সেশনটি রিজুম করা হয়, অর্থাৎ যখন প্রথমবার Session.resume() কল করা হয়। একটি প্লেব্যাক সেশনের ওয়ার্ল্ড অরিজিন শুরু হয় যখন প্রথম ফ্রেমটি রেকর্ড করা হয়, অর্থাৎ যখন Session.resume() এর পরে প্রথমবার Session.startRecording() কল করা হয়।

প্লেব্যাক অ্যাঙ্কর তৈরি

একটি Anchor পুনরায় তৈরি করা খুবই সহজ। HelloArActivity.java তে createRecordedAnchors() নামে একটি ফাংশন যোগ করুন।

// 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 এর onDrawFrame() ফাংশনে createRecordedAnchors() কল করুন।

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

টার্গেট ডিভাইসে পরীক্ষা করুন

আপনার মোবাইল ডিভাইসটি আপনার ডেভেলপমেন্ট মেশিনের সাথে সংযুক্ত করুন এবং অ্যান্ড্রয়েড স্টুডিওতে 'রান' (Run) বোতামে ক্লিক করুন।

প্রথমে, একটি সেশন রেকর্ড করতে রেকর্ড বোতামে ট্যাপ করুন। রেকর্ডিং চলাকালীন, শনাক্ত করা প্লেনগুলিতে ট্যাপ করে কয়েকটি AR মার্কার স্থাপন করুন।

রেকর্ডিং বন্ধ হয়ে গেলে, প্লেব্যাক বোতামে ট্যাপ করুন এবং এইমাত্র রেকর্ড করা ফাইলটি নির্বাচন করুন। প্লেব্যাক শুরু হয়ে যাবে। লক্ষ্য করুন, আপনি অ্যাপটিতে ট্যাপ করার সময় আপনার আগের এআর মার্কারের অবস্থানগুলো ঠিক সেভাবেই দেখা যাচ্ছে।

এই কোডল্যাবের জন্য আপনাকে শুধু এইটুকুই কোডিং করতে হবে।

৬. অভিনন্দন

অভিনন্দন, আপনি এই কোডল্যাবের শেষ প্রান্তে পৌঁছে গেছেন! চলুন দেখে নেওয়া যাক এই কোডল্যাবে আপনি কী কী করেছেন:

  • ARCore Hello AR Java স্যাম্পলটি বিল্ড এবং রান করা হয়েছে।
  • একটি AR সেশন MP4 ফাইলে সংরক্ষণ করার জন্য অ্যাপটিতে একটি রেকর্ড বাটন যোগ করা হয়েছে।
  • MP4 ফাইল থেকে AR সেশন প্লেব্যাক করার জন্য অ্যাপটিতে একটি প্লেব্যাক বাটন যোগ করা হয়েছে।
  • ব্যবহারকারীর তৈরি অ্যাঙ্করগুলো প্লেব্যাকের জন্য MP4 ফাইলে সংরক্ষণ করার একটি নতুন ফিচার যোগ করা হয়েছে।

এই কোডল্যাবটি করতে তোমার কি মজা লেগেছে?

হ্যাঁ না

এই কোডল্যাবটি করতে গিয়ে আপনি কি কোনো দরকারি কিছু শিখলেন?

হ্যাঁ না

আপনি কি এই কোডল্যাবে অ্যাপটি তৈরি করা সম্পন্ন করেছেন?

হ্যাঁ না