Ce guide du développeur explique comment permettre à votre application de basculer facilement entre le contrôle exclusif de la caméra via l'API Android Camera2 et le partage de l'accès à la caméra avec ARCore.
Dans cette rubrique, nous partons du principe que vous avez:
Avoir suivi le guide de démarrage rapide ARCore
Familiarisez-vous avec l'API Android Camera2 (pour en savoir plus, consultez l'exemple Camera2 spécifique à Android).
Créer et exécuter l'application exemple
Lorsque vous compilez et exécutez l'application exemple Shared Camera Java (Appareil photo partagé), celui-ci crée une session ARCore compatible avec l'accès à la caméra partagée. L'application démarre en mode sans RA et ARCore est suspendu.
Lorsque l'application fonctionne en mode non-RA, la visionneuse de l'appareil photo affiche un effet de couleur sépia. Lorsque vous passez en mode RA, l'effet sépia se désactive lorsque l'application rend le contrôle de l'appareil photo à ARCore en reprenant la session suspendue.
Vous pouvez utiliser le bouton de RA dans l'application pour changer de mode. En preview, les deux modes affichent le nombre d'images continues capturées par Camera2.
Pour compiler et exécuter l'exemple d'application Java de la caméra partagée:
Téléchargez et extrayez le SDK Google ARCore pour Android.
Ouvrez le projet
samples/shared_camera_java
.Assurez-vous que votre appareil Android est connecté à l'ordinateur de développement via USB. Pour en savoir plus, consultez la section Appareils compatibles avec ARCore.
Dans Android Studio, cliquez sur Run .
Choisissez votre appareil comme cible de déploiement, puis cliquez sur OK pour lancer l'application exemple sur votre appareil.
Sur l'appareil, confirmez que vous souhaitez autoriser l'application à prendre des photos et à enregistrer des vidéos.
Si vous y êtes invité, mettez à jour ou installez la dernière version d'ARCore.
Utilisez le bouton bascule AR pour passer du mode RA au mode standard et inversement.
Présentation de l'activation du partage de l'accès à l'appareil photo avec ARCore pour une application
Suivez ces étapes pour implémenter l'accès à la caméra partagée avec ARCore dans votre application. Tous les extraits de code sont disponibles dans SharedCameraActivity.java
dans l'exemple shared_camera_java
.
Demander l'autorisation CAMERA
Pour pouvoir utiliser l'appareil photo de l'appareil, l'utilisateur doit accorder l'autorisation CAMERA
à votre application.
Les exemples ARCore incluent un CameraPermissionHelper
, qui fournit des utilitaires permettant de demander l'autorisation appropriée pour votre application.
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)
}
}
Assurez-vous qu'ARCore est installé et à jour
ARCore doit être installé et à jour pour pouvoir être utilisé. L'extrait de code suivant montre comment demander une installation d'ARCore si ce n'est pas déjà fait sur l'appareil.
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
}
}
}
Créer une session ARCore compatible avec le partage de la caméra
Cette opération implique la création de la session, et le stockage de la référence et de l'ID de la caméra partagée ARCore:
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
(Facultatif) Informer ARCore de toutes les surfaces personnalisées
Le fait de demander des surfaces personnalisées supplémentaires augmente les exigences de performances de l'appareil. Pour vous assurer qu'elle fonctionne correctement, testez-la sur les appareils que vos utilisateurs utiliseront.
ARCore demandera deux flux par défaut:
- 1x flux de processeur YUV, actuellement toujours
640x480
.
ARCore utilise ce flux pour le suivi du mouvement. - Flux de GPU 1x, généralement
1920x1080
UtilisezSession#getCameraConfig()
pour déterminer la résolution actuelle du flux GPU.
Vous pouvez modifier la résolution du flux de GPU sur les appareils compatibles à l'aide de getSupportedCameraConfigs()
et setCameraConfig()
.
À titre indicatif, vous pouvez vous attendre à ce qui suit:
Type d'appareil | Flux simultanés acceptés |
---|---|
Téléphones haut de gamme |
|
Téléphones de milieu de gamme |
|
Pour utiliser des surfaces personnalisées, telles qu'une surface de lecteur d'images de processeur, veillez à les ajouter à la liste des surfaces à mettre à jour (par exemple, une ImageReader
).
Java
sharedCamera.setAppSurfaces(this.cameraId, Arrays.asList(imageReader.getSurface()));
Kotlin
sharedCamera.setAppSurfaces(this.cameraId, listOf(imageReader.surface))
Ouvrir l'appareil photo
Ouvrez l'appareil photo à l'aide d'un rappel encapsulé 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)
Utiliser le rappel d'état de la caméra
Dans le rappel d'état de l'appareil photo, stockez une référence à cet appareil et démarrez une nouvelle session de capture.
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()
}
Créer une session de capture
Créez une demande de capture. Utilisez TEMPLATE_RECORD
pour vous assurer que la requête de capture est compatible avec ARCore et pour permettre le basculement fluide entre le mode non-RA et le mode RA lors de l'exécution.
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)
}
}
Commencer en mode non-RA ou RA
Pour commencer à capturer des images, appelez captureSession.setRepeatingRequest()
à partir du rappel d'état onConfigured()
de la session de capture de la caméra.
Reprenez la session ARCore dans le rappel onActive()
pour démarrer en mode RA.
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)
}
Basculez facilement entre les modes non RA et RA lors de l'exécution
Pour passer du mode RA au mode RA et reprendre une session ARCore interrompue:
Java
// Resume the ARCore session.
resumeARCore();
Kotlin
// Resume the ARCore session.
resumeARCore()
Pour passer du mode RA au mode non RA, procédez comme suit:
Java
// Pause ARCore.
sharedSession.pause();
// Create the Camera2 repeating capture request.
setRepeatingCaptureRequest();
Kotlin
// Pause ARCore.
sharedSession.pause()
// Create the Camera2 repeating capture request.
setRepeatingCaptureRequest()