Comment convertir une vidéo au format GIF en utilisant ffmpeg, avec une qualité raisonnable?

311

Je suis en train de convertir un FLVfilm en GIFfichier avec ffmpeg.

ffmpeg -i input.flv -ss 00:00:00.000 -pix_fmt rgb24 -r 10 -s 320x240 -t 00:00:10.000  output.gif

Cela fonctionne très bien, mais le fichier gif en sortie a une qualité très basse.

Des idées comment puis-je améliorer la qualité de gif converti?

Sortie de commande:

ffmpeg -i input.flv -ss 00:00:00.000 -pix_fmt rgb24 -r 10 -s 320x240 -t 00:00:10.000  output.gif
ffmpeg version 0.8.5-6:0.8.5-0ubuntu0.12.10.1, Copyright (c) 2000-2012 the Libav developers
  built on Jan 24 2013 14:52:53 with gcc 4.7.2
*** THIS PROGRAM IS DEPRECATED ***
This program is only provided for compatibility and will be removed in a future release. Please use avconv instead.
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'input.flv':
  Metadata:
    major_brand     : mp42
    minor_version   : 0
    compatible_brands: isommp42
    creation_time   : 2013-02-14 04:00:07
  Duration: 00:00:18.85, start: 0.000000, bitrate: 3098 kb/s
    Stream #0.0(und): Video: h264 (High), yuv420p, 1280x720, 2905 kb/s, 25 fps, 25 tbr, 50 tbn, 50 tbc
    Metadata:
      creation_time   : 1970-01-01 00:00:00
    Stream #0.1(und): Audio: aac, 44100 Hz, stereo, s16, 192 kb/s
    Metadata:
      creation_time   : 2013-02-14 04:00:07
[buffer @ 0x92a8ea0] w:1280 h:720 pixfmt:yuv420p
[scale @ 0x9215100] w:1280 h:720 fmt:yuv420p -> w:320 h:240 fmt:rgb24 flags:0x4
Output #0, gif, to 'output.gif':
  Metadata:
    major_brand     : mp42
    minor_version   : 0
    compatible_brands: isommp42
    creation_time   : 2013-02-14 04:00:07
    encoder         : Lavf53.21.1
    Stream #0.0(und): Video: rawvideo, rgb24, 320x240, q=2-31, 200 kb/s, 90k tbn, 10 tbc
    Metadata:
      creation_time   : 1970-01-01 00:00:00
Stream mapping:
  Stream #0.0 -> #0.0
Press ctrl-c to stop encoding
frame=  101 fps= 32 q=0.0 Lsize=    8686kB time=10.10 bitrate=7045.0kbits/s dup=0 drop=149    
video:22725kB audio:0kB global headers:0kB muxing overhead -61.778676%

Merci.

Kamil Hismatullin
la source
1
Il est amusant de voir comment les gens travaillent toujours avec Palp au format GIF quand APNG est une chose.
Константин Ван le

Réponses:

447

ffmpeg exemple

Sortie GIF de ffmpeg
183k

ffmpegpeut produire du GIF de haute qualité. Il est toujours recommandé d'utiliser une version récente: télécharger ou compiler .

ffmpeg -ss 30 -t 3 -i input.mp4 -vf "fps=10,scale=320:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" -loop 0 output.gif
  • Cet exemple ignorera les 30 premières secondes ( -ss 30) de l'entrée et créera une sortie de 3 secondes ( -t 3).
  • Le filtre fps définit la fréquence d'images.
  • Le filtre d' échelle redimensionnera la sortie à une largeur de 320 pixels et déterminera automatiquement la hauteur tout en préservant le rapport hauteur / largeur.
  • Les filtres palettegen et paletteuse généreront et utiliseront une palette personnalisée générée à partir de votre entrée.
  • Le filtre divisé permet de tout faire en une seule commande.
  • Contrôle en boucle avec -loopoption de sortie. Une valeur de 0est une boucle infinie.

Voir GIF haute qualité avec FFmpeg pour de nombreux autres exemples et options.


convertExemple Imagemagick

Sortie GIF de ffmpeg
227k

