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)では表現できなかった明暗差の大きな映像表現が可能になりました。
| # | 規格名 | 用途 | 色域範囲 | 転送特性 |
|---|---|---|---|---|
| 1 | Rec.709 | HD 放送・Web 配信 | 狭い | SDR(BT.1886) |
| 2 | BT.2020 | 4K/8K 放送 | 非常に広い | SDR/HDR 両対応 |
| 3 | HDR10 | UHD Blu-ray・配信 | BT.2020 使用 | PQ(ST.2084) |
| 4 | HLG | 放送用 HDR | BT.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 でカラーマネジメントを行う際、複数のパラメータを正確に指定する必要があります。colorspace、color_primaries、color_trc、color_rangeなど、似たような名前のパラメータが多数存在し、混同しやすいという問題がありますね。
さらに、入力ファイルのメタデータが正しく設定されていない場合、FFmpeg が自動的に誤った値を推測してしまうことがあります。この場合、明示的にパラメータを指定しないと正しい変換ができません。
解決策
FFmpeg のカラーパラメータ体系の理解
FFmpeg では、色空間に関する情報を複数のパラメータで管理しています。これらを正しく理解することが、適切なカラーマネジメントの第一歩となります。
主要なパラメータは以下の通りです。
| # | パラメータ名 | 役割 | 主な値 |
|---|---|---|---|
| 1 | colorspace | マトリクス係数 | bt709, bt2020nc, bt2020c |
| 2 | color_primaries | 色域(原色) | bt709, bt2020 |
| 3 | color_trc | 転送特性 | bt709, smpte2084, arib-std-b67 |
| 4 | color_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 | 転送特性 | smpte2084 | arib-std-b67 |
| 2 | 輝度表現 | 絶対値 | 相対値 |
| 3 | メタデータ | 必須 | オプション |
| 4 | SDR 互換性 | なし | あり |
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:色が不自然に表示される
エラーコード: なし(視覚的な問題)
症状: 変換後の映像で色合いが大きく変化し、不自然な色になっている
発生条件: 入力ファイルの色空間メタデータが欠落または誤っている場合
解決方法:
- まず入力ファイルの実際の色空間を特定します
bashffprobe -v error -select_streams v:0 \
-show_entries stream=color_space,color_primaries,color_transfer \
input.mp4
- メタデータが
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
- それでも解決しない場合は、
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 ピクセルフォーマットを使用した場合
解決方法:
- 10bit ピクセルフォーマットを明示的に指定します
bashffmpeg -i input.mp4 \
-vf "colorspace=space=bt2020nc:primaries=bt2020:trc=smpte2084" \
-c:v libx265 \
-pix_fmt yuv420p10le \
output_hdr10.mp4
- FFmpeg のビルド時に x265 の 10bit サポートが有効か確認します
bashffmpeg -h encoder=libx265 | grep "Supported pixel formats"
- 10bit 対応の x265 がインストールされていない場合は再ビルドが必要です
エラー 3:zscale フィルタが見つからない
エラーコード: Filter zscale not found
エラーメッセージ:
css[AVFilterGraph @ 0x7f9a1c0] No such filter: 'zscale'
Error initializing complex filters.
発生条件: zimg library なしで FFmpeg がビルドされている場合
解決方法:
- FFmpeg の利用可能なフィルタを確認します
bashffmpeg -filters | grep scale
zscaleが表示されない場合は、scaleフィルタで代替します(機能は限定的)
bashffmpeg -i input_hdr.mp4 \
-vf "scale=in_color_matrix=bt2020:out_color_matrix=bt709" \
output_sdr.mp4
- 完全な HDR→SDR 変換には zimg 対応版 FFmpeg の再インストールが推奨されます
bash# Homebrewの場合(macOS)
brew reinstall ffmpeg --with-zimg
以下の表は、一般的なエラーと対処法をまとめたものです。
| # | エラー内容 | 原因 | 解決方法 |
|---|---|---|---|
| 1 | 色が不自然 | メタデータ欠落 | 入力パラメータを明示指定 |
| 2 | 10bit エンコード失敗 | ピクセルフォーマット誤り | -pix_fmt yuv420p10le指定 |
| 3 | zscale エラー | 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フィルタを適切に使い分け、メタデータも正確に設定する必要がありますね。トラブル発生時は、入力ファイルの色空間情報を確認し、明示的にパラメータを指定することで多くの問題を解決できるでしょう。
バッチ処理を活用すれば、大量のファイルを効率的に変換できます。本記事で紹介した実践例を参考に、皆様のプロジェクトに最適なワークフローを構築してください。
関連リンク
articleFFmpeg カラーマネジメント概観:Rec.709/BT.2020/HDR10/HLG の色域・転送特性を理解
articleFFmpeg ライセンス/特許の実務:GPL/LGPL/nonfree の線引きと社内コンプラ対応
articleFFmpeg 配信設計の実際:tee muxer でマルチプラットフォーム同時配信
articleFFmpeg マッピング完全攻略:-map/-disposition/-metadata の黄金レシピ
articleFFmpeg 静的ビルド完全版:x264/x265/aom/opus/fdk-aac 対応のフル装備手順
articleFFmpeg 画質評価の作法:VMAF/SSIM/PSNR を揃えて測るベンチ手順
articleNotebookLM の強みと弱み:従来ノートアプリとの本質的な違い
articleMySQL キャパシティプランニング:Buffer Pool/IOPS/接続数の見積もり術
articleMotion(旧 Framer Motion)A/B テスト運用:アニメの効果測定とフェイルセーフ切替戦略
articleNode.js で GraphQL サーバー構築:Yoga/Apollo を最小構成で立ち上げる
articleMistral が JSON 破綻する時の対処:出力拘束・再試行・検証リカバリ
articleNext.js の キャッシュ無効化設計:タグ・パス・スケジュールの 3 軸でコントロール
blogiPhone 17シリーズの発表!全モデルiPhone 16から進化したポイントを見やすく整理
blogGoogleストアから訂正案内!Pixel 10ポイント有効期限「1年」表示は誤りだった
blog【2025年8月】Googleストア「ストアポイント」は1年表記はミス?2年ルールとの整合性を検証
blogGoogleストアの注文キャンセルはなぜ起きる?Pixel 10購入前に知るべき注意点
blogPixcel 10シリーズの発表!全モデル Pixcel 9 から進化したポイントを見やすく整理
blogフロントエンドエンジニアの成長戦略:コーチングで最速スキルアップする方法
review今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
reviewついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
review愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
review週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
review新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
review科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来