Примечание. На этой странице рассматривается пакет Camera2. Если вашему приложению не требуются определенные низкоуровневые функции Camera2, рекомендуем использовать CameraX. Обе библиотеки поддерживают 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) ?: return false 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) ?: false } 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.