この記事でわかること
blackdetectフィルタで黒フレーム区間を検出するコマンドblack_min_duration(最小黒フレーム継続時間)の設定pic_th(黒と判定するピクセル比率閾値)の意味pix_th(黒と判定する輝度閾値)の調整- CM区切りやチャプター境界の自動検出への応用
テスト済みバージョン: FFmpeg 6.1で確認済み(ubuntu-latest / CI検証済み) 対象 OS: Windows / macOS / Linux
基本コマンド
ffmpeg -i input.mp4 -vf blackdetect -f null /dev/null
映像の黒フレーム区間を標準エラー出力に表示します。
出力の読み方
[blackdetect @ 0x...] black_start:0 black_end:2.04 black_duration:2.04
[blackdetect @ 0x...] black_start:123.5 black_end:126.0 black_duration:2.5
| フィールド | 説明 |
|---|---|
black_start | 黒区間の開始時刻(秒) |
black_end | 黒区間の終了時刻(秒) |
black_duration | 黒区間の継続時間(秒) |
パラメータの調整
デフォルト値
| パラメータ | デフォルト | 説明 |
|---|---|---|
black_min_duration | 2.0 | この秒数以上続く黒区間のみ報告 |
picture_black_ratio_th (pic_th) | 0.98 | フレーム内の黒ピクセルが98%以上なら黒フレームと判定 |
pixel_black_th (pix_th) | 0.10 | 輝度値(0〜1正規化)がこの値以下なら黒ピクセルと判定 |
カスタム例:0.5秒以上の黒区間を検出
ffmpeg -i input.mp4 -vf "blackdetect=d=0.5:pic_th=0.95:pix_th=0.10" -f null /dev/null
dを小さく: 短い黒フレームも検出(CM境界等)pic_thを小さく: 黒以外のピクセルが多少含まれても検出pix_thを大きく: やや明るいフレームも「黒」として判定
応用例:テレビ録画のCM境界を検出
テレビ録画によく使われる手法で、番組とCMの間に約2秒の黒フレームが入ります:
ffmpeg -i recording.mp4 -vf "blackdetect=d=2.0:pix_th=0.10" -f null /dev/null 2>&1 | grep black_
出力をテキストファイルに保存
ffmpeg -i input.mp4 -vf blackdetect -f null /dev/null 2>&1 | grep black_ > black_segments.txt
誤検出しやすいケース
blackdetect は「黒っぽい全画面」を機械的に判定するため、次のようなケースは意図しない検出が発生しやすいです。
| ケース | 原因 | 対策 |
|---|---|---|
| 暗転演出(フェードイン・フェードアウト) | 演出上の暗転を「区切り」と誤認 | pic_th を 0.99 まで上げる、d を 1.5 秒以上に |
| 黒背景テロップ | テキスト部分以外がほぼ全黒 | pic_th を上げる(0.99)。テロップ自体を除外したい場合は時間範囲を -ss/-to で限定 |
| レターボックス(黒帯) | 上下の黒帯のせいで pic_th=0.5 程度でヒット | crop で本編領域を切り出してから blackdetect を適用 |
| H.264 固定QPの暗いシーン | 圧縮ノイズで完全な黒にならない | pix_th を 0.15〜0.20 に上げて許容を拡大 |
blackdetect と silencedetect の組み合わせ
映像の黒フレームと音声の無音が同時に発生する区間を抽出すると、CM境界やチャプター区切りの検出精度を大きく上げられます。両フィルタの出力を Python で照合する例:
import re
import subprocess
def parse_blackdetect(log):
return [(float(m.group(1)), float(m.group(2)))
for m in re.finditer(r'black_start:([\d.]+).+?black_end:([\d.]+)', log)]
def parse_silencedetect(log):
starts = [float(m.group(1)) for m in re.finditer(r'silence_start: ([\d.]+)', log)]
ends = [float(m.group(1)) for m in re.finditer(r'silence_end: ([\d.]+)', log)]
return list(zip(starts, ends))
def overlap(a, b):
return max(a[0], b[0]) <= min(a[1], b[1])
def find_boundaries(video_path):
log = subprocess.run(
['ffmpeg', '-i', video_path,
'-vf', 'blackdetect=d=1.5:pic_th=0.99',
'-af', 'silencedetect=n=-30dB:d=1.0',
'-f', 'null', '/dev/null'],
capture_output=True, text=True, check=False
).stderr
blacks = parse_blackdetect(log)
silences = parse_silencedetect(log)
return [b for b in blacks if any(overlap(b, s) for s in silences)]
関連リソース
よく使うオプション・フィルタ・コーデック設定をまとめた PDF チートシートです。手元に置いておくと調べる時間を短縮できます。
関連記事
- 無音区間の検出 — silencedetect フィルタで無音部分を特定する
- シーンチェンジ検出 — select/scdet フィルタで場面転換を自動検出
- 動画トリムツール(範囲を指定して切り出し)
動作確認: ffmpeg 6.1 / Ubuntu 24.04 (GitHub Actions runner) 一次ソース: ffmpeg.org/ffmpeg-filters.html#blackdetect / ffmpeg.org/ffmpeg-filters.html
よくある質問
blackdetect の閾値はどう設定する?
d=2:pix_th=0.10(2 秒以上で 10% 以下のピクセルが黒以外)が編集の黒フレームを大体捕捉。pix_th を 0.05 にすると厳格に。
見えてる黒フレームを blackdetect が見逃す
純黒ではなく濃いグレーである可能性が高い。圧縮ノイズで 5〜8% は明るく見えがち。pix_th を 0.15 まで緩めて再試行してください。
黒フレームで自動分割するには?
blackdetect の出力をパースして -ss 範囲を生成し、各セグメントに ffmpeg -c copy で切り出すスクリプトを書く流れです。
シーン検出と blackdetect の関係は?
部分的に重なります — select='gt(scene,0.4)' は大きな映像変化全般、blackdetect は黒・準黒の連続を狙い撃ち。チャプター境界の黒フェードは blackdetect が確実。
静止画にも使える?
いいえ。d で指定した連続時間に達して初めてマッチします。1 枚画像ならピクセル輝度を直接取って判定してください。