FFmpegを使用したビデオの意味のあるサムネイル


80

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異なる画像を取得します。これは常にビデオの最初のフレームを常に選択します。ほとんどの場合、最初のフレームはクレジット/ロゴであり、意味がないため-ss、ビデオの最初の3秒を破棄するために3 を追加しました。

私の最後のコマンドは次のようになります。

ffmpeg -ss 3 -i input.mp4 -vf "select=gt(scene\,0.5)" -frames:v 5 -vsync vfr out%02d.jpg

これは私ができる最善でした。私は5つのビデオしか選んでいないので、それらはすべてビデオの最初からのものであり、ビデオの後半で発生する重要なシーンを見逃す可能性があることに気づきました

他のより良いオプションのためにあなたの脳を選びたいです。


素敵なコマンドの例。FWIW、OS XでFFmpegで生成されたJPEG画像(10.8、FFmpeg 1.1以下)で問題が発生することはありませんでした。2番目から2番目のコマンドは、私にとってはうまく機能します。最後のコマンドも同様です。私はlibopenjpeg..でコンパイルしましたが、それが違いを生むかどうかわかりません。
slhck

有難うございます。ffmpeg config / version detailsを使用して質問を編集しました。このマシンでは1.1にアップグレードしていません。それを行い、結果が変わるかどうかを確認します。
d33pika

1
あなたはUbuntuにいますか?静的ビルドから最新のGit Masterバージョンを試用したり、自分でコンパイルして再実行したりできますか?または最新の安定版。確認したばかりですが、mjpegエンコーダも使用しています。また、とをチェックjpegoptimしましたexiv2。どちらもサンプルコマンドのすべてのJPG結果で問題なく動作します。
slhck

1
更新しましたが、今は動作します!以前のバージョンにはいくつかのバグがあったと思います。
d33pika

先に進んで、新しいバージョンのソリューションを投稿してください。できれば、発生したバグを示す変更ログへのリンクを付けて、新しいバージョンで修正してください。
リズ

回答:


29

理想的には、5つのタイムスパンのそれぞれで40%を超える最初の変更フレームを探してみてください。タイムスパンは、ビデオの1番目、2番目、3番目、4番目、5番目の20%です。

また、クレジットを回避するために、6つの期間に分割し、最初の期間を無視することもできます。

実際には、これはシーン変更チェックと引数を適用してビデオの最初のビットを捨てる間、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

1
完全に黒または白の画像が撮影されますが、どうすればそれらを回避できますか?
d33pika

1
ブラックフレームとそれらのシーケンスを検出するフィルターがあります(ffmpeg.org/ffmpeg-filters.html#blackframeまたはffmpeg.org/ffmpeg-filters.html#blackdetect)。成長するワンライナーにそれらのいずれも使用できないようにしますが、間違いなく黒いフレームを取り除き(別のステップ)、結果のビデオからサムネイルを抽出できるはずです。
AM

5
白いフレームに関しては、今では複雑になっていますが、まだ方法があるように見えます:1.黒いフレームを取り除く2.否定(白が黒に変わる)3.白いフレームを取り除く4.再び否定する5.サムネイルを抽出する(特に1行で黒または白のフレームを削除することができた場合、ここに投稿できますか。将来の読者のために回答に追加できます。または、実際に新しい質問と回答を作成できます。それは間違いなく賛成です。)
午前

3
単純な白黒などの退屈な画像を回避するには、必要以上のサムネイルを生成し、jpegで圧縮して、ファイルサイズの大きい画像を選択します。これは驚くほどうまく機能して、適切なサムネイルを取得します。
サムワトキンス

2
このコマンドは機能しませんでしたUnable to find a suitable output format for 'fps=fps=1/600'。エラーが発生しました。解決策は、-vfその引数の前に追加することです(stackoverflow.com/questions/28519403/ffmpeg-command-issueを参照)
ジョンワイズマン

7

意味のある定義は難しいですが、ビデオファイル全体に効率的に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`

どこ:

  • D- ffmpeg -i <movie>単独から読み取られたビデオ期間、またはffprobe素敵なJSON出力ライターbtwを含むビデオ期間
  • N-必要なサムネイルの総数
  • X-サムネイル番号、1〜N
  • T-サムネイルの時点

単純に、上記は映画の各パーティションの中央のキーフレームを書き留めます。たとえば、映画の長さが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ます。


2
-ss N前に移動するの-iはすごいヒントです。ありがとうございました!
-apinstein

2

私はかつて似たようなことをしましたが、ビデオのすべてのフレームを(1 fpsで)エクスポートし、画像間の違いを計算するperlユーティリティと比較しました。各フレームを前のサムネイルと比較し、すべてのサムネイルと異なる場合は、サムネイルコレクションに追加しました。ここでの利点は、ビデオがシーンAからBに移動し、Aに戻る場合、ffmpegがAの2フレームをエクスポートすることです。


2つの画像を比較するためにどのような要因を使用しましたか?
d33pika

残念ながら、私は覚えていませんが、かなり前のことでした。どの比較方法を使用するかを最初に決定してから、いくつかのテストを行って正しい要因を見つける必要があります。これには時間がかかりません。
エランベンナタン

私はここで大声で考えていますが、これより悪い選択肢ではないでしょうか?ビデオからエクスポートされた2つの画像を比較すると、すでにいくつかの情報が失われています。つまり、2枚の写真よりもコーデック情報から類似度を計算する方が簡単ですね。最近、私はいくつかのアルゴリズム/ライブラリを調べて画像を比較していますが、それらは必要とするほどうまく機能しません。
サミュエル

ffmpegでは、same_qualityフラグを使用して、品質を損なうことなくフレームを抽出できます。コーデック情報を使用する場合、iframeを取得するだけではないことを確認する必要があります。とにかく、そのperlユーティリティは私にとっては問題なく機能し、非常に柔軟に設定できます。こちらをご覧ください:search.cpan.org/~avif/Image-Compare-0.3/Compare.pm
エランベンナタン

2

これを試して

 ffmpeg -i input.mp4 -vf fps= no_of_thumbs_req/total_video_time out%d.png

このコマンドを使用して、ビデオ全体を表す必要な数のサムネイルを生成できます。


の正しい式ではfpsない(no_of_frames_req * fps_of_vid) / total_video_framesでしょうか?
-flolilo

私は反対の解決策を探しています:カメラがより安定していて動かない期間からより多くのフレームを選択しますか?(連続するフレーム間の差は小さく、大きくはありません)。それを行う方法はありますか?
ティナJ

1

ここでは、ライブ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スクリプトでループを実行すると、スクリプトが永久に実行されます。を追加しsleep 30て、頻度を30秒に変更します。ただし、次の動画が始まる前に前回の実行が完了しない可能性があるため、多数の動画でこれを行うことはお勧めしません。

理想的にはcronjobで5分ごとに実行するだけです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.