Hallo, ich muss mit ffmpeg Frames aus Videos extrahieren. Gibt es einen schnelleren Weg als diesen:
ffmpeg -i file.mpg -r 1/1 $filename%03d.jpg
?
parallel -i {} -r 1/1 {.}-%03d.bmp ::: *mpg
Hallo, ich muss mit ffmpeg Frames aus Videos extrahieren. Gibt es einen schnelleren Weg als diesen:
ffmpeg -i file.mpg -r 1/1 $filename%03d.jpg
?
parallel -i {} -r 1/1 {.}-%03d.bmp ::: *mpg
Antworten:
Wenn der JPEG-Codierungsschritt zu leistungsintensiv ist, können Sie die unkomprimierten Frames jederzeit als BMP-Bilder speichern:
ffmpeg -i file.mpg -r 1/1 $filename%03d.bmp
Dies hat auch den Vorteil, dass durch Quantisierung durch Transcodierung in JPEG kein weiterer Qualitätsverlust entsteht. (PNG ist ebenfalls verlustfrei, die Codierung dauert jedoch in der Regel viel länger als die von JPEG.)
ffmpeg -r 1 file.mp4 -r 1 "$filename%03d.png"
ffmpeg -r 1 -i file.mp4 -r 1 "$filename%03d.png
, richtig? (Sie haben das verpasst -i
)
Kam über diese Frage, also hier ein kurzer Vergleich. Vergleichen Sie diese beiden Möglichkeiten, um ein Bild pro Minute aus einem 38 m07 langen Video zu extrahieren:
time ffmpeg -i input.mp4 -filter:v fps=fps=1/60 ffmpeg_%0d.bmp
1m36.029s
Dies dauert lange, da ffmpeg die gesamte Videodatei analysiert, um die gewünschten Frames zu erhalten.
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
0m4.689s
Das ist ungefähr 20 mal schneller. Wir verwenden die schnelle Suche, um zum gewünschten Zeitindex zu gelangen und einen Frame zu extrahieren, und rufen dann für jeden Zeitindex mehrmals ffmpeg auf. Beachten Sie, dass dies -accurate_seek
die Standardeinstellung ist
, und stellen Sie sicher, dass Sie -ss
vor der Eingabevideooption hinzufügen -i
.
Beachten Sie, dass es besser ist , zu verwenden , -filter:v -fps=fps=...
anstatt -r
wie diese ungenau sein können. Obwohl das Ticket als fest markiert ist , sind dennoch einige Probleme aufgetreten. Gehen Sie also besser auf Nummer sicher.
bc
ist kein natives Ubuntu-Paket, stattdessen kann man bash verwenden : let "i = $i * 60"
. Übrigens - ausgezeichnete Idee
-ss
vor -i
. Andernfalls wird das gesamte Video dekodiert und die nicht erforderlichen Frames werden verworfen
ffmpeg
pro Kern Ihres Hosts auszuführen - was (für bmp) zu nahezu linearen Geschwindigkeitsverbesserungen führt (bis Sie auf einen anderen Engpass wie die Festplatte stoßen).
Wenn Sie genau wissen, welche Frames extrahiert werden sollen, z. B. 1, 200, 400, 600, 800, 1000, versuchen Sie Folgendes:
select='eq(n\,1)+eq(n\,200)+eq(n\,400)+eq(n\,600)+eq(n\,800)+eq(n\,1000)' \
-vsync vfr -q:v 2
Ich verwende dies mit einer Pipe zu Imagemagicks Montage, um eine Vorschau von 10 Bildern von Videos zu erhalten. Offensichtlich die Rahmennummern, die Sie mit herausfinden müssenffprobe
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
.
Kleine Erklärung:
+
für OR und*
für AND\,
entkommt einfach dem ,
Charakter-vsync vfr -q:v 2
es scheint nicht zu funktionieren, aber ich weiß nicht warum - jemand?Ich versuchte es. 3600 Frame in 32 Sekunden. Ihre Methode ist sehr langsam. Sie sollten dies versuchen.
ffmpeg -i file.mpg -s 240x135 -vf fps=1 %d.jpg
ffmpeg -i "input URL" -vf fps=1/5 out%d.png
wo die Eingabe-URL ein https-Link sein muss.
ffmpeg -i file.mpg -vf fps=1 %d.jpg
In meinem Fall brauche ich mindestens jede Sekunde Frames. Ich habe oben den Ansatz "Suchen nach" verwendet, mich aber gefragt, ob ich die Aufgabe parallelisieren könnte. Ich habe hier die N-Prozesse mit FIFO-Ansatz verwendet: /unix/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
Im Wesentlichen habe ich den Prozess mit & gegabelt, aber die Anzahl der gleichzeitigen Threads auf N begrenzt.
Dies verbesserte in meinem Fall den Suchansatz von 26 Sekunden auf 16 Sekunden. Das einzige Problem ist, dass der Haupt-Thread nicht sauber zum Terminal zurückkehrt, da stdout überflutet wird.
Das hat bei mir funktioniert
ffmpeg -i file.mp4 -vf fps=1 %d.jpg