本開發人員指南將逐步引導您透過 Android Camera2 API,讓應用程式在專屬控制項之間順利切換,並與 ARCore 共用相機存取權。
本主題假設您:
已完成 ARCore 快速入門導覽課程
熟悉 Android Camera2 API (詳情請參閱 Android 專用的 Camera2 範例)
建構並執行範例應用程式
建構及執行「共用相機 Java」範例應用程式時,系統會建立一個支援共用相機存取權的 ARCore 工作階段。應用程式會以非 AR 模式啟動,同時暫停 ARCore。
當應用程式以非 AR 模式運作時,相機檢視器會顯示深褐色效果。切換到 AR 模式時,懷孕效果會關閉,因為應用程式會透過恢復已暫停的工作階段,將相機控制項傳回 ARCore。
你可以使用應用程式中的 AR 切換按鈕來變更模式。在預覽期間,兩種模式都會顯示 Camera2 擷取的連續影格數量。
如何建構及執行共用相機 Java 範例應用程式:
下載並解壓縮 Android 版 Google ARCore SDK。
開啟
samples/shared_camera_java
專案。確認您的 Android 裝置已透過 USB 連接至開發機器。詳情請參閱 ARCore 支援的裝置。
在 Android Studio 中,按一下 Run 。
選擇您的裝置做為部署目標,然後按一下 OK 在裝置上啟動範例應用程式。
在裝置上,確認您要允許應用程式拍照及錄影。
當系統提示時,請更新或安裝最新版的 ARCore。
使用 AR 切換按鈕,即可在非 AR 和 AR 模式之間切換。
讓應用程式透過 ARCore 分享相機存取權總覽
請按照下列步驟在應用程式中實作使用 ARCore 的共用相機存取權。所有程式碼片段都可以在 shared_camera_java
範例中的 SharedCameraActivity.java
中找到。
要求 CAMERA
權限
如要使用裝置相機,使用者必須授予 CAMERA
權限。ARCore 範例包含 CameraPermissionHelper
,可提供公用程式為應用程式要求正確權限。
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)
}
}
確保已安裝最新版本的 ARCore
必須先安裝並更新 ARCore 才能使用。 下列程式碼片段示範如何要求安裝裝置上的 ARCore。
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
}
}
}
建立支援相機分享功能的 ARCore 工作階段
這包括建立工作階段,並儲存 ARCore 共用相機的參照和 ID:
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
(選用) 告知 ARCore 任何自訂途徑
要求額外的自訂途徑會增加裝置效能需求。為確保應用程式能正常運作,請在使用者要使用的裝置上測試應用程式。
根據預設,ARCore 會要求兩個串流:
- 1x YUV CPU 串流,目前一律為
640x480
。
ARCore 會使用這個串流進行動作追蹤。 - 1 倍 GPU 串流,通常為
1920x1080
使用Session#getCameraConfig()
來判斷目前的 GPU 串流解析度。
您可以使用 getSupportedCameraConfigs()
和 setCameraConfig()
在支援的裝置上變更 GPU 串流的解析度。
大致上來說,您可以預期:
裝置類型 | 支援同時串流 |
---|---|
高階手機 |
|
中階手機 |
|
如要使用自訂途徑 (例如 CPU 圖片讀取器介面),請務必將其新增至需要更新的途徑清單 (例如 ImageReader
)。
Java
sharedCamera.setAppSurfaces(this.cameraId, Arrays.asList(imageReader.getSurface()));
Kotlin
sharedCamera.setAppSurfaces(this.cameraId, listOf(imageReader.surface))
開啟相機
使用 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)
使用相機裝置狀態回呼
在相機裝置狀態回呼中,會儲存相機裝置的參照,並啟動新的擷取工作階段。
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()
}
建立新的擷取工作階段
建立新的擷取要求。使用 TEMPLATE_RECORD
可確保擷取要求與 ARCore 相容,並在執行階段順暢切換非 AR 和 AR 模式。
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)
}
}
以非 AR 或 AR 模式啟動
如要開始擷取影格,請從相機擷取工作階段 onConfigured()
狀態回呼呼叫 captureSession.setRepeatingRequest()
。在 onActive()
回呼中繼續執行 ARCore 工作階段,以啟動 AR 模式。
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)
}
在執行階段輕鬆切換非 AR 或 AR 模式
如何從非 AR 模式切換至 AR 模式並恢復已暫停的 ARCore 工作階段:
Java
// Resume the ARCore session.
resumeARCore();
Kotlin
// Resume the ARCore session.
resumeARCore()
如何從 AR 模式切換至非 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()