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
:
Comme le montre la figure 2, la capture vidéo de CameraX inclut quelques composants architecturaux de haut niveau :
SurfaceProvider
pour la source vidéo.AudioSource
pour 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 :
VideoCapture
est la classe du cas d'utilisation de premier niveau.VideoCapture
se lie à unLifecycleOwner
avec unCameraSelector
et à d'autres cas d'utilisation de CameraX. Pour en savoir plus sur ces concepts et ces utilisations, consultez la page Architecture de CameraX.- Un
Recorder
est une implémentation de VideoOutput étroitement couplée àVideoCapture
.Recorder
permet de capture du contenu vidéo et audio. Une application crée des enregistrements à partir d'unRecorder
. - Un
PendingRecording
configure un enregistrement, ce qui permet d'activer l'audio et de définir un écouteur d'événements. Vous devez utiliser unRecorder
pour créer unPendingRecording
. UnPendingRecording
n'enregistre rien. - Un
Recording
effectue l'enregistrement réel. Vous devez utiliser unPendingRecording
pour créer unRecording
.
La figure 3 illustre les relations entre ces objets :
Légende :
- Créez un
Recorder
avecQualitySelector
. - Configurez le
Recorder
avec l'une desOutputOptions
. - Si nécessaire, activez l'audio avec
withAudioEnabled()
. - Appelez
start()
avec un écouteurVideoRecordEvent
pour commencer l'enregistrement. - Utilisez
pause()
/resume()
/stop()
sur leRecording
pour contrôler l'enregistrement. - Répondez à
VideoRecordEvents
dans 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.UHD
pour une vidéo 4K Ultra HD (2 160 p)Quality.FHD
pour une vidéo en Full HD (1 080 p)Quality.HD
pour une vidéo HD (720 p)Quality.SD
pour 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 specification
deQualitySelector
. 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 deVideoCapture
ou pour la combinaison des cas d'utilisationVideoCapture
etPreview
. Lors de la liaison avec le cas d'utilisationImageCapture
ouImageAnalysis
, 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
OutputOptions
avec leprepareRecording()
. - (Facultatif) Activez l'enregistrement audio.
- Utilisez
start()
pour enregistrer un écouteurVideoRecordEvent
et 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 :
FileDescriptorOutputOptions
pour la capture dans unFileDescriptor
.FileOutputOptions
pour la capture dans unFile
.MediaStoreOutputOptions
pour 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 :
pause
pour 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_STATUS
permet d'enregistrer des statistiques telles que la taille de fichier actuelle et la période enregistrée.VideoRecordEvent.EVENT_TYPE_FINALIZE
est 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