Примечание. На этой странице рассматривается пакет Camera2. Если вашему приложению не требуются определенные низкоуровневые функции Camera2, рекомендуем использовать CameraX. CameraX и Camera2 поддерживают Android 5.0 (уровень API 21) и более поздние версии.
API Camera2 поддерживают съемку HDR-видео, что позволяет просматривать и записывать видеоконтент в формате HDR с помощью камеры. По сравнению со стандартным динамическим диапазоном (SDR), HDR предлагает более широкий диапазон цветов и увеличивает динамический диапазон компонента яркости (с текущих 100 кд/м2 до 1000 кд/м2). Это позволяет получить качество видео, которое более точно соответствует реальной жизни, с насыщенными цветами, яркими светлыми участками и глубокими тенями.
Посмотрите, как HDR-видео передает закат в более ярких деталях.
Требования к устройствам
Не все устройства Android поддерживают запись видео в формате HDR. Прежде чем записывать HDR-видео в приложении, убедитесь, что ваше устройство соответствует следующим требованиям:
- Целевой уровень API – 33 (Android 13).
- Устройство оснащено датчиком камеры с поддержкой 10-битного или более высокого разрешения. Подробнее о том, как проверить поддержку HDR…
Поскольку не все устройства соответствуют предварительным требованиям, вы можете добавить отдельный путь выполнения при настройке захвата HDR-видео в своем приложении. Это позволяет вашему приложению вернуться к SDR на несовместимых устройствах. Также рекомендуем добавить в интерфейс вариант SDR. После этого пользователь сможет переключаться между SDR и HDR при записи видео.
Архитектура съемки HDR
На следующей схеме показаны основные компоненты архитектуры HDR-съемки.
Когда камера снимает кадр в HDR, фреймворк Camera2 выделяет буфер, в котором хранятся обработанные данные с датчика камеры. При необходимости также добавляются метаданные HDR. Затем фреймворк Camera2 ставит заполненный буфер в очередь для выходной поверхности, указанной в CaptureRequest, например для дисплея или видеокодера, как показано на схеме.
Как проверить, поддерживается ли HDR
Прежде чем записывать HDR-видео в приложении, определите, поддерживает ли устройство выбранный профиль HDR.
Используйте метод CameraManager
getCameraCharacteristics(), чтобы получить экземпляр CameraCharacteristics, который можно запросить для получения информации о возможностях HDR вашего устройства.
Чтобы проверить, поддерживает ли устройство HLG10, выполните следующие действия: HLG10 – это базовый стандарт HDR, который производители устройств должны поддерживать на камерах с 10-битным выводом.
Сначала проверьте, поддерживает ли устройство 10-битные профили (глубина цвета для 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 }Затем проверьте, поддерживает ли устройство HLG10 или другой поддерживаемый профиль.
@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; }
Если устройство поддерживает HDR, isHLGSupported() всегда возвращает true. Подробную информацию можно найти в справочной документации по CameraCharacteristics.
Как настроить съемку в формате HDR
Убедившись, что ваше устройство поддерживает HDR, настройте приложение для захвата необработанного видеопотока HDR с камеры. Используйте setDynamicRangeProfile(), чтобы предоставить OutputConfiguration потока с поддерживаемым устройством профилем HDR, который затем передается в CameraCaptureSession при создании. Ознакомьтесь со списком поддерживаемых профилей HDR.
В приведенном ниже примере кода setupSessionDynamicRangeProfile() сначала проверяет, что на устройстве установлена ОС Android 13. Затем он настраивает CameraCaptureSession с профилем HDR, поддерживаемым устройством, как 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
}
}
Когда приложение камеры инициализирует камеру, оно отправляет повторяющийся запрос CaptureRequest для предварительного просмотра записи:
session.setRepeatingRequest(previewRequest, null, cameraHandler)
Чтобы начать запись видео, выполните следующие действия:
// 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)
Как закодировать видео с камеры в формате HDR
Чтобы закодировать видео с камеры в формате HDR и записать файл на диск, используйте MediaCodec.
Сначала получите выходной буфер Surface, в котором хранятся необработанные видеоданные. Для MediaCodec используйте createInputSurface().
Чтобы инициализировать MediaCodec, приложение должно создать MediaFormat с указанным профилем кодека, цветовым пространством, цветовым диапазоном и функцией передачи:
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)
Дополнительную информацию о реализации можно найти в файле EncoderWrapper.kt примера приложения Camera2Video.
Форматы HDR
Начиная с Android 13, камеры с возможностью 10-битного вывода должны поддерживать HLG10 для съемки и воспроизведения HDR. Кроме того, производители устройств могут включить любой формат HDR по своему выбору, используя архитектуру HDR-съемки.
В таблице ниже перечислены доступные форматы HDR и их возможности для записи HDR-видео.
| Формат | Передаточная функция (TF) | Метаданные | Кодек | Битовая глубина |
|---|---|---|---|---|
| HLG10 | HLG | Нет | HEVC | 10-битное видео |
| HDR10 | PQ | Статический | HEVC | 10-битное видео |
| HDR10+ | PQ | Динамическая | HEVC | 10-битное видео |
| Dolby Vision 8.4 | HLG | Динамическая | HEVC | 10-битное видео |
Ресурсы
Пример работающего приложения с функцией записи HDR-видео можно найти в репозитории Camera2Video на GitHub.