Une autre méthode de ligne de commande consiste à diriger de ImageMagick ffmpegvers convert(ou magick).

 ffmpeg -i input.mp4 -vf "fps=10,scale=320:-1:flags=lanczos" -c:v pam -f image2pipe - | convert -delay 10 - -loop 0 -layers optimize output.gif

Réglage de la cadence

Définissez la fréquence d'images avec une combinaison du fpsfiltre dans ffmpeget -delaydans convert. Cela peut devenir compliqué, car convertun flux d'images brut est généré, de sorte qu'aucun fps n'est préservé. Deuxièmement, la -delayvaleur en convertest en ticks (il y a 100 ticks par seconde), pas en images par seconde. Par exemple, avec fps=12.5= 100 / 12,5 = 8 = -delay 8.

convertarrondit la -delayvaleur à un nombre entier, ce qui signifie que les résultats 8,4 et 8 correspondent à 9, ce qui signifie que seules certaines fréquences d'images sont prises en charge lors de la définition d'un délai uniforme pour toutes les images (un délai spécifique peut être défini par image mais il est supérieur cette réponse).

-delaysemble être ignoré si elle est utilisée comme option de sortie, elle doit donc être utilisée auparavant, -comme indiqué dans l'exemple.

Enfin, les navigateurs et les visualiseurs d'images peuvent implémenter un délai minimum, de sorte que vous -delaypouvez être ignoré quand même.

Vidéo fournie par le centre national de formation à la conservation du US Fish & Wildlife Service.

