こんにちはffmpegを使用してビデオからフレームを抽出する必要があります。これよりも高速な方法はありますか。
ffmpeg -i file.mpg -r 1/1 $filename%03d.jpg
?
parallel -i {} -r 1/1 {.}-%03d.bmp ::: *mpg
こんにちはffmpegを使用してビデオからフレームを抽出する必要があります。これよりも高速な方法はありますか。
ffmpeg -i file.mpg -r 1/1 $filename%03d.jpg
?
parallel -i {} -r 1/1 {.}-%03d.bmp ::: *mpg
回答:
JPEGエンコードステップのパフォーマンスが高すぎる場合は、常にフレームを非圧縮でBMP画像として保存できます。
ffmpeg -i file.mpg -r 1/1 $filename%03d.bmp
これには、JPEGへのトランスコーディングによる量子化により、品質の低下が発生しないという利点もあります。(PNGもロスレスですが、エンコードにJPEGよりはるかに時間がかかる傾向があります。)
ffmpeg -r 1 file.mp4 -r 1 "$filename%03d.png"
ffmpeg -r 1 -i file.mp4 -r 1 "$filename%03d.png
、そうですか?(欠落していた-i
)
この質問に出くわしたので、ここで簡単に比較します。これらの2つの異なる方法を比較して、38分07秒の動画から1分あたり1フレームを抽出します。
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
デフォルトであり
、そしてあなたが追加します-ss
入力された映像の前に-i
オプション。
後者は不正確になる可能性が-filter:v -fps=fps=...
ある-r
ため、代わりに使用することをお勧めします。が固定としてチケットがマークされて、私はまだいくつかの問題が発生するので、より良い、それは安全なプレーでした。
bc
はUbuntuのネイティブパッケージではなく、bashを使用できますlet "i = $i * 60"
。ところで-優れたアイデア
-ss
前に追加する良いヒント-i
。そうでない場合、ビデオ全体がデコードされ、不要なフレームは破棄されます
ffmpeg
は、ホストのコアごとに1 つ実行されているようです-(bmpの場合)(ディスクのような他のボトルネックに達するまで)速度がほぼ線形に向上します。
抽出するフレームが正確にわかっている場合(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\,1000)',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
ffmpeg -i "input URL" -vf fps=1/5 out%d.png
入力URLがhttpsリンクでなければならない場所を試し ています。
ffmpeg -i file.mpg -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がフラッディングされるため、メインスレッドが端末に正常に終了しないことです。