T-CREATOR

FFmpeg カラーマネジメント概観:Rec.709/BT.2020/HDR10/HLG の色域・転送特性を理解

FFmpeg カラーマネジメント概観:Rec.709/BT.2020/HDR10/HLG の色域・転送特性を理解

映像制作やストリーミング配信の現場では、色の正確な再現が重要な課題となっています。HDR コンテンツの普及により、Rec.709 だけでなく BT.2020 や HDR10、HLG といった新しい規格への対応が求められるようになりました。

FFmpeg を使った色域変換や転送特性の調整は、一見複雑に見えますが、各パラメータの役割を理解すれば適切な処理が可能になります。本記事では、FFmpeg におけるカラーマネジメントの基本から実践的な活用方法まで、段階的に解説していきますね。

背景

映像規格の進化と色空間の多様化

映像技術は長年にわたって進化を続けてきました。HD 時代には Rec.709 が標準色域として広く採用されていましたが、4K/8K 時代の到来とともに BT.2020 という広色域規格が登場しています。

さらに、HDR(High Dynamic Range)技術の導入により、従来の SDR(Standard Dynamic Range)では表現できなかった明暗差の大きな映像表現が可能になりました。

#規格名用途色域範囲転送特性
1Rec.709HD 放送・Web 配信狭いSDR(BT.1886)
2BT.20204K/8K 放送非常に広いSDR/HDR 両対応
3HDR10UHD Blu-ray・配信BT.2020 使用PQ(ST.2084)
4HLG放送用 HDRBT.2020 使用HLG(ARIB STD-B67)

カラーマネジメントの 3 つの柱

映像のカラーマネジメントは、主に 3 つの要素で構成されています。

色域(Color Primaries)は、赤・緑・青の 3 原色がどの位置にあるかを定義します。転送特性(Transfer Characteristics)は、信号値と輝度の関係を示すガンマカーブを規定していますね。マトリクス係数(Matrix Coefficients)は、RGB と YUV の変換方式を決定します。

以下の図は、これら 3 要素の関係性を示しています。

mermaidflowchart TD
    video["映像データ"]
    video --> primaries["色域<br/>(Color Primaries)"]
    video --> transfer["転送特性<br/>(Transfer Characteristics)"]
    video --> matrix["マトリクス係数<br/>(Matrix Coefficients)"]

    primaries --> |"Rec.709/BT.2020など"| gamut["色再現範囲の定義"]
    transfer --> |"BT.1886/PQ/HLGなど"| gamma["ガンマカーブの定義"]
    matrix --> |"BT.709/BT.2020など"| conversion["RGB⇔YUV変換方式"]

    gamut --> display["ディスプレイ表示"]
    gamma --> display
    conversion --> display

これら 3 要素が正しく設定されていないと、色が不自然に表示されたり、明暗バランスが崩れたりする問題が発生します。

課題

色域変換における課題

異なる色域間で映像を変換する際には、様々な技術的課題が発生します。最も一般的な課題は、広色域から狭色域への変換時に色情報が失われることですね。

例えば、BT.2020 で撮影された鮮やかな赤色を Rec.709 に変換すると、Rec.709 では表現できない色域の情報が失われ、色が濁って見えることがあります。

#課題発生条件影響
1色域外クリッピング広色域 → 狭色域変換鮮やかな色が失われる
2ガンマ不一致転送特性の誤設定明るさが不自然になる
3メタデータ欠落変換時の情報損失再生環境で誤表示
4色相シフト不適切な変換方式色合いが変化する

HDR/SDR 変換の複雑性

HDR から SDR への変換(トーンマッピング)は、特に複雑な処理が必要です。HDR は 10,000 nits 以上の輝度を扱えますが、SDR は通常 100 nits 程度までしか対応していません。

この大きな輝度差を適切に圧縮しないと、明るい部分が白飛びしたり、暗い部分が黒つぶれしたりする問題が発生します。さらに、PQ(Perceptual Quantizer)と HLG(Hybrid Log-Gamma)では転送特性が異なるため、それぞれに適した処理が必要になりますね。

以下の図は、HDR/SDR 変換時の輝度範囲の違いを示しています。

