この記事でわかること
scdetフィルタでシーンチェンジを検出するコマンド- 検出感度
threshold(t)の調整方法 - 各シーンのタイムスタンプをメタデータから取得する方法
selectフィルタと組み合わせたシーン先頭フレームの抽出- シーンチェンジ点のサムネイル一括生成
動作確認: FFmpeg 8.1 / Windows — 本記事のコマンド 4 件を検証スクリプトで実行し、全て成功しました(2026-09-06) 対象 OS: Windows / macOS / Linux
基本コマンド
ffmpeg -i input.mp4 \
-vf "scdet=t=10,metadata=mode=print:key=lavfi.scd.score" \
-f null /dev/null
-f null /dev/null で出力ファイルを生成せず、metadata=print で検出情報を標準エラー出力に表示します。
出力の読み方
[Parsed_metadata_1 @ 0x...] lavfi.scd.score=18.3
[Parsed_metadata_1 @ 0x...] lavfi.scd.time=4.96
[Parsed_metadata_1 @ 0x...] lavfi.scd.score=32.7
[Parsed_metadata_1 @ 0x...] lavfi.scd.time=23.42
| フィールド | 説明 |
|---|---|
lavfi.scd.score |
シーンチェンジスコア(高いほど変化が大きい) |
lavfi.scd.time |
検出時刻(秒) |
threshold(感度)の調整
| パラメータ | デフォルト | 説明 |
|---|---|---|
t / threshold |
10 |
この値以上のスコアをシーンチェンジとして報告 |
ffmpeg -i input.mp4 -vf "scdet=t=20" -f null /dev/null
- 低い値(例: 5): 細かな変化も検出(誤検出増)
- 高い値(例: 40): 明確なカットのみ検出(見逃し増)
- ドキュメンタリーや映画:
10〜20が目安
シーンチェンジ点のフレームを画像として保存
select フィルタと組み合わせて、シーンが変わった瞬間のフレームを画像として保存します:
ffmpeg -i input.mp4 -vf "select='gt(scene,0.35)'" -vsync vfr scene_%04d.png
注意:
selectのsceneはselectフィルタ側のシーンスコアです。scdetのlavfi.scd.scoreとは別の値なので、しきい値も別に調整します。
metadata フィルタでタイムスタンプを確認
ffmpeg -i input.mp4 -vf "scdet=t=10,metadata=print" -f null /dev/null
用途別のthreshold設定例
| 用途 | 推奨 threshold |
|---|---|
| 映画のカット検出 | 8〜15 |
| スポーツ映像 | 15〜25 |
| アニメーション | 10〜20 |
| 監視カメラ映像 | 5〜10 |
| スライドショー動画 | 30〜50 |
よくある注意点
フェードやディゾルブは検出精度が低い
ハードカット(瞬間的な場面転換)は高精度で検出できますが、フェードやディゾルブ(徐々に変化)は scdet では誤検出しやすいです。
長い動画では処理時間がかかる
シーン検出は全フレームをデコードするため、長尺動画では時間がかかります。-ss と -to で部分的に解析することも可能です。
実測: 処理時間とサイズ
計測したコマンドはこれです。
ffmpeg -i input.mp4 -vf "scdet=t=12,metadata=mode=print:key=lavfi.scd.time" -f null -
| 項目 | 実測値 |
|---|---|
| 処理時間 | 7.09 秒(実時間の 16.92 倍速) |
| 出力ファイル | なし(解析のみ) |
計測環境: 1920x1080 / 30fps / 120 秒 / 351.4 MB の H.264 素材(Big Buck Bunny をループ、CC BY 3.0)を、Core i9-14900KF(32 スレッド)+ FFmpeg 8.1 (gyan.dev) で 2026-09-05 に逐次実行しました。生データはデータセットで公開しています。
なぜ 7.09 秒なのか
サイズの欄が空なのは、ファイルが 1 つも生まれないからです。-f null - は全フレームをデコードして scdet に通した後、エンコードもディスク書き込みもせずに捨てます。同じ素材・同じマシンで、フィルタなしの H.264 再エンコード(-c:v libx264 -crf 23 -preset medium)は 27.97 秒かかりました。この差はシーン検出が軽いという話ではなく、エンコーダが動いていないという話です。
反対側と比べると差はもっと大きくなります。フレームをデコードしない -c copy 系の操作は、ストリームの選択 0.41 秒、moov atom の移動 0.49 秒、音声フェード 1.03 秒と、いずれも 1 秒前後で終わります。多重化をやり直しているだけだからです。scdet はその中間に位置します — デコードは全フレーム行い、エンコードはしない。これがコストの正体です。
この記事には以前「8 コア程度のデスクトップ環境では実時間より速く終わることもあります」と書いていましたが、控えめすぎました。32 スレッドの i9 では 16.92 倍速です。ただしこの数字は 1080p / 8bit / H.264 をローカルディスクから読んだ場合のものです。4K や 10bit HEVC ではデコード自体が重くなり、ネットワーク越しの入力では CPU より先に I/O が頭打ちになります。
7.09 秒は画像を 1 枚も書き出していない実行の数字でもあります。検出したシーンを PNG で保存する構成では、ここに画像エンコードとディスク書き込みが上乗せされます(この構成は未計測)。カットが多い動画ほど、検出ではなく PNG 出力の側が支配的になります。
検出結果を編集点として使う場合は、ログの時刻をそのまま -ss に渡す前に、前後0.2〜0.49秒の余白を取ると失敗が減ります。シーン検出は映像の変化点を拾うだけで、音声の切れ目や字幕のタイミングまでは考慮しません。自動分割では短いクリップが大量にできることもあるため、最小尺のフィルタリングをスクリプト側で入れると扱いやすくなります。
カメラのフラッシュ、画面全体の白フェード、ゲーム画面の暗転は、実際のカットでなくても高いスコアになることがあります。検出結果を完全自動で使う前に、代表的な数分だけ手動確認してしきい値を決めてください。
関連記事
動作確認: FFmpeg 8.1 / Windows — 本記事のコマンド 4 件を検証スクリプトで実行し、全て成功しました(2026-09-06) 一次ソース: ffmpeg.org/ffmpeg-filters.html#scdet / ffmpeg.org/ffmpeg-filters.html#select
よくある質問
シーン検出の閾値は?
select='gt(scene,0.35)' で大きなカットを検出するところから始めます。早いカット系コンテンツなら 0.25〜0.3 まで下げ、ハードカットだけ拾うなら 0.45〜0.5 に上げます。scdet の t とは尺度が違う点に注意してください。
タイムスタンプをファイルにエクスポート
ffmpeg -i in.mp4 -filter:v "select='gt(scene,0.4)',showinfo" -f null - 2> scenes.log 後に pts_time を grep。
明らかなカットを見逃す
クロスフェード / フラッシュカットが閾値の下に隠れる場合があります。blackdetect と組み合わせるとフェードアウト系も拾える。
検出シーンで自動分割するには?
はい — タイムスタンプを wrapper スクリプトに渡し、各範囲に ffmpeg -ss A -to B -c copy partN.mp4 を実行する流れ。
アニメでも動く?
はい、ただし閾値を調整。アニメは色分布が均一なため、0.25〜0.3 まで下げるとリアルなカットが拾えます。