이 개발자 가이드에서는 앱에서 전환할 수 있도록 사용 설정하는 단계를 안내합니다. 제어 기능을 통해 카메라의 독점 제어 간에 Android Camera2 API ARCore로 카메라 액세스를 공유할 수 있습니다.
이 주제에서는 다음을 가정합니다.
ARCore 빠른 시작을 완료함
Android Camera2 API (Android 전용 Camera2 샘플 를 참조하세요.
샘플 앱 빌드 및 실행
공유 카메라 Java 샘플 앱을 빌드하고 실행하면 공유 카메라 액세스를 지원하는 ARCore 세션입니다. 앱이 AR이 아닌 언어로 시작됩니다. ARCore가 일시중지된 모드
앱이 AR이 아닌 모드에서 작동할 때 카메라 뷰어에 세피아 색상이 표시됩니다. 있습니다. AR 모드로 전환하면 앱이 실행되면서 세피아 효과가 꺼집니다. 일시중지된 세션을 재개하여 ARCore에 카메라 제어를 반환합니다.
앱에서 AR 스위치를 사용하여 모드를 변경할 수 있습니다. 미리보기 중에는 두 모드 모두 Camera2로 캡처된 연속 프레임 수를 표시합니다.
공유 카메라 Java 샘플 앱을 빌드하고 실행하려면 다음 단계를 따르세요.
다운로드한 다음 압축을 풉니다. Android용 Google ARCore SDK
Google 검색 앱 홈 화면의 오른쪽 상단에 있는
samples/shared_camera_java
프로젝트Android 기기가 개발 머신에 연결되어 있는지 확인합니다. USB를 통해 할 수 있습니다. ARCore 지원 기기를 참고하세요. 확인하시기 바랍니다.
Android 스튜디오에서 Run
를 클릭합니다.
배포 대상으로 기기를 선택하고 OK를 클릭하여 샘플 앱을 다운로드합니다.
기기에서 앱이 사진을 찍고 동영상을 녹화합니다.
메시지가 표시되면 최신 버전의 ARCore를 업데이트하거나 설치합니다.
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가 설치되어 있고 최신 상태여야 합니다. 다음 스니펫은 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의 참조 및 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();
// 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는 기본적으로 두 개의 스트림을 요청합니다.
- YUV CPU 스트림 1개, 현재 항상
640x480
.
ARCore는 이 스트림을 모션 추적에 사용합니다. - 1x GPU 스트림(일반적으로
1920x1080
)Session#getCameraConfig()
사용 현재 GPU 스트림 해상도를 확인합니다.
지원되는 기기에서 GPU 스트림 해상도를 변경하려면
getSupportedCameraConfigs()
드림
및
setCameraConfig()
대략적인 지표로 다음을 예상할 수 있습니다.
기기 유형 | 동시 스트림 지원됨 |
---|---|
고급형 휴대전화 |
|
중간 등급 휴대전화 |
|
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()
상태 콜백에서 호출됩니다.
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);
}
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()