Quyền truy cập vào máy ảnh dùng chung với ARCore

Hướng dẫn dành cho nhà phát triển này sẽ chỉ cho bạn các bước để bật ứng dụng chuyển đổi một cách liền mạch giữa khả năng kiểm soát độc quyền máy ảnh thông qua API Android Camera2 và chia sẻ quyền truy cập máy ảnh với ARCore.

Chủ đề này giả định bạn:

Xây dựng và chạy ứng dụng mẫu

Khi tạo và chạy ứng dụng mẫu Shared Camera Java (Máy ảnh dùng chung), ứng dụng này sẽ tạo một Phiên ARCore hỗ trợ quyền truy cập vào máy ảnh dùng chung. Ứng dụng khởi động ở chế độ không phải AR trong đó ARCore bị tạm dừng.

Khi ứng dụng hoạt động ở chế độ không phải chế độ thực tế tăng cường, trình xem camera sẽ cho thấy màu nâu đỏ hiệu ứng. Khi chuyển sang chế độ AR, hiệu ứng màu nâu đỏ sẽ tắt khi ứng dụng trả về quyền điều khiển máy ảnh cho ARCore bằng cách tiếp tục phiên bị tạm dừng.

Bạn có thể dùng nút chuyển AR trong ứng dụng để thay đổi chế độ. Trong khi dùng thử, cả hai chế độ hiển thị số khung hình liên tục do Camera2 chụp.

Cách tạo và chạy ứng dụng mẫu Java cho Máy ảnh dùng chung:

  1. Tải xuống và giải nén SDK ARCore của Google dành cho Android.

  2. Mở Dự án samples/shared_camera_java.

  3. Đảm bảo rằng thiết bị Android đã kết nối với máy phát triển qua USB. Xem Thiết bị được hỗ trợ của ARCore để biết thông tin chi tiết.

  4. Trong Android Studio, hãy nhấp vào Run .

  5. Chọn thiết bị của bạn làm mục tiêu triển khai rồi nhấp vào OK để chạy ứng dụng mẫu trên thiết bị của bạn.

  6. Trên thiết bị, hãy xác nhận rằng bạn muốn cho phép ứng dụng chụp ảnh và quay video.

  7. Nếu thấy lời nhắc, hãy cập nhật hoặc cài đặt phiên bản ARCore mới nhất.

  8. Dùng nút chuyển AR để thay đổi giữa chế độ không sử dụng công nghệ thực tế tăng cường (AR) và chế độ thực tế tăng cường (AR).

Tổng quan về việc bật ứng dụng để chia sẻ quyền truy cập máy ảnh với ARCore

Hãy làm theo các bước sau để triển khai quyền truy cập máy ảnh dùng chung với ARCore trong ứng dụng của bạn. Tất cả các đoạn mã đều có trong SharedCameraActivity.java trong shared_camera_java mẫu.

Yêu cầu quyền CAMERA

Để có thể sử dụng máy ảnh của thiết bị, người dùng phải cấp cho ứng dụng quyền CAMERA. Các mẫu ARCore bao gồm CameraPermissionHelper, cung cấp các tiện ích để yêu cầu quyền chính xác cho ứng dụng.

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

Đảm bảo ARCore đã được cài đặt và cập nhật

Bạn phải cài đặt và cập nhật ARCore trước khi có thể sử dụng. Đoạn mã sau đây cho biết cách yêu cầu cài đặt ARCore nếu ARCore chưa được cài đặt trên thiết bị.

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

Tạo một phiên ARCore có hỗ trợ tính năng chia sẻ máy ảnh

Việc này bao gồm việc tạo phiên và lưu trữ tham chiếu và ID của ARCore camera dùng chung:

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

(Không bắt buộc) Thông báo cho ARCore về mọi nền tảng tuỳ chỉnh

