Novedades de productos

Presentamos CameraX 1.5: Grabación de video potente y captura de imágenes de nivel profesional

Lectura de 7 min
Scott Nien
Ingeniero de software

El equipo de CameraX se complace en anunciar el lanzamiento de la versión 1.5. Esta actualización más reciente se centra en poner capacidades de nivel profesional al alcance de tu mano y, al mismo tiempo, facilitar la configuración de la sesión de la cámara más que nunca.

Para la grabación de video, los usuarios ahora pueden capturar sin esfuerzo videos impresionantes en cámara lenta o con una alta velocidad de fotogramas. Lo que es más importante, la nueva API de Feature Group te permite habilitar con confianza combinaciones complejas como HDR de 10 bits y 60 FPS, lo que garantiza resultados coherentes en los dispositivos compatibles.

En cuanto a la captura de imágenes , obtienes la máxima flexibilidad con la compatibilidad para capturar archivos DNG (RAW) sin procesar ni comprimir. Además, ahora puedes aprovechar la salida Ultra HDR incluso cuando usas potentes extensiones de cámara.

Estas funciones se basan en la nueva API de SessionConfig, que optimiza la configuración y la reconfiguración de la cámara. Ahora, profundicemos en los detalles de estas nuevas y emocionantes funciones.

Grabación de video potente: Combinaciones de alta velocidad y funciones

CameraX 1.5 expande significativamente sus capacidades de video, lo que permite experiencias de grabación más creativas y sólidas.

Video en cámara lenta y con alta velocidad de fotogramas

Una de nuestras funciones más esperadas, el video en cámara lenta, ya está disponible. Ahora puedes capturar videos de alta velocidad (p.ej., 120 o 240 fps) y codificarlos directamente en un video dramático en cámara lenta. Como alternativa, puedes grabar con la misma alta velocidad de fotogramas para producir videos excepcionalmente fluidos.

La implementación es sencilla si estás familiarizado con la API de VideoCapture.

1. Verifica la compatibilidad con alta velocidad: Usa el nuevo Recorder.getHighSpeedVideoCapabilities() método para consultar si el dispositivo admite esta función.

val cameraInfo = cameraProvider.getCameraInfo(cameraSelector)

val highSpeedCapabilities = Recorder.getHighSpeedVideoCapabilities(cameraInfo)

if (highSpeedCapabilities == null) {
    // This camera device does not support high-speed video.
    return
}

2. Configura y vincula el caso de uso: Usa el videoCapabilities que se muestra (que contiene información sobre la calidad de video admitida) para compilar un HighSpeedVideoSessionConfig. Luego, debes consultar los rangos de velocidad de fotogramas admitidos a través de cameraInfo.getSupportedFrameRateRanges() y establecer el rango deseado. Invoca setSlowMotionEnabled(true) para grabar videos en cámara lenta. De lo contrario, grabará videos con alta velocidad de fotogramas. El paso final es usar el Recorder.prepareRecording().start() normal para comenzar a grabar el video.

val preview = Preview.Builder().build()
val quality = highSpeedCapabilities
        .getSupportedQualities(DynamicRange.SDR).first()

val recorder = Recorder.Builder()
      .setQualitySelector(QualitySelector.from(quality)))
      .build()

val videoCapture = VideoCapture.withOutput(recorder)

val frameRateRange = cameraInfo.getSupportedFrameRateRanges(      
       HighSpeedVideoSessionConfig(videoCapture, preview)
).first()

val sessionConfig = HighSpeedVideoSessionConfig(
    videoCapture, 
    preview, 
    frameRateRange = frameRateRange, 
    // Set true for slow-motion playback, or false for high-frame-rate
    isSlowMotionEnabled = true
)

cameraProvider.bindToLifecycle(
     lifecycleOwner, cameraSelector, sessionConfig)

// Start recording slow motion videos. 
val recording = recorder.prepareRecording(context, outputOption)
      .start(executor, {})

Compatibilidad y limitaciones