mermaidflowchart LR
    subgraph HDR ["HDR (10,000 nits)"]
        hdr_high["ハイライト<br/>1,000-10,000 nits"]
        hdr_mid["中間調<br/>100-1,000 nits"]
        hdr_low["シャドウ<br/>0-100 nits"]
    end

    subgraph mapping ["トーンマッピング処理"]
        compress["輝度圧縮<br/>アルゴリズム"]
    end

    subgraph SDR ["SDR (100 nits)"]
        sdr_high["ハイライト<br/>80-100 nits"]
        sdr_mid["中間調<br/>20-80 nits"]
        sdr_low["シャドウ<br/>0-20 nits"]
    end

    hdr_high --> compress
    hdr_mid --> compress
    hdr_low --> compress

    compress --> sdr_high
    compress --> sdr_mid
    compress --> sdr_low

FFmpeg におけるパラメータ指定の難しさ

FFmpeg でカラーマネジメントを行う際、複数のパラメータを正確に指定する必要があります。colorspacecolor_primariescolor_trccolor_rangeなど、似たような名前のパラメータが多数存在し、混同しやすいという問題がありますね。

さらに、入力ファイルのメタデータが正しく設定されていない場合、FFmpeg が自動的に誤った値を推測してしまうことがあります。この場合、明示的にパラメータを指定しないと正しい変換ができません。

解決策

FFmpeg のカラーパラメータ体系の理解

FFmpeg では、色空間に関する情報を複数のパラメータで管理しています。これらを正しく理解することが、適切なカラーマネジメントの第一歩となります。

主要なパラメータは以下の通りです。

#パラメータ名役割主な値
1colorspaceマトリクス係数bt709, bt2020nc, bt2020c
2color_primaries色域(原色)bt709, bt2020
3color_trc転送特性bt709, smpte2084, arib-std-b67
4color_range色範囲tv(Limited), pc(Full)

これらのパラメータは、入力ファイルの解析時(-iの前)と出力ファイルの設定時(-iの後)の両方で指定可能です。

以下のコマンド例では、入力ファイルの色空間情報を明示的に指定しています。

bash# 入力ファイルの色空間を明示的に指定
ffmpeg -colorspace bt709 -color_primaries bt709 -color_trc bt709 \
       -i input.mp4 output.mp4

このように入力側のパラメータを指定することで、メタデータが欠落しているファイルでも正しく処理できます。

colorspace フィルタの活用

FFmpeg のcolorspaceフィルタは、色域と転送特性の変換を一括で行える強力なツールです。このフィルタを使うことで、複雑な変換処理を簡潔に記述できますね。

基本的な構文は以下の通りです。

bash-vf "colorspace=\
  space=<マトリクス>:\
  primaries=<色域>:\
  trc=<転送特性>:\
  range=<色範囲>"

各パラメータの意味を詳しく見ていきましょう。

spaceは出力のマトリクス係数を指定します。bt709(HD)またはbt2020nc(UHD)が一般的です。

bash# マトリクス係数の指定例
-vf "colorspace=space=bt709"

primariesは出力の色域を指定します。bt709(狭色域)またはbt2020(広色域)を選択できます。

bash# 色域の指定例
-vf "colorspace=primaries=bt2020"

trcは出力の転送特性を指定します。SDR の場合はbt709、HDR10 の場合はsmpte2084(PQ)、HLG の場合はarib-std-b67を使用しますね。

bash# 転送特性の指定例(HDR10)
-vf "colorspace=trc=smpte2084"

rangeは色範囲を指定します。tvは Limited Range(16-235)、pcは Full Range(0-255)を意味します。

bash# 色範囲の指定例
-vf "colorspace=range=tv"

具体的な変換パターンの実装

実際の変換作業では、いくつかの典型的なパターンが存在します。以下、代表的な変換パターンを見ていきましょう。

パターン 1:Rec.709(SDR)から BT.2020(HDR10)への変換

SDR コンテンツを HDR10 に変換する処理です。この変換では、色域の拡張と転送特性の変更が必要になります。

bashffmpeg -i input_sdr.mp4 \
  -vf "colorspace=\
    space=bt2020nc:\
    primaries=bt2020:\
    trc=smpte2084:\
    range=tv" \
  -c:v libx265 -pix_fmt yuv420p10le \
  output_hdr10.mp4

このコマンドでは、10bit エンコードが必須となるためyuv420p10leを指定しています。

パターン 2:HDR10 から Rec.709(SDR)への変換

HDR10 コンテンツを SDR に変換する処理です。トーンマッピングにより輝度範囲を圧縮する必要があります。

bashffmpeg -i input_hdr10.mp4 \
  -vf "zscale=\
    t=linear:npl=100,\
    format=gbrpf32le,\
    zscale=p=bt709,\
    tonemap=tonemap=hable:desat=0,\
    zscale=t=bt709:m=bt709:r=tv,\
    format=yuv420p" \
  -c:v libx264 \
  output_sdr.mp4

