تمت مشاركة إذن الوصول إلى الكاميرا مع ARCore.

يرشدك دليل المطوّرين هذا إلى خطوات تفعيل تطبيقك للتبديل بسلاسة بين التحكّم الحصري في الكاميرا من خلال Android Camera2 API ومشاركة إذن الوصول إلى الكاميرا مع ARCore.

يفترض هذا الموضوع ما يلي:

إنشاء نموذج تطبيق وتشغيله

عند إنشاء تطبيق Shared Camera Java التجريبي وتشغيله، سيتم إنشاء جلسة ARCore تتيح الوصول إلى الكاميرا المشتركة. يبدأ التطبيق في وضع غير متوافق مع الواقع المعزّز، ويتم إيقاف ARCore مؤقتًا.

عندما يعمل التطبيق في وضع غير الواقع المعزّز، يعرض عارض الكاميرا تأثيرًا بلون بني داكن. عند التبديل إلى وضع الواقع المعزّز، يتم إيقاف تأثير اللون البني الداكن لأنّ التطبيق يعيد التحكّم بالكاميرا إلى ARCore من خلال استئناف الجلسة المتوقفة مؤقتًا.

يمكنك استخدام مفتاح التبديل إلى الواقع المعزّز في التطبيق لتغيير الأوضاع. أثناء المعاينة، يعرض كلا الوضعين عدد اللقطات المتتالية التي تم التقاطها باستخدام Camera2.

لإنشاء نموذج تطبيق Java وتشغيله باستخدام ميزة "الكاميرا المشترَكة"، اتّبِع الخطوات التالية:

  1. نزِّل حزمة Google ARCore SDK لنظام التشغيل Android وفكّ ضغطها.

  2. افتح مشروع samples/shared_camera_java.

  3. تأكَّد من توصيل جهاز Android بجهاز التطوير عبر USB. لمزيد من المعلومات، يُرجى الاطّلاع على الأجهزة المتوافقة مع ARCore.

  4. في "استوديو Android"، انقر على Run .

  5. اختَر جهازك كهدف للنشر، وانقر على OK لتشغيل نموذج تطبيق على جهازك.

  6. على الجهاز، أكِّد أنّك تريد السماح للتطبيق بالتقاط الصور وتسجيل الفيديوهات.

  7. إذا طُلب منك ذلك، حدِّث ARCore إلى أحدث إصدار أو ثبِّته.

  8. استخدِم مفتاح التبديل AR للتغيير بين وضعَي الواقع غير المعزّز والواقع المعزّز.

نظرة عامة حول السماح لتطبيق بمشاركة إذن الوصول إلى الكاميرا مع ARCore

اتّبِع الخطوات التالية لتنفيذ ميزة مشاركة الوصول إلى الكاميرا باستخدام ARCore في تطبيقك. تتوفّر جميع مقتطفات الرموز البرمجية في SharedCameraActivity.java ضمن نموذج shared_camera_java.

طلب الإذن CAMERA

لكي يتمكّن المستخدم من استخدام كاميرا الجهاز، يجب أن يمنح تطبيقك إذن CAMERA. تتضمّن نماذج ARCore CameraPermissionHelper، التي توفّر أدوات لطلب الإذن المناسب لتطبيقك.

جافا

protected void onResume() {
  // Request the camera permission, if necessary.
  if (!CameraPermissionHelper.hasCameraPermission(this)) {
      CameraPermissionHelper.requestCameraPermission(this);
  }
}

Kotlin

override fun onResume() {
  // Request the camera permission, if necessary.
  if (!CameraPermissionHelper.hasCameraPermission(this)) {
    CameraPermissionHelper.requestCameraPermission(this)
  }
}

التأكّد من تثبيت ARCore وتحديثه

يجب تثبيت ARCore وتحديثه قبل استخدامه. يوضّح المقتطف التالي كيفية طلب تثبيت ARCore إذا لم يكن مثبَّتًا على الجهاز.

جافا

