HDR 動画キャプチャ

注: このページでは、Camera2 パッケージについて説明します。アプリで Camera2 の特定の低レベルの機能を必要とする場合を除き、CameraX を使用することをおすすめします。CameraX と Camera2 は、どちらも Android 5.0(API レベル 21)以降に対応しています。

Camera2 API のサポート ハイ ダイナミック レンジ(HDR)動画キャプチャ。 カメラで HDR 動画コンテンツを撮影する。標準のダイナミック広告との比較 レンジ(SDR)、HDR ではより広い色彩を使用でき、ダイナミックさが増します (現在の 100 cd/m2 から数千 cd/m2 まで) その結果、日常生活に近い動画品質が得られます。 より色鮮やか、ハイライトはより明るく、シャドウはより暗くなります。

HDR 動画によって、夕焼けを細部まで鮮明に捉えることができます。

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph> 図 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 が搭載されていることを確認できます。 次に、デバイスでサポートされているデバイスで CameraCaptureSession をセットアップします。 OutputConfiguration としての HDR プロファイル:

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 ビット出力機能を持つカメラデバイス HDR キャプチャで HLG10 をサポートし、 playback を使用します。 さらに、デバイス メーカーは任意の HDR 形式を有効にすることができます。 HDR キャプチャ アーキテクチャを使用する。

次の表は、利用可能な HDR 形式とその機能をまとめたものです。 HDR 動画キャプチャに使用できます

形式 伝達関数(TF) メタデータ コーデック ビット深度
HLG10 HLG × HEVC 10 ビット
HDR10 PQ 静的 HEVC 10 ビット
HDR10+ PQ 動的 HEVC 10 ビット
ドルビー ビジョン 8.4 HLG 動的 HEVC 10 ビット

リソース

HDR 動画キャプチャ機能を備えた動作中のアプリについては、 Camera2Video のサンプル ご覧ください。