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 à 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 uma qualidade do vídeo que se aproxima mais da vida real, com cores mais ricas, realces mais brilhantes e sombras mais escuras.

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

Um pôr do sol capturado com qualidade de vídeo SDR Um pôr do sol capturado em qualidade de vídeo HDR
Figura 1. Comparação da qualidade do vídeo SDR (superior) com HDR (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 HDR no seu app, determine se o dispositivo atende aos seguintes pré-requisitos:

  • É destinado ao Android 13 (nível 33 da API).
  • Ter um sensor de câmera de 10 bits ou mais. Para mais informações sobre a compatibilidade com HDR, consulte Verificar a compatibilidade com 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 use o SDR em dispositivos incompatíveis. Além disso, considere adicionar uma opção de IU 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 da 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 coloca o buffer preenchido na fila para a superfície de saída referenciada no CaptureRequest, como uma tela ou um codificador de vídeo, conforme mostrado no diagrama.

Verificar a compatibilidade com HDR

Antes de capturar vídeos HDR no seu app, determine se o dispositivo é compatível com o perfil HDR escolhido.

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

As etapas a seguir verificam se um dispositivo é compatível com HLG10. HLG10 é o padrão HDR básico que os fabricantes de dispositivos precisam oferecer 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):

    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):

    @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 chosen profile, in this case HLG10
        return availableProfiles.contains(DynamicRangeProfiles.HLG10)
      }
      return false;
    }
    

Se o dispositivo for compatível com HDR, isHLGSupported() sempre vai retornar true. Para mais informações, consulte a documentação de referência do CameraCharacteristics.

Configurar a captura HDR

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

No exemplo de código abaixo, 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:

  /**
   * Creates a [CameraCaptureSession] with a dynamic range profile.
   */
  private fun setupSessionWithDynamicRangeProfile(
      dynamicRange: Long,
      device: CameraDevice,
      targets: List<Surface>,
      handler: Handler? = null,
      stateCallback: CameraCaptureSession.StateCallback
  ): Boolean {
      if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
          val outputConfigs = mutableListOf<OutputConfiguration>()
          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 uma CaptureRequest repetida para visualizar a gravação:

session.setRepeatingRequest(previewRequest, null, cameraHandler)

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

// 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 Surface de saída, que é mapeado para um buffer que armazena dados de vídeo brutos. Para MediaCodec, use createInputSurface().

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

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 EncoderWrapper.kt do app de exemplo Camera2Video.

Formatos HDR

No Android 13 e versões mais recentes, os dispositivos de câmera com recursos de saída de 10 bits precisam oferecer suporte ao HLG10 para captura e reprodução em HDR. 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
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 ver um app funcional com o recurso de captura de vídeo HDR, consulte o exemplo Camera2Video no GitHub.