llogan
la source
4
Ajout de quelques exemples de résultats (mais toujours des cadres). Ici, le premier fichier fait 4,1 Mo, le second environ 8 Mo.
Slhck
2
@ LordNeckbeard, vous êtes génial! merci beaucoup-vf scale=320:-1,format=rgb8,format=rgb24
Kamil Hismatullin
6
A propos, pour la convertcommande de conversion des images PNG que j'ai finalement utilisées convert -delay 5 -loop 0 -dither None -colors 80 "frames/ffout*.png" -fuzz "40%" -layers OptimizeFrame "output.gif", ce qui réduit un peu la taille globale du fichier
Wilf
2
D'accord, je l'ai, je l'ai utilisé scale=0:-1, donc quand vous réglez l'échelle sur 0, cela prendra l'échelle de la vidéo.
Mousa Alfhaily
2
Ce Q & R doit être encodé de manière permanente dans un tome (ou peut-être simplement "épinglé" pour l'instant) car dans cent ans, toutes les communications se feront via des mèmes. Je pense que l'activité sur ce post à elle seule en parle.
Jonathan Neufeld
87

Si vous préférez éviter les fichiers image intermédiaires, les commandes fournies par LordNeckBeard peuvent être acheminées entre ffmpeget celles d'ImageMagick convertafin qu'aucun fichier intermédiaire ne soit requis:

ffmpeg -i input.flv -vf scale=320:-1 -r 10 -f image2pipe -vcodec ppm - | convert -delay 5 -loop 0 - output.gif

Le -f image2pipedit ffmpeg pour diviser la vidéo en images et le rendre apte à être canalisé sur et -vcodec ppmspécifie le format de sortie pour être ppm (pour une raison quelconque si le format est .png, soit convertne lit pas toutes les images du tuyau ou ffmpeg - t ne pas les afficher tous). Le -pour les deux commandes spécifie qu'un tuyau sera utilisé pour la sortie et l'entrée, respectivement.

Pour optimiser le résultat sans enregistrer de fichier, vous pouvez diriger la sortie de convertvers une seconde convertcommande:

ffmpeg -i input.flv -vf scale=320:-1 -r 10 -f image2pipe -vcodec ppm - | convert -delay 5 -loop 0 - gif:- | convert -layers Optimize - output.gif

Le gif:-dit convertde diriger sa sortie sous forme de données au format gif et -layers Optimizeindique à la seconde convertà effectuer optimize-frameet optimize-transparancyméthodes (voir Introduction à l'optimisation d'animation ImageMagick ). Notez que la sortie du -layers Optimizefichier peut ne pas toujours fournir une taille de fichier plus petite, vous pouvez donc essayer de convertir en un gif sans optimisation au préalable pour en être sûr.

N'oubliez pas que pendant tout ce processus, tout est en mémoire, vous aurez donc besoin de suffisamment de mémoire si les images sont assez volumineuses.

remarquable
la source
1
Cet ensemble de commandes fonctionne également avecavconv
raphael
Vous devriez fusionner les deux dernières commandes de conversion:convert -delay 5 -loop 0 -layers Optimize - output.gif
Clément
Le gif semble fonctionner à deux fois la vitesse de la vidéo source?
Titan
@Titan pense que c'est le -r 10 dans la première commande et le -delay 5 dans la seconde. J'ai changé le délai à 10 également et il semble jouer normalement maintenant.
Steven Huang
2
Vous pouvez également éviter les fichiers image intermédiaires en utilisant le splitfiltre de ffmpeg. Pas besoin de ffmpeg -ss 30 -t 3 -i "input.flv fps=10,scale=320:-1:flags=lanczos,split[x][z];[z]palettegen[y];[x][y]paletteuse" output.gif
siffler
37

A partir de ffmpeg 2.6, nous pouvons faire encore mieux:

palette="/tmp/palette.png"
filters="fps=15,scale=320:-1:flags=lanczos"

ffmpeg -i input.flv -vf "$filters,palettegen" -y $palette
ffmpeg -i input.flv -i $palette -lavfi "$filters [x]; [x][1:v] paletteuse" -y output.gif

HT

pje
la source
18

J'ai créé ma propre version du script, qui paramètre également la résolution de sortie et la fréquence d'images.

Courir ./gifenc.sh input.mov output.gif 720 10générera une sortie GIF 720p large 10fps du film que vous lui avez donné. Vous devrez peut-être faire chmod +x gifenc.shpour le fichier.

#!/bin/sh

palette="/tmp/palette.png"

filters="fps=$4,scale=$3:-1:flags=lanczos"

ffmpeg -v warning -i "$1" -vf "$filters,palettegen" -y "$palette"
ffmpeg -v warning -i "$1" -i $palette -lavfi "$filters [x]; [x][1:v] paletteuse" -y "$2"

Vous pouvez lire les détails sur mon Github

Hypothèses: ffmpeg est installé et le script se trouve dans le même dossier que les autres fichiers.

thevangelist
la source
3
Merci beaucoup pour votre script. Je viens de le tester et ça marche très bien!
Orschiro
15

La réponse de @ Stephane est très bonne. Mais il y aura un avertissement comme Buffer queue overflow, dropping.pour certaines vidéos, et l'image générée gifa été supprimée.

Voici une meilleure version avec fifofiltre à éviter Buffer queue overflowlors de l'utilisation du paletteusefiltre. En utilisant le splitfiltre pour éviter la création d'un fichier PNG de palette intermédiaire.

ffmpeg -i input.mp4 -filter_complex 'fps=10,scale=320:-1:flags=lanczos,split [o1] [o2];[o1] palettegen [p]; [o2] fifo [o3];[o3] [p] paletteuse' out.gif
Alijandro
la source
Si je comprends bien, vous divisez l’entrée en o1 et o2 et vous copiez o2 en o3. Alors pourquoi avez-vous besoin de o3? Pourquoi ne pas simplement utiliser o2 directement?
Chloé
1
@Chloe Avez-vous vu l' fifoopération de filtrage entre o2et o3? Pour éviter l' Buffer queue overflowavertissement.
Alijandro
+1 Cela fonctionne vraiment bien pour moi (et a résolu le problème mentionné).
Iain Collins
J'adore cette solution. Gloire!
Leonid Usov
10

fait un script, testé et fonctionne.

usage:

./avi2gif.sh ./vokoscreen-2015-05-28_12-41-56.avi

AVOIR PHUN :)

vim avi2gif.sh

#!/bin/sh

INPUT=$1

# default settings, modify if you want.

START_AT_SECOND=0; # in seconds, if you want to skip the first 30 seconds put 30 here

LENGTH_OF_GIF_VIDEO=9999999; # in seconds, how long the gif animation should be

echo "Generate a palette:"
ffmpeg -y -ss $START_AT_SECOND -t $LENGTH_OF_GIF_VIDEO -i $INPUT -vf fps=10,scale=320:-1:flags=lanczos,palettegen palette.png

