Ein Aufzeichnungssystem zeichnet in der Regel Video- und Audiostreams auf, komprimiert sie, führt die beiden Streams zusammen und schreibt den resultierenden Stream dann auf die Festplatte.
In CameraX ist der VideoCapture-Anwendungsfall die Lösung für die Videoaufnahme:
VideoCapture verarbeitet.Wie in Abbildung 2 dargestellt, umfasst die CameraX-Videoaufnahme einige Architekturkomponenten auf hoher Ebene:
SurfaceProviderfür die Videoquelle.AudioSourcefür die Audioquelle.- Zwei Encoder zum Codieren und Komprimieren von Video- und Audiodaten.
- Ein Media-Muxer zum Muxen der beiden Streams.
- Ein File Saver zum Schreiben des Ergebnisses.
Die VideoCapture API abstrahiert die komplexe Erfassungs-Engine und bietet Anwendungen eine viel einfachere und unkompliziertere API.
VideoCapture API – Übersicht
VideoCapture ist ein CameraX-Anwendungsfall, der gut allein oder in Kombination mit anderen Anwendungsfällen funktioniert. Welche Kombinationen unterstützt werden, hängt von den Hardwarefunktionen der Kamera ab. Preview und VideoCapture ist jedoch auf allen Geräten eine gültige Kombination.
Die VideoCapture API besteht aus den folgenden Objekten, die mit Anwendungen kommunizieren:
VideoCaptureist die Anwendungsfallklasse der obersten Ebene.VideoCapturewird an einLifecycleOwnermit einemCameraSelectorund anderen CameraX-Use-Cases gebunden. Weitere Informationen zu diesen Konzepten und Verwendungen finden Sie unter CameraX-Architektur.- Ein
Recorderist eine Implementierung von VideoOutput, die eng mitVideoCapturegekoppelt ist.Recorderwird zum Erfassen von Video- und Audiodaten verwendet. Eine Anwendung erstellt Aufnahmen aus einemRecorder. - Mit
PendingRecordingwird eine Aufzeichnung konfiguriert. Dabei können Optionen wie das Aktivieren von Audio und das Festlegen eines Event-Listeners angegeben werden. Sie müssen einRecorderverwenden, um einPendingRecordingzu erstellen. EinePendingRecordingnimmt nichts auf. - Die eigentliche Aufnahme erfolgt über eine
Recording. Sie müssen einPendingRecordingverwenden, um einRecordingzu erstellen.
Abbildung 3 zeigt die Beziehungen zwischen diesen Objekten:
Legende:
- Erstellen Sie einen
RecordermitQualitySelector. - Konfigurieren Sie das
Recordermit einem derOutputOptions. - Aktivieren Sie bei Bedarf die Audioausgabe mit
withAudioEnabled(). - Rufen Sie
start()mit einemVideoRecordEvent-Listener auf, um die Aufnahme zu starten. - Verwende
pause()/resume()/stop()auf derRecording, um die Aufnahme zu steuern. - Reagieren Sie in Ihrem Event-Listener auf
VideoRecordEvents.
Die detaillierte API-Liste finden Sie in der Datei current.txt im Quellcode.
VideoCapture API verwenden
So binden Sie den CameraX-Anwendungsfall VideoCapture in Ihre App ein:
- Bind
VideoCapture. - Aufzeichnung vorbereiten und konfigurieren
- Laufzeitaufzeichnung starten und steuern
In den folgenden Abschnitten wird beschrieben, was Sie in den einzelnen Schritten tun können, um eine End-to-End-Aufzeichnungssitzung zu erhalten.
VideoCapture binden
So binden Sie den VideoCapture-Anwendungsfall:
- Erstellen Sie ein
Recorder-Objekt. - Erstellen Sie ein
VideoCapture-Objekt. - Mit einer
Lifecycleverknüpfen
Die CameraX VideoCapture API folgt dem Builder-Entwurfsmuster. Anwendungen verwenden Recorder.Builder, um ein Recorder zu erstellen. Sie können die Videoauflösung für die Recorder auch über ein QualitySelector-Objekt konfigurieren.
CameraX Recorder unterstützt die folgenden vordefinierten Qualities für Videoauflösungen:
Quality.UHDfür 4K-Ultra-HD-Videogröße (2160p)Quality.FHDfür Full-HD-Videogröße (1080p)Quality.HDfür HD-Videogröße (720p)Quality.SDfür SD-Videogröße (480p)
Beachten Sie, dass CameraX auch andere Auflösungen auswählen kann, wenn die App dazu autorisiert ist.
Die genaue Videogröße jeder Auswahl hängt von den Funktionen der Kamera und des Encoders ab. Weitere Informationen finden Sie in der Dokumentation zu CamcorderProfile.
Anwendungen können die Auflösung konfigurieren, indem sie ein QualitySelector erstellen.
Sie können ein QualitySelector mit einer der folgenden Methoden erstellen:
Geben Sie einige bevorzugte Auflösungen mit
fromOrderedList()an und fügen Sie eine Fallback-Strategie hinzu, die verwendet werden soll, wenn keine der bevorzugten Auflösungen unterstützt wird.CameraX kann den besten Fallback-Abgleich basierend auf den Funktionen der ausgewählten Kamera bestimmen. Weitere Informationen finden Sie in der
FallbackStrategy specificationvonQualitySelector. Mit dem folgenden Code wird beispielsweise die höchstmögliche Auflösung für die Aufnahme angefordert. Wenn keine der angeforderten Auflösungen unterstützt werden kann, wird CameraX autorisiert, eine Auflösung auszuwählen, die der Auflösung „Quality.SD“ am nächsten kommt:val qualitySelector = QualitySelector.fromOrderedList( listOf(Quality.UHD, Quality.FHD, Quality.HD, Quality.SD), FallbackStrategy.lowerQualityOrHigherThan(Quality.SD))Frage zuerst die Kamerafunktionen ab und wähle dann mit
QualitySelector::from()eine der unterstützten Auflösungen aus: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() } }Die von
QualitySelector.getSupportedQualities()zurückgegebene Funktion funktioniert garantiert entweder für den AnwendungsfallVideoCaptureoder für die Kombination der AnwendungsfälleVideoCaptureundPreview. Bei der Bindung mit dem AnwendungsfallImageCaptureoderImageAnalysiskann die Bindung in CameraX fehlschlagen, wenn die erforderliche Kombination auf der angeforderten Kamera nicht unterstützt wird.
Sobald Sie ein QualitySelector haben, kann die Anwendung ein VideoCapture-Objekt erstellen und die Bindung ausführen. Diese Bindung ist dieselbe wie bei anderen Anwendungsfällen:
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)
}
bindToLifecycle() gibt ein Camera-Objekt zurück. In diesem Leitfaden finden Sie weitere Informationen zum Steuern der Kameraausgabe, z. B. Zoom und Belichtung.
Das Recorder wählt das am besten geeignete Format für das System aus. Der gängigste Video-Codec ist H.264 AVC mit dem Containerformat MPEG‑4.
Aufnahme konfigurieren und erstellen
Aus einem Recorder kann die Anwendung Aufzeichnungsobjekte erstellen, um Video- und Audioaufnahmen durchzuführen. Anwendungen erstellen Aufzeichnungen, indem sie Folgendes tun:
- Konfigurieren Sie
OutputOptionsmit derprepareRecording(). - Optional: Aktivieren Sie die Audioaufnahme.
- Verwenden Sie
start(), um einenVideoRecordEvent-Listener zu registrieren und mit der Videoaufnahme zu beginnen.
Mit Recorder wird ein Recording-Objekt zurückgegeben, wenn Sie die Funktion start() aufrufen.
Ihre Anwendung kann dieses Recording-Objekt verwenden, um die Aufnahme zu beenden oder andere Aktionen auszuführen, z. B. die Aufnahme zu pausieren oder fortzusetzen.
Ein Recorder unterstützt jeweils ein Recording-Objekt. Sie können eine neue Aufzeichnung starten, nachdem Sie Recording.stop() oder Recording.close() für das vorherige Recording-Objekt aufgerufen haben.
Sehen wir uns diese Schritte genauer an. Zuerst konfiguriert die Anwendung OutputOptions für einen Recorder mit Recorder.prepareRecording().
Ein Recorder unterstützt die folgenden Arten von OutputOptions:
FileDescriptorOutputOptionszum Erfassen in einerFileDescriptor.FileOutputOptionszum Erfassen in einemFile.MediaStoreOutputOptionszum Erfassen in einerMediaStore.
Bei allen OutputOptions-Typen können Sie mit setFileSizeLimit() eine maximale Dateigröße festlegen. Andere Optionen sind spezifisch für den jeweiligen Ausgabetyp, z. B. ParcelFileDescriptor für FileDescriptorOutputOptions.
prepareRecording() gibt ein PendingRecording-Objekt zurück. Das ist ein Zwischenobjekt, das zum Erstellen des entsprechenden Recording-Objekts verwendet wird. PendingRecording ist eine temporäre Klasse, die in den meisten Fällen unsichtbar sein sollte und nur selten von der App im Cache gespeichert wird.
Anwendungen können die Aufzeichnung weiter konfigurieren, z. B.:
- Aktivieren Sie Audio mit
withAudioEnabled(). - Registrieren Sie einen Listener, der Ereignisse zur Videoaufzeichnung mit
start(Executor, Consumer<VideoRecordEvent>)empfangen soll. - Ermöglichen Sie, dass eine Aufnahme kontinuierlich aufgezeichnet wird, während die VideoCapture, an die sie angehängt ist, mit
PendingRecording.asPersistentRecording()an eine andere Kamera gebunden wird.
Rufen Sie PendingRecording.start() an, um die Aufnahme zu starten. CameraX wandelt PendingRecording in Recording um, stellt die Aufnahmeanfrage in die Warteschlange und gibt das neu erstellte Recording-Objekt an die Anwendung zurück.
Sobald die Aufnahme auf dem entsprechenden Kameragerät beginnt, sendet CameraX ein VideoRecordEvent.EVENT_TYPE_START-Ereignis.
Das folgende Beispiel zeigt, wie Video und Audio in einer MediaStore-Datei aufgezeichnet werden:
// 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)
Die Kameravorschau wird auf der Frontkamera standardmäßig gespiegelt, Videos, die mit VideoCapture aufgenommen werden, jedoch nicht. Mit CameraX 1.3 ist es jetzt möglich, Videoaufnahmen zu spiegeln, sodass die Vorschau der Frontkamera und das aufgenommene Video übereinstimmen.
Es gibt drei MirrorMode-Optionen: MIRROR_MODE_OFF, MIRROR_MODE_ON und MIRROR_MODE_ON_FRONT_ONLY. Um die Kamera-Vorschau zu verwenden, empfiehlt Google, MIROR_MODE_ON_FRONT_ONLY zu verwenden. Das bedeutet, dass die Spiegelung für die Rückkamera nicht, aber für die Frontkamera aktiviert ist. Weitere Informationen zu MirrorMode finden Sie unter MirrorMode constants.
Dieses Code-Snippet zeigt, wie VideoCapture.Builder.setMirrorMode() mit MIRROR_MODE_ON_FRONT_ONLY aufgerufen wird. Weitere Informationen finden Sie unter 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);
Aktive Aufzeichnung steuern
Sie können eine laufende Recording mit den folgenden Methoden pausieren, fortsetzen und beenden:
pause, um die aktuelle aktive Aufnahme zu pausieren.resume(), um eine pausierte aktive Aufzeichnung fortzusetzen.stop(), um die Aufnahme zu beenden und alle zugehörigen Aufnahmeobjekte zu leeren.mute(), um die aktuelle Aufnahme stummzuschalten oder die Stummschaltung aufzuheben.
Sie können stop() aufrufen, um eine Recording zu beenden, unabhängig davon, ob sich die Aufzeichnung im pausierten oder aktiven Aufzeichnungsstatus befindet.
Wenn Sie ein EventListener mit PendingRecording.start() registriert haben, kommuniziert das Recording über ein VideoRecordEvent.
VideoRecordEvent.EVENT_TYPE_STATUSwird zum Aufzeichnen von Statistiken wie der aktuellen Dateigröße und dem aufgezeichneten Zeitraum verwendet.VideoRecordEvent.EVENT_TYPE_FINALIZEwird für das Aufzeichnungsergebnis verwendet und enthält Informationen wie den URI der endgültigen Datei sowie alle zugehörigen Fehler.
Sobald Ihre App ein EVENT_TYPE_FINALIZE erhält, das auf eine erfolgreiche Aufzeichnungssitzung hinweist, können Sie über den in OutputOptions angegebenen Speicherort auf das aufgezeichnete Video zugreifen.
Zusätzliche Ressourcen
Weitere Informationen zu CameraX finden Sie in den folgenden zusätzlichen Ressourcen:
- Codelab „Erste Schritte mit CameraX“
- Offizielle CameraX-Beispiel-App
- Aktuelle Liste der CameraX Video Capture API
- CameraX-Versionshinweise
- CameraX-Quellcode