Questa pagina illustra l'architettura di CameraX, compresa la sua struttura, come lavorare con l'API, come lavorare con i cicli di vita e come combinare i casi d'uso.
Struttura CameraX
Puoi utilizzare CameraX per interfacciarti con la fotocamera di un dispositivo tramite un un'astrazione chiamata caso d'uso. Sono disponibili i seguenti casi d'uso:
- Anteprima: accetta una piattaforma per la visualizzazione di un'anteprima, come una
PreviewView
. - Analisi delle immagini: fornisce buffer accessibili alla CPU per l'analisi, come e il machine learning.
- Acquisizione di immagini: acquisisce e salva una foto.
- Acquisizione video: acquisisci video e audio con
VideoCapture
I casi d'uso possono essere combinati e attivi contemporaneamente. Ad esempio, un'app può consentire l'utente vede l'immagine che la videocamera vede usando un caso d'uso di anteprima, ha un il caso d'uso dell'analisi delle immagini che determina se le persone nella foto siano che sorridono e includi un caso d'uso di acquisizione di immagini per scattare una foto quando lo sono.
Modello API
Per lavorare con la libreria, specifica quanto segue:
- Il caso d'uso desiderato con le opzioni di configurazione.
- Cosa fare con i dati di output collegando i listener.
- Il flusso previsto, ad esempio quando abilitare le videocamere e quando produrre i dati. associando il caso d'uso all'architettura Android Cicli di vita.
Esistono due modi per scrivere un'app CameraX:
CameraController
(ideale se
vuoi il modo più semplice per usare CameraX) o
CameraProvider
(ideale se
richiedono una maggiore flessibilità).
Controller videocamera
Un'CameraController
fornisce la maggior parte delle funzionalità di base di CameraX in una singola
. Richiede un piccolo codice di configurazione e gestisce automaticamente la videocamera
inizializzazione, gestione dei casi d'uso, rotazione target, tocco per mettere a fuoco
pizzica per eseguire lo zoom e altro ancora. La classe concreta che si estende CameraController
è
LifecycleCameraController
Kotlin
val previewView: PreviewView = viewBinding.previewView var cameraController = LifecycleCameraController(baseContext) cameraController.bindToLifecycle(this) cameraController.cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA previewView.controller = cameraController
Java
PreviewView previewView = viewBinding.previewView; LifecycleCameraController cameraController = new LifecycleCameraController(baseContext); cameraController.bindToLifecycle(this); cameraController.setCameraSelector(CameraSelector.DEFAULT_BACK_CAMERA); previewView.setController(cameraController);
I valori predefiniti di UseCase
per CameraController
sono Preview
, ImageCapture
e
ImageAnalysis
. Per disattivare ImageCapture
o ImageAnalysis
, oppure per attivare
VideoCapture
attivo, utilizza
setEnabledUseCases()
.
Per ulteriori utilizzi di CameraController
, consulta
Esempio di scanner di codici QR
o il
Video di base su CameraController
.
Fornitore fotocamera
L'CameraProvider
è comunque facile da usare, ma dato che lo sviluppatore dell'app gestisce
maggiore è la configurazione, ci sono più opportunità di
personalizzazione della configurazione,
come abilitare la rotazione dell'immagine di output o impostare il formato dell'immagine di output in
ImageAnalysis
. Puoi anche utilizzare un Surface
personalizzato per l'anteprima della fotocamera
per una maggiore flessibilità, mentre con CameraController devi usare un
PreviewView
. L'utilizzo del codice Surface
esistente potrebbe essere utile se
è già un input per altre parti della tua app.
Puoi configurare i casi d'uso utilizzando i metodi set()
e finalizzarli con l'build()
. Ogni oggetto caso d'uso fornisce un insieme di API specifiche per il caso d'uso. Per
Ad esempio, il caso d'uso relativo all'acquisizione di immagini fornisce una chiamata al metodo takePicture()
.
Invece di un'applicazione che inserisce chiamate a metodi specifici di avvio e arresto
onResume()
e onPause()
, l'applicazione specifica un ciclo di vita da associare
la fotocamera, usando
cameraProvider.bindToLifecycle()
Questo ciclo di vita informa quindi CameraX quando configurare la sessione di acquisizione della videocamera
e assicura che lo stato della videocamera cambi in modo appropriato per adattarsi alle transizioni del ciclo di vita.
Per la procedura di implementazione per ogni caso d'uso, consulta Implementare una anteprima, Analizza immagini, Immagine di acquisizione e Acquisizione video
Il caso d'uso dell'anteprima interagisce con un
Surface
per la visualizzazione. Applicazioni
crea il caso d'uso con le opzioni di configurazione utilizzando il seguente codice:
Kotlin
val preview = Preview.Builder().build() val viewFinder: PreviewView = findViewById(R.id.previewView) // The use case is bound to an Android Lifecycle with the following code val camera = cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview) // PreviewView creates a surface provider and is the recommended provider preview.setSurfaceProvider(viewFinder.getSurfaceProvider())
Java
Preview preview = new Preview.Builder().build(); PreviewView viewFinder = findViewById(R.id.view_finder); // The use case is bound to an Android Lifecycle with the following code Camera camera = cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview); // PreviewView creates a surface provider, using a Surface from a different // kind of view will require you to implement your own surface provider. preview.previewSurfaceProvider = viewFinder.getSurfaceProvider();
Per altri esempi di codice, guarda l'esempio ufficiale di CameraX Google Cloud.
Cicli di vita di CameraX
CameraX osserva un ciclo di vita per determinare quando aprire la videocamera e quando creare una sessione di acquisizione e quando fermarsi e arrestarsi. Le API dei casi d'uso offrono e i callback per monitorare l'avanzamento.
Come spiegato in Combinare i casi d'uso, puoi associare alcuni mix di a un singolo ciclo d'uso. Se la tua app deve supportare casi d'uso che non possono essere combinati, puoi eseguire una delle seguenti operazioni:
- Raggruppa i casi d'uso compatibili in più di uno fragment e poi passa da frammenti
- Crea un componente personalizzato del ciclo di vita e utilizzalo per controllare manualmente la videocamera ciclo di vita
Se disaccoppia i casi d'uso di visualizzazione e fotocamera Proprietari del ciclo di vita (ad esempio,
se utilizzi un ciclo di vita personalizzato o una conservazione
frammento), allora
deve garantire che tutti i casi d'uso non siano vincolati da CameraX utilizzando
ProcessCameraProvider.unbindAll()
:
o svincolando singolarmente ogni caso d'uso. In alternativa, quando vincoli a utilizzare
a un ciclo di vita, puoi lasciare che CameraX
gestire l'apertura e la chiusura della sessione di acquisizione e svincolare i casi d'uso.
Se tutte le funzionalità della videocamera corrispondono al ciclo di vita di un singolo
un componente sensibile al ciclo di vita, come
AppCompatActivity
o un
AppCompat
frammento, quindi utilizza il ciclo di vita del componente durante l'associazione
per tutti i casi d'uso desiderati si assicurerà che la funzionalità della fotocamera sia pronta
quando il componente sensibile al ciclo di vita è attivo e smaltito in modo sicuro,
consumare alcuna risorsa, altrimenti.
Proprietari ciclo di vita personalizzato
Per richieste avanzate, puoi creare un prompt
LifecycleOwner
per attivare
per controllare in modo esplicito il ciclo di vita della sessione CameraX anziché associarlo a un
Android LifecycleOwner
standard.
Il seguente esempio di codice mostra come creare un LifecycleOwner personalizzato semplice:
Kotlin
class CustomLifecycle : LifecycleOwner { private val lifecycleRegistry: LifecycleRegistry init { lifecycleRegistry = LifecycleRegistry(this); lifecycleRegistry.markState(Lifecycle.State.CREATED) } ... fun doOnResume() { lifecycleRegistry.markState(State.RESUMED) } ... override fun getLifecycle(): Lifecycle { return lifecycleRegistry } }
Java
public class CustomLifecycle implements LifecycleOwner { private LifecycleRegistry lifecycleRegistry; public CustomLifecycle() { lifecycleRegistry = new LifecycleRegistry(this); lifecycleRegistry.markState(Lifecycle.State.CREATED); } ... public void doOnResume() { lifecycleRegistry.markState(State.RESUMED); } ... public Lifecycle getLifecycle() { return lifecycleRegistry; } }
Con questo LifecycleOwner
, la tua app può posizionare le transizioni di stato come preferisci
nel suo codice. Per ulteriori informazioni sull'implementazione
di questa funzionalità nella tua app,
consulta Implementazione di un modello
LifecycleOwner.
Casi d'uso simultanei
I casi d'uso possono essere eseguiti contemporaneamente. Sebbene i casi d'uso possano essere associati in modo sequenziale
ciclo di vita, è meglio associare tutti i casi d'uso con un'unica chiamata
CameraProcessProvider.bindToLifecycle()
. Per ulteriori informazioni sulle
per le modifiche alla configurazione, consulta Gestire la configurazione
modifiche.
Nel seguente esempio di codice, l'app specifica i due casi d'uso da creare e vengono eseguiti contemporaneamente. Specifica anche il ciclo di vita da utilizzare in modo che si avviino e si arrestino in base al ciclo di vita.
Kotlin
private lateinit var imageCapture: ImageCapture override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val cameraProviderFuture = ProcessCameraProvider.getInstance(this) cameraProviderFuture.addListener(Runnable { // Camera provider is now guaranteed to be available val cameraProvider = cameraProviderFuture.get() // Set up the preview use case to display camera preview. val preview = Preview.Builder().build() // Set up the capture use case to allow users to take photos. imageCapture = ImageCapture.Builder() .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) .build() // Choose the camera by requiring a lens facing val cameraSelector = CameraSelector.Builder() .requireLensFacing(CameraSelector.LENS_FACING_FRONT) .build() // Attach use cases to the camera with the same lifecycle owner val camera = cameraProvider.bindToLifecycle( this as LifecycleOwner, cameraSelector, preview, imageCapture) // Connect the preview use case to the previewView preview.setSurfaceProvider( previewView.getSurfaceProvider()) }, ContextCompat.getMainExecutor(this)) }
Java
private ImageCapture imageCapture; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); PreviewView previewView = findViewById(R.id.previewView); ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(this); cameraProviderFuture.addListener(() -> { try { // Camera provider is now guaranteed to be available ProcessCameraProvider cameraProvider = cameraProviderFuture.get(); // Set up the view finder use case to display camera preview Preview preview = new Preview.Builder().build(); // Set up the capture use case to allow users to take photos imageCapture = new ImageCapture.Builder() .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) .build(); // Choose the camera by requiring a lens facing CameraSelector cameraSelector = new CameraSelector.Builder() .requireLensFacing(lensFacing) .build(); // Attach use cases to the camera with the same lifecycle owner Camera camera = cameraProvider.bindToLifecycle( ((LifecycleOwner) this), cameraSelector, preview, imageCapture); // Connect the preview use case to the previewView preview.setSurfaceProvider( previewView.getSurfaceProvider()); } catch (InterruptedException | ExecutionException e) { // Currently no exceptions thrown. cameraProviderFuture.get() // shouldn't block since the listener is being called, so no need to // handle InterruptedException. } }, ContextCompat.getMainExecutor(this)); }
È garantito che le seguenti combinazioni di configurazione siano supportate (quando L'anteprima o l'acquisizione video sono obbligatorie, ma non entrambe contemporaneamente:
Anteprima o Video Capture | Acquisizione di immagini | Analisi | Descrizioni |
---|---|---|---|
Fornisci all'utente un'anteprima o registra un video, scatta una foto e analizza lo stream di immagini. | |||
Scatta una foto e analizza lo stream di immagini. | |||
Fornisci all'utente un'anteprima o registra un video e scatta una foto. | |||
Fornisci all'utente un'anteprima o registra un video e analizza l'immagine flusso di dati. |
Quando sono necessarie sia l'anteprima che l'acquisizione del video, il seguente caso d'uso combinazioni sono supportate in modo condizionale:
Anteprima | Acquisizione video | Acquisizione di immagini | Analisi | Requisito speciale |
---|---|---|---|---|
Garantito per tutte le videocamere | ||||
Dispositivo con videocamera LIMITATA (o migliore). | ||||
Fotocamera LEVEL_3 (o migliore). |
Inoltre,
- Ogni caso d'uso può funzionare da solo. Ad esempio, un'app può registrare video senza utilizzare l'anteprima.
- Quando le estensioni sono attivate, solo
ImageCapture
ePreview
il funzionamento della combinazione. A seconda dell'implementazione dell'OEM, potrebbe non essere possibile aggiungere ancheImageAnalysis
; le estensioni non possono da abilitare per il caso d'usoVideoCapture
. Controlla il Documentazione di riferimento sulle estensioni per maggiori dettagli. - A seconda della funzionalità della videocamera, alcune videocamere potrebbero supportare la combinazione a a una risoluzione più bassa, ma non è possibile supportare la stessa combinazione risoluzioni più alte.
Il livello di hardware supportato
può essere recuperato da Camera2CameraInfo
. Ad esempio, il seguente codice
controlla se la fotocamera posteriore predefinita è un dispositivo LEVEL_3
:
Kotlin
@androidx.annotation.OptIn(ExperimentalCamera2Interop::class) fun isBackCameraLevel3Device(cameraProvider: ProcessCameraProvider) : Boolean { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { return CameraSelector.DEFAULT_BACK_CAMERA .filter(cameraProvider.availableCameraInfos) .firstOrNull() ?.let { Camera2CameraInfo.from(it) } ?.getCameraCharacteristic(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL) == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3 } return false }
Java
@androidx.annotation.OptIn(markerClass = ExperimentalCamera2Interop.class) Boolean isBackCameraLevel3Device(ProcessCameraProvider cameraProvider) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { List\<CameraInfo\> filteredCameraInfos = CameraSelector.DEFAULT_BACK_CAMERA .filter(cameraProvider.getAvailableCameraInfos()); if (!filteredCameraInfos.isEmpty()) { return Objects.equals( Camera2CameraInfo.from(filteredCameraInfos.get(0)).getCameraCharacteristic( CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL), CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3); } } return false; }
Autorizzazioni
L'app dovrà avere
Autorizzazione CAMERA
. A
salvare le immagini nei file, sarà inoltre necessario
WRITE_EXTERNAL_STORAGE
autorizzazione, tranne che sui dispositivi con Android 10 o versioni successive.
Per ulteriori informazioni sulla configurazione delle autorizzazioni per la tua app, leggi l'articolo Richiedere Autorizzazioni app.
Requisiti
CameraX ha i seguenti requisiti di versione minimi:
- Livello API Android 21
- Componenti dell'architettura Android 1.1.1
Per le attività che tengono conto del ciclo di vita, utilizza
FragmentActivity
oppure
AppCompatActivity
.
Dichiara le dipendenze
Per aggiungere una dipendenza su CameraX, devi aggiungere il ruolo Google Maven repository al tuo progetto.
Apri il file settings.gradle
del tuo progetto e aggiungi il repository google()
come illustrato di seguito:
Alla moda
dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() } }
Kotlin
dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() } }
Aggiungi il seguente codice alla fine del blocco Android:
Alla moda
android { compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } // For Kotlin projects kotlinOptions { jvmTarget = "1.8" } }
Kotlin
android { compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } // For Kotlin projects kotlinOptions { jvmTarget = "1.8" } }
Aggiungi quanto segue al file build.gradle
di ogni modulo per un'app:
trendy
dependencies { // CameraX core library using the camera2 implementation def camerax_version = "1.4.0-rc01" // The following line is optional, as the core library is included indirectly by camera-camera2 implementation "androidx.camera:camera-core:${camerax_version}" implementation "androidx.camera:camera-camera2:${camerax_version}" // If you want to additionally use the CameraX Lifecycle library implementation "androidx.camera:camera-lifecycle:${camerax_version}" // If you want to additionally use the CameraX VideoCapture library implementation "androidx.camera:camera-video:${camerax_version}" // If you want to additionally use the CameraX View class implementation "androidx.camera:camera-view:${camerax_version}" // If you want to additionally add CameraX ML Kit Vision Integration implementation "androidx.camera:camera-mlkit-vision:${camerax_version}" // If you want to additionally use the CameraX Extensions library implementation "androidx.camera:camera-extensions:${camerax_version}" }
Kotlin
dependencies { // CameraX core library using the camera2 implementation val camerax_version = "1.4.0-rc01" // The following line is optional, as the core library is included indirectly by camera-camera2 implementation("androidx.camera:camera-core:${camerax_version}") implementation("androidx.camera:camera-camera2:${camerax_version}") // If you want to additionally use the CameraX Lifecycle library implementation("androidx.camera:camera-lifecycle:${camerax_version}") // If you want to additionally use the CameraX VideoCapture library implementation("androidx.camera:camera-video:${camerax_version}") // If you want to additionally use the CameraX View class implementation("androidx.camera:camera-view:${camerax_version}") // If you want to additionally add CameraX ML Kit Vision Integration implementation("androidx.camera:camera-mlkit-vision:${camerax_version}") // If you want to additionally use the CameraX Extensions library implementation("androidx.camera:camera-extensions:${camerax_version}") }
Per ulteriori informazioni su come configurare la tua app in modo che sia conforme a questi requisiti, consulta la sezione Dichiarazione delle dipendenze.
Interoperabilità di CameraX con Camera2
CameraX è basata su Camera2 e offre modalità di lettura e scrittura nell'implementazione di Camera2. Per i dettagli completi, consulta Pacchetto Interop.
Per ulteriori informazioni su come CameraX ha configurato le proprietà Camera2, utilizza
Camera2CameraInfo
per leggere l'elemento CameraCharacteristics
sottostante. Puoi anche scegliere di scrivere il testo della fotocamera sottostante
in uno dei seguenti due percorsi:
Usa
Camera2CameraControl
, che ti consente di impostare le proprietà sull'elementoCaptureRequest
, come la modalità di messa a fuoco automatica.Estendi una FotocameraX
UseCase
con unCamera2Interop.Extender
. Ciò ti consente di impostare le proprietà su CaptureRequest, proprio comeCamera2CameraControl
Ti offre anche alcuni controlli aggiuntivi, come l'impostazione del caso d'uso dello stream su per ottimizzare la videocamera in base al tuo scenario di utilizzo. Per informazioni, vedi Utilizzare i casi d'uso di Stream per migliorare del rendimento.
Il seguente esempio di codice utilizza casi d'uso di streaming per ottimizzare per una videochiamata.
Utilizza Camera2CameraInfo
per recuperare se è disponibile il caso d'uso dello stream di videochiamate. Quindi, utilizza un
Camera2Interop.Extender
per impostare il caso d'uso del flusso sottostante.
Kotlin
// Set underlying Camera2 stream use case to optimize for video calls. val videoCallStreamId = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL.toLong() // Check available CameraInfos to find the first one that supports // the video call stream use case. val frontCameraInfo = cameraProvider.getAvailableCameraInfos() .first { cameraInfo -> val isVideoCallStreamingSupported = Camera2CameraInfo.from(cameraInfo) .getCameraCharacteristic( CameraCharacteristics.SCALER_AVAILABLE_STREAM_USE_CASES )?.contains(videoCallStreamId) val isFrontFacing = (cameraInfo.getLensFacing() == CameraSelector.LENS_FACING_FRONT) (isVideoCallStreamingSupported == true) && isFrontFacing } val cameraSelector = frontCameraInfo.cameraSelector // Start with a Preview Builder. val previewBuilder = Preview.Builder() .setTargetAspectRatio(screenAspectRatio) .setTargetRotation(rotation) // Use Camera2Interop.Extender to set the video call stream use case. Camera2Interop.Extender(previewBuilder).setStreamUseCase(videoCallStreamId) // Bind the Preview UseCase and the corresponding CameraSelector. val preview = previewBuilder.build() camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview)
Java
// Set underlying Camera2 stream use case to optimize for video calls. Long videoCallStreamId = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL.toLong(); // Check available CameraInfos to find the first one that supports // the video call stream use case. List<CameraInfo> cameraInfos = cameraProvider.getAvailableCameraInfos(); CameraInfo frontCameraInfo = null; for (cameraInfo in cameraInfos) { Long[] availableStreamUseCases = Camera2CameraInfo.from(cameraInfo) .getCameraCharacteristic( CameraCharacteristics.SCALER_AVAILABLE_STREAM_USE_CASES ); boolean isVideoCallStreamingSupported = Arrays.List(availableStreamUseCases) .contains(videoCallStreamId); boolean isFrontFacing = (cameraInfo.getLensFacing() == CameraSelector.LENS_FACING_FRONT); if (isVideoCallStreamingSupported && isFrontFacing) { frontCameraInfo = cameraInfo; } } if (frontCameraInfo == null) { // Handle case where video call streaming is not supported. } CameraSelector cameraSelector = frontCameraInfo.getCameraSelector(); // Start with a Preview Builder. Preview.Builder previewBuilder = Preview.Builder() .setTargetAspectRatio(screenAspectRatio) .setTargetRotation(rotation); // Use Camera2Interop.Extender to set the video call stream use case. Camera2Interop.Extender(previewBuilder).setStreamUseCase(videoCallStreamId); // Bind the Preview UseCase and the corresponding CameraSelector. Preview preview = previewBuilder.build() Camera camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview)
Risorse aggiuntive
Per saperne di più su CameraX, consulta le risorse aggiuntive che seguono.
Codelab
Esempio di codice