echo "Output the GIF using the palette:"
ffmpeg -ss $START_AT_SECOND -t $LENGTH_OF_GIF_VIDEO -i $INPUT -i palette.png -filter_complex "fps=10,scale=320:-1:flags=lanczos[x];[x][1:v]paletteuse" $INPUT.gif

btw: vokoscreen est un excellent outil ScreenCapturing pour Linux :)

MERCI BEAUCOUP Michael Kohaupt :) Rock stable.

Quelques statistiques de taille de fichier:

5,3 M = vokoscreen-2015-04-28_15-43-17.avi -> vokoscreen-2015-05-28_12-41-56.avi.gif = 1013K

voir les résultats ici.

canoodle
la source
10

La méthodeffmpeg with palette peut être exécutée en une seule commande, sans fichier intermédiaire ..png

ffmpeg -y -ss 30 -t 3 -i input.flv -filter_complex \
"fps=10,scale=320:-1:flags=lanczos[x];[x]split[x1][x2]; \
[x1]palettegen[p];[x2][p]paletteuse" output.gif

Cela peut être fait grâce au splitfiltre.

Stéphane
la source
10

Linux / Unix / macOS

Après l’ approche de @LordNeckbeard avec ffmpegcommande, veuillez trouver la fonction Bash utile suivante qui peut être ajoutée à votre ~/.bash_profilefichier:

# Convert video to gif file.
# Usage: video2gif video_file (scale) (fps)
video2gif() {
  ffmpeg -y -i "${1}" -vf fps=${3:-10},scale=${2:-320}:-1:flags=lanczos,palettegen "${1}.png"
  ffmpeg -i "${1}" -i "${1}.png" -filter_complex "fps=${3:-10},scale=${2:-320}:-1:flags=lanczos[x];[x][1:v]paletteuse" "${1}".gif
  rm "${1}.png"
}

Une fois la fonction chargée (manuellement ou depuis . ~/.bash_profile), vous devriez avoir une nouvelle video2gifcommande.

Exemple d'utilisation:

video2gif input.flv

ou:

video2gif input.flv 320 10

Échelle jusqu'à 320 largeur avec 10 images par seconde.

Vous pouvez également spécifier un format vidéo différent (tel que mp4).


macOS

Vous pouvez essayer l' application GIF Brewery qui permet de créer des fichiers GIF à partir de fichiers vidéo.


Alternativement, plusieurs sites Web effectuent une conversion en ligne gratuitement.

Kenorb
la source
votre script génère pour moi une erreur à propos de l'absence de fichier png et je ne reçois aucune sortie gif, mais le fichier d'entrée .mp4 reste inchangé
lacostenycoder
7

La réponse sélectionnée suppose que vous souhaitez redimensionner la vidéo source et modifier ses images par seconde dans le gif généré. Si vous n'avez pas besoin de le faire, les opérations suivantes fonctionnent:

src="input.flv"
dest="output.gif"
palette="/tmp/palette.png"

ffmpeg -i $src -vf palettegen -y $palette
ffmpeg -i $src -i $palette -lavfi paletteuse -y $dest

Cela m'a été utile lorsque je voulais un gif reproduisant fidèlement la vidéo source que j'utilisais.

Jet Blue
la source
6

Pour les utilisateurs de Windows:
créez un video2gif.batfichier dans le répertoire Windows avec le contenu suivant:

@echo off
set arg1=%1
set arg2=%arg1:~0,-4%
ffmpeg -y -i %arg1% -vf fps=10,scale=-1:-1:flags=lanczos,palettegen %TEMP%\palette.png
ffmpeg -i %arg1% -i %TEMP%\palette.png -filter_complex "fps=10,scale=-1:-1:flags=lanczos[x];[x][1:v]paletteuse" %arg2%.gif
del /f %TEMP%\palette.png

Et puis n'importe où vous pouvez l'utiliser comme ceci:

video2gif myvideo.mp4

Ensuite, vous avez myvideo.gifdans le répertoire en cours.
S'il myvideo.gify en a eu, demandez à vous de l'écrire.

MODIFIER:

Je suggère d'utiliser ce script batch: https://github.com/NabiKAZ/video2gif

