захват HDR-видео

Примечание: Эта страница относится к пакету Camera2 . Если вашему приложению не требуются специфические низкоуровневые функции Camera2, мы рекомендуем использовать CameraX . И CameraX, и Camera2 поддерживают Android 5.0 (уровень API 21) и выше.

API Camera2 поддерживают захват видео с расширенным динамическим диапазоном (HDR), что позволяет просматривать и записывать HDR-видеоконтент с помощью камеры. По сравнению со стандартным динамическим диапазоном (SDR), HDR предлагает более широкий диапазон цветов и увеличивает динамический диапазон компонента яркости (с текущих 100 кд/м² до тысяч кд/м²). Это приводит к качеству видео, более точно соответствующему реальной жизни, с более насыщенными цветами, более яркими бликами и более темными тенями.

Посмотрите, как HDR-видео запечатлевает закат в более ярких и детализированных кадрах.

Рисунок 1. Сравнение качества видео в режимах SDR (сверху) и HDR (снизу).

Требования к устройству

Не все устройства Android поддерживают запись HDR-видео. Прежде чем записывать HDR-видео в своем приложении, убедитесь, что ваше устройство соответствует следующим требованиям:

  • Предназначен для Android 13 (уровень API 33).
  • Имеет датчик камеры с поддержкой 10-битной или более высокой четкости. Для получения дополнительной информации о поддержке HDR см. раздел «Проверка поддержки HDR» .

Поскольку не все устройства соответствуют необходимым требованиям, вы можете добавить отдельный путь выполнения кода при настройке захвата HDR-видео в вашем приложении. Это позволит вашему приложению переключаться на SDR на несовместимых устройствах. Также рассмотрите возможность добавления опции пользовательского интерфейса для SDR. Пользователь сможет переключаться между SDR и HDR в зависимости от своих потребностей в видеозаписи.

архитектура захвата HDR

На следующей диаграмме показаны основные компоненты архитектуры захвата HDR-изображений.

Схема архитектуры захвата HDR.
Рисунок 2. Схема архитектуры захвата HDR.

Когда камера захватывает кадр в режиме HDR, платформа Camera2 выделяет буфер для хранения обработанного выходного сигнала датчика камеры. Она также добавляет соответствующие метаданные HDR, если это требуется профилем HDR. Затем платформа Camera2 ставит заполненный буфер в очередь для выходной поверхности, указанной в запросе CaptureRequest , например, дисплея или видеокодера, как показано на диаграмме.

Проверьте наличие поддержки HDR.

Перед записью HDR-видео в приложении убедитесь, что устройство поддерживает желаемый HDR-профиль.

Используйте метод ` getCameraCharacteristics() ` CameraManager , чтобы получить экземпляр CameraCharacteristics , из которого можно запросить информацию о возможностях HDR вашего устройства.

Следующие шаги проверяют, поддерживает ли устройство HLG10. HLG10 — это базовый стандарт HDR, который производители устройств обязаны поддерживать на камерах с 10-битным выводом.

  1. Для начала проверьте, поддерживает ли устройство 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
    }
  2. Далее проверьте, поддерживает ли устройство профиль 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 desired 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,
      handler: Handler? = null,
      stateCallback: CameraCaptureSession.StateCallback
  ): Boolean {
      if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
          val outputConfigs = mutableListOf()
          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 .

Сначала получите OutputSurface , который соответствует буферу, хранящему необработанные видеоданные. Для 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-видео.

Формат Передаточная функция (ПФ) Метаданные Кодек Глубина бита
HLG10 HLG Нет HEVC 10-битный
HDR10 ПК Статический HEVC 10-битный
HDR10+ ПК Динамический HEVC 10-битный
Dolby Vision 8.4 HLG Динамический HEVC 10-битный

Ресурсы

Рабочий пример приложения с функцией захвата HDR-видео можно найти на GitHub в демонстрационном проекте Camera2Video .