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.
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, é 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 o 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.
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 plataforma de saída referenciada no
CaptureRequest, como uma tela ou um codificador de
vídeo, conforme mostrado no diagrama.
Verificar se há suporte para 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.
Primeiro, verifique se o dispositivo é compatível com 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) ?: return false for (capability in availableCapabilities) { if (capability == CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT) { return true } } return false }
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) ?: false } 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 solicitação 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, 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 ver um app de trabalho com o recurso de captura de vídeo HDR, consulte o exemplo Camera2Video no GitHub.