この変換では、複数のフィルタを組み合わせて段階的に処理を行っています。

zscaleフィルタは、より高度な色空間変換を提供します。t=linearで線形色空間に変換し、npl=100でピーク輝度を 100nits に設定していますね。

パターン 3:HLG から Rec.709(SDR)への変換

HLG コンテンツを SDR に変換する処理です。HLG は相対的な転送特性を持つため、HDR10 とは異なるアプローチが必要です。

bashffmpeg -i input_hlg.mp4 \
  -vf "colorspace=\
    space=bt709:\
    primaries=bt709:\
    trc=bt709:\
    range=tv" \
  -c:v libx264 \
  output_sdr.mp4

HLG は SDR との後方互換性があるため、HDR10 よりも比較的シンプルな変換が可能です。

メタデータの適切な管理

色空間情報は、映像データだけでなくメタデータとしても記録する必要があります。FFmpeg では、コンテナレベルとコーデックレベルの両方でメタデータを設定できますね。

以下は、HDR10 メタデータを含む変換コマンドの例です。

bashffmpeg -i input.mp4 \
  -vf "colorspace=space=bt2020nc:primaries=bt2020:trc=smpte2084" \
  -c:v libx265 \
  -x265-params "colorprim=bt2020:transfer=smpte2084:colormatrix=bt2020nc" \
  -pix_fmt yuv420p10le \
  output_hdr10.mp4

-x265-paramsオプションで、H.265 コーデック固有のメタデータを設定しています。

さらに詳細な HDR10 メタデータ(マスタリングディスプレイ情報など)を設定する場合は、以下のように記述します。

bash-x265-params "\
  colorprim=bt2020:\
  transfer=smpte2084:\
  colormatrix=bt2020nc:\
  master-display=\
    G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(10000000,50):\
  max-cll=1000,400"

これらのパラメータは、ディスプレイの色域情報やコンテンツの最大輝度を指定するものです。

具体例

実践例 1:YouTube 向け HDR10 コンテンツの作成

YouTube に HDR コンテンツをアップロードする際は、特定の仕様に従う必要があります。ここでは、Rec.709 の SDR 素材から YouTube HDR 仕様のファイルを作成する手順を解説します。

ステップ 1:入力ファイルの確認

まず、入力ファイルの色空間情報を確認しましょう。

bashffprobe -v error \
  -select_streams v:0 \
  -show_entries stream=color_space,color_primaries,color_transfer \
  -of default=noprint_wrappers=1 \
  input.mp4

このコマンドで、現在の色空間設定が表示されます。出力例は以下の通りです。

inicolor_space=bt709
color_primaries=bt709
color_transfer=bt709

ステップ 2:HDR10 への変換

確認した情報をもとに、HDR10 形式に変換します。YouTube は PQ(SMPTE ST 2084)転送特性を推奨していますね。

bashffmpeg -i input.mp4 \
  -vf "colorspace=\
    space=bt2020nc:\
    primaries=bt2020:\
    trc=smpte2084:\
    range=tv" \
  -c:v libx265 \
  -preset medium \
  -crf 18 \
  -pix_fmt yuv420p10le \
  output_youtube_hdr.mp4

-crf 18は高品質を維持するための設定で、値が小さいほど高品質になります。

ステップ 3:メタデータの追加

YouTube HDR には、HDR10 メタデータが必須です。以下のコマンドで追加しましょう。

bashffmpeg -i input.mp4 \
  -vf "colorspace=space=bt2020nc:primaries=bt2020:trc=smpte2084:range=tv" \
  -c:v libx265 \
  -preset medium \
  -crf 18 \
  -pix_fmt yuv420p10le \
  -x265-params "\
    colorprim=bt2020:\
    transfer=smpte2084:\
    colormatrix=bt2020nc:\
    master-display=G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(10000000,50):\
    max-cll=1000,400" \
  output_youtube_hdr.mp4

マスターディスプレイパラメータは、DCI-P3 ディスプレイの標準値を使用しています。

以下の図は、変換処理の全体フローを示しています。

mermaidflowchart TD
    input["入力ファイル<br/>(Rec.709 SDR)"]
    check["ffprobeで色空間確認"]
    convert["colorspaceフィルタ<br/>で変換処理"]
    encode["H.265エンコード<br/>(10bit)"]
    meta["HDR10メタデータ追加"]
    output["出力ファイル<br/>(BT.2020 HDR10)"]

    input --> check
    check --> convert
    convert --> encode
    encode --> meta
    meta --> output

    style input fill:#e1f5ff
    style output fill:#ffe1e1

