ARCore를 통한 공유 카메라 액세스

이 개발자 가이드에서는 앱에서 전환할 수 있도록 사용 설정하는 단계를 안내합니다. 제어 기능을 통해 카메라의 독점 제어 간에 Android Camera2 API ARCore로 카메라 액세스를 공유할 수 있습니다.

이 주제에서는 다음을 가정합니다.

샘플 앱 빌드 및 실행

공유 카메라 Java 샘플 앱을 빌드하고 실행하면 공유 카메라 액세스를 지원하는 ARCore 세션입니다. 앱이 AR이 아닌 언어로 시작됩니다. ARCore가 일시중지된 모드

앱이 AR이 아닌 모드에서 작동할 때 카메라 뷰어에 세피아 색상이 표시됩니다. 있습니다. AR 모드로 전환하면 앱이 실행되면서 세피아 효과가 꺼집니다. 일시중지된 세션을 재개하여 ARCore에 카메라 제어를 반환합니다.

앱에서 AR 스위치를 사용하여 모드를 변경할 수 있습니다. 미리보기 중에는 두 모드 모두 Camera2로 캡처된 연속 프레임 수를 표시합니다.

공유 카메라 Java 샘플 앱을 빌드하고 실행하려면 다음 단계를 따르세요.

  1. 다운로드한 다음 압축을 풉니다. Android용 Google ARCore SDK

  2. Google 검색 앱 홈 화면의 오른쪽 상단에 있는 samples/shared_camera_java 프로젝트

  3. Android 기기가 개발 머신에 연결되어 있는지 확인합니다. USB를 통해 할 수 있습니다. ARCore 지원 기기를 참고하세요. 확인하시기 바랍니다.

  4. Android 스튜디오에서 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);
  }
}

Kotlin

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

ARCore가 설치되어 있고 최신 상태인지 확인하세요.

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의 참조 및 ID를 저장하는 작업이 포함됩니다. 공유 카메라:

자바

// 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. YUV CPU 스트림 1개, 현재 항상 640x480.
    ARCore는 이 스트림을 모션 추적에 사용합니다.
  2. 1x GPU 스트림(일반적으로 1920x1080
    ) Session#getCameraConfig() 사용 현재 GPU 스트림 해상도를 확인합니다.

지원되는 기기에서 GPU 스트림 해상도를 변경하려면 getSupportedCameraConfigs() 드림 및 setCameraConfig()

대략적인 지표로 다음을 예상할 수 있습니다.

기기 유형 동시 스트림 지원됨
고급형 휴대전화
  • YUV CPU 스트림 2개(예: 640x4801920x1080
  • 1x GPU 스트림(예: <ph type="x-smartling-placeholder">1920x1080</ph>
  • 1x 비정기적인 고해상도 정지 이미지(JPEG)(예: <ph type="x-smartling-placeholder">12MP</ph>
중간 등급 휴대전화
  • YUV CPU 스트림 2개(예: 640x4801920x1080
  • 1x GPU 스트림(예: <ph type="x-smartling-placeholder">1920x1080</ph>
를 통해 개인정보처리방침을 정의할 수 있습니다. 또는 <ph type="x-smartling-placeholder">
    </ph>
  • YUV CPU 스트림 1개(예: 640x480 또는 1920x1080
  • 1x GPU 스트림(예: <ph type="x-smartling-placeholder">1920x1080</ph>
  • 1x 비정기적인 고해상도 정지 이미지(JPEG)(예: <ph type="x-smartling-placeholder">12MP</ph>

CPU 이미지 리더 노출 영역과 같은 맞춤 노출 영역을 사용하려면 이를 추가해야 합니다. 업데이트해야 하는 표시 경로 목록으로 (예: 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와 호환되는지 확인하고 원활한 런타임 시 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);
  }
}

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

AR 또는 AR 모드가 아닌 모드에서 시작

프레임 캡처를 시작하려면 captureSession.setRepeatingRequest()를 호출합니다. 카메라 캡처 세션 onConfigured() 상태 콜백에서 호출됩니다. onActive() 콜백 내에서 ARCore 세션을 재개하여 AR 모드에서 시작합니다.

자바

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

런타임 시 AR이 아닌 모드와 AR 모드 간에 원활하게 전환합니다.

AR 외 모드에서 AR 모드로 전환하고 일시중지된 ARCore 세션을 재개하려면 다음 단계를 따르세요.

자바

// Resume the ARCore session.
resumeARCore();

Kotlin

// Resume the ARCore session.
resumeARCore()

AR 모드에서 비 AR 모드로 전환하는 방법:

자바

// Pause ARCore.
sharedSession.pause();

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

Kotlin

// Pause ARCore.
sharedSession.pause()

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