本開發人員指南將逐步說明如何讓應用程式透過 Android Camera2 API 專屬控制相機,並與 ARCore 共用相機存取權,兩者之間可無縫切換。
本主題假設您:
已完成 ARCore 快速入門導覽課程
熟悉 Android Camera2 API (如要瞭解詳情,請參閱 Android 專用的 Camera2 範例)
建構並執行範例應用程式
建構並執行 Shared Camera Java 範例應用程式時,系統會建立支援共用相機存取權的 ARCore 工作階段。應用程式會以非 AR 模式啟動,並暫停 ARCore。
應用程式在非 AR 模式下運作時,相機檢視畫面會顯示深褐色效果。切換至 AR 模式時,應用程式會恢復暫停的工作階段,將相機控制權交還給 ARCore,因此懷舊色調效果會關閉。
您可以在應用程式中使用 AR 切換鈕變更模式。預覽時,這兩種模式都會顯示 Camera2 擷取的連續影格數。
如要建構及執行 Shared Camera Java 範例應用程式,請按照下列步驟操作:
下載並解壓縮 Google ARCore SDK for Android。
開啟
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,下列程式碼片段會說明如何要求安裝 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 預設會要求兩個串流:
- 1 個 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()
。