دسترسی به دوربین مشترک با ARCore

این راهنمای توسعه‌دهنده، شما را در مراحل فعال‌سازی برنامه‌تان برای جابجایی یکپارچه بین کنترل انحصاری دوربین از طریق Android Camera2 API و اشتراک‌گذاری دسترسی دوربین با ARCore راهنمایی می‌کند.

این مبحث فرض می‌کند که شما:

ساخت و اجرای برنامه نمونه

وقتی برنامه نمونه Shared Camera Java را می‌سازید و اجرا می‌کنید، یک جلسه ARCore ایجاد می‌شود که از دسترسی مشترک به دوربین پشتیبانی می‌کند. برنامه در حالت غیر AR شروع می‌شود و ARCore متوقف می‌شود.

وقتی برنامه در حالت غیر واقعیت افزوده (AR) کار می‌کند، نمایشگر دوربین یک جلوه رنگی قهوه‌ای (sepia) را نمایش می‌دهد. هنگام تغییر به حالت واقعیت افزوده (AR)، جلوه قهوه‌ای خاموش می‌شود زیرا برنامه با از سرگیری جلسه متوقف شده، کنترل دوربین را به ARCore برمی‌گرداند.

می‌توانید از دکمه‌ی AR در برنامه برای تغییر حالت‌ها استفاده کنید. در طول پیش‌نمایش، هر دو حالت تعداد فریم‌های متوالی ضبط‌شده توسط Camera2 را نمایش می‌دهند.

برای ساخت و اجرای برنامه نمونه دوربین مشترک جاوا:

  1. کیت توسعه نرم‌افزاری گوگل آرکور (Google ARCore SDK) برای اندروید را دانلود و استخراج کنید.

  2. پروژه samples/shared_camera_java را باز کنید.

  3. مطمئن شوید که دستگاه اندروید شما از طریق USB به دستگاه توسعه متصل است. برای اطلاعات دقیق‌تر به دستگاه‌های پشتیبانی‌شده توسط ARCore مراجعه کنید.

  4. در اندروید استودیو، Run کلیک کنید .

  5. دستگاه خود را به عنوان هدف استقرار انتخاب کنید و برای اجرای برنامه نمونه روی دستگاه خود، OK کلیک کنید.

  6. در دستگاه، تأیید کنید که می‌خواهید به برنامه اجازه دهید عکس بگیرد و فیلم ضبط کند.

  7. در صورت درخواست، آخرین نسخه ARCore را به‌روزرسانی یا نصب کنید.

  8. برای تغییر بین حالت‌های غیر AR و AR از کلید 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);
  }
}

کاتلین

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

کاتلین

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

کاتلین

// 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. ۱ برابر جریان YUV CPU ، در حال حاضر همیشه 640x480 .
    ARCore از این جریان برای ردیابی حرکت استفاده می‌کند.
  2. یک جریان GPU ، معمولاً 1920x1080
    برای تعیین وضوح جریان فعلی GPU Session#getCameraConfig() استفاده کنید.

شما می‌توانید وضوح جریان GPU را در دستگاه‌های پشتیبانی‌شده با استفاده از getSupportedCameraConfigs() و setCameraConfig() تغییر دهید.

به عنوان یک شاخص تقریبی، می‌توانید انتظار داشته باشید:

نوع دستگاه پشتیبانی از پخش همزمان
گوشی‌های رده بالا
  • دو استریم YUV CPU ، مثلاً 640x480 و 1920x1080
  • ۱ برابر جریان GPU ، مثلاً 1920x1080
  • ۱ بار تصویر ثابت با وضوح بالا (JPEG)، مثلاً 12MP
گوشی‌های میان‌رده
  • دو استریم YUV CPU ، مثلاً 640x480 و 1920x1080
  • ۱ برابر جریان GPU ، مثلاً 1920x1080
–یا–
  • ۱ برابر جریان‌های YUV CPU ، مثلاً 640x480 –یا– 1920x1080
  • ۱ برابر جریان GPU ، مثلاً 1920x1080
  • ۱ بار تصویر ثابت با وضوح بالا (JPEG)، مثلاً 12MP

برای استفاده از سطوح سفارشی، مانند سطح خواننده تصویر CPU، حتماً آن را به لیست سطوحی که باید به‌روزرسانی شوند (مثلاً یک ImageReader ) اضافه کنید.

جاوا

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

کاتلین

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

دوربین را باز کنید

دوربین را با استفاده از یک فراخوانیِ ARCore-wrapped باز کنید:

جاوا

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

کاتلین

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

کاتلین

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

یک جلسه ضبط جدید ایجاد کنید

یک درخواست ضبط جدید بسازید. از TEMPLATE_RECORD استفاده کنید تا مطمئن شوید که درخواست ضبط با ARCore سازگار است و امکان جابجایی یکپارچه بین حالت غیر AR و AR را در زمان اجرا فراهم می‌کند.

جاوا

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

کاتلین

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

در حالت غیر AR یا AR شروع کنید

برای شروع ضبط فریم‌ها، تابع captureSession.setRepeatingRequest() را از فراخوانی حالت onConfigured() session ضبط دوربین فراخوانی کنید. برای شروع در حالت AR، جلسه 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);
}

کاتلین

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

در زمان اجرا، به طور یکپارچه بین حالت‌های غیر AR یا AR جابجا شوید

برای تغییر از حالت غیر AR به AR و از سرگیری یک جلسه ARCore متوقف شده:

جاوا

// Resume the ARCore session.
resumeARCore();

کاتلین

// Resume the ARCore session.
resumeARCore()

برای تغییر از حالت AR به حالت غیر AR:

جاوا

// Pause ARCore.
sharedSession.pause();

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

کاتلین

// Pause ARCore.
sharedSession.pause()

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