La grabación de alta velocidad requiere compatibilidad específica con CameraConstrainedHighSpeedCaptureSession y CamcorderProfile. Siempre realiza la verificación de capacidades y habilita la grabación de alta velocidad solo en dispositivos compatibles para evitar una mala experiencia del usuario. Actualmente, esta función es compatible con las cámaras traseras de casi todos los dispositivos Pixel y modelos seleccionados de otros fabricantes.

Consulta la entrada de blog para obtener más detalles.

Combina funciones con confianza: La API de Feature Group

CameraX 1.5 presenta la API de Feature Group, que elimina las conjeturas sobre la compatibilidad de funciones. Según la API de consulta de combinación de funciones de Android 15, ahora puedes habilitar con confianza varias funciones juntas, lo que garantiza una sesión de cámara estable. Actualmente, Feature Group admite HDR (HLG), 60 fps, estabilización de vista previa y Ultra HDR. Por ejemplo, puedes habilitar HDR, 60 fps y la estabilización de vista previa de forma simultánea en las series Pixel 10 y Galaxy S25. Se planean mejoras futuras para incluir la grabación en 4K y el zoom ultra gran angular. 

La API de Feature Group habilita dos casos de uso esenciales:

Caso de uso 1: Priorizar la mejor calidad

Si deseas capturar contenido con la mejor combinación posible de funciones, puedes proporcionar una lista priorizada. CameraX intentará habilitarlas en orden y seleccionará la primera combinación que el dispositivo admita por completo.

val sessionConfig = SessionConfig(
    useCases = listOf(preview, videoCapture),
    preferredFeatureGroup = listOf(
        GroupableFeature.HDR_HLG10,
        GroupableFeature.FPS_60,
        GroupableFeature.PREVIEW_STABILIZATION
    )
).apply {
    // (Optional) Get a callback with the enabled features to update your UI.
    setFeatureSelectionListener { selectedFeatures ->
        updateUiIndicators(selectedFeatures)
    }
}
processCameraProvider.bindToLifecycle(activity, cameraSelector, sessionConfig)

En este ejemplo, CameraX intenta habilitar las funciones en este orden:

  1. HDR + 60 FPS + Estabilización de vista previa
  2. HDR + 60 FPS
  3. HDR + Estabilización de vista previa
  4. HDR
  5. 60 FPS + Estabilización de vista previa
  6. 60 FPS
  7. Estabilización de vista previa
  8. Ninguno

Caso de uso 2: Compilar una IU de configuración orientada al usuario

Ahora puedes reflejar con precisión qué combinaciones de funciones se admiten en la IU de configuración de tu app, inhabilitando los botones de activación para opciones no compatibles, como la imagen que se muestra a continuación. 

unsupported-features-disabled.gif

Para determinar si se debe atenuar un botón de activación, usa los siguientes códigos para verificar la compatibilidad con la combinación de funciones. Inicialmente, consulta el estado de cada función individual. Una vez que se habilita una función, vuelve a consultar las funciones restantes con las funciones habilitadas para ver si sus botones de activación ahora deben atenuarse debido a restricciones de compatibilidad.

fun disableFeatureIfNotSuported(
   enabledFeatures: Set<GroupableFeature>,     
   featureToCheck:GroupableFeature
) {
 val sessionConfig = SessionConfig(
     useCases = useCases,
     requiredFeatureGroup = enabledFeatures + featureToCheck
 )
 val isSupported = cameraInfo.isFeatureGroupSupported(sessionConfig)

 if (!isSupported) {
     // disable the toggle for featureToCheck
 }
}

Consulta la entrada de blog de Feature Group para obtener más información. 