実践例 2:放送用 HLG コンテンツの作成

HLG(Hybrid Log-Gamma)は、BBC と NHK が共同開発した放送向け HDR 規格です。SDR 環境でも自然に表示できる後方互換性が特徴ですね。

HLG の特徴理解

HLG は、PQ とは異なる転送特性を持っています。シーン参照(Scene-referred)方式のため、絶対的な輝度値ではなく相対的な明るさで表現されます。

#項目HDR10(PQ)HLG
1転送特性smpte2084arib-std-b67
2輝度表現絶対値相対値
3メタデータ必須オプション
4SDR 互換性なしあり

HLG 変換コマンド

Rec.709 素材から HLG に変換する基本コマンドは以下の通りです。

bashffmpeg -i input_sdr.mp4 \
  -vf "colorspace=\
    space=bt2020nc:\
    primaries=bt2020:\
    trc=arib-std-b67:\
    range=tv" \
  -c:v libx265 \
  -preset medium \
  -crf 18 \
  -pix_fmt yuv420p10le \
  output_hlg.mp4

HLG の場合、trc=arib-std-b67を指定することが重要です。

コーデックパラメータの設定

H.265 エンコーダにも HLG 情報を明示的に伝えましょう。

bashffmpeg -i input_sdr.mp4 \
  -vf "colorspace=space=bt2020nc:primaries=bt2020:trc=arib-std-b67:range=tv" \
  -c:v libx265 \
  -preset medium \
  -crf 18 \
  -pix_fmt yuv420p10le \
  -x265-params "\
    colorprim=bt2020:\
    transfer=arib-std-b67:\
    colormatrix=bt2020nc" \
  output_hlg.mp4

HLG はマスターディスプレイメタデータが不要なため、HDR10 よりもシンプルな設定になっています。

実践例 3:トラブルシューティング

カラーマネジメント処理では、様々なエラーが発生する可能性があります。代表的なエラーと解決方法を見ていきましょう。

エラー 1:色が不自然に表示される

エラーコード: なし(視覚的な問題)

症状: 変換後の映像で色合いが大きく変化し、不自然な色になっている

発生条件: 入力ファイルの色空間メタデータが欠落または誤っている場合

解決方法:

  1. まず入力ファイルの実際の色空間を特定します
bashffprobe -v error -select_streams v:0 \
  -show_entries stream=color_space,color_primaries,color_transfer \
  input.mp4
  1. メタデータがunknownの場合、実際の色空間を明示的に指定します
bash# 入力がRec.709の場合
ffmpeg -colorspace bt709 -color_primaries bt709 -color_trc bt709 \
  -i input.mp4 \
  -vf "colorspace=space=bt2020nc:primaries=bt2020:trc=smpte2084" \
  output.mp4
  1. それでも解決しない場合は、iallパラメータで入力側も明示します
bashffmpeg -i input.mp4 \
  -vf "colorspace=\
    iall=bt709:\
    space=bt2020nc:\
    primaries=bt2020:\
    trc=smpte2084" \
  output.mp4

エラー 2:10bit エンコードの失敗

エラーコード: Error: Incompatible pixel format 'yuv420p' for codec 'libx265'

エラーメッセージ:

lua[libx265 @ 0x7f8b2c0] Incompatible pixel format 'yuv420p' for codec 'libx265'
Error initializing output stream 0:0

発生条件: HDR10 や HLG 変換時に 8bit ピクセルフォーマットを使用した場合

解決方法:

  1. 10bit ピクセルフォーマットを明示的に指定します
bashffmpeg -i input.mp4 \
  -vf "colorspace=space=bt2020nc:primaries=bt2020:trc=smpte2084" \
  -c:v libx265 \
  -pix_fmt yuv420p10le \
  output_hdr10.mp4
  1. FFmpeg のビルド時に x265 の 10bit サポートが有効か確認します
bashffmpeg -h encoder=libx265 | grep "Supported pixel formats"
  1. 10bit 対応の x265 がインストールされていない場合は再ビルドが必要です

エラー 3:zscale フィルタが見つからない

エラーコード: Filter zscale not found

エラーメッセージ:

css[AVFilterGraph @ 0x7f9a1c0] No such filter: 'zscale'
Error initializing complex filters.

発生条件: zimg library なしで FFmpeg がビルドされている場合