boolean isARCoreSupportedAndUpToDate() {
  // Make sure that ARCore is installed and supported on this device.
  ArCoreApk.Availability availability = ArCoreApk.getInstance().checkAvailability(this);
  switch (availability) {
    case SUPPORTED_INSTALLED:
      return true;

    case SUPPORTED_APK_TOO_OLD:
    case SUPPORTED_NOT_INSTALLED:
        // Requests an ARCore installation or updates ARCore if needed.
        ArCoreApk.InstallStatus installStatus = ArCoreApk.getInstance().requestInstall(this, userRequestedInstall);
        switch (installStatus) {
          case INSTALL_REQUESTED:
            return false;
          case INSTALLED:
            return true;
        }
      return false;

    default:
      // Handle the error. For example, show the user a snackbar that tells them
      // ARCore is not supported on their device.
      return false;
  }
}

Kotlin

// Determine ARCore installation status.
// Requests an ARCore installation or updates ARCore if needed.
fun isARCoreSupportedAndUpToDate(): Boolean {
  when (ArCoreApk.getInstance().checkAvailability(this)) {
    Availability.SUPPORTED_INSTALLED -> return true

    Availability.SUPPORTED_APK_TOO_OLD,
    Availability.SUPPORTED_NOT_INSTALLED -> {
      when(ArCoreApk.getInstance().requestInstall(this, userRequestedInstall)) {
        InstallStatus.INSTALLED -> return true
        else -> return false
      }
    }

    else -> {
      // Handle the error. For example, show the user a snackbar that tells them
      // ARCore is not supported on their device.
      return false
    }
  }
}

إنشاء جلسة ARCore تتيح مشاركة الكاميرا

يتضمّن ذلك إنشاء الجلسة وتخزين المرجع والمعرّف الخاصين بالكاميرا المشترَكة في ARCore:

جافا

// Create an ARCore session that supports camera sharing.
sharedSession = new Session(this, EnumSet.of(Session.Feature.SHARED_CAMERA))

// Store the ARCore shared camera reference.
sharedCamera = sharedSession.getSharedCamera();

// Store the ID of the camera that ARCore uses.
cameraId = sharedSession.getCameraConfig().getCameraId();

Kotlin

// Create an ARCore session that supports camera sharing.
sharedSession = Session(this, EnumSet.of(Session.Feature.SHARED_CAMERA))

// Store the ARCore shared camera reference.
sharedCamera = sharedSession.sharedCamera

// Store the ID of the camera that ARCore uses.
cameraId = sharedSession.cameraConfig.cameraId

(اختياري) إبلاغ ARCore بأي أسطح مخصّصة

يؤدي طلب أسطح مخصّصة إضافية إلى زيادة متطلبات الأداء على الجهاز. لضمان عمل تطبيقك بشكل جيد، اختبِره على الأجهزة التي سيستخدمها المستخدمون.

سيطلب ARCore تلقائيًا بثَّين:

  1. بث واحد لوحدة المعالجة المركزية (CPU) بتنسيق YUV، ويكون دائمًا 640x480 حاليًا.
    يستخدم ARCore هذا البث من أجل تتبُّع الحركة.
  2. بث بدقة 1x GPU، عادةً 1920x1080
    استخدِم Session#getCameraConfig() لتحديد دقة بث GPU الحالية.

يمكنك تغيير دقة بث وحدة معالجة الرسومات على الأجهزة المتوافقة باستخدام getSupportedCameraConfigs() و setCameraConfig().

كمؤشر تقريبي، يمكنك توقُّع ما يلي:

نوع الجهاز أحداث البث المتزامنة المتاحة
الهواتف المتطورة
  • مصدران لبيانات YUV لوحدة المعالجة المركزية، مثل 640x480 و1920x1080
  • بث واحد لوحدة معالجة الرسومات، مثل 1920x1080
  • صورة ثابتة واحدة بدقة عالية (JPEG)، مثل 12MP
هواتف من المستوى المتوسط
  • مصدران لبيانات YUV لوحدة المعالجة المركزية، مثل 640x480 و1920x1080
  • بث واحد لوحدة معالجة الرسومات، مثل 1920x1080
–or–
  • مصدر واحد لبيانات YUV لوحدة المعالجة المركزية، مثلاً 640x480 أو 1920x1080
  • بث واحد لوحدة معالجة الرسومات، مثل 1920x1080
  • صورة ثابتة واحدة بدقة عالية (JPEG)، مثل 12MP

