Captura de vídeo HDR

Observação: esta página se refere ao pacote Camera2. A menos que seu app exija recursos específicos de baixo nível do Camera2, recomendamos o uso do CameraX. CameraX e Camera2 oferecem suporte ao Android 5.0 (nível 21 da API) e versões mais recentes.

As APIs Camera2 oferecem suporte a captura de vídeo High Dynamic Range (HDR), o que permite visualizar e gravar conteúdo de vídeo em HDR usando a câmera. Em comparação com o intervalo dinâmico padrão (SDR), o HDR oferece uma variedade maior de cores e aumenta o intervalo dinâmico do componente de luminância (dos 100 cd/m2 atuais para 1.000 s de cd/m2). Isso resulta em qualidade de vídeo que se aproxima mais da vida real, com cores mais ricas, realces mais brilhantes e sombras mais escuras.

Saiba como o vídeo HDR captura um pôr do sol com detalhes mais vibrantes.

Figura 1. Comparação da qualidade de vídeo SDR (acima) e HDR (abaixo).

Pré-requisitos do dispositivo

Nem todos os dispositivos Android oferecem suporte à captura de vídeo HDR. Antes de capturar vídeo HDR no seu app, determine se o dispositivo atende aos seguintes pré-requisitos:

  • Tem como destino o Android 13 (nível 33 da API).
  • Tem um sensor de câmera de 10 bits ou mais. Para mais informações sobre o suporte a HDR, consulte Verificar o suporte a HDR.

Como nem todos os dispositivos atendem aos pré-requisitos, você pode adicionar um caminho de código separado ao configurar a captura de vídeo HDR no seu app. Isso permite que o app volte para SDR em dispositivos incompatíveis. Além disso, considere adicionar uma opção de interface para SDR. O usuário pode alternar entre SDR e HDR para as necessidades de gravação de vídeo.

Arquitetura de captura HDR

O diagrama a seguir mostra os principais componentes da arquitetura de captura HDR.

Diagrama de arquitetura de captura HDR.
Figura 2. Diagrama de arquitetura de captura HDR.

Quando um dispositivo de câmera captura um frame em HDR, o framework Camera2 aloca um buffer que armazena a saída processada do sensor da câmera. Ele também anexa os metadados HDR respectivos, se exigido pelo perfil HDR. Em seguida, o framework Camera2 enfileira o buffer preenchido para a superfície de saída referenciada no CaptureRequest, como um display ou codificador de vídeo, conforme mostrado no diagrama.

Verificar o suporte a HDR

Antes de capturar vídeo HDR no seu app, determine se o dispositivo oferece suporte ao perfil HDR desejado.

Use o método CameraManager getCameraCharacteristics() para receber uma CameraCharacteristics instância, que pode ser consultada para as capacidades HDR do dispositivo.

As etapas a seguir verificam se um dispositivo oferece suporte a HLG10. HLG10 é o padrão HDR de linha de base que os fabricantes de dispositivos precisam oferecer suporte em câmeras com saída de 10 bits.

  1. Primeiro, verifique se o dispositivo oferece suporte a perfis de 10 bits (a profundidade 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. Em seguida, verifique se o dispositivo oferece suporte a HLG10 (ou outro perfil compatível):

    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;
    }

Se o dispositivo oferece suporte a HDR, isHLGSupported() sempre retorna true. Para mais informações, consulte a CameraCharacteristics documentação de referência.

Configurar a captura HDR

Depois de garantir que o dispositivo oferece suporte a HDR, configure o app para capturar um stream de vídeo HDR bruto da câmera. Use setDynamicRangeProfile() para fornecer o OutputConfiguration do stream com um perfil HDR compatível com o dispositivo, que é transmitido para a CameraCaptureSession após a criação. Consulte a lista de perfis HDR compatíveis.

No exemplo de código a seguir, setupSessionDynamicRangeProfile() primeiro verifica se o dispositivo está executando o Android 13. Em seguida, ele configura a CameraCaptureSession com o perfil HDR compatível com o dispositivo como uma 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
      }
  }
  

Quando o app de câmera inicializa a câmera, ele envia um repetido CaptureRequest para visualizar a gravação:

Kotlin

session.setRepeatingRequest(previewRequest, null, cameraHandler)

E também para iniciar a gravação de vídeo:

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)

Codificar o stream da câmera HDR

Para codificar o stream da câmera HDR e gravar o arquivo no disco, use MediaCodec.

Primeiro, receba a OutputSurface, que é mapeada para um buffer que armazena dados de vídeo brutos. Para MediaCodec, use createInputSurface().

Para inicializar MediaCodec, um app precisa criar um MediaFormat com um perfil de codec, espaço de cor, intervalo de cores e função de transferência especificados:

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 mais detalhes sobre a implementação, consulte o app de exemplo Camera2Video EncoderWrapper.kt.

Formatos HDR

A partir do Android 13, os dispositivos de câmera com recursos de saída de 10 bits precisam oferecer suporte a HLG10 para captura e reprodução de HDR. Além disso, os fabricantes de dispositivos podem ativar qualquer formato HDR de sua escolha usando a arquitetura de captura HDR.

A tabela a seguir resume os formatos HDR disponíveis e seus recursos para captura de vídeo HDR.

Formato Função de transferência (TF, na sigla em inglês) Metadados Codec Profundidade de bit
HLG10 HLG Não HEVC 10 bits
HDR10 PQ Estático HEVC 10 bits
HDR10+ PQ Dinâmico HEVC 10 bits
Dolby Vision 8.4 HLG Dinâmico HEVC 10 bits

Recursos

Para um app funcional com funcionalidade de captura de vídeo HDR, consulte o exemplo Camera2Video no GitHub.