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

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

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

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

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

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

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

لإنشاء نموذج تطبيق جافا من الكاميرا المشتركة وتشغيله:

  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، الذي يوفّر أدوات مساعدة لطلب الإذن الصحيح لتطبيقك.

Java

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

Kotlin

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

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

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

Java

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

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

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

Kotlin

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

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

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

إنشاء جلسة ARCore متوافقة مع ميزة مشاركة الكاميرا

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

Java

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

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

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

Kotlin

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

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

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

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

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

سيطلب تطبيق ARCore عمليتَي بث تلقائيًا:

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

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

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

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

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

Java

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

Kotlin

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

فتح الكاميرا

افتح الكاميرا باستخدام معاودة اتصال ملفوفة في ARCore:

Java

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

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

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

Kotlin

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

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

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

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

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

Java

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

Kotlin

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

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

أنشئ طلب التقاط جديدًا. استخدِم TEMPLATE_RECORD للتأكّد من توافق طلب الالتقاط مع ARCore، وللسماح بالتبديل السلس بين وضع "الواقع المعزّز" و"الواقع المعزّز" في وقت التشغيل.

Java

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

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

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

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

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

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

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

Kotlin

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

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

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

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

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

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

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

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

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

Java

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

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

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

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

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

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

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

Kotlin

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

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

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

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

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

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

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

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

Java

// Resume the ARCore session.
resumeARCore();

Kotlin

// Resume the ARCore session.
resumeARCore()

للتبديل من وضع "الواقع المعزّز" إلى وضع "الواقع المعزّز":

Java

// Pause ARCore.
sharedSession.pause();

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

Kotlin

// Pause ARCore.
sharedSession.pause()

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