FFmpegは、ビデオを表すためのサムネイルとして使用できるビデオから画像をキャプチャできます。その最も一般的な方法は、 FFmpeg Wiki にあります。
しかし、私はある間隔でランダムなフレームを選びたくはありません。シーンの変化を捉えるためにFFmpegでフィルタを使用するオプションがいくつかあります。
フィルタthumbnail
は、ビデオ内で最も代表的なフレームを見つけようとします。
ffmpeg -i input.mp4 -vf "thumbnail,scale=640:360" -frames:v 1 thumb.png
次のコマンドは、前のシーンと比較して40%を超える変化があるフレームだけを選択し(したがってシーンの変化もおそらく)、5つのPNGのシーケンスを生成します。
ffmpeg -i input.mp4 -vf "select=gt(scene\,0.4),scale=640:360" -frames:v 5 thumb%03d.png
上記のコマンドの情報クレジットは Fabio Sonnati です。 2番目の画像は、n枚の画像を取得して最高の画像を選択できるので、よさそうです。私はそれを試してみて、それは同じ画像を5回生成しました。
さらに調査を重ねた結果、次のことがわかりました。
ffmpeg -i input.mp4 -vf "select=gt(scene\,0.5)" -frames:v 5 -vsync vfr out%02d.png
-vsync vfr
はあなたが異なる画像を取得することを保証します。これは常にビデオの最初のフレームを選択します。ほとんどの場合、最初のフレームはクレジット/ロゴであり意味がありません。そのため、ビデオの最初の3秒を破棄するために-ss
3を追加しました。
私の最後のコマンドはこのようになります:
ffmpeg -ss 3 -i input.mp4 -vf "select=gt(scene\,0.5)" -frames:v 5 -vsync vfr out%02d.jpg
これは私ができる最善でした。私は5つのビデオしか選んでいないので、それらはすべてビデオの最初からのもので、ビデオの後半で発生する重要なシーンを見逃してしまう可能性があることに気付きました。
私は他のよりよい選択のためにあなたの頭脳を選びたいと思います。
理想的には、タイムスパンがビデオの1、2、3、4、および5th 20%である5つのタイムスパンのそれぞれの中で最初の> 40%変化するフレームを探してみてください。
また、クレジットを避けるために6つの期間に分割し、1番目の期間を無視することもできます。
実際には、これはシーンチェンジチェックとビデオの最初のビットを捨てるというあなたの主張を適用しながらfpsを低い数値に設定することを意味します。
...何かのようなもの:
ffmpeg -ss 3 -i input.mp4 -vf "select=gt(scene\,0.4)" -frames:v 5 -vsync vfr -vf fps=fps=1/600 out%02d.jpg
意味のあるを定義するのは難しいですが、ビデオファイル全体にN個のサムネールを効率的に作成したい場合は、ユーザーがアップロードしたコンテンツで制作時にサムネールを生成します。
for X in 1..N
T = integer( (X - 0.5) * D / N )
run `ffmpeg -ss <T> -i <movie>
-vf select="eq(pict_type\,I)" -vframes 1 image<X>.jpg`
どこで:
ffmpeg -i <movie>
単独またはffprobe
から読み取られます。これにはNice JSON出力ライターがあります。単に上記は、映画の各区画の中央のキーフレームを書き留めます。例えば。映画の長さが300秒で、3枚のサムネイルが必要な場合は、50秒、150秒、250秒後に1キーフレームかかります。 5枚のサムネイルの場合は、30秒、90秒、150秒、210秒、270秒になります。ムービーの長さDに応じてNを調整できます。 5分の映画には3つのサムネイルがありますが、1時間に20のサムネイルがあります。
上記のffmpeg
コマンドを呼び出すたびに、1GB H.264の場合、1秒の何分の一(!)かかります。それは即座に<time>
の位置にジャンプし(-ss
の前に-i
を気にする)、実質的に完全なJPEGである最初のキーフレームをとるためです。正確な時間的位置に合わせてムービーをレンダリングするのに浪費する時間はありません。
上記のscale
や他のサイズ変更方法を混在させることができます。単色のフレームを削除したり、thumbnail
のような他のフィルタと混ぜることもできます。
私はかつて似たようなことをしましたが、私はビデオのすべてのフレームを(1 fpsで)エクスポートし、それらを画像間の差を計算するPerlユーティリティと比較しました。各フレームを前のサムネイルと比較し、それがすべてのサムネイルと異なる場合は、それをサムネイルコレクションに追加しました。ここでの利点は、ビデオがシーンAからBに移動し、それらがAに戻った場合、ffmpegは2フレームのAをエクスポートすることです。
これを試して
ffmpeg -i input.mp4 -vf fps= no_of_thumbs_req/total_video_time out%d.png
このコマンドを使用して、ビデオ全体を代表する必要な数のサムネイルを生成できます。
これは私がポスターとして使用するためにライブm3u8ストリームのための定期的なサムネイルを生成するためにすることです。サムネイルを生成するためだけに継続的なffmpegタスクを実行すると、すべてのCPUが消費されるので、代わりに60秒ごとにcronjobを実行してストリームのすべてのサムネイルを生成します。
#!/usr/bin/env bash
## this is slow but gives better thumbnails (takes about 1+ minutes for 20 files)
#-vf thumbnail,scale=640:360 -frames:v 1 poster.png
## this is faster but thumbnails are random (takes about 8 seconds for 20 files)
#-vf scale=640:360 -frames:v 1 poster.png
cd ~/path/to/streams
find . -type f \
-name "*.m3u8" \
-execdir sh -c 'ffmpeg -y -i "$0" -vf scale=640:360 -frames:v 1 "poster.png"' \
{} \;
60秒よりも頻繁に実行する必要がある場合(cronjobの制限)、スクリプト内でwhile
ループを実行すると永久に実行されます。頻度を30秒に変更するには、sleep 30
を追加するだけです。ただし、前回の実行は次の動画の開始前に完了しない可能性があるため、多数の動画でこれを実行することはお勧めしません。
理想的にはcronjobを使用して、5分ごとに実行します。