Este guia para desenvolvedores mostra as etapas para permitir a troca do seu app perfeitamente entre o controle exclusivo da câmera por meio do API Android Camera2 e compartilhar o acesso à câmera com o ARCore.
Neste tópico, pressupõe-se que você:
Concluir o Guia de início rápido do ARCore
Conhecer o API Android Camera2 Consulte o exemplo da Camera2 específica para Android. para saber mais)
Criar e executar o aplicativo de amostra
Quando você cria e executa o app de exemplo Câmera compartilhada Java (em inglês), ele cria uma Sessão do ARCore que oferece suporte ao acesso compartilhado à câmera. O app não é iniciado em RA com o ARCore pausado.
Quando o app opera em modo não RA, o visor da câmera mostra uma cor sépia efeito Ao alternar para o modo RA, o efeito sépia é desativado conforme o app retorna o controle da câmera ao ARCore retomando a sessão pausada.
Você pode usar o interruptor de RA no app para mudar os modos. Durante a prévia, os dois modos mostra o número de frames contínuos capturados pela Camera2.
Para criar e executar o app de exemplo Java de câmera compartilhada:
Faça o download e extraia o SDK do ARCore do Google para Android.
Abra o Projeto
samples/shared_camera_java
.Verifique se o dispositivo Android está conectado à máquina de desenvolvimento via USB. Consulte Dispositivos compatíveis com o ARCore para mais detalhes.
No Android Studio, clique em Run
.
Escolha seu dispositivo como destino da implantação e clique em OK para iniciar a app de exemplo no seu dispositivo.
No dispositivo, confirme que você quer permitir que o app tire fotos e gravar vídeo.
Se solicitado, atualize ou instale a versão mais recente do ARCore.
Use a chave AR para alternar entre os modos RA e não RA.
Visão geral da ativação de um app para compartilhar o acesso à câmera com o ARCore
Siga estas etapas para implementar o acesso compartilhado à câmera com o ARCore no seu app.
Todos os snippets de código estão disponíveis na
SharedCameraActivity.java
em shared_camera_java
amostra.
Solicitar permissão de CAMERA
Para poder usar a câmera do dispositivo, o usuário
precisa conceder a permissão CAMERA
ao app.
Os exemplos do ARCore incluem um CameraPermissionHelper
,
que fornece utilitários para solicitar a permissão correta para seu 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)
}
}
Verifique se o ARCore está instalado e atualizado
O ARCore precisa estar instalado e atualizado antes de ser usado. O snippet a seguir mostra como solicitar uma instalação do ARCore se ele ainda não tiver sido instalado no 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
}
}
}
Criar uma sessão do ARCore compatível com o compartilhamento de câmera
Isso envolve criar a sessão e armazenar a referência e o ID do ARCore câmera compartilhada:
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
(Opcional) Informar o ARCore sobre qualquer superfície personalizada
Solicitar plataformas personalizadas adicionais aumenta as demandas de desempenho do dispositivo. Para garantir um bom desempenho, teste o app nos dispositivos em que o que os usuários utilizarão.
O ARCore solicitará dois fluxos por padrão:
- 1x fluxo de CPU YUV, atualmente sempre
640x480
.
O ARCore usa esse stream para rastreamento de movimento. - Um stream de GPU 1x, normalmente
1920x1080
UsarSession#getCameraConfig()
para determinar a resolução de stream da GPU atual.
Para alterar a resolução do stream da GPU em dispositivos compatíveis, use
getSupportedCameraConfigs()
e
setCameraConfig()
Como um indicador aproximado, você pode esperar:
Tipo de dispositivo | Compatível com streams simultâneos |
---|---|
Telefones de última geração |
|
Telefones de nível médio |
|
Para usar superfícies personalizadas, como uma superfície de leitor de imagem da CPU, adicione-as
à lista de plataformas que precisam ser atualizadas
Por exemplo, um ImageReader
.
Java
sharedCamera.">setAppSurfaces(this.cameraId, Arrays.asList(imageReader.getSurface()));
Kotlin
sharedCamera.">setAppSurfaces(this.cameraId, listOf(imageReader.surface))
Abrir a câmera
Abra a câmera usando um callback encapsulado pelo 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)
Usar o callback de estado do dispositivo da câmera
No callback de estado do dispositivo da câmera, armazene uma referência a ele. iniciar uma nova sessão de captura.
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()
}
Criar uma nova sessão de captura
Crie uma nova solicitação de captura. Usar TEMPLATE_RECORD
para garantir que a solicitação de captura seja compatível com o ARCore e permitir
alternando entre os modos RA e não RA no momento da execução.
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)
}
}
Iniciar no modo RA ou que não seja de RA
Para começar a capturar frames, chame captureSession.setRepeatingRequest()
.
do callback de estado onConfigured()
da sessão de captura da câmera.
Retome a sessão do ARCore no callback onActive()
para iniciar no modo 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)
}
Alterne facilmente entre os modos RA e não RA durante a execução
Para alternar do modo não RA para o modo RA e retomar uma sessão pausada do ARCore:
Java
// Resume the ARCore session.
resumeARCore();
Kotlin
// Resume the ARCore session.
resumeARCore()
Para mudar do modo RA para o modo não RA:
Java
// Pause ARCore.
sharedSession.pause();
// Create the Camera2 repeating capture request.
setRepeatingCaptureRequest();
Kotlin
// Pause ARCore.
sharedSession.pause()
// Create the Camera2 repeating capture request.
setRepeatingCaptureRequest()