Más mejoras de video

  • Mejoras de la cámara simultánea: Con CameraX 1.5.1, ahora puedes vincular los casos de uso de Preview + ImageCapture + VideoCapture de forma simultánea para cada SingleCameraConfig en modo no de composición. Además, en el modo de composición (los mismos casos de uso con CompositionSettings),  ahora puedes establecer el CameraEffect que se aplica al resultado final de la composición.
  • Silenciamiento dinámico: Ahora puedes iniciar una grabación en estado silenciado con PendingRecording.withAudioEnabled(boolean initialMuted) y permitir que el usuario reactive el sonido más tarde con Recording.mute(boolean muted).
  • Manejo mejorado de almacenamiento insuficiente: CameraX ahora envía de forma confiable el error VideoRecordEvent.Finalize.ERROR_INSUFFICIENT_STORAGE, lo que permite que tu app controle correctamente las situaciones de almacenamiento bajo y le informe al usuario.
  • Mejora de luz baja: En dispositivos compatibles (como la serie Pixel 10), puedes habilitar CameraControl.enableLowLightBoostAsync para iluminar automáticamente la vista previa y las transmisiones de video en entornos oscuros.

Captura de imágenes de nivel profesional

CameraX 1.5 incluye actualizaciones importantes en ImageCapture para los desarrolladores que exigen la máxima calidad y flexibilidad.

Libera el control creativo con la captura DNG (RAW)

Para tener un control completo sobre el procesamiento posterior, CameraX ahora admite la captura DNG (RAW). Esto te da acceso a los datos de imagen sin procesar ni comprimir directamente desde el sensor de la cámara, lo que permite la edición y la gradación de color de nivel profesional. La API admite la captura del archivo DNG solo o la captura simultánea de salidas JPEG y DNG. Consulta el siguiente código de muestra para obtener información sobre cómo capturar archivos JPEG y DNG de forma simultánea.

val capabilities = ImageCapture.getImageCaptureCapabilities(cameraInfo)
val imageCapture = ImageCapture.Builder().apply {
    if (capabilities.supportedOutputFormats
             .contains(OUTPUT_FORMAT_RAW_JPEG)) {
        // Capture both RAW and JPEG formats.
        setOutputFormat(OUTPUT_FORMAT_RAW_JPEG)
    }
}.build()
// ... bind imageCapture to lifecycle ...


// Provide separate output options for each format.
val outputOptionRaw = /* ... configure for image/x-adobe-dng ... */
val outputOptionJpeg = /* ... configure for image/jpeg ... */
imageCapture.takePicture(
    outputOptionRaw,
    outputOptionJpeg,
    executor,
    object : ImageCapture.OnImageSavedCallback {
        override fun onImageSaved(results: OutputFileResults) {
            // This callback is invoked twice: once for the RAW file
            // and once for the JPEG file.
        }

        override fun onError(exception: ImageCaptureException) {}
    }
)

Ultra HDR para extensiones de cámara

Obtén lo mejor de ambos mundos: la impresionante fotografía computacional de las extensiones de cámara (como el modo nocturno) combinada con el color brillante y el rango dinámico de Ultra HDR. Esta función ahora es compatible con muchos teléfonos Android premium recientes, como las series Pixel 9/10 y Samsung S24/S25.

// Support UltraHDR when Extension is enabled. 

val extensionsEnabledCameraSelector = extensionsManager
     .getExtensionEnabledCameraSelector(
        CameraSelector.DEFAULT_BACK_CAMERA, ExtensionMode.NIGHT)

