blackdetect は、画面がほぼ真っ黒になっている区間を探すフィルタです。見つけた区間ごとに、始まりと終わりの時刻、長さを秒で表示します。シーンの区切りや CM の切れ目を探すときに使います。
基本コマンド
ffmpeg -i input.mp4 -vf blackdetect -f null /dev/null
黒い区間の時刻が、標準エラー出力(ターミナルに流れるログ)に表示されます。-f null /dev/null は、ファイルを書き出さずに解析だけをする指定です。
出力の読み方
[Parsed_blackdetect_0 @ 0x...] black_start:0 black_end:2.04 black_duration:2.04
[Parsed_blackdetect_0 @ 0x...] black_start:123.5 black_end:126 black_duration:2.5
1 行が 1 つの黒い区間です。
| フィールド | 説明 |
|---|---|
black_start |
黒い区間が始まる時刻(秒) |
black_end |
黒い区間が終わる時刻(秒) |
black_duration |
黒い区間の長さ(秒) |
パラメータの調整
デフォルト値
| パラメータ | デフォルト | 説明 |
|---|---|---|
black_min_duration (d) |
2.0 |
この秒数以上続いた黒い区間だけを表示する |
picture_black_ratio_th (pic_th) |
0.98 |
画面の98%以上が黒い画素(ピクセル)なら、黒いフレームとみなす |
pixel_black_th (pix_th) |
0.10 |
明るさ(黒を0、白を1とした値)がこの値以下の画素を、黒い画素とみなす |
カスタム例:0.5秒以上の黒区間を検出
pic_th をデフォルトの 0.98 より小さくして、少しゆるく判定しています。
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 の切れ目に黒い画面が入るときは、その黒い区間を探して切れ目を見つけられます。切れ目の黒い画面は短いこともあるので、d を小さくします。d=0.1 なら、0.1 秒(30fps で 3 フレーム)以上続く黒い区間を拾います。
ffmpeg -i recording.mp4 -vf "blackdetect=d=0.1:pix_th=0.10" -f null /dev/null 2>&1 | grep black_
grep black_ で、黒い区間の行だけを取り出しています。Windows のコマンドプロンプトでは、grep black_ の代わりに findstr black_ を使います。
出力をテキストファイルに保存
ffmpeg -i input.mp4 -vf blackdetect -f null /dev/null 2>&1 | grep black_ > black_segments.txt
黒い区間の行だけが black_segments.txt に保存されます。
誤検出しやすいケース
blackdetect は、画面の暗さだけで機械的に判定します。そのため、次のような映像では狙いと違う結果になりがちです。
| ケース | 原因 | 対策 |
|---|---|---|
| 暗転演出(フェードイン・フェードアウト) | 演出で暗くなった部分を区切りと判定してしまう | pic_th を 0.99 まで上げる。d を長めにする(デフォルトの 2 秒より短くしない) |
| 黒背景のテロップ | 文字以外がほぼ真っ黒 | pic_th を上げる(0.99)。テロップの部分を外したいときは、-ss/-to で調べる時間を絞る |
| レターボックス(上下の黒帯) | 黒帯のせいで pic_th=0.5 程度でも引っかかる |
crop で本編の部分だけを切り出してから blackdetect をかける |
| H.264 固定QPの暗いシーン | 圧縮ノイズで完全な黒にならない | pix_th を 0.15〜0.20 に上げて、許容範囲を広げる |
blackdetect と silencedetect の組み合わせ
画面が黒く、同時に音も消えている区間だけを拾うと、CM の切れ目やチャプターの区切りをより正確に見つけられます。silencedetect は、無音の区間を探すフィルタです。次の Python の例は、FFmpeg を1回実行して両方のフィルタの結果を読み取り、無音と重なる黒い区間だけを返します。
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=0.1:pic_th=0.99',
'-af', 'silencedetect=n=-30dB:d=0.5',
'-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)]
戻り値は、条件に合った黒い区間を(開始秒, 終了秒)の組で並べたリストです。
関連記事
- 無音区間の検出 — silencedetect フィルタで無音部分を特定する
- シーンチェンジ検出 — select/scdet フィルタで場面転換を自動検出
- 動画トリムツール(範囲を指定して切り出し)
よくある質問
blackdetect の閾値はどう設定する?
d=2:pix_th=0.10(2 秒以上続く区間を拾い、明るさが 0.10 以下の画素を黒とみなす。どちらもデフォルト値)では、2 秒以上続く黒い画面を拾えます。それより短い黒は、d を下げると拾えます。pix_th を 0.05 にすると、判定が厳しくなります。
見えてる黒フレームを blackdetect が見逃す
黒い部分が 2 秒より短い可能性があります。デフォルトの d=2 では、2 秒未満の黒い区間は表示されません。d を小さくしてください(たとえば d=0.1)。1 フレームだけの黒なら、d=0 にします。真っ黒ではなく、濃いグレーになっている可能性もあります。明るさが pix_th(デフォルト 0.10)を超える画素は黒と数えられないので、pix_th を 0.15 まで上げて、もう一度試してください。ロゴや字幕など、画面の一部だけが黒くないときは、pic_th を下げます。
黒フレームで自動分割するには?
スクリプトを書いて処理します。blackdetect の出力から黒い区間の時刻を読み取り、それをもとに -ss で範囲を決めて、区間ごとに ffmpeg -c copy で切り出します。-c copy は再エンコードしない分、切れ目が直前のキーフレーム(単独で表示できるフレーム)の位置にずれることがあります。フレーム単位でぴったり切りたいときは、-c copy を外して再エンコードしてください。
シーン検出と blackdetect の関係は?
役割が一部重なります。select='gt(scene,0.4)' は、画面の大きな変化全般を拾います。blackdetect は、黒やほぼ黒の画面が続く区間だけを狙います。チャプターの境目に黒いフェードが入る映像なら、blackdetect の方が確実です。
静止画にも使える?
d=0 を付ければ使えます。画像 1 枚だと黒い区間の長さが 0 秒になるので、デフォルトの d=2 では何も表示されません。黒い画像なら、ffmpeg -i image.png -vf blackdetect=d=0 -f null /dev/null で black_start:0 black_end:0 black_duration:0 と表示されます。