Comment générer rapidement des GIF animés de faible qualité avec ffmpeg?

3

Nous générons beaucoup de GIF miniatures dont la qualité importe peu autant que le temps nécessaire à leur génération. La génération de fichiers GIF de haute qualité avec ffmpeg est très bien couverte, mais je n’ai pas beaucoup de chance de savoir comment générer des fichiers de qualité médiocre aussi rapidement que possible.

Le calcul de la palette occupe la majeure partie du temps d'exécution à l'aide de la commande suivante (extraite de la réponse du filtre graphique à chaînes multiples: Comment créer efficacement un gif de la meilleure palette à partir d'une partie vidéo directement à partir du Web ):

ffmpeg -y -threads 8 -r 24 -f image2 -start_number 1 -i "frames.%04d.jpg" -filter_complex "fps=24,scale=150:-1:flags=fast_bilinear,split=2 [a][b]; [a] palettegen [pal] fifo [b]; [b] [pal] paletteuse" output.gif

Le temps d'exécution de cette commande avec 1000 images est d'environ 72 secondes. Environ 67 secondes correspondent à la palette, puis la génération GIF réelle prend environ 5 secondes. J'aimerais réduire au maximum le temps d'exécution total et accepter de perdre beaucoup de qualité d'image pour la rapidité.

Rjak
la source
1
Votre commande est syntaxiquement incorrecte. il vous manque une [b]étiquette. Quoi qu'il en soit, l'utilisation de la palette est environ 200⨉ plus lente à en juger par un test rapide. Ne pas l'utiliser du tout n'est pas une option pour vous?
slhck
@slhck Je trouve que la documentation ffmpeg sur ce sujet est assez difficile à maîtriser, mais je l’ai suggérée pour éliminer la palette: ffmpeg -y -r 24 -f image2 -start_number 1 -i "frames.%04d.jpg" -filter:v "scale=150:-1:flags=fast_bilinear" output.gifLes deux problèmes suivants: ) Je ne suis pas sûr à 100% que cette commande élimine complètement le calcul de palette (uniquement que le calcul de palette que je spécifiais auparavant n’est pas inclus).
Rjak
1
Oui, c'est essentiellement ce que je voulais dire. Désolé de ne pas être aussi explicite, je pensais que vous saviez ce que faisait la commande de filtrage que vous utilisiez. Dans mes tests, laissant la palette tout en fait accéléré la commande de manière significative . Qu'est-ce qui vous a amené à la conclusion initiale que l'encodage réel ne prenait que 5 secondes?
slhck
Observation de la production, ce qui n’est probablement pas un excellent indicateur. Lorsque j'exécute la commande sans génération de palette, l'indicateur "image en cours" augmente immédiatement et nous commençons à traiter les images. Lorsque je l'exécute avec la génération de palette, l'image actuelle reste à 0 jusqu'à environ 5 secondes avant la fin du traitement, puis elle tourne très rapidement dans toutes les images.
Rjak
1
Oui, c'est aussi ce que j'observe, mais c'est beaucoup plus rapide alors. Mais je suppose que cela dépend de la longueur de la vidéo. Pour être honnête, je ne sais pas s'il existe un moyen plus rapide de générer le GIF que de le faire ffmpeg -i <input> <scale> <output.gif>.
Slhck

Réponses:

2

Votre utilisation des filtres palettegen/ paletteuserend la commande plus lente. Le moyen le plus simple d’obtenir un GIF de qualité inférieure serait:

ffmpeg -f image2 -i "frames.%04d.jpg" output.gif

Avec mise à l'échelle supplémentaire:

ffmpeg -f image2 -i "frames.%04d.jpg" -vf scale=150:-1 output.gif

Vous pouvez également supprimer des images dans le fichier GIF de sortie, c'est-à-dire échantillonner les images, afin qu'elles ne soient pas toutes traitées. Par exemple, pour n’avoir qu’une sortie FPS, en utilisant un fpsfiltre:

ffmpeg -i "frames.%04d.jpg" -vf "fps=fps=1,scale=150:-1" output.gif
slhck
la source
Je pense qu'il y a une faute de frappe dans ce dernier exemple ... devrait être `-vf" fps = 1, scale = 150: -1 ". Le temps d'exécution du deuxième exemple est de 68,48s. Spécifier fps = 1 donne un GIF de 1 FPS, mais la source étant 120 fps, le résultat est lu trop lentement et le temps d'exécution n'est pas suffisamment amélioré (59,44 secondes). J'expérimente avec l'utilisation du chargeur de concat et d'avoir ffmpeg lu chaque Nième image. Ainsi, si j'échantillonne toutes les 5 images à l'aide du redimensionnement de Lanczos et de la génération de palette par image, la qualité temporelle est superbe, la qualité des couleurs est superbe et la commande est exécutée en moins de 8 secondes.
Rjak
Je vais partager le tout dans un commentaire ici, une fois que je l'ai entièrement testé et que les délais d'exécution sont respectés.
Rjak
@Rjak La première option du fpsfiltre est nommée fps, elles sont donc équivalentes. Si votre source est 120 images par seconde, vous devez spécifier -framerate 120 -i "frames…"car la valeur par défaut pour l'entrée est 24.
slhck
1

J'étais chargé de réduire le temps nécessaire pour générer un fichier GIF animé aussi proche que possible de 30 images de long pour une largeur de 150 pixels. La plupart des séquences que nous générons ont moins de 1000 images. Nous avions une séquence de 15 000 images et nos noeuds de rendu prenaient 17 minutes pour produire ce fichier GIF de ~ 30 images, ce qui est trop lent.

Nous utilisions ffmpeg comme démultiplexeur et piping pour imagemagick. Après plusieurs heures d’expérimentation, je suis arrivé aux conclusions suivantes:

  • Le nombre de trames d' entrées que vous demandez ffmpeg à traiter est de loin la contribution la plus percutante en termes de vitesse d'exécution. Si l'utilisation du démultiplexeur concat pour ignorer les images en entrée est une option, cela fera la plus grande différence de performances. En prenant chaque cinquième image, j'ai été en mesure de réduire le temps de calcul total à 1 minute 45 secondes avec une mise à l'échelle des lanczos de haute qualité et un calcul de palette par image. La création de notre vignette d'aperçu à 30 images prend désormais moins d'une seconde .

  • L'algorithme de redimensionnement était le deuxième impact le plus important en termes de performances (mais loin derrière). L'utilisation de fast_bilinear au lieu de lanczos a permis de gagner 150 secondes de temps de calcul sur les 15 000 images.

  • La variable la moins impactante était le calcul de palette, et cela variait avec l'algorithme de redimensionnement. Avec plus de 15 000 images utilisant des lanczos, nous avons économisé environ 17 secondes de temps d’exécution en éliminant le calcul des palettes. Avec fast_bilinear, nous avons économisé environ 75 secondes de temps d'exécution.

Comme l’algorithme de redimensionnement et le calcul de la palette étaient négligeables, nous avons fini par les garder à la plus haute qualité. Nous avons réduit notre temps de calcul de 17 minutes à moins d'une seconde principalement en indiquant à ffmpeg de ne pas lire les fichiers d'entrée.

ENTRÉE CLÉ: CADRES D'ENTRÉE SAUTÉS vs CADRES DE SORTIE SAUTÉS

Notre processus prenait si longtemps parce que la suppression de trame n'aide pas le temps d'exécution lors de l'utilisation du démultiplexeur image2. Si vous utilisez le -rdrapeau et le fpsfiltre, vous affecterez le nombre d'images apparaissant dans le fichier GIF final, mais ffmpeg semble toujours utiliser quelque chose avec les 15 000 images en entrée.

La seule façon pour moi de faire en sorte que ffmpeg ignore les trames d’entrée est d’utiliser le concatdémultiplexeur.

Voici comment je génère maintenant des vignettes GIF animées de haute qualité sur ma machine de développement en moins d'une seconde en ignorant les images d'entrée:

# create text file which describes the ~30 input frames we want ffmpeg to process
seq -f "file 'left_frames.%04g.jpg'" 10000 500 25000 > tmp.txt

# generate the animated gif using ffmpeg only
ffmpeg -f concat -i tmp.txt -filter_complex "scale=150:-1:flags=lanczos,split=2 [a][b]; [a] palettegen [pal]; [b] fifo [b]; [b] [pal] paletteuse" output.gif
Rjak
la source