この記事でわかること

  • 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_duration2.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 チートシートです。手元に置いておくと調べる時間を短縮できます。

FFmpeg チートシート

関連記事


動作確認: 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 枚画像ならピクセル輝度を直接取って判定してください。