it-swarm.com.de

Schnellster Weg, um Frames mit ffmpeg zu extrahieren?

Hallo, ich muss mit ffmpeg Frames aus Videos extrahieren. Gibt es einen schnelleren Weg, als dies zu tun:

ffmpeg -i file.mpg -r 1/1 $filename%03d.jpg

?

81
Stpn

Wenn der JPEG-Codierungsschritt zu leistungsintensiv ist, können Sie die unkomprimierten Bilder immer 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 auch verlustfrei, dauert jedoch normalerweise viel länger als das Kodieren mit JPEG.)

101
Multimedia Mike

Kam über diese Frage, also hier ein schneller Vergleich. Vergleichen Sie diese zwei Möglichkeiten, um ein Bild pro Minute aus einem 38m07s 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, einen Frame zu extrahieren und dann für jeden Zeitindex mehrmals ffmpeg aufzurufen. Beachten Sie, dass -accurate_seekdie Standardeinstellung Ist, und stellen Sie sicher, dass Sie -ss vor der -i-Option für das Eingabevideo hinzufügen.

Beachten Sie, dass es besser ist, -filter:v -fps=fps=... anstelle von -r zu verwenden, da letzteres möglicherweise ungenau ist. Obwohl das Ticket als fixiert markiert ist , habe ich immer noch Probleme gehabt, also besser auf Nummer sicher gehen.

48
blutorange

Wenn Sie genau wissen, welche Frames extrahiert werden sollen, z. B. 1, 200, 400, 600, 800, 1000, versuchen Sie es mit:

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 von allen Videos eine Vorschau von 10 Bildern zu erhalten. Natürlich müssen Sie die Frame-Nummern mit ffprobe ermitteln.

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

.

Kleine Erklärung:

  1. In ffmpeg-Ausdrücken steht + für OR und * für AND
  2. \, geht einfach von dem ,-Zeichen ab
  3. Ohne -vsync vfr -q:v 2 scheint es nicht zu funktionieren, aber ich weiß nicht warum - jemand?
6
Voy

Ich versuchte es. 3600 Bilder in 32 Sekunden. Ihre Methode ist sehr langsam. Sie sollten dies versuchen.

ffmpeg -i file.mpg -s 240 x 135 -vf fps = 1% d.jpg

0
Kübra

In meinem Fall brauche ich mindestens jede Sekunde Frames. Ich habe oben den Ansatz "Suchen nach" verwendet, fragte mich aber, ob ich die Aufgabe parallelisieren könnte. Ich habe die N-Prozesse mit dem Ansatz FIFO hier verwendet: 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
    (
    "[email protected]" 
    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 & eingeteilt, aber die Anzahl der gleichzeitigen Threads auf N begrenzt.

Dies verbesserte die "Suche nach" Annäherung von 26 Sekunden auf 16 Sekunden in meinem Fall. Das einzige Problem ist, dass der Haupt-Thread nicht sauber zum Terminal zurückkehrt, da stdout überflutet wird.

0
Tycon