لاستخدام أسطح مخصّصة، مثل سطح قارئ صور لوحدة المعالجة المركزية، احرص على إضافتها إلى قائمة الأسطح التي يجب تعديلها (على سبيل المثال، ImageReader).

جافا

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

Kotlin

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

فتح الكاميرا

افتح الكاميرا باستخدام دالة ردّ الاتصال المضمّنة في ARCore:

جافا

// Wrap the callback in a shared camera callback.
CameraDevice.StateCallback wrappedCallback =
    sharedCamera.createARDeviceStateCallback(cameraDeviceCallback, backgroundHandler);

// Store a reference to the camera system service.
cameraManager = (CameraManager) this.getSystemService(Context.CAMERA_SERVICE);

// Open the camera device using the ARCore wrapped callback.
cameraManager.openCamera(cameraId, wrappedCallback, backgroundHandler);

Kotlin

// Wrap the callback in a shared camera callback.
val wrappedCallback = sharedCamera.createARDeviceStateCallback(cameraDeviceCallback, backgroundHandler)

// Store a reference to the camera system service.
val cameraManager = this.getSystemService(Context.CAMERA_SERVICE) as CameraManager

// Open the camera device using the ARCore wrapped callback.
cameraManager.openCamera(cameraId, wrappedCallback, backgroundHandler)

استخدام معاودة الاتصال بحالة جهاز الكاميرا

في معاودة الاتصال بحالة جهاز الكاميرا، خزِّن مرجعًا لجهاز الكاميرا وابدأ جلسة تسجيل جديدة.

جافا

public void onOpened(@NonNull CameraDevice cameraDevice) {
    Log.d(TAG, "Camera device ID " + cameraDevice.getId() + " opened.");
    SharedCameraActivity.this.cameraDevice = cameraDevice;
    createCameraPreviewSession();
}

Kotlin

fun onOpened(cameraDevice: CameraDevice) {
  Log.d(TAG, "Camera device ID " + cameraDevice.id + " opened.")
  this.cameraDevice = cameraDevice
  createCameraPreviewSession()
}

إنشاء جلسة تسجيل جديدة

إنشاء طلب التقاط جديد استخدِم TEMPLATE_RECORD لضمان توافق طلب الالتقاط مع ARCore، وللسماح بالتبديل السلس بين وضعَي الواقع المعزّز وغير المعزّز في وقت التشغيل.

جافا

void createCameraPreviewSession() {
  try {
    // Create an ARCore-compatible capture request using `TEMPLATE_RECORD`.
    previewCaptureRequestBuilder =
        cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);

    // Build a list of surfaces, starting with ARCore provided surfaces.
    List<Surface> surfaceList = sharedCamera.getArCoreSurfaces();

    // (Optional) Add a CPU image reader surface.
    surfaceList.add(cpuImageReader.getSurface());

    // The list should now contain three surfaces:
    // 0. sharedCamera.getSurfaceTexture()
    // 1. …
    // 2. cpuImageReader.getSurface()

    // Add ARCore surfaces and CPU image surface targets.
    for (Surface surface : surfaceList) {
      previewCaptureRequestBuilder.addTarget(surface);
    }

    // Wrap our callback in a shared camera callback.
    CameraCaptureSession.StateCallback wrappedCallback =
        sharedCamera.createARSessionStateCallback(cameraSessionStateCallback, backgroundHandler);

    // Create a camera capture session for camera preview using an ARCore wrapped callback.
    cameraDevice.createCaptureSession(surfaceList, wrappedCallback, backgroundHandler);
  } catch (CameraAccessException e) {
    Log.e(TAG, "CameraAccessException", e);
  }
}

Kotlin

fun createCameraPreviewSession() {
  try {
    // Create an ARCore-compatible capture request using `TEMPLATE_RECORD`.
    previewCaptureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD)

    // Build a list of surfaces, starting with ARCore provided surfaces.
    val surfaceList: MutableList<Surface> = sharedCamera.arCoreSurfaces

    // (Optional) Add a CPU image reader surface.
    surfaceList.add(cpuImageReader.getSurface())

    // The list should now contain three surfaces:
    // 0. sharedCamera.getSurfaceTexture()
    // 1. …
    // 2. cpuImageReader.getSurface()

    // Add ARCore surfaces and CPU image surface targets.
    for (surface in surfaceList) {
      previewCaptureRequestBuilder.addTarget(surface)
    }

    // Wrap the callback in a shared camera callback.
    val wrappedCallback = sharedCamera.createARSessionStateCallback(cameraSessionStateCallback, backgroundHandler)

    // Create a camera capture session for camera preview using an ARCore wrapped callback.
    cameraDevice.createCaptureSession(surfaceList, wrappedCallback, backgroundHandler)
  } catch (e: CameraAccessException) {
    Log.e(TAG, "CameraAccessException", e)
  }
}

