web-dev-qa-db-fra.com

Le moyen le plus rapide d’extraire des images avec ffmpeg?

Bonjour, j'ai besoin d'extraire des images de vidéos en utilisant ffmpeg. Y a-t-il un moyen plus rapide de le faire que cela:

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

?

81
Stpn

Si l'étape d'encodage JPEG est trop intensive en performances, vous pouvez toujours stocker les images non compressées sous forme d'images BMP:

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

Cela présente également l’avantage de ne pas engendrer davantage de perte de qualité grâce à la quantification par transcodage au format JPEG. (Le format PNG est également sans perte mais a tendance à prendre beaucoup plus de temps que JPEG à encoder.)

101
Multimedia Mike

Je suis tombé sur cette question, alors voici une comparaison rapide. Comparez ces deux manières différentes d'extraire une image par minute d'une vidéo d'une longueur de 38m07s:

time ffmpeg -i input.mp4 -filter:v fps=fps=1/60 ffmpeg_%0d.bmp

1m36.029s

Cela prend beaucoup de temps, car ffmpeg analyse l’ensemble du fichier vidéo pour obtenir les images souhaitées.

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

C'est environ 20 fois plus vite. Nous utilisons la recherche rapide pour atteindre l'index de temps souhaité et extraire une image, puis appelons ffmpeg plusieurs fois pour chaque index de temps. Notez que -accurate_seekest la valeur par défaut Et assurez-vous d’ajouter -ss avant l’option vidéo -i.

Notez qu'il vaut mieux utiliser -filter:v -fps=fps=... au lieu de -r comme ce dernier peut être inexact. Bien que le ticket est marqué comme étant fixe , j'ai quand même rencontré des problèmes, il est donc préférable de jouer prudemment.

48
blutorange

Si vous savez exactement quelles images extraire, par exemple 1, 200, 400, 600, 800, 1000, essayez d’utiliser:

select='eq(n\,1)+eq(n\,200)+eq(n\,400)+eq(n\,600)+eq(n\,800)+eq(n\,1000)' \
       -vsync vfr -q:v 2

J'utilise ceci avec un tuyau vers le montage de Imagemagick pour obtenir un aperçu de 10 images à partir de n'importe quelle vidéo. De toute évidence, les numéros de trame que vous devez comprendre à l'aide de 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

.

Petite explication:

  1. Dans les expressions ffmpeg, + correspond à OR et * à AND.
  2. \, échappe simplement au caractère ,
  3. Sans -vsync vfr -q:v 2, cela ne semble pas fonctionner, mais je ne sais pas pourquoi - quelqu'un?
6
Voy

Je l'ai essayé. 3600 image en 32 secondes. votre méthode est vraiment lente. Tu devrais essayer ça.

ffmpeg -i fichier.mpg -s 240x135 -vf fps = 1% d.jpg

0
Kübra

Dans mon cas, j'ai besoin de cadres au moins toutes les secondes. J'ai utilisé l'approche 'chercher à' ci-dessus mais je me suis demandé si je pouvais paralléliser la tâche. J'ai utilisé les N processus avec l'approche FIFO ici: 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

En gros, j'ai lancé le processus avec & mais j'ai limité le nombre de threads simultanés à N.

Cela a amélioré l'approche 'chercher à' de 26 secondes à 16 secondes dans mon cas. Le seul problème est que le thread principal ne retourne pas proprement au terminal, car stdout est inondé.

0
Tycon