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, 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.
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.
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 }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.