I want make an animated .gif
from an .mp4
video. I would prefer to do it from the command line, so please only list command line tools.

- 28,474

- 84,289
-
1You can use this script on Github that uses FFMPEG and generates intermediate color palette for better picture quality. – NG_ Apr 24 '19 at 08:36
4 Answers
ffmpeg
3.4.4 can do it directly on Ubuntu 18.04
You likely want to use something like:
sudo apt install ffmpeg
wget -O opengl-rotating-triangle.mp4 https://github.com/cirosantilli/media/blob/master/opengl-rotating-triangle.mp4?raw=true
ffmpeg \
-i opengl-rotating-triangle.mp4 \
-r 15 \
-vf scale=512:-1 \
-ss 00:00:03 -to 00:00:06 \
opengl-rotating-triangle.gif
opengl-rotating-triangle.gif
Image info: 426kB, 45 frames, 512x512 apparent size, coalesced, conversion time on a Lenovo P51: 0.5s.
The above conversion also worked after a ulimit -Sv 1000000
(DRAM usage limited to 1GB), so it does "not consume huge amounts of memory" like previous attempts I did with Imagemagick which almost killed my machine. 500MB however failed because ffmpeg failed to load its shared libraries... time to upgrade your RAM ;-)?
Test data generation procedure described on this post.
The output has a visible dotting pattern, which is not as visible in "ffmpeg + convert" method below. We can try to improve the image quality with methods described at:
- https://superuser.com/questions/556029/how-do-i-convert-a-video-to-gif-using-ffmpeg-with-reasonable-quality
- https://stackoverflow.com/questions/42980663/ffmpeg-high-quality-animated-gif
E.g. using the palettegen
filter:
ffmpeg \
-i opengl-rotating-triangle.mp4 \
-r 15 \
-vf "scale=512:-1,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" \
-ss 00:00:03 -to 00:00:06 \
opengl-rotating-triangle-palettegen.gif
opengl-rotating-triangle-palettegen.gif
Image info: 979K, 45 frames, 512x512 apparent size, coalesced, conversion time on a Lenovo P51: 3.5s.
So we see that:
- the dotting pattern is much less visible now
- GIF size roughly doubled. TODO: why does simply choosing a palette increase the image size? Is it because now more colors so we need more bits per color? How to observe each palette?
- generation time was 7x slower, presumably because ffmpeg is first scanning through the entire video to determine an optimal palette
We could also play with documented palettegen
parameters like palettegen=max_colors=16
to achieve different size quality trade-off points.
Argument breakdown
-ss 00:00:03 -to 00:00:06
: start and end time to cut the video from.No, GIFs are not the best way to
piratedistribute videos online.-vf scale=512:-1
: make the output512
pixels in height, and adjust width to maintain the aspect ratio.This is a common use case for images for the web, which tend to have much smaller resolution than video.
If you remove this option, the output GIF has the same height as the input video.
The original video height can be found for example with
ffprobe
: https://superuser.com/questions/595177/how-to-retrieve-video-file-information-from-command-line-under-linux/1035178#1035178 and is 1024 x 1024 in our case.-r 15
: sampling FPS.For example, the original video was 30 FPS, so
-r 15
means thatffmpeg
will pick one frame in every 2 (= 30 / 15
).The perceived output FPS is adjusted to match the input however, so you won't notice a speedup, only greater granularity.
The input FPS can be found with
ffprobe
, and the total number of input frames can be found withmediainfo
as explained at: https://superuser.com/questions/84631/how-do-i-get-the-number-of-frames-in-a-video-on-the-linux-command-line/1044894#1044894I recommend this option because video formats usually have a higher framerate due to the larger resolution. With smaller GIFs, the lower framerate is less noticeable, and so we can skip some frames and make smaller GIFs.
Video camera footage example
If you want to see the result quality of a video camera video from Wikimedia Commons with a similar command:
wget https://upload.wikimedia.org/wikipedia/commons/f/f9/STS-132_Liftoff_Space_Shuttle_Atlantis.ogv
ffmpeg -i STS-132_Liftoff_Space_Shuttle_Atlantis.ogv -r 15 -vf scale=512:-1 \
-ss 00:00:17 -to 00:00:22 STS-132_Liftoff_Space_Shuttle_Atlantis.gif
STS-132_Liftoff_Space_Shuttle_Atlantis.gif
Image info: 1.3MB, 75 frames, 512x288 apparent size, coalesced (has minimal effect however, because footage pans slightly from the start), conversion time on a Lenovo P51: 2.3s.
Here is a version with palettegen
but only 2 seconds to fit the 2MiB upload limit:
Image info: 1.5MB, 30 frames, 512x288 apparent size, conversion time on a Lenovo P51: 43s.
A more direct:
sudo apt-get install ffmpeg
ffmpeg -i in.mp4 out.gif
also works, but the output GIF would be way larger than the input video, because video formats can compress more efficiently across frames with advanced algorithms, while GIF can only does a simple rectangular frame diff.
Before 18.04: ffmpeg
+ convert
one-liner without intermediate files
ffmpeg
could not handle GIF previously. The best I had was something along:
sudo apt-get install ffmpeg imagemagick
ffmpeg -i opengl-rotating-triangle.mp4 -r 15 -vf scale=512:-1 \
-ss 00:00:03 -to 00:00:06 -f image2pipe -vcodec ppm - |
convert -deconstruct -delay 5 -loop 0 - opengl-rotating-triangle-image-magick.gif
opengl-rotating-triangle-image-magick.gif
Image info: 995kB, 45 frames, 512x512 apparent size, coalesced.
For the Atlantis shuttle footage, and analogous:
ffmpeg -i STS-132_Liftoff_Space_Shuttle_Atlantis.ogv -r 15 -vf scale=512:-1 \
-ss 00:00:17 -to 00:00:22 -f image2pipe -vcodec ppm - |
convert -deconstruct -delay 5 -loop 0 - STS-132_Liftoff_Space_Shuttle_Atlantis_512x.gif
produced better looking output, but the final GIF was considerably larger at 6.2MB, so I can't upload it.
Explanation of some of the arguments:
-loop 0
: add the Netscape Gif extension Loop count field to the output. 0 means infinite loop as described at: http://www.vurdalakov.net/misc/gif/netscape-looping-application-extensioneog
,firefox
and chromium all loop infinitely by default even without it, so I'm not sure how necessary it is anymore.-delay 5
: time waited before showing the next frame, in hundreths of second, as described at: https://en.wikipedia.org/wiki/GIF#Animated_GIF byte 324. So100
means 1 FPS,5
means1 / 0.5 == 20FPS
.-deconstruct
: compress across frames with rectangular diffs, see also: how can I resize an animated GIF file using ImageMagick?
Even if you reduce the height and framerate, the output GIF may still be larger than the video, since "real" non-GIF video formats compress across frames, while GIF only compresses individual frames.
A direct:
convert input.mp4 rpi2-bare-metal-blink.gif
worked, but almost killed my computer because of memory overflow, and produced an ouptput 100x larger for my 2s 1Mb input file. Maybe one day ImageMagick will catch up.
Tested on Ubuntu 17.10.
Gifski
This is another option that was brought to my attention and which claims intelligent algorithms, so let's try it out.
First we need to convert the video to a sequence of images, and then feed that into gifsky, e.g.:
sudo snap install gifski
mkdir -p frames
ffmpeg \
-i opengl-rotating-triangle.mp4 \
-r 15 \
-vf scale=512:-1 \
-ss 00:00:03 -to 00:00:06 \
frames/%04d.png
gifski -o opengl-rotating-triangle-gifski.gif frames/*.png
opengl-rotating-triangle-gifski.gif
Image info: 954K, 45 frames, 512x512 apparent size, not coalesced, conversion time on a Lenovo P51: 4.8s.
And the 2s STS:
Image info: 1.6M, 30 frames, 512x288 apparent size, not coalesced, conversion time on a Lenovo P51: 2.8s.
So for me, subjectively, this did not appear to offer significant benefit over ffmpeg's palettegen
.

- 28,474
-
1Your delay does not match your -r value (the resulting gif is 2x speed). Also you added a scale argument for no apparent reason (it makes the gif really small). – asmeurer Oct 21 '16 at 17:51
-
@asmeurer thanks for feedback. I tested it and felt the result was what I wanted. Likely the small size because Gifs are usually for web usage and must be small, and fast to improve the effect of the loop of a short video. Those parameters can of course be edited to fit other's needs. – Ciro Santilli OurBigBook.com Oct 21 '16 at 20:00
-
2
-
2For those who are wondering: removing
-r 10
will bring the GIF back to normal speed. – Mitch Feb 13 '17 at 08:05 -
3
-
@AdamGoldman this may be because the video format compresses across frames, while the GIF only withing frames. Added that to answer. – Ciro Santilli OurBigBook.com Jan 17 '18 at 23:36
-
Might be worth mentioning that this script doesn't handle many seconds of video. Trying it on a 45 second clip will just crash the script. It's the same issue with gifify, since it's essentially just a wrapper. See https://github.com/vvo/gifify/issues/99 – oligofren Jan 30 '18 at 16:02
-
@oligofren thanks for head up. Is it running out of memory? Does saving to files as in https://askubuntu.com/a/648604/52975 solve it? – Ciro Santilli OurBigBook.com Jan 30 '18 at 16:38
-
1@CiroSantilli华涌低端人口六四事件法轮功 After the process had been running for 3 minutes it had used 30% of all memory, according to
top
, after 4 minutes it was at 50%, etc. As I only had 8GB of RAM, that made my computer start stuttering for all operations, due to it needing to use the swap disk. We'll see how far it goes, right now theconvert
process is using 5.5GB of RAM ... Storing the entire in-process file in-memory doesn't seem very clever. – oligofren Jan 31 '18 at 12:35 -
It didn't crash my computer, but it wasn't finished after 15 minutes so I just had to kill. It might work theoretically, but not practically :) – oligofren Jan 31 '18 at 12:56
-
-
@OverCoder send patches to ffmpeg and imagemagick of course – Ciro Santilli OurBigBook.com Feb 15 '18 at 00:18
-
1@CiroSantilli华涌低端人口六四事件法轮功 How would I be sending them in patches? I mean how would I then end up with one GIF? – OverCoder Feb 15 '18 at 00:27
-
@OverCoder I am half joking, but maybe it is in principle possible for
ffmpeg
andconvert
to process very large files little by little through the pipe, and output it little by little to the .gif, much like you can docat | grep
on a huge file. I'm not sure if this is truly the case, someone would have to study their codebases and the formats involved. – Ciro Santilli OurBigBook.com Feb 15 '18 at 13:35 -
I see. This is terrible though, as I was only converting a 53 seconds of MP4 to GIF, so having 7GB free memory and yet my computer totally freezing is uhh – OverCoder Feb 15 '18 at 16:15
-
1@OverCoder new
ffmpeg
can do the conversion directly as shown in updated answer, give it a try. – Ciro Santilli OurBigBook.com Oct 27 '18 at 18:56 -
1@oligofren new
ffmpeg
can do the conversion directly as shown in updated answer, give it a try. – Ciro Santilli OurBigBook.com Oct 27 '18 at 18:56 -
In the simplest case, this worked for me:
ffmpeg -i vim-surround-html-tags.mp4 vim-surround-html-tags.gif
– Victoria Stuart May 22 '20 at 17:00 -
1@VictoriaStuart yes, that should work. I'm just giving extra options that I feel most people will also generally want. – Ciro Santilli OurBigBook.com May 22 '20 at 17:06
-
You might want to put the simplest example right at the beginning as a sort of "summary" to the whole answer:
sudo apt-get install ffmpeg
and thenffmpeg -i in.mp4 out.gif
. – Gabriel Staples Jan 10 '22 at 16:53
Two steps:
Extract Images from Video
Create a directory called frames in the same directory with your
.mp4
file. Use command:ffmpeg -i video.mp4 -r 5 'frames/frame-%03d.jpg'
-r 5 stands for FPS value for better quality choose bigger number adjust the value with the -delay in 2nd step to keep the same animation speed %03d gives sequential filename number in decimal form
-
cd frames convert -delay 20 -loop 0 *.jpg myimage.gif
-delay 20 means the time between each frame is 0.2 seconds which match 5 fps above. When choosing this value 1 = 100 fps 2 = 50 fps 4 = 25 fps 5 = 20 fps 10 = 10 fps 20 = 5 fps 25 = 4 fps 50 = 2 fps 100 = 1 fps in general 100/delay = fps -loop 0 means repeat forever
Docs: convert gif options
You will end up with an rather big file, have a look at the image magick guide to optimize gif on options you can add to the second step command to obtain a smaller file.
-
1great answer- some additional info: ffmpeg can be installed using directions here – chepyle Mar 29 '16 at 02:02
-
4Keep in mind that the
frames
folder must exist for the first command to work. – totymedli Jun 07 '17 at 15:09 -
4For those that want a quick way to optimize that generally works and are too lazy to read the link, just add
-layers Optimize
to the lastconvert
command, before*.jpg
. Check the output though, it might be affected. For me it reduced the gif size from 5 MB to 700 KB without any perceivable loss in quality :) – cpury Jul 10 '17 at 08:54 -
Thanks that was an interesting process, a 5.6MB mp4 ended up a 236MB gif, not sure I'll be putting that one up on my website ;) Possibly a gif needs to be limited to seconds rather than a minute. – cardamom Sep 12 '17 at 09:37
-
3Instead of using the JPG file format, very lossy with the default settings, I'd recommend using PNG for the initial file export.
ffmpeg -i video.mp4 -r 5 'frames/frame-%03d.png'
. – Pierre F Jun 07 '18 at 11:15
gifify is an all-in-one node-based utility that simplifies the conversion. It depends on nodejs
, npm
, ffmpeg
, and imagemagick
which are all available in the repos.
Once you have npm
installed you can install gifify
globally with:
npm install -g gifify
A video can be converted to a .GIF with:
gifify video.mp4 -o video.gif
You can also optionally set a start and end position in the video and add a text caption:
gifify clip.mp4 -o clip.gif --from 01:48:23.200 --to 01:48:25.300 --text 'we are the knights who say nip!'
❗️ It can take several minutes for the conversion to complete even with smaller videos.
NOTE:
ffmpeg
andimagemagick
might need to be compiled with some specific libraries (i.e. libass and fontconfig accordingly).

- 1,452
- 17
- 18
-
Doesn't handle approx > 40 sec clips: https://github.com/vvo/gifify/issues/99 – oligofren Jan 30 '18 at 16:03
-
119.04: Another required package is
gifsicle
, but then another problem occurs: https://github.com/vvo/gifify/issues/95 Also, would you mind telling us npm novices in what directory to runnpm install
and whether to run it as root or not? Thanks! – Nicolas Raoul Apr 18 '19 at 04:13 -
-
You have to install gifsicle globally, then ffmpeg from npm globally as well, I don't think using npm is the best solution here. because if the developer of the package
gifify
wanted this package to be executed from command line for daily use, he would have made it a command-line utility by adding the sh-bang at the first line. and hence, this package is only meant to be used in applications, for programmers, not for daily use. – Normal Sep 27 '22 at 22:01
Full Disclosure: This is my project.
If you are using linux, you can use linux-mpv-gif-generator
You will need ffmpeg, kdialog & mpv.
sudo apt install ffmpeg kdialog mpv
You have to place mpv-gif.lua
in $HOME/.config/mpv/scripts
Now when you run a video on mpv, you will be able to use g to set start frame, G to set end frame, Ctrl+g to create gif. When you press Ctrl+g, it will ask where you want to save the gif.

- 710