Captura de video HDR

Nota: En esta página, se hace referencia al paquete Camera2. A menos que tu app requiera funciones específicas y de bajo nivel de Camera2, te recomendamos usar CameraX. CameraX y Camera2 admiten Android 5.0 (nivel de API 21) y versiones posteriores.

Las APIs de Camera2 admiten la captura de video de alto rango dinámico (HDR), que te permite obtener una vista previa y grabar contenido de video HDR con la cámara. En comparación con el rango dinámico estándar (SDR), HDR ofrece un rango de colores más amplio y aumenta el rango dinámico del componente de luminancia (de los 100 cd/m2 actuales a miles de cd/m2). Esto da como resultado una calidad de video que se ajusta más a la vida real, con colores más vivos, zonas brillantes más brillantes y sombras más oscuras.

Mira cómo los videos HDR capturan un atardecer con más detalle.

Figura 1: Comparación de la calidad de video SDR (superior) y HDR (inferior).

Requisitos previos del dispositivo

No todos los dispositivos Android admiten la captura de videos HDR. Antes de capturar videos HDR en tu app, determina si tu dispositivo cumple con los siguientes requisitos previos:

  • Se orienta a Android 13 (nivel de API 33).
  • Tener un sensor de la cámara con una capacidad de 10 bits o superior Para obtener más información sobre la compatibilidad con HDR, consulta Cómo comprobar la compatibilidad con HDR.

Debido a que no todos los dispositivos cumplen con los requisitos previos, puedes agregar una ruta de código separada cuando configuras la captura de video HDR en tu app. Esto permite que la app recurra a SDR en dispositivos no compatibles. Además, considera agregar una opción de IU para SDR. Luego, el usuario puede alternar entre SDR y HDR según sus necesidades de grabación de video.

Arquitectura de captura HDR

En el siguiente diagrama, se muestran los componentes principales de la arquitectura de captura HDR.

Diagrama de arquitectura de captura HDR.
Figura 2: Diagrama de arquitectura de captura HDR.

Cuando un dispositivo de cámara captura un fotograma en HDR, el framework de Camera2 asigna un búfer que almacena el resultado procesado del sensor de la cámara. También adjunta los metadatos HDR correspondientes si el perfil HDR lo requiere. Luego, el framework de Camera2 pone en cola el búfer propagado para la superficie de salida a la que se hace referencia en CaptureRequest, como un codificador de pantalla o video, como se muestra en el diagrama.

Cómo comprobar la compatibilidad con HDR

Antes de capturar videos HDR en tu app, determina si el dispositivo es compatible con el perfil HDR deseado.

Usa el método CameraManager getCameraCharacteristics() para obtener una instancia de CameraCharacteristics, que puedes consultar sobre las capacidades de HDR de tu dispositivo.

Los siguientes pasos permiten verificar si un dispositivo es compatible con HLG10. HLG10 es el estándar HDR de referencia que los fabricantes de dispositivos deben admitir en las cámaras con salida de 10 bits.

  1. Primero, verifica si el dispositivo es compatible con perfiles de 10 bits (la profundidad de bits para HLG10):

    Kotlin

    private fun isTenBitProfileSupported(cameraId: String): Boolean {
      val cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId)
      val availableCapabilities = cameraCharacteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES)
      for (capability in availableCapabilities!!) {
          if (capability == CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT) {
              return true
          }
      }
      return false
    }
    
  2. A continuación, comprueba si el dispositivo es compatible con HLG10 (o otro perfil compatible):

    Kotlin

    @RequiresApi(api = 33)
    private fun isHLGSupported(cameraId: String): Boolean {
    if (isTenBitProfileSupported(cameraId)) {
      Val cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId)
      val availableProfiles = cameraCharacteristics
      .get(CameraCharacteristics.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES)!!
      .getSupportedProfiles()
    
      // Checks for the desired profile, in this case HLG10
      return availableProfiles.contains(DynamicRangeProfiles.HLG10)
    }
    return false;
    }
    

Si el dispositivo admite HDR, isHLGSupported() siempre muestra true. Para obtener más información, consulta la documentación de referencia de CameraCharacteristics.

Configurar captura HDR

Después de asegurarte de que el dispositivo sea compatible con HDR, configura la app para que capture una transmisión de video HDR sin procesar desde la cámara. Usa setDynamicRangeProfile() para proporcionar al OutputConfiguration de la transmisión un perfil HDR compatible con el dispositivo, que luego se pasa a CameraCaptureSession cuando se crea. Consulta la lista de perfiles HDR compatibles.

En la siguiente muestra de código, setupSessionDynamicRangeProfile() primero verifica que el dispositivo ejecute Android 13. Luego, configura el CameraCaptureSession con el perfil HDR compatible con el dispositivo como OutputConfiguration:

Kotlin

  /**
  * Creates a [CameraCaptureSession] with a dynamic range profile.
  */
  private fun setupSessionWithDynamicRangeProfile(
          dynamicRange: Long,
          device: CameraDevice,
          targets: List,
          handler: Handler? = null,
          stateCallback: CameraCaptureSession.StateCallback
  ): Boolean {
      if (android.os.Build.VERSION.SDK_INT >=
              android.os.Build.VERSION_CODES.TIRAMISU) {
          val outputConfigs = mutableListOf()
              for (target in targets) {
                  val outputConfig = OutputConfiguration(target)
                  //sets the dynamic range profile, for example DynamicRangeProfiles.HLG10
                  outputConfig.setDynamicRangeProfile(dynamicRange)
                  outputConfigs.add(outputConfig)
              }

          device.createCaptureSessionByOutputConfigurations(
                  outputConfigs, stateCallback, handler)
          return true
      } else {
          device.createCaptureSession(targets, stateCallback, handler)
          return false
      }
  }

}

Cuando la app de la cámara inicializa la cámara, envía una CaptureRequest repetitiva para obtener una vista previa de la grabación:

Kotlin

session.setRepeatingRequest(previewRequest, null, cameraHandler)

También debes hacer lo siguiente para comenzar la grabación de video:

Kotlin

// Start recording repeating requests, which stops the ongoing preview
//  repeating requests without having to explicitly call
//  `session.stopRepeating`
session.setRepeatingRequest(recordRequest,
        object : CameraCaptureSession.CaptureCallback() {
    override fun onCaptureCompleted(session: CameraCaptureSession,
            request: CaptureRequest, result: TotalCaptureResult) {
        if (currentlyRecording) {
            encoder.frameAvailable()
        }
    }
}, cameraHandler)

Codifica la transmisión de la cámara HDR

Para codificar la transmisión de la cámara HDR y escribir el archivo en el disco, usa MediaCodec.

Primero, obtén el OutputSurface, que se asigna a un búfer que almacena datos de video sin procesar. Para MediaCodec, usa createInputSurface().

Para inicializar MediaCodec, una app debe crear un objeto MediaFormat con un perfil de códec, un espacio de color, un rango de colores y una función de transferencia específicos:

Kotlin

val mimeType = when {
    dynamicRange == DynamicRangeProfiles.STANDARD -> MediaFormat.MIMETYPE_VIDEO_AVC
    dynamicRange < DynamicRangeProfiles.PUBLIC_MAX ->
            MediaFormat.MIMETYPE_VIDEO_HEVC
    else -> throw IllegalArgumentException("Unknown dynamic range format")
}

val codecProfile = when {
    dynamicRange == DynamicRangeProfiles.HLG10 ->
            MediaCodecInfo.CodecProfileLevel.HEVCProfileMain10
    dynamicRange == DynamicRangeProfiles.HDR10 ->
            MediaCodecInfo.CodecProfileLevel.HEVCProfileMain10HDR10
    dynamicRange == DynamicRangeProfiles.HDR10_PLUS ->
            MediaCodecInfo.CodecProfileLevel.HEVCProfileMain10HDR10Plus
    else -> -1
}
// Failing to correctly set color transfer causes quality issues
// for example, washout and color clipping
val transferFunction = when (codecProfile) {
    MediaCodecInfo.CodecProfileLevel.HEVCProfileMain10 ->
            MediaFormat.COLOR_TRANSFER_HLG
    MediaCodecInfo.CodecProfileLevel.HEVCProfileMain10HDR10 ->
            MediaFormat.COLOR_TRANSFER_ST2084
    MediaCodecInfo.CodecProfileLevel.HEVCProfileMain10HDR10Plus ->
            MediaFormat.COLOR_TRANSFER_ST2084
    else -> MediaFormat.COLOR_TRANSFER_SDR_VIDEO
}

val format = MediaFormat.createVideoFormat(mimeType, width, height)

// Set some properties.  Failing to specify some of these can cause the MediaCodec
// configure() call to throw an exception.
format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
        MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface)
format.setInteger(MediaFormat.KEY_BIT_RATE, bitRate)
format.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate)
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL)

if (codecProfile != -1) {
    format.setInteger(MediaFormat.KEY_PROFILE, codecProfile)
    format.setInteger(MediaFormat.KEY_COLOR_STANDARD,
            MediaFormat.COLOR_STANDARD_BT2020)
    format.setInteger(MediaFormat.KEY_COLOR_RANGE, MediaFormat.COLOR_RANGE_LIMITED)
    format.setInteger(MediaFormat.KEY_COLOR_TRANSFER, transferFunction)
    format.setFeatureEnabled(MediaCodecInfo.CodecCapabilities.FEATURE_HdrEditing,
            true)
}

mediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)

Para obtener más detalles sobre la implementación, consulta el EncoderWrapper.kt de la app de ejemplo de Camera2Video.

Formatos HDR

A partir de Android 13, los dispositivos de cámara con capacidades de salida de 10 bits deben admitir HLG10 para la captura y la reproducción HDR. Además, los fabricantes de dispositivos pueden habilitar cualquier formato HDR de su elección con la arquitectura de captura HDR.

En la siguiente tabla, se resumen los formatos HDR disponibles y sus capacidades para la captura de video HDR.

Formato Función de transferencia (TF) Metadatos Códec Profundidad de bits
HLG10 HLG No HEVC 10 bits
HDR10 Pregunta de calidad Estático HEVC 10 bits
HDR10+ Pregunta de calidad Dinámico HEVC 10 bits
Dolby Vision 8.4 HLG Dinámico HEVC 10 bits

Recursos

Para ver una app que funcione con la función de captura de video HDR, consulta el ejemplo de Camera2Video en GitHub.