Create an animated gif from a video source using ffmpeg, imagemagick and gifsicle

Written by - 0 comments

Published on - Listed in Multimedia Linux


ffmpeg is the Swiss Army Knife when it comes to video manipulation on the command line. It allows to do all kinds of manipulations to a video, such as changing the video or audio codecs, resize (scale) the video, change bitrate or frames per second rate and many many more.

But ffmpeg can also be used to export the video into an animated GIF. (Animated) GIFs are by nature rather small in size - these days they've become a way to express emotions or reactions in social media. What a come-back the GIFs have made since the flashy websites in the 90s!

Resize the original video

As mentioned, GIFs (should be) are small in size but a recorded video with a high resolution (such as Full HD) are way too big. The source video should first be resized (scaled) to a more common GIF size. In this example, the video is scaled to a 320 pixel width and a dynamic height (keeping the same aspect ratio):

ck@mintp ~ $ ffmpeg -i /tmp/VID_20200921_083738.mp4 -vf scale=320:-1 /tmp/Video.mp4

The difference in size of the original (VID_20200921_083738.mp4) and the scaled video (Video.mp4) speaks for itself: 

ck@mintp ~ $ du -h /tmp/V*
15M    /tmp/VID_20200921_083738.mp4
256K   /tmp/Video.mp4

Alright, now that we have a small sized video file, this one can be used to create an animated GIF.

Convert video into an animated gif

Exporting and converting the video into an animated gif is actually much easier than one would think of:

ck@mintp ~ $ ffmpeg -i /tmp/Video.mp4 -vf "fps=10" -loop 0 /tmp/output3.gif

The hidden secret is that ffmpeg automatically detects that it should create a GIF from the file suffix (.gif). The additional parameters -vf "fps10" tell ffmpeg to use 10 frames per second and -loop 0 creates an infinite "play" of the GIF.

But something is bothering: The file size of the GIF:

ck@mintp ~ $ du -h /tmp/output3.gif
1.1M    /tmp/output3.gif

Why is the final GIF larger than the video?

The reasons are: Compression and Colour. Most modern video codecs and JPEG pictures use a compression level (which can be adjusted). The Graphics Interchange Format (GIF) however was never made for photos/pictures. GIF was created for graphics, as the name says. GIF also only allows 256 colors per still image - this means that additional colours (coming from a video file, which is basically a series of jpeg pictures) need to be coped with more gif images (adding the additional colours) in between.

Using a colour palette

Another method of creating a GIF is by extracting a "colour palette" of the video first (see this excellent blog post from Cassidy K for more detailed information). The goal with this method is to create a base image and all the changes (movements) are applied as layers on top of the base image. This should greatly reduce the resulting GIF size.

First to create a palette file:

ck@mintp ~ $ ffmpeg -i /tmp/Video.mp4 -vf "fps=15,palettegen=stats_mode=diff" /tmp/palette.png

The created file is very small, simply containing color information:

ck@mintp ~ $ du -h /tmp/palette.png
4.0K    /tmp/palette.png

When opening the palette file with an image viewer (here Nomacs) a 16x16 pixel colour table is showing:

Exported colour palette from a video file

Now using this palette another GIF can be created:

ck@mintp ~ $ ffmpeg -i /tmp/Video.mp4 -i /tmp/palette.png -lavfi "fps=10,paletteuse=dither=bayer:bayer_scale=5:diff_mode=rectangle" /tmp/output4.gif

But looking at the image size of output4.gif, it looks as if this GIF resulted in an even bigger size:

ck@mintp ~ $ du -h /tmp/output*
1.1M    /tmp/output3.gif
2.2M    /tmp/output4.gif

The problem is that the original source is a filmed video sequence (with a shaky hand). So there is a lot of movement and every little camera shake results in big changes. This can be seen nicely if the GIF is taken apart into single images (here opened with ImageMagick QT):

Animated gif sequence seen with ImageMagick QT

This blows up the GIF - even more as with a simple image sequence without the differences.

The colour palette method is therefore not a good way for creating GIFs from a "real life" video but works much better for drawn/computer animation sequences.

What about ImageMagick (convert)?

Yes, ImageMagick (the Swiss Army Knife for graphic manipulation) is also able to create animated GIFs (read article Create an animated gif image from still images on the cli using imagemagick) but instead of using a bunch of still images, the input source can also be a video file:

ck@mintp ~ $ convert -delay 1x30 -loop 0 /tmp/Video.mp4 /tmp/output5.gif

However, the conversion takes a very long time (compared to ffmpeg) and the final GIF's size is blown up (even bigger than using ffmpeg):

ck@mintp ~ $ du -h /tmp/output*
1.1M    /tmp/output3.gif
2.2M    /tmp/output4.gif
9.2M    /tmp/output5.gif

Further reduce the GIF size with gifsicle

So far the best sized GIF is still the first method, using the ffmpeg defaults (without a colour palette): output3.gif. With gifsicle the already existing animated GIF can be optimized:

ckadm@mintp ~ $ gifsicle -O3 /tmp/output3.gif -o /tmp/output6.gif
ckadm@mintp ~ $ du -h /tmp/output*
1.1M    /tmp/output3.gif
2.2M    /tmp/output4.gif
9.2M    /tmp/output5.gif
1004K    /tmp/output6.gif

gifsicle offers three optimization levels (-O):

  • 1: Stores only the changed portion of each image. This is the default.
  • 2: Also uses transparency to shrink the file further.
  • 3: Try several optimization methods (usually slower, sometimes better results).

After having tried all three levels, level 3 resulted in the lowest file size.

TL;DR

Creating an animated GIF from a (real life filmed) video, doesn't actually make sense. The GIF format was never created for this purpose and as the 256 colour limitation comes in play, the additional colours need to be coped with additional images in the animation sequence. Due to this fact, GIFs actually result in a bigger file size than the source video file (with a decent compression/codec).

However in our current time there is no animated GIF successor. Directly showing and playing a video file would be the obvious solution, but not all programs/apps support video files (I'm not even mentioning a codec war). This leaves us - again - with the old GIF format. Therefore the best way to create an animated GIF from a filmed video sequence is by using ffmpeg and then optimize the animated GIF with gifsicle.

Final animated gif output after ffmpeg and gifsicle


Add a comment

Show form to leave a comment

Comments (newest first)

No comments yet.

RSS feed

Blog Tags:

  AWS   Android   Ansible   Apache   Apple   Atlassian   BSD   Backup   Bash   Bluecoat   CMS   Chef   Cloud   Coding   Consul   Containers   CouchDB   DB   DNS   Database   Databases   Docker   ELK   Elasticsearch   Filebeat   FreeBSD   Galera   Git   GlusterFS   Grafana   Graphics   HAProxy   HTML   Hacks   Hardware   Icinga   Influx   Internet   Java   KVM   Kibana   Kodi   Kubernetes   LVM   LXC   Linux   Logstash   Mac   Macintosh   Mail   MariaDB   Minio   MongoDB   Monitoring   Multimedia   MySQL   NFS   Nagios   Network   Nginx   OSSEC   OTRS   Office   OpenSearch   PGSQL   PHP   Perl   Personal   PostgreSQL   Postgres   PowerDNS   Proxmox   Proxy   Python   Rancher   Rant   Redis   Roundcube   SSL   Samba   Seafile   Security   Shell   SmartOS   Solaris   Surveillance   Systemd   TLS   Tomcat   Ubuntu   Unix   VMWare   VMware   Varnish   Virtualization   Windows   Wireless   Wordpress   Wyse   ZFS   Zoneminder