Novedades de productos

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

Lectura de 7 min
Ver el perfil de Scott Nien
Scott Nien Ingeniero de software

El equipo de CameraX se complace en anunciar el lanzamiento de la versión 1.5. Esta actualización se enfoca en poner funciones de nivel profesional al alcance de tu mano y, al mismo tiempo, facilitar la configuración de la sesión de la cámara como nunca antes.

En cuanto a la grabación de videos, ahora los usuarios pueden capturar sin esfuerzo videos increíbles en cámara lenta o con una alta velocidad de fotogramas. Y 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 todos 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 las potentes extensiones de la cámara.

La base de estas funciones es la nueva API de SessionConfig, que optimiza la configuración y la reconfiguración de la cámara. Ahora, analicemos 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.

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

Ya está disponible una de nuestras funciones más esperadas: los videos en cámara lenta. 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 velocidad de fotogramas alta para producir videos excepcionalmente fluidos.

La implementación es sencilla si conoces la API de VideoCapture.

1. Verifica la compatibilidad con alta velocidad: Usa el nuevo método Recorder.getHighSpeedVideoCapabilities() 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, se grabarán videos con una alta velocidad de fotogramas. El último paso 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 capacidad y habilita la grabación de alta velocidad solo en los dispositivos compatibles para evitar una mala experiencia del usuario. Actualmente, esta función es compatible con las cámaras posteriores de casi todos los dispositivos Pixel y algunos modelos de otros fabricantes.

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

Combina atributos con confianza: la API de Feature Group

CameraX 1.5 presenta la API de Feature Group, que elimina las conjeturas sobre la compatibilidad de las funciones. Según la API de consulta de combinación de funciones de Android 15, ahora puedes habilitar varias funciones juntas con confianza, lo que garantiza una sesión de cámara estable. Actualmente, el grupo de funciones 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 la vista previa de forma simultánea en las series Pixel 10 y Galaxy S25. Se planea incluir mejoras futuras, como la grabación en 4K y el zoom ultra gran angular. 

La API de grupos de funciones habilita dos casos de uso esenciales:

Caso de uso 1: Priorizar la mejor calidad

Si deseas capturar 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 y estabilización de la vista previa
  4. HDR
  5. 60 FPS y estabilización de la vista previa
  6. 60 FPS
  7. Estabilización de versión preliminar
  8. Ninguno

Caso de uso 2: Compila una IU de configuración para el 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 las opciones no admitidas, como se muestra en la siguiente imagen. 

unsupported-features-disabled.gif

Para determinar si se debe inhabilitar 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 interruptores ahora deben estar inhabilitados 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 sobre los grupos de funciones para obtener más información. 

Más mejoras de video

  • Mejoras en la cámara simultánea: Con CameraX 1.5.1, ahora puedes vincular los casos de uso de Preview, ImageCapture y VideoCapture de forma simultánea para cada SingleCameraConfig en el modo sin composición. Además, en el modo de redacció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 active el sonido más tarde con Recording.mute(boolean muted).
  • Mejoras en el manejo de almacenamiento insuficiente: Ahora, CameraX envía de forma confiable el error VideoRecordEvent.Finalize.ERROR_INSUFFICIENT_STORAGE, lo que permite que tu app controle correctamente las situaciones de poco almacenamiento y se lo informe al usuario.
  • Mejorador con poca luz: En los dispositivos compatibles (como la serie Pixel 10), puedes habilitar CameraControl.enableLowLightBoostAsync para iluminar automáticamente las transmisiones de video y la vista previa 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 en DNG (RAW)

Para tener un control total sobre el procesamiento posterior, CameraX ahora admite la captura en DNG (RAW). Esto te brinda acceso a los datos de imagen sin procesar ni comprimir directamente desde el sensor de la cámara, lo que permite realizar ediciones y correcciones 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 ver 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 las extensiones de la cámara

Obtén lo mejor de ambos mundos: la impresionante fotografía computacional de las extensiones de la 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 y 10, y las series Samsung S24 y 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()

Mejoras de la API principal y de usabilidad

Una nueva forma de configurar: SessionConfig

Como se ve 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 manuales a unbind(): Las APIs de CameraX están optimizadas para el ciclo de vida. De forma implícita, “desvinculará” 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 realizar llamadas de desvinculación.
  2. Control determinístico de la velocidad de fotogramas: La nueva API de SessionConfig presenta una forma determinística 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 después de una configuración correcta. Para garantizar la precisión, debes consultar las velocidades de fotogramas compatibles con CameraInfo.getSupportedFrameRateRanges(SessionConfig). Si pasas 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 biblioteca camera-compose 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 las próximas versiones.

Mejoras en ImageAnalysis y CameraControl

  • Ajuste de la intensidad de la linterna: Obtén un control detallado de 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. Esto se habilita invocando 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 archivo libs.versions.toml. (Recomendamos usar la versión 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, agrega lo siguiente a las dependencias de 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 de desarrolladores de CameraX o envía un informe de errores:

Escrito por:
Continuar leyendo