Por lo general, un sistema de captura graba transmisiones de video y audio, las comprime, combina varias transmisiones y, luego, escribe la transmisión resultante en el disco.

En CameraX, la solución para la captura de video es el caso de uso de VideoCapture:

VideoCaptureComo se muestra en la figura 2, la captura de video de CameraX incluye algunos componentes arquitectónicos de alto nivel:
SurfaceProviderpara la fuente de videoAudioSourcepara la fuente de audio- Dos codificadores para codificar y comprimir video/audio
- Un combinador de medios para combinar las dos transmisiones
- Un ahorro de archivos para escribir el resultado
La API de VideoCapture simplifica el motor de captura complejo y proporciona a las aplicaciones una API mucho más simple y directa.
Descripción general de la API de VideoCapture
VideoCapture es un caso de uso de CameraX que funciona bien por sí solo o cuando se combina con otros casos de uso. Las combinaciones específicas admitidas dependen de las capacidades del hardware de la cámara, aunque Preview y VideoCapture son una combinación válida de casos de uso en todos los dispositivos.
La API de VideoCapture consta de los siguientes objetos que se comunican con aplicaciones:
VideoCapturees la clase de caso de uso de nivel superior.VideoCapturese vincula a unLifecycleOwnercon unCameraSelectory otros UseCases de CameraX. Para obtener más información sobre estos conceptos y usos, consulta Arquitectura de CameraX.- Un
Recorderes una implementación de VideoOutput que tiene un acoplamiento alto conVideoCapture.Recorderse usa para realizar la captura de video y audio. Una aplicación crea grabaciones a partir de unRecorder. - Un
PendingRecordingconfigura una grabación y proporciona opciones como habilitar el audio y configurar un objeto de escucha de eventos. Debes usarRecorderpara crear unaPendingRecording.PendingRecordingno graba nada. Recordingrealiza la grabación. Debes usarPendingRecordingpara crear unRecording.
En la Figura 3, se muestran las relaciones entre estos objetos:

Leyenda:
- Crea una
RecorderconQualitySelector. - Configura
Recordercon una de lasOutputOptions. - Si es necesario, habilita el audio con
withAudioEnabled(). - Llama a
start()con un objeto de escuchaVideoRecordEventpara comenzar a grabar. - Usa
pause()/resume()/stop()enRecordingpara controlar la grabación. - Responde a
VideoRecordEventsdentro del objeto de escucha de eventos.
La lista detallada de las API se encuentra en el archivo current.txt dentro del código fuente.
Cómo usar la API de VideoCapture
Para integrar el caso de uso de CameraX VideoCapture a tu app, haz lo siguiente:
- Vincula
VideoCapture. - Prepara y configura la grabación.
- Inicia y controla la grabación del tiempo de ejecución.
En las siguientes secciones, se describe lo que puedes hacer en cada paso para obtener una sesión de grabación completa.
Cómo vincular VideoCapture
Para vincular el caso de uso de VideoCapure, haz lo siguiente:
- Crea un objeto
Recorder. - Crea el objeto
VideoCapture. - Haz la vinculación a
Lifecycle.
La API de CameraX VideoCapture sigue el patrón de diseño del compilador. Las aplicaciones usan Recorder.Builder para crear un Recorder. También puedes configurar la resolución del video para Recorder mediante un objeto QualitySelector.
CameraX Recorder admite las siguientes Qualities predefinidas para resoluciones de video:
Quality.UHDpara videos con resolución 4K Ultra HD (2160p)Quality.FHDpara videos con resolución Full HD (1080p)Quality.HDpara videos con resolución HD (720p)Quality.SDpara videos con resolución SD (480p)
Ten en cuenta que CameraX también podrá elegir otras resoluciones cuando lo autorice la app.
La resolución exacta del video de cada selección depende de la cámara y las capacidades del codificador. Para obtener más información, consulta la documentación de CamcorderProfile.
Para configurar la resolución, las aplicaciones pueden crear un QualitySelector.
QualitySelector se puede crear con uno de los siguientes métodos:
Brinda algunas resoluciones preferidas mediante
fromOrderedList()y agrega una estrategia de resguardo para usar en caso de que no se admita ninguna de las resoluciones preferidas.CameraX puede decidir la mejor coincidencia de resguardo según la capacidad de la cámara seleccionada. Para obtener más detalles, consulta el objeto
FallbackStrategy specificationdeQualitySelector. Por ejemplo, el siguiente código solicita la resolución más alta compatible para la grabación y, si no se admite ninguna de las resoluciones de solicitud, autoriza a CameraX a elegir la que esté más cerca de la resolución Quality.SD:val qualitySelector = QualitySelector.fromOrderedList( listOf(Quality.UHD, Quality.FHD, Quality.HD, Quality.SD), FallbackStrategy.lowerQualityOrHigherThan(Quality.SD))Consulta las capacidades de la cámara primero y elige una de las resoluciones compatibles mediante
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() } }Ten en cuenta que se garantiza que la capacidad que se muestra de
QualitySelector.getSupportedQualities()funcione para el caso de uso deVideoCaptureo la combinación deVideoCaptureyPreview. Cuando se realiza la vinculación con el caso de uso deImageCaptureoImageAnalysis, es posible que CameraX falle al hacerlo si la combinación requerida no es compatible con la cámara solicitada.
Una vez que tengas un QualitySelector, la aplicación podrá crear un objeto VideoCapture y realizar la vinculación. Ten en cuenta que esta vinculación es la misma que con otros casos de 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)
}
Ten en cuenta que bindToLifecycle() muestra un objeto Camera. Consulta esta guía a fin de obtener más información para controlar la salida de la cámara, como el zoom y la exposición.
Recorder selecciona el formato más adecuado para el sistema. El códec de video más común es H.264 AVC con formato de contenedor MPEG-4.
Cómo configurar y crear una grabación
Desde un Recorder, la aplicación puede crear objetos de grabación para realizar la captura de audio y de video. Las aplicaciones crean grabaciones de la siguiente manera:
- Configuran
OutputOptionsconprepareRecording(). - Habilita la grabación de audio (opcional).
- Usa
start()para registrar un objeto de escuchaVideoRecordEventy comienza a capturar videos.
El objeto Recorder muestra un objeto Recording cuando llamas a la función start().
Tu aplicación puede usar este objeto Recording para finalizar la captura o realizar otras acciones, como pausar o reanudar.
Recorder admite un objeto Recording por vez. Puedes iniciar una grabación nueva una vez que hayas llamado a Recording.stop() o Recording.close() en el objeto Recording anterior.
Analicemos estos pasos con más detalle. Primero, la aplicación configura OutputOptions para una grabadora con Recorder.prepareRecording().
Recorder admite los siguientes tipos de OutputOptions:
FileDescriptorOutputOptionspara hacer la captura en unFileDescriptorFileOutputOptionspara hacer la captura en unFileMediaStoreOutputOptionspara hacer la captura en unMediaStore
Todos los tipos OutputOptions te permiten establecer un tamaño de archivo máximo con setFileSizeLimit(). Otras opciones son específicas del tipo de salida individual, como ParcelFileDescriptor para FileDescriptorOutputOptions.
prepareRecording() muestra un objeto PendingRecording, que es un objeto intermedio que se usa para crear la Recording correspondiente. PendingRecording es una clase transitoria que debería ser invisible en la mayoría de los casos y la app rara vez almacena en caché.
Las aplicaciones pueden configurar las siguientes opciones de la grabación:
- Habilitar el audio con
withAudioEnabled() - Registrar un objeto de escucha para recibir eventos de grabación de video con
start(Executor, Consumer<VideoRecordEvent>) - Permitir una grabación continua mientras que el elemento VideoCapture adjunto se envía a otra cámara, con
PendingRecording.asPersistentRecording().
Para comenzar a grabar, llama a PendingRecording.start(). CameraX convierte el PendingRecording en un Recording, pone en cola la solicitud de grabación y muestra el objeto Recording recién creado a la aplicación.
Una vez que comienza la grabación en el dispositivo correspondiente, CameraX envía un evento VideoRecordEvent.EVENT_TYPE_START.
En el siguiente ejemplo, se muestra cómo grabar video y audio en un archivo 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)
La vista previa de la cámara se duplica en la cámara frontal de forma predeterminada, pero eso no sucede con los videos grabados por VideoCapture. Con CameraX 1.3, ahora es posible duplicar las grabaciones de video de modo que la vista previa de la cámara frontal coincida con el video grabado.
Existen tres opciones de MirrorMode: MIRROR_MODE_OFF, MIRROR_MODE_ON y MIRROR_MODE_ON_FRONT_ONLY. Para alinear la vista previa de la cámara, Google recomienda que uses MIRROR_MODE_ON_FRONT_ONLY, lo que significa que no se habilitará la duplicación para la cámara posterior, pero sí para la frontal. Para obtener más información sobre MirrorMode, consulta MirrorMode constants.
Este fragmento de código te muestra cómo llamar a VideoCapture.Builder.setMirrorMode() usando MIRROR_MODE_ON_FRONT_ONLY. Si deseas obtener información detallada, consulta 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);
Cómo controlar una grabación activa
Puedes pausar, reanudar y detener una Recording en curso mediante los siguientes métodos:
pausepara pausar la grabación activa actualresume()para reanudar una grabación activa en pausastop()para finalizar la grabación y limpiar los objetos de grabación asociadosmute()para silenciar o activar el sonido de la grabación actual
Ten en cuenta que puedes llamar a stop() para finalizar una Recording, independientemente de si la grabación está en estado de pausa o en estado activo.
Si registraste un EventListener con PendingRecording.start(), Recording se comunica mediante VideoRecordEvent.
VideoRecordEvent.EVENT_TYPE_STATUSse usa para grabar estadísticas, como el tamaño actual del archivo y el intervalo de tiempo grabado.VideoRecordEvent.EVENT_TYPE_FINALIZEse usa para el resultado de la grabación y, además, incluye información como el URI del archivo final junto con cualquier error relacionado.
Una vez que la app reciba un EVENT_TYPE_FINALIZE que indique una sesión de grabación exitosa, podrás acceder al video capturado desde la ubicación que se haya especificado en OutputOptions.
Recursos adicionales
Para obtener más información sobre CameraX, consulta los siguientes recursos adicionales:
- Codelab para empezar a usar CameraX
- App de ejemplo de CameraX oficial
- Lista más reciente de la API de captura de video de CameraX
- Notas de la versión de CameraX
- Código fuente de CameraX