In genere, un sistema di acquisizione registra stream video e audio, li comprime, esegue il Mux dei due flussi e scrive il flusso risultante su disco.
In CameraX, la soluzione per l'acquisizione video è il caso d'uso di VideoCapture
:
Come mostrato nella Figura 2, l'acquisizione video di CameraX include alcuni componenti architettonici di alto livello:
SurfaceProvider
per l'origine video.AudioSource
per la sorgente audio.- Due codificatori per codificare e comprimere i contenuti video/audio.
- Un media muxer per eseguire il mux dei due stream.
- Un salvaschermo per scrivere il risultato.
L'API Video Capture astrae il complesso motore di acquisizione e fornisce alle applicazioni un'API molto più semplice e diretta.
Panoramica dell'API Video Capture
VideoCapture
è un caso d'uso di CameraX che funziona bene da solo o in combinazione con altri casi d'uso. Combinazioni specifiche supportate dipendono dalle funzionalità dell'hardware della fotocamera, ma Preview
e VideoCapture
sono una combinazione di casi d'uso valida su tutti i dispositivi.
L'API Video Capture è composta dai seguenti oggetti che comunicano con le applicazioni:
VideoCapture
è la classe dei casi d'uso di primo livello.VideoCapture
si associa a unLifecycleOwner
con unCameraSelector
e altri casi d'uso di CameraX. Per ulteriori informazioni su questi concetti e utilizzi, consulta Architettura di CameraX.- Un elemento
Recorder
è un'implementazione di VideoOutput strettamente accoppiata aVideoCapture
.Recorder
viene utilizzato per acquisire video e audio. Un'applicazione crea registrazioni da unRecorder
. - Un elemento
PendingRecording
configura una registrazione e offre opzioni come l'attivazione dell'audio e l'impostazione di un listener di eventi. Devi utilizzare unRecorder
per creare unPendingRecording
. UnPendingRecording
non registra nulla. - Un
Recording
esegue la registrazione effettiva. Devi utilizzare unPendingRecording
per creare unRecording
.
La Figura 3 mostra le relazioni tra questi oggetti:
Legenda:
- Crea una
Recorder
conQualitySelector
. - Configura
Recorder
con uno degliOutputOptions
. - Abilita l'audio con
withAudioEnabled()
, se necessario. - Chiama
start()
con un ascoltatoreVideoRecordEvent
per iniziare a registrare. - Usa
pause()
/resume()
/stop()
sullaRecording
per controllare la registrazione. - Rispondi a
VideoRecordEvents
all'interno del listener di eventi.
L'elenco dettagliato delle API si trova nel file current.txt all'interno del codice sorgente.
Utilizzo dell'API Video Capture
Per integrare il caso d'uso VideoCapture
di CameraX nella tua app,
procedi nel seguente modo:
- Associa
VideoCapture
. - Preparare e configurare la registrazione.
- Avvia e controlla la registrazione di runtime.
Le seguenti sezioni descrivono cosa puoi fare in ogni passaggio per avviare una sessione di registrazione end-to-end.
Associa acquisizione video
Per associare il caso d'uso VideoCapure
:
- Crea un oggetto
Recorder
. - Crea l'oggetto
VideoCapture
. - Associa a
Lifecycle
.
L'API CameraX Video Capture segue il pattern di progettazione dello strumento per la creazione. Le applicazioni
utilizzano Recorder.Builder
per creare un Recorder
. Puoi anche configurare la risoluzione video per Recorder
tramite un oggetto QualitySelector
.
CameraX Recorder
supporta le seguenti risoluzioni video Qualities
predefinite:
Quality.UHD
per dimensioni video ultra HD 4K (2160p)Quality.FHD
per dimensioni video Full HD (1080p)Quality.HD
per dimensioni video HD (720p)Quality.SD
per dimensioni video SD (480p)
Tieni presente che CameraX può scegliere anche altre risoluzioni se autorizzato dall'app.
Le dimensioni esatte del video di ogni selezione dipendono dalle capacità della videocamera e del codificatore. Per ulteriori informazioni, consulta la documentazione relativa a CamcorderProfile
.
Le applicazioni possono configurare la risoluzione creando un
QualitySelector
.
Puoi creare un QualitySelector
utilizzando uno dei seguenti metodi:
Fornisci alcune delle risoluzioni preferite utilizzando
fromOrderedList()
e includi una strategia di riserva da utilizzare nel caso in cui nessuna delle risoluzioni preferite sia supportata.CameraX può decidere la corrispondenza di riserva migliore in base alle funzionalità della videocamera selezionata. Per ulteriori dettagli, consulta
FallbackStrategy specification
diQualitySelector
. Ad esempio, il codice seguente richiede la risoluzione massima supportata per la registrazione e, se nessuna delle risoluzioni può essere supportata, autorizza CameraX a scegliere quella più vicina alla risoluzione Quality.SD:val qualitySelector = QualitySelector.fromOrderedList( listOf(Quality.UHD, Quality.FHD, Quality.HD, Quality.SD), FallbackStrategy.lowerQualityOrHigherThan(Quality.SD))
Prima esegui una query sulle funzionalità della fotocamera e scegli tra le risoluzioni supportate utilizzando
QualitySelector::from()
:val cameraInfo = cameraProvider.availableCameraInfos.filter { Camera2CameraInfo .from(it) .getCameraCharacteristic(CameraCharacteristics.LENS\_FACING) == CameraMetadata.LENS_FACING_BACK } val supportedQualities = QualitySelector.getSupportedQualities(cameraInfo[0]) val filteredQualities = arrayListOf (Quality.UHD, Quality.FHD, Quality.HD, Quality.SD) .filter { supportedQualities.contains(it) } // Use a simple ListView with the id of simple_quality_list_view viewBinding.simpleQualityListView.apply { adapter = ArrayAdapter(context, android.R.layout.simple_list_item_1, filteredQualities.map { it.qualityToString() }) // Set up the user interaction to manually show or hide the system UI. setOnItemClickListener { _, _, position, _ -> // Inside View.OnClickListener, // convert Quality.* constant to QualitySelector val qualitySelector = QualitySelector.from(filteredQualities[position]) // Create a new Recorder/VideoCapture for the new quality // and bind to lifecycle val recorder = Recorder.Builder() .setQualitySelector(qualitySelector).build() // ... } } // A helper function to translate Quality to a string fun Quality.qualityToString() : String { return when (this) { Quality.UHD -> "UHD" Quality.FHD -> "FHD" Quality.HD -> "HD" Quality.SD -> "SD" else -> throw IllegalArgumentException() } }
Tieni presente che la funzionalità restituita da
QualitySelector.getSupportedQualities()
è garantita per il funzionamento sia per il caso d'usoVideoCapture
o per la combinazione di casi d'usoVideoCapture
ePreview
. Quando si esegue l'associazione insieme al caso d'usoImageCapture
oImageAnalysis
, CameraX potrebbe comunque non riuscire a eseguire l'associazione quando la combinazione richiesta non è supportata sulla videocamera richiesta.
Una volta che hai un QualitySelector
, l'applicazione può creare un
oggetto VideoCapture
ed eseguire l'associazione. Tieni presente che questa associazione è
uguale agli altri casi d'uso:
val recorder = Recorder.Builder()
.setExecutor(cameraExecutor).setQualitySelector(qualitySelector)
.build()
val videoCapture = VideoCapture.withOutput(recorder)
try {
// Bind use cases to camera
cameraProvider.bindToLifecycle(
this, CameraSelector.DEFAULT_BACK_CAMERA, preview, videoCapture)
} catch(exc: Exception) {
Log.e(TAG, "Use case binding failed", exc)
}
Tieni presente che bindToLifecycle()
restituisce un oggetto Camera
. Consulta questa guida per ulteriori informazioni su come controllare l'output della fotocamera, come lo zoom e l'esposizione.
L'Recorder
seleziona il formato più adatto per il sistema. Il codec video più comune è H.264 AVC) con formato container MPEG-4.
Configura e crea registrazione
Da un Recorder
, l'applicazione può creare oggetti registrazione per eseguire l'acquisizione video e audio. Le applicazioni creano registrazioni procedendo nel seguente modo:
- Configura
OutputOptions
conprepareRecording()
. - (Facoltativo) Attiva la registrazione audio.
- Usa
start()
per registrare un ascoltatoreVideoRecordEvent
e iniziare l'acquisizione video.
Recorder
restituisce un oggetto Recording
quando chiami la funzione start()
.
L'applicazione può utilizzare questo oggetto Recording
per completare l'acquisizione o eseguire altre azioni, ad esempio mettere in pausa o riprendere.
Recorder
supporta un oggetto Recording
alla volta. Puoi avviare una
nuova registrazione dopo aver chiamato Recording.stop()
o
Recording.close()
sull'oggetto Recording
precedente.
Esaminiamo questi passaggi in modo più dettagliato. Innanzitutto, l'applicazione configura
OutputOptions
per un Registratore con Recorder.prepareRecording()
.
Un Recorder
supporta i seguenti tipi di OutputOptions
:
FileDescriptorOutputOptions
per acquisire immagini in unaFileDescriptor
.FileOutputOptions
per acquisire immagini in unaFile
.MediaStoreOutputOptions
per acquisire immagini in unaMediaStore
.
Tutti i tipi di OutputOptions
consentono di impostare una dimensione massima dei file con
setFileSizeLimit()
. Altre opzioni sono specifiche per il singolo
tipo di output, ad esempio ParcelFileDescriptor
per FileDescriptorOutputOptions
.
prepareRecording()
restituisce un oggetto PendingRecording
, ovvero un oggetto intermedio utilizzato per creare l'oggetto Recording
corrispondente. PendingRecording
è una classe temporanea che dovrebbe essere invisibile nella maggior parte dei casi e che raramente viene memorizzata nella cache dall'app.
Le applicazioni possono configurare ulteriormente la registrazione, ad esempio:
- Attiva l'audio con
withAudioEnabled()
. - Registra un listener per ricevere eventi di registrazione video
con
start(Executor, Consumer<VideoRecordEvent>)
. - Consenti a una registrazione di registrare in modo continuo mentre la funzionalità Video Capture a cui è collegata
viene riportata a un'altra fotocamera, con
PendingRecording.asPersistentRecording()
.
Per avviare la registrazione, chiama il numero PendingRecording.start()
. CameraX trasforma PendingRecording
in Recording
, mette in coda la richiesta di registrazione e restituisce all'applicazione l'oggetto Recording
appena creato.
Una volta avviata la registrazione sulla videocamera corrispondente, CameraX invia un
evento VideoRecordEvent.EVENT_TYPE_START
.
L'esempio seguente mostra come registrare video e audio in un file MediaStore
:
// Create MediaStoreOutputOptions for our recorder
val name = "CameraX-recording-" +
SimpleDateFormat(FILENAME_FORMAT, Locale.US)
.format(System.currentTimeMillis()) + ".mp4"
val contentValues = ContentValues().apply {
put(MediaStore.Video.Media.DISPLAY_NAME, name)
}
val mediaStoreOutput = MediaStoreOutputOptions.Builder(this.contentResolver,
MediaStore.Video.Media.EXTERNAL_CONTENT_URI)
.setContentValues(contentValues)
.build()
// 2. Configure Recorder and Start recording to the mediaStoreOutput.
val recording = videoCapture.output
.prepareRecording(context, mediaStoreOutput)
.withAudioEnabled()
.start(ContextCompat.getMainExecutor(this), captureListener)
Per impostazione predefinita, l'anteprima della fotocamera è visibile sulla fotocamera anteriore, mentre i video registrati da Video Capture non vengono sottoposti a mirroring per impostazione predefinita. Con CameraX 1.3 è ora possibile eseguire il mirroring delle registrazioni video in modo che l'anteprima della fotocamera anteriore e il video registrato corrispondano.
Sono disponibili tre opzioni MirrorMode: MIRROR_MODE_OFF, MIRROR_MODE_ON e
MIRROR_MODE_ON_FRONT_only. Per allinearsi all'anteprima della fotocamera, Google consiglia di utilizzare MIROR_MODE_ON_FRONT_ ONLY, il che significa che la mirroring non è abilitata per la fotocamera posteriore, ma è abilitata per la fotocamera anteriore. Per saperne di più su MirrorMode, consulta
MirrorMode constants
.
Questo snippet di codice mostra come chiamare
VideoCapture.Builder.setMirrorMode()
utilizzando MIRROR_MODE_ON_FRONT_ONLY
. Per
ulteriori informazioni, visita la pagina setMirrorMode()
.
Kotlin
val recorder = Recorder.Builder().build() val videoCapture = VideoCapture.Builder(recorder) .setMirrorMode(MIRROR_MODE_ON_FRONT_ONLY) .build() useCases.add(videoCapture);
Java
Recorder.Builder builder = new Recorder.Builder(); if (mVideoQuality != QUALITY_AUTO) { builder.setQualitySelector( QualitySelector.from(mVideoQuality)); } VideoCapture<Recorder> videoCapture = new VideoCapture.Builder<>(builder.build()) .setMirrorMode(MIRROR_MODE_ON_FRONT_ONLY) .build(); useCases.add(videoCapture);
Controllare una registrazione attiva
Puoi mettere in pausa, riprendere e interrompere un Recording
in corso utilizzando i seguenti metodi:
pause
per mettere in pausa la registrazione attiva in quel momento.resume()
per riprendere una registrazione attiva in pausa.stop()
per terminare la registrazione e svuotare gli eventuali oggetti registrati associati.mute()
per disattivare o riattivare l'audio della registrazione corrente.
Tieni presente che puoi chiamare stop()
per terminare Recording
indipendentemente dal fatto che la registrazione sia in pausa o attiva.
Se hai registrato un EventListener
con
PendingRecording.start()
, il Recording
comunica
utilizzando un
VideoRecordEvent
.
VideoRecordEvent.EVENT_TYPE_STATUS
viene utilizzato per registrare statistiche come la dimensione attuale del file e l'intervallo di tempo registrato.VideoRecordEvent.EVENT_TYPE_FINALIZE
viene utilizzato per il risultato della registrazione e include informazioni quali l'URI del file finale ed eventuali errori correlati.
Quando l'app riceve un EVENT_TYPE_FINALIZE
che indica una sessione di registrazione riuscita, puoi accedere al video acquisito dalla posizione specificata in OutputOptions
.
Risorse aggiuntive
Per scoprire di più su CameraX, consulta le seguenti risorse aggiuntive:
- Guida introduttiva al codelab su CameraX
- Esempio di app ufficiale CameraX
- Elenco più recente delle API di acquisizione video di CameraX
- Note di rilascio di CameraX
- Codice sorgente di CameraX