Un sistema di acquisizione in genere registra flussi video e audio, li comprime, li multiplexa e quindi scrive il flusso risultante sul disco.
In CameraX, la soluzione per l'acquisizione video è il
caso d'uso VideoCapture:
VideoCapture.Come mostrato nella figura 2, l'acquisizione video di CameraX include alcuni componenti architetturali di alto livello:
SurfaceProviderper la sorgente video.AudioSourceper la sorgente audio.- Due codificatori per codificare e comprimere video/audio.
- Un muxer multimediale per muxare i due stream.
- Un salvataggio di file per scrivere il risultato.
L'API VideoCapture astrae il complesso motore di acquisizione e fornisce alle applicazioni un'API molto più semplice e diretta.
Panoramica dell'API VideoCapture
VideoCapture è un caso d'uso di CameraX che funziona bene da solo o se
combinato con altri casi d'uso. Le combinazioni specifiche supportate dipendono dalle
funzionalità hardware della videocamera, ma Preview e VideoCapture sono una
combinazione di casi d'uso valida su tutti i dispositivi.
L'API VideoCapture è costituita dai seguenti oggetti che comunicano con le applicazioni:
VideoCaptureè la classe di casi d'uso di primo livello.VideoCapturesi associa a unLifecycleOwnercon unCameraSelectore altri UseCases di CameraX. Per ulteriori informazioni su questi concetti e utilizzi, vedi Architettura di CameraX.- Un
Recorderè un'implementazione di VideoOutput strettamente accoppiata aVideoCapture.Recorderviene utilizzato per eseguire l'acquisizione di video e audio. Un'applicazione crea registrazioni da unRecorder. - Una
PendingRecordingconfigura una registrazione, fornendo opzioni come l'attivazione dell'audio e l'impostazione di un listener di eventi. Per creare unPendingRecording, devi utilizzare unRecorder. UnPendingRecordingnon registra nulla. - Un
Recordingesegue la registrazione effettiva. Per creare unRecording, devi utilizzare unPendingRecording.
La Figura 3 mostra le relazioni tra questi oggetti:
Legenda:
- Crea un
RecorderconQualitySelector. - Configura
Recordercon uno deiOutputOptions. - Se necessario, attiva l'audio con
withAudioEnabled(). - Chiama
start()con unVideoRecordEventascoltatore per iniziare la registrazione. - Utilizza
pause()/resume()/stop()sulRecordingper controllare la registrazione. - Rispondi a
VideoRecordEventsall'interno del listener di eventi.
L'elenco dettagliato delle API è disponibile nel file current.txt all'interno del codice sorgente.
Utilizzo dell'API VideoCapture
Per integrare lo scenario d'uso VideoCapture di CameraX nella tua app,
fai quanto segue:
- Associa
VideoCapture. - Prepara e configura la registrazione.
- Avvia e controlla la registrazione della durata.
Le sezioni seguenti descrivono cosa puoi fare in ogni passaggio per ottenere una sessione di registrazione end-to-end.
Bind VideoCapture
Per associare lo scenario d'uso VideoCapture:
- Crea un oggetto
Recorder. - Crea l'oggetto
VideoCapture. - Associa a un
Lifecycle.
L'API CameraX VideoCapture segue il pattern di progettazione del builder. 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 Qualities predefinite
per le risoluzioni video:
Quality.UHDper le dimensioni dei video 4K Ultra HD (2160p)Quality.FHDper le dimensioni video Full HD (1080p)Quality.HDper le dimensioni dei video HD (720p)Quality.SDper le dimensioni dei video SD (480p)
Tieni presente che CameraX può anche scegliere altre risoluzioni quando autorizzato dall'app.
Le dimensioni esatte del video di ogni selezione dipendono dalle funzionalità della videocamera e del codificatore. Per saperne di più, 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 risoluzioni preferite utilizzando
fromOrderedList()e includi una strategia di fallback da utilizzare nel caso in cui nessuna delle risoluzioni preferite sia supportata.CameraX può decidere la migliore corrispondenza di riserva in base alla funzionalità della videocamera selezionata. Per maggiori dettagli, consulta
QualitySelector'sFallbackStrategy specification. Ad esempio, il seguente codice richiede la risoluzione più alta supportata per la registrazione e, se nessuna delle risoluzioni richieste 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))Esegui prima una query sulle funzionalità della videocamera 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()funziona sicuramente per il caso d'usoVideoCaptureo per la combinazione dei casi d'usoVideoCaptureePreview. Quando viene eseguito il binding insieme al caso d'usoImageCaptureoImageAnalysis, CameraX potrebbe comunque non riuscire a eseguire il binding quando la combinazione richiesta non è supportata dalla fotocamera richiesta.
Una volta ottenuto un QualitySelector, l'applicazione può creare un oggetto VideoCapture ed eseguire il binding. Tieni presente che questo binding è
lo stesso degli 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. Per ulteriori informazioni sul controllo dell'output della videocamera, ad esempio zoom ed esposizione, consulta questa guida.
Recorder seleziona il formato più adatto al sistema. Il codec video più comune è H.264 AVC con formato contenitore MPEG-4.
Configurare e creare una registrazione
Da un Recorder, l'applicazione può creare oggetti di registrazione per
eseguire l'acquisizione di video e audio. Le applicazioni creano registrazioni eseguendo
le seguenti operazioni:
- Configura
OutputOptionsconprepareRecording(). - (Facoltativo) Attiva la registrazione audio.
- Utilizza
start()per registrare unVideoRecordEventascoltatore e avvia l'acquisizione video.
Recorder restituisce un oggetto Recording quando chiami la funzione start().
La tua applicazione può utilizzare questo oggetto Recording per terminare
l'acquisizione o per eseguire altre azioni, come la sospensione o la ripresa.
Un Recorder supporta un solo oggetto Recording alla volta. Puoi iniziare una
nuova registrazione dopo aver chiamato Recording.stop() o
Recording.close() sull'oggetto Recording precedente.
Esaminiamo questi passaggi più nel dettaglio. Innanzitutto, l'applicazione configura
OutputOptions per un registratore con Recorder.prepareRecording().
Un Recorder supporta i seguenti tipi di OutputOptions:
FileDescriptorOutputOptionsper l'acquisizione in unFileDescriptor.FileOutputOptionsper l'acquisizione in unFile.MediaStoreOutputOptionsper l'acquisizione in unMediaStore.
Tutti i tipi OutputOptions consentono di impostare una dimensione massima del file con
setFileSizeLimit(). Altre opzioni sono specifiche per il singolo tipo di output, ad esempio ParcelFileDescriptor per FileDescriptorOutputOptions.
prepareRecording() restituisce un oggetto PendingRecording, che è un oggetto intermedio utilizzato per creare l'oggetto Recording corrispondente. PendingRecording è una classe temporanea che dovrebbe
essere invisibile nella maggior parte dei casi e 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 continuamente mentre VideoCapture a cui è collegata viene riassegnato a un'altra videocamera, con
PendingRecording.asPersistentRecording().
Per avviare la registrazione, chiama il numero PendingRecording.start(). CameraX trasforma
PendingRecording in un Recording, mette in coda la richiesta di registrazione
e restituisce all'applicazione l'oggetto Recording appena creato.
Una volta avviata la registrazione sul dispositivo 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)
Mentre l'anteprima della videocamera viene sottoposta a mirroring sulla videocamera anteriore per impostazione predefinita, i video registrati da VideoCapture 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.
Esistono tre opzioni per 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 il mirroring non è abilitato per la fotocamera posteriore, ma è abilitato per quella anteriore. Per saperne di più su MirrorMode, vedi
MirrorMode constants.
Questo snippet di codice mostra come chiamare
VideoCapture.Builder.setMirrorMode() utilizzando MIRROR_MODE_ON_FRONT_ONLY. Per
maggiori informazioni, vedi 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:
pauseper mettere in pausa la registrazione attiva corrente.resume()per riprendere una registrazione attiva in pausa.stop()per terminare la registrazione ed eliminare gli eventuali oggetti di registrazione associati.mute()per disattivare o riattivare l'audio della registrazione corrente.
Tieni presente che puoi chiamare il numero stop() per terminare una Recording indipendentemente
dal fatto che la registrazione sia in stato di pausa o attiva.
Se hai registrato un EventListener con
PendingRecording.start(), il Recording comunica
utilizzando un
VideoRecordEvent.
VideoRecordEvent.EVENT_TYPE_STATUSviene utilizzato per registrare statistiche come le dimensioni attuali del file e l'intervallo di tempo registrato.VideoRecordEvent.EVENT_TYPE_FINALIZEviene utilizzato per il risultato della registrazione e include informazioni quali l'URI del file finale insieme a eventuali errori correlati.
Una volta che 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 saperne di più su CameraX, consulta le seguenti risorse aggiuntive:
- Codelab Guida introduttiva a CameraX
- App di esempio CameraX ufficiale
- Elenco delle API CameraX Video Capture più recenti
- Note di rilascio di CameraX
- Codice sorgente di CameraX