Nabi KAZ
la source
2
Je vois que vous avez fait deux choses ici: (1) écrit les commandes en tant que script de commande Windows (.BAT) et (2) a fourni une combinaison de filtres différente (aucune des autres réponses n'utilise les deux fps=10 et scale=-1:-1).  La réponse de Sun nous a déjà donné un fichier batch, et celui-ci (comme les scripts shell dans la réponse de pje et la réponse de l'évangéliste ) a l'avantage d'affecter la liste des filtres à une variable ( une fois ),… - (suite)
Scott
1
(Suite)… donc il n'est pas nécessaire d'épeler la liste deux fois (comme le fait votre fichier batch). (Je suppose que cela crée un risque que, si l'utilisateur édite le script pour modifier l'une des listes mais pas l'autre, l'incohérence posera un problème.) Pouvez-vous au moins expliquer votre choix de filtres ( fps=10,scale=-1:-1)? (Voir la réponse de notable pour un exemple d'explication de parties d'une commande.)
Scott
1
@Scott Vous avez dit correct, alors j'écris un nouveau script utile ici: github.com/NabiKAZ/video2gif
Nabi KAZ
4

Vous trouverez ci-dessous le fichier de commandes pour les utilisateurs Windows:

gifenc.bat:

set start_time=0
set duration=60
set palette="c:\temp\palette.png"
set filters="fps=15,scale=-1:-1:flags=lanczos"
ffmpeg -v warning -ss %start_time% -t %duration% -i %1 -vf "%filters%,palettegen" -y %palette%
ffmpeg -v warning -ss %start_time% -t %duration% -i %1 -i %palette% -lavfi "%filters% [x]; [x][1:v] paletteuse" -y %2

Source: GIF haute qualité avec FFmpeg: Extraire un échantillon

Si vous voulez seulement utiliser une variable d'entrée et que le nom de sortie ait uniquement l'extension GIF (prononcé JIF), utilisez plutôt ceci:

set start_time=0
set duration=60
set palette="c:\temp\palette.png"
set filters="fps=15,scale=-1:-1:flags=lanczos"
ffmpeg -v warning -ss %start_time% -t %duration% -i %1 -vf "%filters%,palettegen" -y %palette%
set var1=%1
set var2=%var1:~0,-4%
ffmpeg -v warning -ss %start_time% -t %duration% -i %1 -i %palette% -lavfi "%filters% [x]; [x][1:v] paletteuse" -y %var2%.gif
Soleil
la source
3

Comment ajouter une entrée de menu contextuel Windows 7/10 "clic droit" pour convertir votre fichier vidéo en gif

Certaines des autres réponses ont mentionné le script video2gif , que j'ai utilisé. Mais, vous pouvez utiliser n'importe quel script.

Pour créer l'option de menu contextuel, vous devez modifier votre registre. Ouvrez une invite de commande powershell, exécutant w / admin privs. Exécutez ces commandes:

$key = "Registry::HKEY_CLASSES_ROOT\`*\shell\Run Video2Gif"
New-Item -Path $key"\Command" -Value "C:\dev\ffmpeg\ffmpeg-3.4.2-win64-static\bin\video2gif.bat `"%1`"" -Force

Maintenant, lorsque vous cliquez avec le bouton droit sur un fichier, vous avez l'option "Exécuter Video2Gif"!

Au fait, j'ai installé ffmpeg C:\dev\ffmpeg\ffmpeg-3.4.2-win64-static\et mets le video2gif.batscript dans le répertoire bin juste à côté ffmpeg.exe. J'ai également ajouté C:\dev\ffmpeg\ffmpeg-3.4.2-win64-static\binà mes fenêtres PATH, mais je ne pense pas que vous ayez à le faire.

Si vous souhaitez avoir la possibilité de fournir au script des drapeaux / arguments de ligne de commande supplémentaires, créez un nouveau fichier nommé video2gif-prompt.batet faites-le référencer par le registre au lieu de video2gif.bat:

@echo off
set /p inp=Enter extrta args, if desired:
C:\dev\ffmpeg\ffmpeg-3.4.2-win64-static\bin\video2gif.bat %* %inp%

Vous pouvez toujours appuyer sur Entrée pour obtenir rapidement les valeurs par défaut.

chris
la source