بدء استخدام التطبيق في وضع غير الواقع المعزّز أو في وضع الواقع المعزّز

لبدء التقاط اللقطات، استدعِ captureSession.setRepeatingRequest() من معاودة الاتصال بحالة onConfigured() لجلسة التقاط الكاميرا. استأنِف جلسة ARCore ضِمن معاودة الاتصال onActive() لبدء التشغيل في وضع الواقع المعزّز.

جافا

// Repeating camera capture session state callback.
CameraCaptureSession.StateCallback cameraSessionStateCallback =
    new CameraCaptureSession.StateCallback() {

      // Called when ARCore first configures the camera capture session after
      // initializing the app, and again each time the activity resumes.
      @Override
      public void onConfigured(@NonNull CameraCaptureSession session) {
        captureSession = session;
        setRepeatingCaptureRequest();
      }

      @Override
      public void onActive(@NonNull CameraCaptureSession session) {
        if (arMode && !arcoreActive) {
          resumeARCore();
        }
      }
    };

// A repeating camera capture session capture callback.
CameraCaptureSession.CaptureCallback cameraCaptureCallback =
    new CameraCaptureSession.CaptureCallback() {
      @Override
      public void onCaptureCompleted() {
        shouldUpdateSurfaceTexture.set(true);
      }
    };

void setRepeatingCaptureRequest() {
    captureSession.setRepeatingRequest(
        previewCaptureRequestBuilder.build(), cameraCaptureCallback, backgroundHandler);
}

void resumeARCore() {
    // Resume ARCore.
    sharedSession.resume();
    arcoreActive = true;

    // Set the capture session callback while in AR mode.
    sharedCamera.setCaptureCallback(cameraCaptureCallback, backgroundHandler);
}

Kotlin

val cameraSessionStateCallback = object : CameraCaptureSession.StateCallback() {
      // Called when ARCore first configures the camera capture session after
      // initializing the app, and again each time the activity resumes.
  override fun onConfigured(session: CameraCaptureSession) {
    captureSession = session
    setRepeatingCaptureRequest()
  }

  override fun onActive(session: CameraCaptureSession) {
    if (arMode && !arcoreActive) {
      resumeARCore()
    }
  }
}

val cameraCaptureCallback = object : CameraCaptureSession.CaptureCallback() {
  override fun onCaptureCompleted(
    session: CameraCaptureSession,
    request: CaptureRequest,
    result: TotalCaptureResult
  ) {
    shouldUpdateSurfaceTexture.set(true);
  }
}

fun setRepeatingCaptureRequest() {
  captureSession.setRepeatingRequest(
    previewCaptureRequestBuilder.build(), cameraCaptureCallback, backgroundHandler
  )
}

fun resumeARCore() {
    // Resume ARCore.
    sharedSession.resume()
    arcoreActive = true

    // Set the capture session callback while in AR mode.
    sharedCamera.setCaptureCallback(cameraCaptureCallback, backgroundHandler)
}

التبديل بسلاسة بين وضعَي الواقع المعزّز وغير الواقع المعزّز في وقت التشغيل

للتبديل من وضع غير واقع معزّز إلى وضع الواقع المعزّز واستئناف جلسة ARCore تم إيقافها مؤقتًا، اتّبِع الخطوات التالية:

جافا

// Resume the ARCore session.
resumeARCore();

Kotlin

// Resume the ARCore session.
resumeARCore()

للتبديل من وضع الواقع المعزّز إلى وضع غير الواقع المعزّز، اتّبِع الخطوات التالية:

جافا

// Pause ARCore.
sharedSession.pause();

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

Kotlin

// Pause ARCore.
sharedSession.pause()

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