Ten przewodnik dla programistów zawiera instrukcje umożliwiające aplikacji płynne przełączanie się między wyłącznym sterowaniem kamerą za pośrednictwem interfejsu API Android Camera2 a udostępnianiem dostępu do kamery za pomocą ARCore.
W tym temacie założono, że:
Ukończyłeś Szybki start ARCore
Zaznajomieni z interfejsem API Android Camera2 ( przejrzyj przykład Camera2 dla systemu Android, aby dowiedzieć się więcej)
Zbuduj i uruchom przykładową aplikację
Podczas tworzenia i uruchamiania przykładowej aplikacji Shared Camera Java tworzy ona sesję ARCore, która obsługuje dostęp do udostępnionej kamery. Aplikacja uruchamia się w trybie innym niż AR, z wstrzymanym ARCore.
Gdy aplikacja działa w trybie innym niż AR, kamera wyświetla efekt koloru sepii. Po przełączeniu w tryb AR efekt sepii wyłącza się, gdy aplikacja przywraca sterowanie aparatem do ARCore, wznawiając wstrzymaną sesję.
Możesz użyć przełącznika AR w aplikacji, aby zmienić tryby. Podczas podglądu oba tryby wyświetlają liczbę ciągłych klatek zarejestrowanych przez Aparat2.
Aby zbudować i uruchomić przykładową aplikację Shared Camera Java:
Pobierz i wyodrębnij pakiet SDK Google ARCore na Androida .
Otwórz projekt
samples/shared_camera_java
.Upewnij się, że Twoje urządzenie z Androidem jest połączone z maszyną programistyczną przez USB. Zobacz Urządzenia obsługiwane przez ARCore, aby uzyskać szczegółowe informacje.
W Android Studio kliknij Run
.
Wybierz swoje urządzenie jako cel wdrożenia i kliknij OK , aby uruchomić przykładową aplikację na swoim urządzeniu.
Na urządzeniu potwierdź, że chcesz zezwolić aplikacji na robienie zdjęć i nagrywanie wideo.
Jeśli zostaniesz o to poproszony, zaktualizuj lub zainstaluj najnowszą wersję ARCore.
Użyj przełącznika AR , aby przełączać się między trybami bez AR i AR.
Omówienie włączania aplikacji do udostępniania dostępu do aparatu za pomocą ARCore
Wykonaj te czynności, aby zaimplementować dostęp do współdzielonej kamery za pomocą ARCore w swojej aplikacji. Wszystkie fragmenty kodu są dostępne w SharedCameraActivity.java
w przykładzie shared_camera_java
.
Poproś o pozwolenie na CAMERA
Aby móc korzystać z kamery urządzenia, użytkownik musi przyznać aplikacji uprawnienia CAMERA
. Przykłady ARCore zawierają CameraPermissionHelper
, który zapewnia narzędzia do żądania odpowiednich uprawnień dla Twojej aplikacji.
Jawa
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)
}
}
Upewnij się, że ARCore jest zainstalowany i aktualny
ARCore musi być zainstalowany i aktualny, zanim będzie można go używać. Poniższy fragment kodu pokazuje, jak zażądać instalacji ARCore, jeśli nie został jeszcze zainstalowany na urządzeniu.
Jawa
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
}
}
}
Utwórz sesję ARCore, która obsługuje udostępnianie kamery
Wiąże się to z utworzeniem sesji i przechowywaniem referencji i identyfikatora udostępnionej kamery ARCore:
Jawa
// 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
(Opcjonalnie) Poinformuj ARCore o wszelkich niestandardowych powierzchniach
Żądanie dodatkowych powierzchni niestandardowych zwiększa wymagania dotyczące wydajności urządzenia. Aby upewnić się, że działa dobrze, przetestuj swoją aplikację na urządzeniach, z których będą korzystać użytkownicy.
ARCore domyślnie zażąda dwóch strumieni:
- 1x strumień procesora YUV , obecnie zawsze
640x480
.
ARCore używa tego strumienia do śledzenia ruchu . - Strumień 1x GPU , zwykle
1920x1080
UżyjSession#getCameraConfig()
, aby określić bieżącą rozdzielczość strumienia GPU.
Możesz zmienić rozdzielczość strumienia GPU na obsługiwanych urządzeniach, używając getSupportedCameraConfigs()
i setCameraConfig()
.
Jako przybliżony wskaźnik możesz oczekiwać:
Rodzaj urządzenia | Obsługiwane jednoczesne strumienie |
---|---|
Telefony z najwyższej półki |
|
Telefony średniej klasy |
|
Aby użyć powierzchni niestandardowych, takich jak powierzchnia czytnika obrazów procesora, dodaj ją do listy powierzchni, które wymagają aktualizacji (na przykład ImageReader
).
Jawa
sharedCamera.setAppSurfaces(this.cameraId, Arrays.asList(imageReader.getSurface()));
Kotlin
sharedCamera.setAppSurfaces(this.cameraId, listOf(imageReader.surface))
Otworzyć aparat
Otwórz kamerę za pomocą wywołania zwrotnego w ARCore:
Jawa
// 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)
Użyj wywołania zwrotnego stanu urządzenia kamery
W wywołaniu zwrotnym stanu urządzenia z kamerą zapisz odniesienie do urządzenia z kamerą i rozpocznij nową sesję przechwytywania.
Jawa
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()
}
Utwórz nową sesję przechwytywania
Zbuduj nowe żądanie przechwytywania. Użyj TEMPLATE_RECORD
, aby upewnić się, że żądanie przechwytywania jest zgodne z ARCore i umożliwić płynne przełączanie między trybem innym niż AR i AR w czasie wykonywania.
Jawa
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)
}
}
Zacznij w trybie innym niż AR lub AR
Aby rozpocząć przechwytywanie ramek, wywołaj captureSession.setRepeatingRequest()
z sesji przechwytywania kamery onConfigured()
w wywołaniu zwrotnym stanu. Wznów sesję ARCore w wywołaniu zwrotnym onActive()
, aby rozpocząć w trybie AR.
Jawa
// 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)
}
Płynnie przełączaj się między trybami innymi niż AR lub AR w czasie pracy
Aby przełączyć się z trybu bez AR na tryb AR i wznowić wstrzymaną sesję ARCore:
Jawa
// Resume the ARCore session.
resumeARCore();
Kotlin
// Resume the ARCore session.
resumeARCore()
Aby przełączyć się z trybu AR na tryb bez AR:
Jawa
// Pause ARCore.
sharedSession.pause();
// Create the Camera2 repeating capture request.
setRepeatingCaptureRequest();
Kotlin
// Pause ARCore.
sharedSession.pause()
// Create the Camera2 repeating capture request.
setRepeatingCaptureRequest()