Việc yêu cầu thêm nền tảng tuỳ chỉnh sẽ làm tăng nhu cầu về hiệu suất của thiết bị. Để đảm bảo ứng dụng hoạt động tốt, hãy thử nghiệm ứng dụng của bạn trên các thiết bị mà người dùng sẽ sử dụng.

Theo mặc định, ARCore sẽ yêu cầu hai luồng:

  1. Luồng CPU YUV 1x, hiện luôn là 640x480.
    ARCore sử dụng luồng này để theo dõi chuyển động.
  2. Luồng GPU 1x, thường là 1920x1080
    Sử dụng Session#getCameraConfig() để xác định độ phân giải luồng GPU hiện tại.

Bạn có thể thay đổi độ phân giải của luồng GPU trên những thiết bị được hỗ trợ bằng cách sử dụng getSupportedCameraConfigs()setCameraConfig().

Như chỉ báo sơ bộ, có thể bạn sẽ thấy:

Loại thiết bị Hỗ trợ phát trực tuyến đồng thời
Điện thoại cao cấp
  • 2x luồng CPU YUV, ví dụ: 640x4801920x1080
  • 1x GPU stream, ví dụ: 1920x1080
  • gấp 1 lần hình ảnh tĩnh có độ phân giải cao (thỉnh thoảng cao) (JPEG), ví dụ: 12MP
Điện thoại cấp trung
  • 2x luồng CPU YUV, ví dụ: 640x4801920x1080
  • 1x GPU stream, ví dụ: 1920x1080
–hoặc–
  • 1x luồng CPU YUV, ví dụ: 640x480 – hoặc – 1920x1080
  • 1x GPU stream, ví dụ: 1920x1080
  • gấp 1 lần hình ảnh tĩnh có độ phân giải cao (thỉnh thoảng cao) (JPEG), ví dụ: 12MP

Để sử dụng nền tảng tuỳ chỉnh, chẳng hạn như bề mặt trình đọc hình ảnh bằng CPU, hãy nhớ thêm nền tảng đó vào danh sách nền tảng cần được cập nhật (ví dụ: ImageReader).

Java

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

Kotlin

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

Mở máy ảnh

Mở máy ảnh bằng lệnh gọi lại được gói 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)

Sử dụng lệnh gọi lại trạng thái thiết bị máy ảnh

Trong lệnh gọi lại trạng thái thiết bị máy ảnh, lưu trữ tham chiếu đến thiết bị máy ảnh và bắt đầu một phiên chụp mới.

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

Tạo phiên chụp mới

Tạo một yêu cầu chụp mới. Sử dụng TEMPLATE_RECORD để đảm bảo rằng yêu cầu chụp ảnh tương thích với ARCore và để cho phép liền mạch chuyển đổi giữa chế độ không sử dụng công nghệ thực tế tăng cường và chế độ thực tế tăng cường trong thời gian chạy.

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

Bắt đầu ở chế độ không sử dụng công nghệ thực tế tăng cường hoặc thực tế tăng cường

Để bắt đầu chụp khung hình, hãy gọi captureSession.setRepeatingRequest() từ lệnh gọi lại trạng thái onConfigured() trong phiên chụp ảnh. Tiếp tục phiên ARCore trong lệnh gọi lại onActive() để bắt đầu ở chế độ thực tế tăng cường.

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

Chuyển đổi liền mạch giữa chế độ không sử dụng công nghệ thực tế tăng cường (AR) hoặc thực tế tăng cường (AR) trong thời gian chạy

Cách chuyển từ chế độ không sử dụng công nghệ thực tế tăng cường sang chế độ thực tế tăng cường và tiếp tục một phiên ARCore đã tạm dừng:

Java

// Resume the ARCore session.
resumeARCore();

Kotlin

// Resume the ARCore session.
resumeARCore()

Cách chuyển từ chế độ AR sang chế độ không phải AR:

Java

// Pause ARCore.
sharedSession.pause();

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

Kotlin

// Pause ARCore.
sharedSession.pause()

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