Un système de capture enregistre généralement des flux vidéo et audio, les compresse, multiplexe les deux flux, puis écrit le flux obtenu sur le disque.
Dans CameraX, la solution de capture vidéo est le cas d'utilisation VideoCapture :
VideoCapture.Comme le montre la figure 2, la capture vidéo de CameraX inclut quelques composants architecturaux de haut niveau :
SurfaceProviderpour la source vidéo.AudioSourcepour la source audio.- Deux encodeurs permettent d'encoder et de compresser la vidéo et l'audio.
- Un multiplexeur multimédia pour combiner les deux flux.
- Un saver de fichier pour écrire le résultat.
L'API VideoCapture fait abstraction du moteur de capture complexe et fournit aux applications une API bien plus simple et directe.
Présentation de l'API VideoCapture
VideoCapture est un cas d'utilisation de CameraX qui fonctionne bien seul ou lorsqu'il est combiné à d'autres cas d'utilisation. Les combinaisons spécifiques compatibles dépendent des capacités matérielles de l'appareil photo, mais Preview et VideoCapture forment une combinaison valide pour tous les appareils.
L'API VideoCapture comprend les objets suivants qui communiquent avec les applications :
VideoCaptureest la classe du cas d'utilisation de premier niveau.VideoCapturese lie à unLifecycleOwneravec unCameraSelectoret à d'autres cas d'utilisation de CameraX. Pour en savoir plus sur ces concepts et ces utilisations, consultez la page Architecture de CameraX.- Un
Recorderest une implémentation de VideoOutput étroitement couplée àVideoCapture.Recorderpermet de capture du contenu vidéo et audio. Une application crée des enregistrements à partir d'unRecorder. - Un
PendingRecordingconfigure un enregistrement, ce qui permet d'activer l'audio et de définir un écouteur d'événements. Vous devez utiliser unRecorderpour créer unPendingRecording. UnPendingRecordingn'enregistre rien. - Un
Recordingeffectue l'enregistrement réel. Vous devez utiliser unPendingRecordingpour créer unRecording.
La figure 3 illustre les relations entre ces objets :
Légende :
- Créez un
RecorderavecQualitySelector. - Configurez le
Recorderavec l'une desOutputOptions. - Si nécessaire, activez l'audio avec
withAudioEnabled(). - Appelez
start()avec un écouteurVideoRecordEventpour commencer l'enregistrement. - Utilisez
pause()/resume()/stop()sur leRecordingpour contrôler l'enregistrement. - Répondez à
VideoRecordEventsdans votre écouteur d'événements.
La liste détaillée des API se trouve dans le fichier current.txt à l'intérieur du code source.
Utiliser l'API VideoCapture
Pour intégrer le cas d'utilisation VideoCapture de CameraX dans votre application, procédez comme suit :
- Liez
VideoCapture. - Préparez et configurez l'enregistrement.
- Démarrez et contrôlez l'enregistrement de l'environnement d'exécution.
Les sections suivantes décrivent ce que vous pouvez faire à chaque étape pour obtenir une session d'enregistrement de bout en bout.
Lier VideoCapture
Pour lier le cas d'utilisation VideoCapure, procédez comme suit :
- Créez un objet
Recorder. - Créez un objet
VideoCapture. - Liez-les à un
Lifecycle.
L'API CameraX VideoCapture respecte le schéma de conception du compilateur. Les applications utilisent Recorder.Builder pour créer un Recorder. Vous pouvez également configurer la résolution vidéo de Recorder via un objet QualitySelector.
CameraX Recorder est compatible avec les Qualities prédéfinies pour les résolutions vidéo :
Quality.UHDpour une vidéo 4K Ultra HD (2 160 p)Quality.FHDpour une vidéo en Full HD (1 080 p)Quality.HDpour une vidéo HD (720 p)Quality.SDpour une vidéo SD (480 p)
Sachez que CameraX peut également choisir d'autres résolutions si l'application le permet.
La taille exacte de la vidéo de chaque sélection dépend des capacités de l'appareil photo et de l'encodeur. Pour en savoir plus, consultez la documentation pour CamcorderProfile.
Les applications peuvent configurer la résolution en créant un QualitySelector.
Vous pouvez créer un QualitySelector à l'aide de l'une des méthodes suivantes :
Indiquez quelques résolutions privilégiées à l'aide de
fromOrderedList()et incluez une stratégie de remplacement à utiliser si aucune des résolutions souhaitées n'est compatible.CameraX peut choisir la meilleure correspondance de remplacement en fonction de la capacité de l'appareil photo sélectionné. Pour en savoir plus, consultez la
FallbackStrategy specificationdeQualitySelector. Par exemple, le code suivant demande la résolution la plus élevée pour l'enregistrement. Si aucune des résolutions de requête ne peut être acceptée, autorisez CameraX à en choisir une résolution qui se rapproche le plus de la résolution Quality.SD :val qualitySelector = QualitySelector.fromOrderedList( listOf(Quality.UHD, Quality.FHD, Quality.HD, Quality.SD), FallbackStrategy.lowerQualityOrHigherThan(Quality.SD))Commencez par interroger les capacités de l'appareil photo, puis choisissez l'une des résolutions compatibles à l'aide de
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() } }Notez que la capacité renvoyée par
QualitySelector.getSupportedQualities()garantit le fonctionnement avec le cas d'utilisation deVideoCaptureou pour la combinaison des cas d'utilisationVideoCaptureetPreview. Lors de la liaison avec le cas d'utilisationImageCaptureouImageAnalysis, CameraX peut tout de même échouer si la combinaison requise n'est pas compatible avec l'appareil photo demandé.
Une fois que vous disposez d'un QualitySelector, l'application peut créer un objet VideoCapture et effectuer la liaison. Notez que cette liaison est identique à celle utilisée pour d'autres cas d'utilisation :
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)
}
Notez que bindToLifecycle() renvoie un objet Camera. Pour en savoir plus sur le contrôle de la sortie de l'appareil photo, comme le zoom et l'exposition, consultez ce guide.
Le Recorder sélectionne le format le plus adapté au système. Le codec vidéo le plus courant est H.264 AVC au format de conteneur MPEG-4.
Configurer et créer un enregistrement
À partir d'un Recorder, l'application peut créer des objets d'enregistrement pour effectuer la capture vidéo et audio. Les applications créent des enregistrements en procédant comme suit :
- Configurez
OutputOptionsavec leprepareRecording(). - (Facultatif) Activez l'enregistrement audio.
- Utilisez
start()pour enregistrer un écouteurVideoRecordEventet commencer à enregistrer des vidéos.
Le Recorder renvoie un objet Recording lorsque vous appelez la fonction start().
Votre application peut utiliser cet objet Recording pour terminer la capture ou effectuer d'autres actions, telles que la mise en pause ou la reprise.
Un objet Recorder accepte un seul objet Recording à la fois. Vous pouvez démarrer un nouvel enregistrement une fois que vous avez appelé Recording.stop() ou Recording.close() sur l'objet Recording précédent.
Examinons ces étapes plus en détail. Tout d'abord, l'application configure les OutputOptions pour un enregistreur avec Recorder.prepareRecording().
Un Recorder est compatible avec les types de OutputOptions suivants :
FileDescriptorOutputOptionspour la capture dans unFileDescriptor.FileOutputOptionspour la capture dans unFile.MediaStoreOutputOptionspour la capture dans unMediaStore.
Tous les types OutputOptions vous permettent de définir une taille de fichier maximale avec setFileSizeLimit(). D'autres options sont propres au type de sortie individuel, par exemple ParcelFileDescriptor pour les FileDescriptorOutputOptions.
prepareRecording() renvoie un objet PendingRecording, qui est un objet intermédiaire utilisé pour créer l'objet Recording correspondant. PendingRecording est une classe temporaire qui doit être invisible dans la plupart des cas et qui est rarement mise en cache par l'application.
Les applications peuvent également configurer l'enregistrement, par exemple :
- Activez l'audio avec
withAudioEnabled(). - Enregistrez un écouteur pour recevoir des événements d'enregistrement vidéo avec
start(Executor, Consumer<VideoRecordEvent>). - Permet à un enregistrement d'enregistrer en continu alors que la VideoCapture à laquelle il est associé est reliée à une autre caméra, avec
PendingRecording.asPersistentRecording().
Pour commencer l'enregistrement, appelez PendingRecording.start(). CameraX transforme le PendingRecording en un Recording, met la requête en file d'attente et renvoie l'objet Recording nouvellement créé à l'application.
Une fois que l'enregistrement a commencé sur l'appareil photo correspondant, CameraX envoie un événement VideoRecordEvent.EVENT_TYPE_START.
L'exemple suivant montre comment enregistrer du contenu vidéo et audio dans un fichier 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)
Alors que par défaut, l'aperçu de la caméra avant est mis en miroir, ce n'est pas le cas des vidéos enregistrées par VideoCapture. Avec CameraX 1.3, il est maintenant possible de mettre en miroir les enregistrements vidéo afin que l'aperçu de la caméra avant et la vidéo enregistrée correspondent.
Trois options existent pour le mode MirrorMode : MIRROR_MODE_OFF, MIRROR_MODE_ON et MIRROR_MODE_ON_FRONT_ONLY. Pour aligner l'aperçu de la caméra, Google recommande d'utiliser MIROR_MODE_ON_FRONT_ONLY, ce qui signifie que la mise en miroir n'est pas activée pour la caméra arrière, mais l'est pour la caméra avant. Pour en savoir plus sur le mode MirrorMode, consultez MirrorMode constants.
Cet extrait de code vous montre comment appeler VideoCapture.Builder.setMirrorMode() à l'aide de MIRROR_MODE_ON_FRONT_ONLY. Pour en savoir plus, consultez 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);
Contrôler un enregistrement actif
Vous pouvez suspendre, reprendre et arrêter un Recording en cours à l'aide des méthodes suivantes :
pausepour suspendre l'enregistrement actif en cours.resume()pour reprendre un enregistrement actif mis en pausestop()pour terminer l'enregistrement et vider tous les objets d'enregistrement associés.mute()pour activer ou désactiver le son de l'enregistrement actuel.
Notez que vous pouvez appeler stop() pour arrêter un Recording, que l'enregistrement soit mis en pause ou actif.
Si vous avez enregistré un EventListener avec PendingRecording.start(), Recording communique à l'aide d'un VideoRecordEvent.
VideoRecordEvent.EVENT_TYPE_STATUSpermet d'enregistrer des statistiques telles que la taille de fichier actuelle et la période enregistrée.VideoRecordEvent.EVENT_TYPE_FINALIZEest utilisé pour le résultat de l'enregistrement et inclut des informations telles que l'URI du fichier final ainsi que les erreurs associées.
Une fois que votre application reçoit un EVENT_TYPE_FINALIZE indiquant une session d'enregistrement réussie, vous pouvez accéder à la vidéo capturée à partir de l'emplacement spécifié dans OutputOptions.
Ressources supplémentaires
Pour en savoir plus sur CameraX, consultez les ressources supplémentaires suivantes :
- Premiers pas avec l'atelier de programmation CameraX
- Application exemple officielle de CameraX
- Dernière liste d'API de CameraX VideoCapture
- Notes de version de CameraX
- Code source de CameraX