Questa guida per gli sviluppatori illustra i passaggi per consentire alla tua app di passare senza problemi dal controllo esclusivo della fotocamera tramite l' API Camera2 di Android alla condivisione dell'accesso alla fotocamera con ARCore.
Questo argomento presuppone che tu:
Abbiamo completato la guida rapida di ARCore
Conosci l'API Camera2 di Android (per saperne di più, consulta l'esempio di Camera2 specifico per Android)
Crea ed esegui l'app di esempio
Quando crei ed esegui l'app di esempio Shared Camera Java, viene creata una sessione ARCore che supporta l'accesso condiviso alla fotocamera. L'app viene avviata in modalità non AR, con ARCore in pausa.
Quando l'app funziona in modalità non AR, il visualizzatore della fotocamera mostra un effetto di colore seppia. Quando si passa alla modalità AR, l'effetto seppia viene disattivato quando l'app restituisce il controllo della fotocamera ad ARCore riprendendo la sessione in pausa.
Puoi utilizzare l'opzione AR nell'app per cambiare modalità. Durante l'anteprima, entrambe le modalità mostrano il numero di frame continui acquisiti da Camera2.
Per creare ed eseguire l'app di esempio Shared Camera Java:
Scarica ed estrai l' SDK Google ARCore per Android.
Apri il
samples/shared_camera_javaprogetto.Assicurati che il dispositivo Android sia collegato alla macchina di sviluppo tramite USB. Per informazioni dettagliate, consulta Dispositivi supportati da ARCore .
In Android Studio, fai clic su Run
.
Scegli il tuo dispositivo come target di deployment e fai clic su OK per avviare l' app di esempio sul dispositivo.
Sul dispositivo, conferma di voler consentire all'app di scattare foto e registrare video.
Se ti viene richiesto, aggiorna o installa la versione più recente di ARCore.
Utilizza l'opzione AR per passare dalla modalità non AR alla modalità AR e viceversa.
Panoramica dell'attivazione dell'accesso condiviso alla fotocamera con ARCore in un'app
Segui questi passaggi per implementare l'accesso condiviso alla fotocamera con ARCore nella tua app.
Tutti gli snippet di codice sono disponibili in
SharedCameraActivity.java
nell'esempio shared_camera_java.
Richiedi l'autorizzazione CAMERA
Per poter utilizzare la fotocamera del dispositivo, l'utente
deve concedere alla tua app l'autorizzazione CAMERApermission.
Gli esempi di ARCore includono un CameraPermissionHelper,
che fornisce utilità per richiedere l'autorizzazione corretta per la tua app.
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)
}
}
Assicurati che ARCore sia installato e aggiornato
ARCore deve essere installato e aggiornato prima di poter essere utilizzato. Il seguente snippet mostra come richiedere l'installazione di ARCore se non è già stato installato sul dispositivo.
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
}
}
}
Crea una sessione ARCore che supporti la condivisione della fotocamera
Ciò comporta la creazione della sessione e l'archiviazione del riferimento e dell'ID della fotocamera condivisa di 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
(Facoltativo) Informa ARCore di eventuali superfici personalizzate
La richiesta di superfici personalizzate aggiuntive aumenta le esigenze di prestazioni del dispositivo. Per garantire prestazioni ottimali, testa l'app sui dispositivi che verranno utilizzati dagli utenti.
Per impostazione predefinita, ARCore richiederà due stream:
- 1 stream CPU YUV, attualmente sempre
640x480.
ARCore utilizza questo stream per il rilevamento del movimento. - Un stream GPU 1x, in genere
1920x1080
UtilizzaSession#getCameraConfig()per determinare la risoluzione corrente dello stream GPU.
Puoi modificare la risoluzione dello stream GPU sui dispositivi supportati utilizzando
getSupportedCameraConfigs()
e
setCameraConfig().
Come indicatore approssimativo, puoi aspettarti:
| Tipo di dispositivo | Stream simultanei supportati |
|---|---|
| Smartphone di fascia alta |
|
| Smartphone di fascia media |
|
Per utilizzare superfici personalizzate, ad esempio una superficie di lettura delle immagini della CPU, assicurati di aggiungerla
all'elenco delle superfici da aggiornare
(ad esempio, un ImageReader).
Java
sharedCamera.">setAppSurfaces(this.cameraId, Arrays.asList(imageReader.getSurface()));
Kotlin
sharedCamera.">setAppSurfaces(this.cameraId, listOf(imageReader.surface))
Apri la fotocamera
Apri la fotocamera utilizzando un callback con wrapping 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)
Utilizza il callback dello stato del dispositivo della fotocamera
Nel callback dello stato del dispositivo della fotocamera, memorizza un riferimento al dispositivo della fotocamera e avvia una nuova sessione di acquisizione.
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()
}
Crea una nuova sessione di acquisizione
Crea una nuova richiesta di acquisizione. Use TEMPLATE_RECORD
per assicurarti che la richiesta di acquisizione sia compatibile con ARCore e per consentire il passaggio senza problemi dalla modalità non AR alla modalità AR e viceversa in fase di runtime.
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)
}
}
Avvia in modalità non AR o AR
Per iniziare ad acquisire frame, chiama captureSession.setRepeatingRequest()
dal callback dello stato onConfigured() della sessione di acquisizione della fotocamera.
Riprendi la sessione ARCore all'interno del onActive() callback per avviare in modalità 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)
}
Passa senza problemi dalla modalità non AR alla modalità AR e viceversa in fase di runtime
Per passare dalla modalità non AR alla modalità AR e riprendere una sessione ARCore in pausa:
Java
// Resume the ARCore session.
resumeARCore();
Kotlin
// Resume the ARCore session.
resumeARCore()
Per passare dalla modalità AR alla modalità non 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()
.