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.
Extract Images from Video
Create a directory called frames in the same directory with your
.mp4file. 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.
convert one-liner without intermediate files
sudo apt-get install ffmpeg imagemagick ffmpeg -i input.mp4 -r 10 -f image2pipe -vcodec ppm - | \ convert -delay 5 -loop 0 - output.gif
produced the output quickly and with a reasonable size compared to that of the input file.
Explanation of some of the arguments:
-r 10: sampling FPS. So for example, if the original video had 30 FPS,
-r 10means that
ffmpegwill pick one frame in every 3. The input FPS can be found with
ffprobe, and the total number of input frames can be found with
mediainfoas explained at: https://superuser.com/questions/84631/how-do-i-get-the-number-of-frames-in-a-video-on-the-linux-command-line/1044894#1044894 A relatively low value like
10will mean less output frames, and thus smaller GIFs.
-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-extension
firefoxand 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. So
100means 1 FPS,
1 / 0.5 == 20FPS.
Further optional arguments you likely want:
ffmpeg -vf scale=320:-1: make the output
320pixels in height. This is common use case for GIFs for the web. If you remove this option, the output GIF has the same height as the input video. The original 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 the output with
ffmpeg -ss 00:02:26 -to 00:02:36: only convert the video from 02 mins 26 seconds to 02 minutes 36 seconds. See also: https://stackoverflow.com/questions/18444194/cutting-the-videos-based-on-start-and-end-time-using-ffmpeg
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.
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.
gifify is an all-in-one node-based utility that simplifies the conversion. It depends on
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.
imagemagickmight need to be compiled with some specific libraries (i.e. libass and fontconfig accordingly).