val imageCapabilities = ImageCapture.getImageCaptureCapabilities(
               cameraProvider.getCameraInfo(extensionsEnabledCameraSelector)

val imageCapture = ImageCapture.Builder()
     .apply {
       if (imageCapabilities.supportedOutputFormats
                .contains(OUTPUT_FORMAT_JPEG_ULTRA_HDR) {
           setOutputFormat(OUTPUT_FORMAT_JPEG_ULTRA_HDR)

       }

     }.build()

API central y mejoras de usabilidad

Una nueva forma de configurar: SessionConfig

Como se muestra en los ejemplos anteriores, SessionConfig es un concepto nuevo en CameraX 1.5. Centraliza la configuración y simplifica la API de dos maneras clave:

  1. No más llamadas unbind() manuales: Las APIs de CameraX reconocen el ciclo de vida. “Desvinculará” implícitamente tus casos de uso cuando se destruya la actividad o cualquier otro LifecycleOwner. Sin embargo, para actualizar los casos de uso o cambiar de cámara, debes llamar a unbind() o unbindAll() antes de volver a vincular. Ahora, con CameraX 1.5, cuando vinculas un nuevo SessionConfig, CameraX actualiza la sesión sin problemas, lo que elimina la necesidad de llamadas de desvinculación.
  2. Control determinista de la velocidad de fotogramas: La nueva API de SessionConfig presenta una forma determinista de administrar la velocidad de fotogramas. A diferencia del setTargetFrameRate anterior, que solo era una sugerencia, este nuevo método garantiza que se aplicará el rango de velocidad de fotogramas especificado cuando la configuración se realice correctamente. Para garantizar la precisión, debes consultar las velocidades de fotogramas admitidas con CameraInfo.getSupportedFrameRateRanges(SessionConfig). Cuando se pasa el SessionConfig completo, CameraX puede determinar con precisión los rangos admitidos según las configuraciones de transmisión.

Camera-Compose ahora es estable

Sabemos cuánto disfrutas de Jetpack Compose y nos complace anunciar que la camera-compose biblioteca ahora es estable en la versión 1.5.1! Esta versión incluye correcciones de errores críticos relacionados con el uso de CameraXViewfinder con funciones de Compose como moveableContentOf y Pager, además de resolver un problema de estiramiento de la vista previa. Seguiremos agregando más funciones a camera-compose en versiones futuras.

Mejoras de ImageAnalysis y CameraControl

  • Ajuste de la intensidad de la linterna: Obtén un control detallado sobre la linterna del dispositivo con las nuevas APIs. Puedes consultar la intensidad máxima admitida con CameraInfo.getMaxTorchStrengthLevel() y, luego, establecer el nivel deseado con CameraControl.setTorchStrengthLevel().
  • Compatibilidad con NV21 en ImageAnalysis: Ahora puedes solicitar el formato de imagen NV21 directamente desde ImageAnalysis, lo que simplifica la integración con otras bibliotecas y APIs. Para ello, invoca ImageAnalysis.Builder.setOutputImageFormat(OUTPUT_IMAGE_FORMAT_NV21).

Comienza hoy mismo

Actualiza tus dependencias a CameraX 1.5 hoy mismo y explora las nuevas y emocionantes funciones. Ya queremos ver tus ideas en acción.

Para usar CameraX 1.5,  agrega las siguientes dependencias a tu libs.versions.toml. (Te recomendamos que uses 1.5.1, que contiene muchas correcciones de errores críticos y mejoras de la cámara simultánea).

[versions]

camerax = "1.5.1"


[libraries]

..

androidx-camera-core = { module = "androidx.camera:camera-core", version.ref = "camerax" }

androidx-camera-compose = { module = "androidx.camera:camera-compose", version.ref = "camerax" }

androidx-camera-view = { module = "androidx.camera:camera-view", version.ref = "camerax" }

androidx-camera-lifecycle = { group = "androidx.camera", name = "camera-lifecycle", version.ref = "camerax" }

androidx-camera-camera2 = { module = "androidx.camera:camera-camera2", version.ref = "camerax" }

androidx-camera-extensions = { module = "androidx.camera:camera-extensions", version.ref = "camerax" }

Luego, agrégalas a las dependencias build.gradle.kts de tu módulo:

dependencies {

  ..

  implementation(libs.androidx.camera.core)
  implementation(libs.androidx.camera.lifecycle)

  implementation(libs.androidx.camera.camera2)

  implementation(libs.androidx.camera.view) // for PreviewView 
  implementation(libs.androidx.camera.compose) // for compose UI

  implementation(libs.androidx.camera.extensions) // For Extensions 

}

¿Tienes preguntas o quieres comunicarte con el equipo de CameraX? Únete al grupo de discusión para desarrolladores de CameraX o presenta un informe de errores:

Escrito por:

Seguir leyendo