Captura de vídeo HDR

Observação:esta página se refere ao pacote Camera2. A menos que seu app exija recursos específicos e 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 à captura de vídeo em 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, na sigla em inglês), 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 uma qualidade de vídeo que se aproxima mais da vida real, com cores mais vivas, destaques mais brilhantes e sombras mais escuras.

Confira como vídeos em HDR capturam um pôr do sol com mais detalhes.

Figura 1. Comparação da qualidade de vídeo entre SDR (parte superior) e HDR (parte inferior).

Pré-requisitos do dispositivo

Nem todos os dispositivos Android são compatíveis com a captura de vídeo HDR. Antes de capturar vídeos em HDR no seu app, verifique se o dispositivo atende aos seguintes pré-requisitos:

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

Como nem todos os dispositivos atendem aos pré-requisitos, é possível adicionar um caminho de código separado ao configurar a captura de vídeo HDR no app. Isso permite que o app use 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 de acordo com 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 da arquitetura de captura em HDR.
Figura 2. Diagrama da arquitetura de captura em 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 respectivos metadados HDR, se exigido pelo perfil de HDR. O framework do Camera2 coloca o buffer preenchido para a superfície de saída referenciada em CaptureRequest, como um codificador de tela ou vídeo, conforme mostrado no diagrama.

Conferir a compatibilidade com HDR

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

Use o método CameraManager getCameraCharacteristics() para acessar uma instância CameraCharacteristics, que pode ser consultada sobre os recursos HDR do dispositivo.

As etapas a seguir verificam se um dispositivo é compatível com HLG10. HLG10 é o padrão HDR de referência com 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 é compatível com 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 tiver suporte a HDR, o isHLGSupported() sempre retornará true. Para mais informações, consulte a documentação de referência CameraCharacteristics.

Configurar a captura HDR

Depois de garantir que o dispositivo ofereça suporte a HDR, configure o app para capturar um stream de vídeo em HDR bruto da câmera. Use setDynamicRangeProfile() para fornecer ao OutputConfiguration da transmissão um perfil HDR compatível com o dispositivo, que será transmitido para o CameraCaptureSession durante a criação. Veja a lista de perfis HDR compatíveis.

No exemplo de código abaixo, o setupSessionDynamicRangeProfile() primeiro verifica se o dispositivo está executando o Android 13. Em seguida, ele configura o CameraCaptureSession com o perfil HDR compatível com o dispositivo como um 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 inicializa a câmera, ele envia um CaptureRequest repetitivo para visualizar a gravação:

Kotlin

session.setRepeatingRequest(previewRequest, null, cameraHandler)

Para iniciar a gravação do 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, acesse o OutputSurface, que é mapeado para um buffer que armazena dados brutos de vídeo. Para MediaCodec, use createInputSurface().

Para inicializar MediaCodec, um app precisa criar uma 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 saber mais sobre a implementação, consulte a EncoderWrapper.kt do app de exemplo Camera2Video.

Formatos HDR

No Android 13 e versões mais recentes, dispositivos de câmera com recursos de saída de 10 bits precisam oferecer suporte a HLG10 para captura HDR e reprodução. Além disso, os fabricantes de dispositivos podem ativar qualquer formato HDR que quiserem usando a arquitetura de captura HDR.

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

Formato Função de transferência (TF) Metadados Codec Profundidade de bit
Hl 10 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 a funcionalidade de captura de vídeo HDR, consulte o exemplo Camera2Video no GitHub (link em inglês).