HDR 影片擷取

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

Camera2 API 支援高動態範圍 (HDR) 影片擷取功能,可讓您使用相機預覽及錄製 HDR 影片內容。與標準動態範圍 (SDR) 相比,HDR 不僅提供更多色彩範圍,還能增加亮度元件的動態範圍 (從目前的 100 cd/m2 至 cd/m2 的 1000s)。因此影片畫質會更貼近真實生活中的大小,且色彩更豐富、高亮度部分更亮,陰影部分更暗。

快來看看 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 是裝置製造商必須在具有 10 位元輸出的相機上支援的基準 HDR 基準。

  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) Metadata 編碼器 位元深度
HTTP 即時串流 HLG HEVC 10 位元
HDR10 PQ 靜態 HEVC 10 位元
HDR10+ PQ 動態 HEVC 10 位元
Dolby Vision 8.4 HLG 動態 HEVC 10 位元

資源

如需具有 HDR 影片拍攝功能的可運作應用程式,請參閱 GitHub 上的 Camera2Video 範例