FFmpeg: high quality animated GIF?
Solution 1
I've written a tool specifically for maximum quality:
ffmpeg -i video.mp4 frame%04d.png
gifski -o clip.gif frame*.png
It generates good per-frame palettes, but also combines palettes across frames, achieving even thousands of colors per frame.
If you want to reduce the video dimensions, add a scaling filter:
ffmpeg -i video.mp4 -vf scale=400:240 frame%04d.png
If you want to reduce the frame rate, add the fps
filter:
ffmpeg -i video.mp4 -vf fps=12 frame%04d.png
You can combine the filters with -vf scale=400:240,fps=12
Solution 2
The key issue is that any gif picture or frame has an extremely limited palette of only 256 of the possible millions of colors in your video.
So, fairly recently (2015, version 2.6) ffmpeg got the palettegen and paletteuse filters that can generate better pallettes for each frame.
Therefore, make sure you are using a fairly recent version of ffmpeg.
So, there's your secret and key search term to get you to make high quality gifs in no time - study up on palettegen filters. Reddit beware.
Some references:
Solution 3
shell_exec("/usr/bin/ffmpeg -i video.mkv -r 20 -f image2pipe -vcodec ppm - | convert -delay 5 - output.gif");
I suppose you have no imageMagick installed on your environment, because "convert" is one of IM's tools.
As for the video artifacts, it is caused by the default dithering method in FFmpeg. For best results, I'd recommend floyd_steinberg
or sierra2_4a
, and maybe bayer
with scale set to 3. (Also, there's no such things like "huge" pixels, they are the atomic elements of raster images.)
On the other side, you can achieve better results with ffmpeg only. First, I'd generate a palette of the input video:
ffmpeg -i <your_input.mkv> -filter_complex "fps=10;scale=500:-1:flags=lanczos,palettegen=stats_mode=full" -t 10 palette.png
Then, use this color template to generate the actual gif file:
ffmpeg -i <your_input.mkv> -i palette.png -filter_complex "[0]fps=10;scale=500:-1:flags=lanczos[scaled]; [scaled][1:v] paletteuse=dither=sierra2_4a" -t 10 <output.gif>
You might need to fiddle with the params and the dithering methods to achieve best result. You may also try to generate new palette for each frame, so you can skip the first pass, and use the new
option in the paletteuse
filter.
Related videos on Youtube
David Hope
Updated on July 09, 2022Comments
-
David Hope almost 2 years
I'm generating animated a GIF from a video on my server.
The generated GIF is not really high quality and it looks like the pixels are huge.
Example:
This is how I generate the GIF:
shell_exec("/usr/bin/ffmpeg -i video.mkv -vf scale=500:-1 -t 10 -r 10 image.gif");
I did a search on Google and came across this:
shell_exec("/usr/bin/ffmpeg -i video.mkv -r 20 -f image2pipe -vcodec ppm - | convert -delay 5 - output.gif");
But the command above doesn't do anything and no output.gif is being generated at all.
There are some tutorials that I came across but none of them worked for me and some of them involve using ImageMagick which I dont have access to.
Could someone please let me know if there is a clear way to generate a high-quality GIF using FFmpeg?
-
harry over 5 yearsAwesome work. I'm exploring imageoptim as a result of seeing the quality of gifski.
-
paradox460 over 4 yearsJust a note: you can combine the two commands into one using a slightly more complex filtergraph: ffmpeg -i <your_input.mkv> -filter_complex "fps=10;scale=500:-1:flags=lanczos,split[v1][v2]; [v1]palettegen=stats_mode=full [palette];[v2]palette]paletteuse=dither=sierra2_4a" -t 10 <output.gif>
-
TigerhawkT3 over 4 yearsThat color space is beautiful, but the resulting file size in my quick test is 3-4x what I get with ffmpeg's default gif encoder. Am I doing something wrong? I'm using the latest Windows exe available from GitHub releases (version 0.8.5).
-
Kornel over 4 yearsIt's normal that higher-quality file takes much more space. The best way to reduce gif size is to reduce motion (area that changes between frames) or framerate. You can also try giflossy (
gifsicle --lossy
). -
Martin Castin over 2 years@paradox460 I think your comment should be an answer to make it more visible