HDR 影片擷取

注意:本頁面所述是指 Camera2 套件。除非應用程式需要 Camera2 的特定低階功能,否則建議使用 CameraX。CameraX 和 Camera2 均支援 Android 5.0 (API 級別 21) 以上版本。

Camera2 API 支援高動態範圍 (HDR) 影片拍攝功能,讓您使用相機預覽及錄製 HDR 影片內容。相較於標準動態範圍 (SDR),HDR 提供更廣泛的色彩範圍,並增加亮度元素的動態範圍 (從目前的 100 cd/m2 提高至 1000s cd/m2)。這項技術可呈現更豐富的色彩、更明亮的亮部和更深沉的陰影,讓影片畫質更貼近現實。

看看 HDR 影片如何捕捉日落的鮮豔細節。

圖 1. SDR (上) 與 HDR (下) 影片畫質比較。

裝置必要條件

並非所有 Android 裝置都支援 HDR 影片拍攝功能。 在應用程式中拍攝 HDR 影片前,請先確認裝置是否符合下列必要條件:

  • 以 Android 13 (API 級別 33) 為目標版本。
  • 搭載支援 10 位元以上的相機感應器。如要進一步瞭解 HDR 支援情形,請參閱「確認 HDR 支援情形」。

由於並非所有裝置都符合必要條件,因此在應用程式中設定 HDR 影片擷取功能時,您可以新增個別的程式碼路徑。這樣一來,應用程式就能在不相容的裝置上改用 SDR。此外,也建議新增 SDR 的 UI 選項。使用者可以根據影片錄製需求,在 SDR 和 HDR 之間切換。

HDR 擷取架構

下圖顯示 HDR 擷取架構的主要元件。

HDR 擷取架構圖。
圖 2 HDR 擷取架構圖。

當攝影機裝置以 HDR 格式擷取影格時,Camera2 架構會分配緩衝區,儲存處理後的攝影機感應器輸出內容。如果 HDR 設定檔需要,也會附加相應的 HDR 中繼資料。 接著,Camera2 框架會將填入的緩衝區排入佇列,以供 CaptureRequest 參照的輸出途徑使用,例如螢幕或影片編碼器 (如圖表所示)。

確認 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,其中包含裝置支援的 HDR 設定檔,然後在建立時傳遞至 CameraCaptureSession。請參閱清單,瞭解支援的 HDR 設定檔。

在下列程式碼範例中,setupSessionDynamicRangeProfile() 會先檢查裝置是否執行 Android 13。接著,它會將裝置支援的 HDR 設定檔設為 OutputConfiguration,藉此設定 CameraCaptureSession

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 拍攝和播放。此外,裝置製造商可使用 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 影片拍攝功能的可運作應用程式,請參閱 GitHub 上的 Camera2Video 範例