こんにちは、ffmpegを使用して動画からフレームを抽出する必要があります。これよりも速い方法はありますか。
ffmpeg -i file.mpg -r 1/1 $filename%03d.jpg
?
JPEGエンコードステップのパフォーマンスが過度に集中している場合、フレームを常に非圧縮でBMPイメージとして保存できます。
ffmpeg -i file.mpg -r 1/1 $filename%03d.bmp
これには、JPEGへのトランスコーディングによる量子化による品質の低下が生じないという利点もあります。 (PNGもロスレスですが、エンコードにJPEGよりもはるかに時間がかかる傾向があります。)
この質問に出くわしたので、簡単に比較してみましょう。 38m07sの長さのビデオから毎分1フレームを抽出するこれら2つの異なる方法を比較します。
time ffmpeg -i input.mp4 -filter:v fps=fps=1/60 ffmpeg_%0d.bmp
1分36.029秒
Ffmpegはビデオファイル全体を解析して目的のフレームを取得するため、これには時間がかかります。
time for i in {0..39} ; do ffmpeg -accurate_seek -ss `echo $i*60.0 | bc` -i input.mp4 -frames:v 1 period_down_$i.bmp ; done
0分4.689秒
これは約20倍高速です。高速シークを使用して目的の時間インデックスに移動し、フレームを抽出してから、時間インデックスごとにffmpegを数回呼び出します。 -accurate_seek
がdefault であり、入力ビデオ-ss
オプションの前に必ず-i
を追加してください。
-filter:v -fps=fps=...
の代わりに-r
を使用することをお勧めします。 後者は不正確かもしれません。fixed 、まだいくつかの問題が発生したので、安全にプレイする方が良い。
1、200、400、600、800、1000など、抽出するフレームが正確にわかっている場合は、次を使用してみてください。
select='eq(n\,1)+eq(n\,200)+eq(n\,400)+eq(n\,600)+eq(n\,800)+eq(n\,1000)' \
-vsync vfr -q:v 2
これをImagemagickのモンタージュへのパイプで使用して、任意のビデオから10フレームのプレビューを取得しています。明らかに、ffprobe
を使用して把握する必要があるフレーム番号
ffmpeg -i myVideo.mov -vf \
select='eq(n\,1)+eq(n\,200)+eq(n\,400)+eq(n\,600)+eq(n\,800)+eq(n\,100)',scale=320:-1 \
-vsync vfr -q:v 2 -f image2pipe -vcodec ppm - \
| montage -tile x1 -geometry "1x1+0+0<" -quality 100 -frame 1 - output.png
。
簡単な説明:
+
はORを表し、*
はANDを表します\,
は、単に,
文字をエスケープしています-vsync vfr -q:v 2
がなければ動作しないようですが、その理由はわかりません-誰か?私はそれを試してみました。 32秒で3600フレーム。あなたの方法は本当に遅いです。これを試してみてください。
ffmpeg -i file.mpg -s 240x135 -vf fps = 1%d.jpg
私の場合、少なくとも毎秒フレームが必要です。上記の「シーク先」アプローチを使用しましたが、タスクを並列化できるかどうか疑問に思いました。ここでFIFOアプローチでNプロセスを使用しました: https://unix.stackexchange.com/questions/103920/parallelize-a-bash-for-loop/216475#216475
open_sem(){
mkfifo /tmp/pipe-$$
exec 3<>/tmp/pipe-$$
rm /tmp/pipe-$$
local i=$1
for((;i>0;i--)); do
printf %s 000 >&3
done
}
run_with_lock(){
local x
read -u 3 -n 3 x && ((0==x)) || exit $x
(
"$@"
printf '%.3d' $? >&3
)&
}
N=16
open_sem $N
time for i in {0..39} ; do run_with_lock ffmpeg -ss `echo $i` -i /tmp/input/GOPR1456.MP4 -frames:v 1 /tmp/output/period_down_$i.jpg & done
基本的に&でプロセスを分岐しましたが、同時スレッドの数をNに制限しました。
これにより、私の場合、「シーク先」アプローチが26秒から16秒に改善されました。唯一の問題は、stdoutがフラッディングされるため、メインスレッドが端末に正常に戻らないことです。