HDR 视频拍摄

注意:本页介绍的是 Camera2 软件包。除非您的应用需要 Camera2 中的特定低级功能,否则我们建议您使用 CameraX。CameraX 和 Camera2 都支持 Android 5.0(API 级别 21)及更高版本。

Camera2 API 支持 高动态范围 (HDR) 视频拍摄,可让您预览并 使用相机录制 HDR 视频内容。与标准动态相比 范围 (SDR)、HDR 提供的色彩范围更广 亮度分量的范围(从当前的 100 cd/m2 到 1000 cd/m2)。 这样生成的视频质量更接近真实情况, 更丰富的色彩、更明亮的高光和更深的阴影。

看看 HDR 视频如何以更鲜艳的细节展现日落美景。

<ph type="x-smartling-placeholder">
</ph>
图 1.SDR(顶部)与 HDR(底部)视频质量的比较。

设备前提条件

并非所有 Android 设备都支持 HDR 视频拍摄。 在应用中拍摄 HDR 视频之前,请先确定您的设备是否符合 以下前提条件:

  • 以 Android 13(API 级别 33)为目标平台。
  • 具有支持 10 位或更高级别的相机传感器。如需详细了解 HDR, 有关是否支持,请参阅检查 HDR 支持情况

由于并非所有设备都满足前提条件,因此您可以单独添加代码 路径。 这样一来,您的应用便可以在不兼容的设备上回退到 SDR。 此外,请考虑为 SDR 添加界面选项。然后,用户可以 SDR 和 HDR 之间的联系,以满足他们的视频录制需求。

HDR 拍摄架构

下图显示了 HDR 拍摄架构的主要组件。

HDR 拍摄架构图。
图 2. HDR 拍摄架构图。

当相机设备以 HDR 格式拍摄帧时,Camera2 框架会分配 用于存储处理的相机传感器输出的缓冲区。 如果 HDR 配置文件需要,它还会附加相应的 HDR 元数据。 然后,Camera2 框架会将已填充的缓冲区加入输出 Surface 的队列 CaptureRequest 中引用,例如 display 或 如图所示。

检查是否支持 HDR

在应用中拍摄 HDR 视频之前,请先确定设备是否支持 设置所需的 HDR 配置文件

使用 CameraManager getCameraCharacteristics() 方法获取 CameraCharacteristics 您可以查询设备的 HDR 功能。

以下步骤用于检查设备是否支持 HLG10。 HLG10 是设备制造商必须支持的基准 HDR 标准 在具有 10 位输出的相机上。

  1. 首先,检查设备是否支持 10 位配置文件(HLG10 的位深):

    Kotlin

    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(或其他受支持的配置文件):

    Kotlin

    @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 然后向该配置文件传递 发送至CameraCaptureSession 。 请参阅支持的 HDR 配置文件列表

在以下代码示例中,setupSessionDynamicRangeProfile() 首先检查 确认设备搭载的是 Android 13。 然后,它会使用设备支持的 CameraCaptureSession 设置 HDR 配置文件,如 OutputConfiguration

Kotlin

  /**
  * 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 预览录制内容:

Kotlin

session.setRepeatingRequest(previewRequest, null, cameraHandler)

此外,要开始录制视频,请执行以下操作:

Kotlin

// 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,其中包含指定的 编解码器配置文件、颜色空间、颜色范围和转换函数:

Kotlin

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)

有关实现的详情,请参见 Camera2Video 示例应用的 EncoderWrapper.kt

HDR 格式

从 Android 13 开始,具有 10 位输出功能的相机设备 必须支持 HLG10 进行 HDR 拍摄,并且 playback(播放)。 此外,设备制造商可以启用他们选择的任何 HDR 格式 使用 HDR 拍摄架构

下表总结了可用的 HDR 格式及其功能 。

格式 传递函数 (TF) 元数据 编解码器 位元深度
HLG10 HLG HEVC 10 位
HDR10 PQ 静态 HEVC 10 位
HDR10+ PQ 动态 HEVC 10 位
杜比视界 8.4 HLG 动态 HEVC 10 位

资源

如需了解具有 HDR 视频拍摄功能且能正常运行的应用,请参阅 Camera2Video 示例