この記事でわかること

  • HDR(HDR10/HLG)とSDRの違い
  • zscale フィルタを使ったHDR→SDR変換の基本コマンド
  • 色空間・カラープリミティブ・トランスファー関数の変換
  • YouTube/Web配信向けのSDR出力設定
  • よくあるエラーと対処法

テスト済みバージョン: FFmpeg 7.0で確認済み
対象 OS: Windows / macOS / Linux


HDR と SDR の違い

項目SDR(Standard Dynamic Range)HDR(High Dynamic Range)
色空間BT.709BT.2020
転送特性BT.709 (ガンマ)PQ (HDR10) / HLG
ピクセル深度8bit10bit
輝度範囲100 nit1000〜10000 nit

HDR動画をSDR環境で再生すると、映像が白飛び・色ずれを起こすことがあります。適切なトーンマッピングで自然な見栄えのSDR映像に変換できます。


事前確認 — 動画のHDR情報を確認する

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

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

出力例(HDR10):

pix_fmt=yuv420p10le
color_space=bt2020nc
color_transfer=smpte2084
color_primaries=bt2020

出力例(HLG):

pix_fmt=yuv420p10le
color_space=bt2020nc
color_transfer=arib-std-b67
color_primaries=bt2020

基本コマンド — HDR10 → SDR(BT.709)

zscale を使ったトーンマッピング(推奨)

zscaleフィルタ(libzimgが必要)を使った高品質変換:

ffmpeg -i input_hdr.mp4 \
  -vf "zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=hable,zscale=t=bt709:m=bt709:r=tv,format=yuv420p" \
  -c:v libx264 -crf 18 -preset slow \
  -c:a copy \
  output_sdr.mp4

このフィルタチェーンは以下の処理を行います:

  1. zscale=t=linear:npl=100 — 線形光に変換(PQからリニア)
  2. format=gbrpf32le — 32bit浮動小数点に変換(精度確保)
  3. zscale=p=bt709 — BT.2020からBT.709へのカラープリミティブ変換
  4. tonemap=hable — Hableトーンマッピングで輝度圧縮
  5. zscale=t=bt709:m=bt709:r=tv — BT.709ガンマ・matrix・制限レンジに変換
  6. format=yuv420p — 8bit YUV 4:2:0に変換

トーンマッピングアルゴリズムの比較

tonemap= で異なるアルゴリズムを指定できます。

# Hable(フィルムルック、推奨)
-vf "zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=hable,zscale=t=bt709:m=bt709:r=tv,format=yuv420p"

# Reinhard(シンプルで自然)
-vf "zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=reinhard,zscale=t=bt709:m=bt709:r=tv,format=yuv420p"

# Mobius(中間的なコントラスト)
-vf "zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=mobius,zscale=t=bt709:m=bt709:r=tv,format=yuv420p"

# Clip(単純クリッピング、最速だが白飛びあり)
-vf "zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=clip,zscale=t=bt709:m=bt709:r=tv,format=yuv420p"
アルゴリズム特徴推奨用途
hableハイライトを自然に圧縮、コントラスト保持汎用
reinhardシンプル、中性的な見た目自然な映像
mobiusハイライトと影のバランスドキュメンタリー
clip単純カット、高速テスト・比較

HLG → SDR 変換

ffmpeg -i input_hlg.mp4 \
  -vf "zscale=t=linear,format=gbrpf32le,zscale=p=bt709,tonemap=hable,zscale=t=bt709:m=bt709:r=tv,format=yuv420p" \
  -c:v libx264 -crf 18 -preset slow \
  -c:a copy \
  output_sdr.mp4

HLGの場合は npl=100 の指定が不要です(HLGは相対輝度)。


colorspace フィルタを使う方法(zscale が使えない場合)

libzimgがない環境では colorspace フィルタを使用できます(精度はやや低下):

ffmpeg -i input_hdr.mp4 \
  -vf "colorspace=bt709:iall=bt2020:fast=1,format=yuv420p" \
  -c:v libx264 -crf 18 -preset slow \
  -c:a copy \
  output_sdr.mp4

YouTube アップロード向けの設定

YouTube はSDR映像で H.264、CRF 18〜20 推奨です。

ffmpeg -i input_hdr.mp4 \
  -vf "zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=hable,zscale=t=bt709:m=bt709:r=tv,format=yuv420p" \
  -c:v libx264 -crf 18 -preset slow \
  -pix_fmt yuv420p \
  -color_primaries bt709 \
  -color_trc bt709 \
  -colorspace bt709 \
  -c:a aac -b:a 256k \
  output_youtube_sdr.mp4

-color_primaries -color_trc -colorspace の3つのメタデータタグを明示することで、プレイヤーが正しい色空間を認識します。


一括変換スクリプト(フォルダ内のHDR動画をすべてSDRに変換)

#!/bin/bash
for f in *.mp4; do
  ffmpeg -i "$f" \
    -vf "zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=hable,zscale=t=bt709:m=bt709:r=tv,format=yuv420p" \
    -c:v libx264 -crf 18 -preset slow \
    -pix_fmt yuv420p \
    -color_primaries bt709 -color_trc bt709 -colorspace bt709 \
    -c:a copy \
    "sdr_${f}"
done

トラブルシューティング

zscale が見つからない

No such filter: 'zscale'

FFmpegがlibzimgなしでビルドされています。

# macOS
brew install ffmpeg  # Homebrewビルドはlibzimgを含む

# Ubuntu
sudo apt install ffmpeg  # 最新版を確認

映像が緑色・ピンク色になる

色空間変換のパラメータが間違っています。ffprobecolor_transfer を確認し、HLG入力には t=arib-std-b67、HDR10には t=smpte2084 を指定してください。

映像が暗すぎる / 白飛びしている

トーンマッピングアルゴリズムを変更してみてください。暗い場合は npl 値を上げる(例: npl=203)か、reinhard を試します。

# npl値を上げてより明るいSDRに
-vf "zscale=t=linear:npl=203,format=gbrpf32le,zscale=p=bt709,tonemap=hable,zscale=t=bt709:m=bt709:r=tv,format=yuv420p"

ピクセルフォーマットエラー

10bitのHDR入力を libx264(8bit)に渡す際は format=yuv420p を必ず最後に指定します。


関連リソース

よく使うオプション・フィルタ・コーデック設定をまとめた PDF チートシートです。手元に置いておくと調べる時間を短縮できます。

FFmpeg チートシート

関連記事


動作確認: ffmpeg 7.0 / Ubuntu 24.04
一次ソース: ffmpeg.org/ffmpeg-filters.html#zscale