解決方法:

  1. FFmpeg の利用可能なフィルタを確認します
bashffmpeg -filters | grep scale
  1. zscaleが表示されない場合は、scaleフィルタで代替します(機能は限定的)
bashffmpeg -i input_hdr.mp4 \
  -vf "scale=in_color_matrix=bt2020:out_color_matrix=bt709" \
  output_sdr.mp4
  1. 完全な HDR→SDR 変換には zimg 対応版 FFmpeg の再インストールが推奨されます
bash# Homebrewの場合(macOS)
brew reinstall ffmpeg --with-zimg

以下の表は、一般的なエラーと対処法をまとめたものです。

#エラー内容原因解決方法
1色が不自然メタデータ欠落入力パラメータを明示指定
210bit エンコード失敗ピクセルフォーマット誤り-pix_fmt yuv420p10le指定
3zscale エラーzimg 未対応ビルドFFmpeg 再インストール
4明るさ異常転送特性の不一致trcパラメータ確認

実践例 4:バッチ処理での一括変換

複数のファイルを一括で変換する場合、シェルスクリプトを活用すると効率的です。

基本的なバッチ処理スクリプト

以下は、フォルダ内の全 MP4 ファイルを HDR10 に変換する Bash スクリプトの例です。

bash#!/bin/bash

# 入力フォルダと出力フォルダを設定
input_dir="./input"
output_dir="./output_hdr10"

# 出力フォルダが存在しない場合は作成
mkdir -p "$output_dir"

ここでは、処理に必要なディレクトリの準備を行っています。

次に、ファイルを順次処理するループを追加します。

bash# すべてのMP4ファイルを処理
for file in "$input_dir"/*.mp4; do
  # ファイル名を取得
  filename=$(basename "$file")
  echo "Processing: $filename"

  # HDR10に変換
  ffmpeg -i "$file" \
    -vf "colorspace=space=bt2020nc:primaries=bt2020:trc=smpte2084:range=tv" \
    -c:v libx265 \
    -preset medium \
    -crf 18 \
    -pix_fmt yuv420p10le \
    -x265-params "colorprim=bt2020:transfer=smpte2084:colormatrix=bt2020nc" \
    "$output_dir/$filename"

  echo "Completed: $filename"
done

エラーハンドリング付きスクリプト

実運用では、エラーハンドリングを追加することが重要です。

bash#!/bin/bash

input_dir="./input"
output_dir="./output_hdr10"
log_file="./conversion.log"

mkdir -p "$output_dir"

# ログファイルの初期化
echo "Conversion started at $(date)" > "$log_file"

for file in "$input_dir"/*.mp4; do
  filename=$(basename "$file")
  echo "Processing: $filename" | tee -a "$log_file"

  # FFmpeg実行と結果チェック
  if ffmpeg -i "$file" \
    -vf "colorspace=space=bt2020nc:primaries=bt2020:trc=smpte2084:range=tv" \
    -c:v libx265 \
    -preset medium \
    -crf 18 \
    -pix_fmt yuv420p10le \
    -x265-params "colorprim=bt2020:transfer=smpte2084:colormatrix=bt2020nc" \
    "$output_dir/$filename" 2>&1 | tee -a "$log_file"; then
    echo "SUCCESS: $filename" | tee -a "$log_file"
  else
    echo "ERROR: $filename conversion failed" | tee -a "$log_file"
  fi
done

echo "Conversion completed at $(date)" >> "$log_file"

このスクリプトでは、各ファイルの処理結果をログファイルに記録し、成功・失敗を追跡できるようにしています。

まとめ

FFmpeg を使ったカラーマネジメントは、パラメータの意味を理解すれば決して難しくありません。Rec.709、BT.2020、HDR10、HLG といった各規格の特性を把握し、適切なパラメータを選択することが重要です。

カラーマネジメントの 3 つの柱である色域(Color Primaries)、転送特性(Transfer Characteristics)、マトリクス係数(Matrix Coefficients)をそれぞれ正しく設定することで、意図した通りの色再現が可能になります。

特に HDR 変換では、colorspaceフィルタやzscaleフィルタを適切に使い分け、メタデータも正確に設定する必要がありますね。トラブル発生時は、入力ファイルの色空間情報を確認し、明示的にパラメータを指定することで多くの問題を解決できるでしょう。

バッチ処理を活用すれば、大量のファイルを効率的に変換できます。本記事で紹介した実践例を参考に、皆様のプロジェクトに最適なワークフローを構築してください。

関連リンク