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!
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.
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.
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:
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):
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.
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
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):
After having tried all three levels, level 3 resulted in the lowest file size.
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.
No comments yet.
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