Ein Erfassungssystem zeichnet Video- und Audiostreams in der Regel auf, komprimiert sie, muxiert die beiden Streams und schreibt den resultierenden Stream auf die Festplatte.
In CameraX ist die Lösung für die Videoaufnahme der Anwendungsfall VideoCapture
:
Wie in Abbildung 2 gezeigt, umfasst die CameraX-Videoaufnahme einige allgemeine Architekturkomponenten:
SurfaceProvider
für die Videoquelle.AudioSource
für Audioquelle.- Zwei Encoder zur Codierung und Komprimierung von Video/Audio.
- Ein Media-Muxer, um die beiden Streams zu mux
- Ein Dateisparmodus, um das Ergebnis zu schreiben.
Die VideoCapture API abstrahiert das komplexe Aufnahmemodul und bietet Anwendungen eine wesentlich einfachere API.
VideoCapture API – Übersicht
VideoCapture
ist ein CameraX-Anwendungsfall, der allein oder in Kombination mit anderen Anwendungsfällen gut funktioniert. Bestimmte unterstützte Kombinationen hängen von den Funktionen der Kamerahardware ab. Preview
und VideoCapture
sind jedoch für alle Geräte eine zulässige Kombination aus Anwendungsfällen.
Die VideoCapture API besteht aus den folgenden Objekten, die mit Anwendungen kommunizieren:
VideoCapture
ist die übergeordnete Anwendungsfallklasse.VideoCapture
wird an eineLifecycleOwner
mitCameraSelector
und anderen CameraX-Anwendungsfällen gebunden. Weitere Informationen zu diesen Konzepten und Verwendungen finden Sie unter CameraX-Architektur.- Ein
Recorder
ist eine Implementierung von VideoOutput, die eng mitVideoCapture
verknüpft ist.Recorder
wird für die Video- und Audioaufnahme verwendet. Eine Anwendung erstellt Aufzeichnungen aus einerRecorder
. - Ein
PendingRecording
konfiguriert eine Aufzeichnung und bietet Optionen wie das Aktivieren von Audio und das Festlegen eines Event-Listeners. Sie müssen einenRecorder
verwenden, um einePendingRecording
zu erstellen.PendingRecording
zeichnet nichts auf. - Die eigentliche Aufzeichnung wird mit
Recording
durchgeführt. Sie müssen einenPendingRecording
verwenden, um eineRecording
zu erstellen.
In Abbildung 3 sind die Beziehungen zwischen diesen Objekten dargestellt:
Legende:
- Erstellen Sie ein
Recorder
mitQualitySelector
. - Konfigurieren Sie
Recorder
mit einer derOutputOptions
. - Aktivieren Sie bei Bedarf Audio mit
withAudioEnabled()
. - Rufen Sie
start()
mit einemVideoRecordEvent
-Listener auf, um mit der Aufzeichnung zu beginnen. - Verwenden Sie
pause()
/resume()
/stop()
aufRecording
, um die Aufzeichnung zu steuern. - Sie reagieren im Event-Listener auf
VideoRecordEvents
.
Eine detaillierte API-Liste finden Sie in der current.txt-Datei im Quellcode.
VideoCapture API verwenden
So binden Sie den VideoCapture
-Anwendungsfall von CameraX in Ihre Anwendung ein:
- Binden Sie
VideoCapture
. - Aufzeichnung vorbereiten und konfigurieren
- Laufzeitaufzeichnung starten und steuern
In den folgenden Abschnitten wird beschrieben, was Sie in den einzelnen Schritten für eine End-to-End-Aufzeichnung tun können.
Videoaufnahme binden
So binden Sie den Anwendungsfall VideoCapure
:
- Erstellen Sie ein
Recorder
-Objekt. - Erstellen Sie ein
VideoCapture
-Objekt. - An eine
Lifecycle
binden.
Die CameraX VideoCapture API richtet sich nach dem Designmuster des Builders. Anwendungen verwenden Recorder.Builder
, um eine Recorder
zu erstellen. Sie können die Videoauflösung für Recorder
auch über ein QualitySelector
-Objekt konfigurieren.
CameraX Recorder
unterstützt die folgenden vordefinierten Qualities
für Videoauflösungen:
Quality.UHD
für 4K-Ultra-HD-Videogröße (2160p)Quality.FHD
für Full-HD-Videogröße (1080p)Quality.HD
für HD-Videogröße (720p)Quality.SD
für SD-Videogröße (480p)
Beachte, dass CameraX nach Genehmigung der App auch andere Auflösungen auswählen kann.
Die genaue Videogröße der jeweiligen 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 durch Erstellen einer QualitySelector
konfigurieren.
Sie können ein QualitySelector
mit einer der folgenden Methoden erstellen:
Geben Sie einige bevorzugte Lösungen mit
fromOrderedList()
an und geben Sie eine Fallback-Strategie für den Fall an, dass keine der bevorzugten Lösungen unterstützt wird.CameraX kann die beste Fallback-Übereinstimmung anhand der Funktion der ausgewählten Kamera ermitteln. Weitere Informationen finden Sie unter
FallbackStrategy specification
vonQualitySelector
. Mit dem folgenden Code wird beispielsweise die höchste unterstützte Auflösung für die Aufzeichnung angefordert. Wenn keine der Anfrageauflösungen unterstützt werden kann, autorisieren Sie CameraX, eine Auflösung auszuwählen, die der Quality.SD-Auflösung am nächsten kommt:val qualitySelector = QualitySelector.fromOrderedList( listOf(Quality.UHD, Quality.FHD, Quality.HD, Quality.SD), FallbackStrategy.lowerQualityOrHigherThan(Quality.SD))
Fragen Sie zuerst die Kamerafunktionen ab und wählen Sie 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 entweder für den AnwendungsfallVideoCapture
oder die Kombination ausVideoCapture
undPreview
. Wenn Sie eine Bindung zusammen mit dem AnwendungsfallImageCapture
oderImageAnalysis
erstellen, schlägt CameraX bei der Bindung möglicherweise trotzdem fehl, wenn die erforderliche Kombination von 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 die gleiche 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. Weitere Informationen zur Steuerung der Kameraausgabe, z. B. Zoom und Belichtung, finden Sie in diesem Leitfaden.
Recorder
wählt das am besten geeignete Format für das System aus. Der gängigste Video-Codec ist H.264 AVC mit Containerformat MPEG-4.
Aufzeichnung konfigurieren und erstellen
Aus einer Recorder
kann die Anwendung Aufnahmeobjekte für die Video- und Audioaufnahme erstellen. So erstellen Sie Aufzeichnungen in Anwendungen:
- Konfigurieren Sie
OutputOptions
mit derprepareRecording()
. - Optional: Aktivieren Sie die Audioaufnahme.
- Verwenden Sie
start()
, um einenVideoRecordEvent
-Listener zu registrieren und mit der Videoaufnahme zu beginnen.
Recorder
gibt ein Recording
-Objekt zurück, wenn Sie die start()
-Funktion aufrufen.
Ihre App kann dieses Recording
-Objekt verwenden, um die Aufzeichnung abzuschließen oder andere Aktionen auszuführen, z. B. um sie zu pausieren oder fortzusetzen.
Ein Recorder
unterstützt jeweils ein Recording
-Objekt. Sie können eine neue Aufzeichnung starten, sobald Sie Recording.stop()
oder Recording.close()
für das vorherige Recording
-Objekt aufgerufen haben.
Sehen wir uns diese Schritte einmal genauer an. Zuerst konfiguriert die Anwendung den OutputOptions
für einen Rekorder mit Recorder.prepareRecording()
.
Ein Recorder
unterstützt die folgenden Typen von OutputOptions
:
FileDescriptorOutputOptions
zum Erfassen in einemFileDescriptor
.FileOutputOptions
zum Aufnehmen in einFile
.MediaStoreOutputOptions
zum Erfassen in einemMediaStore
.
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. Dies ist ein Zwischenobjekt, mit dem das entsprechende Recording
-Objekt erstellt wird. PendingRecording
ist eine temporäre Klasse, die in den meisten Fällen unsichtbar sein sollte und von der Anwendung selten im Cache gespeichert wird.
Anwendungen können die Aufzeichnung weiter konfigurieren, z. B.:
- Audio mit
withAudioEnabled()
aktivieren. - Registrieren Sie einen Listener, um mit
start(Executor, Consumer<VideoRecordEvent>)
Videoaufnahmeereignisse zu empfangen. - Mit
PendingRecording.asPersistentRecording()
kannst du zulassen, dass eine Aufzeichnung rund um die Uhr aufgenommen wird, während die damit verbundene VideoCapture-Kamera mit einer anderen Kamera wieder aufgenommen wird.
Um die Aufzeichnung zu starten, ruf PendingRecording.start()
an. CameraX wandelt PendingRecording
in ein Recording
-Objekt 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 eine MediaStore
-Datei aufgenommen 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)
Während die Kameravorschau standardmäßig auf der Frontkamera gespiegelt wird, werden mit VideoCapture aufgenommene Videos standardmäßig nicht gespiegelt. Mit CameraX 1.3 ist es jetzt möglich, Videoaufnahmen zu spiegeln, sodass die Vorschau der Frontkamera und das aufgezeichnete Video übereinstimmen.
Es gibt drei MirrorMode-Optionen: MIRROR_MODE_OFF, MIRROR_MODE_ON und MIRROR_MODE_ON_FRONT_ONLY. Zur Ausrichtung auf die Kameravorschau empfiehlt Google die Verwendung von MIROR_MODE_ON_FRONT_ONLY. Das bedeutet, dass die Spiegelung nicht für die Rückkamera, sondern für die Frontkamera aktiviert ist. Weitere Informationen zum Spiegelmodus 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 Aufzeichnungen steuern
Mit den folgenden Methoden können Sie einen laufenden Recording
pausieren, fortsetzen und beenden:
pause
, um die aktuell aktive Aufzeichnung zu pausieren.resume()
, um eine pausierte aktive Aufzeichnung fortzusetzen.stop()
, um die Aufzeichnung abzuschließen und alle zugehörigen Aufzeichnungsobjekte zu löschen.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 Status „Pausiert“ oder „Aktiv“ befindet.
Wenn Sie ein EventListener
bei PendingRecording.start()
registriert haben, kommuniziert das Recording
mithilfe von VideoRecordEvent
.
VideoRecordEvent.EVENT_TYPE_STATUS
wird für die Aufzeichnung von Statistiken wie der aktuellen Dateigröße und der aufgezeichneten Zeitspanne verwendet.VideoRecordEvent.EVENT_TYPE_FINALIZE
wird für das Aufzeichnungsergebnis verwendet und enthält Informationen wie den URI der endgültigen Datei sowie alle damit verbundenen Fehler.
Sobald Ihre App eine EVENT_TYPE_FINALIZE
empfängt, die auf eine erfolgreiche Aufnahmesitzung hinweist, können Sie von dem in OutputOptions
angegebenen Standort aus auf das aufgenommene Video zugreifen.
Weitere Informationen
Weitere Informationen zu CameraX finden Sie in den folgenden zusätzlichen Ressourcen:
- Erste Schritte mit CameraX-Codelab
- Offizielle CameraX-Beispiel-App
- Neueste Liste der CameraX Video Capture API
- CameraX-Versionshinweise
- CameraX-Quellcode