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

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

این موضوع شما را فرض می کند:

برنامه نمونه را بسازید و اجرا کنید

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

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

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

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

  1. Google ARCore SDK برای Android را دانلود و استخراج کنید.

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

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

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

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

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

جاوا

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

کاتلین

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

کاتلین

// 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() در حالت پاسخ تماس بگیرید. برای شروع در حالت 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()