Create animated GIF and WebP from videos using FFmpeg

2021-02-2819:3517251mattj.io

Saturday, February 27, 2021 Also published on Medium A guide to using FFmpeg to create all the animated content you want. Whether it’s for a website, a presentation, or sharing a fun clip with a…

Saturday, February 27, 2021

Also published on Medium

A guide to using FFmpeg to create all the animated content you want.

Whether it’s for a website, a presentation, or sharing a fun clip with a friend on chat, you might want to convert a video to an animated GIF or animated WebP. Unfortunately, the visual tools for doing this vary by your operating system. Additionally, most conversion tools don’t support the WebP format, even in 2021. WebP is based on VP8, a relatively recent video codec standard compared to the GIF image format.

So, this guide is for those who are willing to learn a bit of terminal in order to convert any video to the animated format of their choosing. The best part: this will work on all major operating systems and gives you all the control of the output you could want!

Example GIF of typing "GIF" on a mechanical keyboard

Let’s get started!

Prerequisites

To use this guide, you will need the following:

  • Basic knowledge of how to open and use the terminal on your operating system. If you need a cheat sheet or introductory guides, check out Terminal Cheat Sheet.
  • FFmpeg v4+ installed on your operating system and executable from your path. Here are some suggested places to learn down to do this:

What is FFmpeg?

From Wikipedia:

FFmpeg is a free and open-source software project consisting of a large suite of libraries and programs for handling video, audio, and other multimedia files and streams.

For our purposes, we will use it to convert between formats, such as videos to GIFs or animated WebP. It has many uses, so I recommend checking it out for all your video processing needs!

Before you start: make sure you can run FFmpeg from your terminal

Since all of these commands require FFmpeg, we need to make sure it’s available.

Open your terminal, and run this:

If FFmpeg is available, you will note output similar to this:

FFmpeg version 4.3.1 Copyright © 2000–2020 the FFmpeg developers
...
Checking the FFmpeg version on Linux

Version 4 or higher of FFmpeg is recommended for this guide.

If you get an output that says something similar to command not found: ffmpeg -version, then check the Prerequisites section above and make sure you have FFmpeg installed on your system.

Convert to an animated GIF using FFmpeg

Convert a whole video to GIF

Base command

ffmpeg -i $INPUT_FILENAME \
-vf "fps=$OUTPUT_FPS,scale=$OUTPUT_WIDTH:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" \
-loop $NUMBER_OF_LOOPS $OUTPUT_FILENAME

# Change these placeholders:
# * $INPUT_FILENAME - path to the input video.
# * $OUTPUT_FPS - ouput frames per second. Start with `10`.
# * $OUTPUT_WIDTH - output width in pixels. Aspect ratio is maintained.
# * $NUMBER_OF_LOOPS - use `0` to loop forever, or a specific number of loops.
# * $OUTPUT_FILENAME - the name of the output animated GIF.

Example usage of this command

Here is an example of this command with the input options filled out:

ffmpeg -i "sample_recording.mp4" \
-vf "fps=10,scale=720:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" \
-loop 0 sample_recording.gif

Convert part of a video to GIF

Base command

This is the base command with various options for converting part of a video to an animated GIF:

ffmpeg -ss $INPUT_START_TIME -t $LENGTH -i $INPUT_FILENAME \
-vf "fps=$OUTPUT_FPS,scale=$OUTPUT_WIDTH:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" \
-loop $NUMBER_OF_LOOPS $OUTPUT_FILENAME

# Change these placeholders:
# * $INPUT_START_TIME - number of seconds in the input video to start from.
# * $LENGTH - number of seconds to convert from the input video.
# * $INPUT_FILENAME - path to the input video.
# * $OUTPUT_FPS - ouput frames per second. Start with `10`.
# * $OUTPUT_WIDTH - output width in pixels. Aspect ratio is maintained.
# * $NUMBER_OF_LOOPS - use `0` to loop forever, or a specific number of loops.
# * $OUTPUT_FILENAME - the name of the output animated GIF.

Example usage of this command

Here is an example of this command with the input options filled out:

ffmpeg -ss 32.5 -t 7 -i "sample_recording.mp4" \
-vf "fps=10,scale=720:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" \
-loop 0 sample_recording.gif

Convert to an animated WebP using FFmpeg

Convert a whole video to animated WebP

Base command

This is the base command with various options for converting an entire video to an animated WebP. You can use options like FPS, output width, and quality to determine the file size and quality of your output:

ffmpeg -i $INPUT_FILENAME \
-vf "fps=$OUTPUT_FPS,scale=$OUTPUT_WIDTH:-1:flags=lanczos" \
-vcodec libwebp -lossless 0 -compression_level 6 \
-q:v $OUTPUT_QUALITY -loop $NUMER_OF_LOOPS \
-preset picture -an -vsync 0 $OUTPUT_FILENAME

# Change these placeholders:
# * $INPUT_FILENAME - path to the input video.
# * $OUTPUT_FPS - ouput frames per second. Start with `10`.
# * $OUTPUT_WIDTH - output width in pixels. Aspect ratio is maintained.
# * $OUTPUT_QUALITY - quality of the WebP output. Start with `50`.
# * $NUMBER_OF_LOOPS - use `0` to loop forever, or a specific number of loops.
# * $OUTPUT_FILENAME - the name of the output animated WebP.

Example usage of this command

Here is an example of this command with the input options filled out:

ffmpeg -i "sample_recording.mp4" \
-vf "fps=10,scale=720:-1:flags=lanczos" \
-vcodec libwebp -lossless 0 -compression_level 6 \
-q:v 50 -loop 0 \
-preset picture -an -vsync 0 sample_recording.webp

Convert part of a video to animated WebP

Base command

This is the base command with various options for converting part of a video to an animated WebP:

ffmpeg -ss $INPUT_START_TIME -t $LENGTH -i $INPUT_FILENAME \
-vf "fps=$OUTPUT_FPS,scale=$OUTPUT_WIDTH:-1:flags=lanczos" \
-vcodec libwebp -lossless 0 -compression_level 6 \
-q:v $OUTPUT_QUALITY -loop $NUMER_OF_LOOPS \
-preset picture -an -vsync 0 $OUTPUT_FILENAME

# Change these placeholders:
# * $INPUT_START_TIME - number of seconds in the input video to start from.
# * $LENGTH - number of seconds to convert from the input video.
# * $INPUT_FILENAME - path to the input video.
# * $OUTPUT_FPS - ouput frames per second. Start with `10`.
# * $OUTPUT_WIDTH - output width in pixels. Aspect ratio is maintained.
# * $OUTPUT_QUALITY - quality of the WebP output. Start with `50`.
# * $NUMBER_OF_LOOPS - use `0` to loop forever, or a specific number of loops.
# * $OUTPUT_FILENAME - the name of the output animated WebP.

Example usage of this command

Here is an example of this command with the input options filled out:

ffmpeg -ss 32.5 -t 7 -i "sample_recording.mp4" \
-vf "fps=10,scale=720:-1:flags=lanczos" \
-vcodec libwebp -lossless 0 -compression_level 6 \
-q:v 50 -loop 0 \
-preset picture -an -vsync 0 sample_recording.webp

When should I use an animated GIF versus an animated WebP?

This depends on the quality, size, and support you want for your output. Modern browsers have support for animated WebP and the quality tends to be higher, but the processing power required is also higher.

Next steps

This guide serves as a brief introduction to using FFmpeg to create an animated GIF or animated WebP from a video, but there is so much more you can do with the tool. There are also many options that FFmpeg supports for these formats that are not covered.

You can also get the code for all the commands and examples in one place by visiting the GitHub Gist here.


Read the original article

Comments

  • By nicbou 2021-02-2821:087 reply

    Perhaps it's time to start a collection of ffmpeg commands for every situation, similar to bro pages [1]. I feel like I have to look at my old projects every time I need to use it. It took me a lot of trial and error to write an all-purpose ffmpeg command.

    This is how I convert videos to 720p web-playable videos (if it's not already web-playable):

    https://github.com/nicbou/homeserver/blob/22c0a160f9df5f4c34...

    This is how I create hover previews like on modern streaming sites:

    https://github.com/nicbou/timeline/blob/9d9340930ed0213dffdd...

    [1] http://bropages.org/tar

    • By _joel 2021-03-012:10

    • By devadvance 2021-02-2822:09

      The hover previews is an awesome example. Thanks for sharing!

      I like collections of commands. However, the challenges that seem unsolved are (1) keeping the example in sync with the CLI options, and (2) making it easy to dig into parts of examples. The former is a classic documentation problem, of course.

    • By gitgud 2021-03-010:36

      Thanks for sharing!

      I use a collection of commands in a dotfiles [1] repo I share around a few machines.

      This [2] command, compresses any video into a small web-playable file with relatively high quality so you can quickly share HD footage.

          ffcompress INPUT.mp4
          # creates INPUT.compressed.mp4
      
      [1] https://github.com/benwinding/dotfiles

      [2] https://github.com/benwinding/dotfiles/blob/master/bin/ffcom...

    • By lozf 2021-03-0112:28

      Something like FFmprovisr:

      https://amiaopensource.github.io/ffmprovisr/

      https://github.com/amiaopensource/ffmprovisr

      (CC Licensed, they accept pull requests.)

      ---

      The ffmpeg subreddit also has some helpful contributors:

      https://old.reddit.com/r/ffmpeg/

    • By panabee 2021-02-2821:433 reply

      this is a wonderful idea. we launched a repo here to do exactly this; we'll update the repo over time as we collect commands.

      https://github.com/HotpotDesign/FFMpeg-Online

      could we list and credit your commands?

      • By nicbou 2021-02-2823:211 reply

        Sure, they're open source for a reason!

        The videoprocessing one is more mature. It's been converting various torrents movies to playable mp4s for a few years.

        The 10x1s preview looks magical once you see it in production. It's also a great introduction to ffmpeg filter syntax, which really isn't that complex.

        • By panabee 2021-02-2823:25

          thanks! i just wanted to confirm your permission before posting on the repo. :)

          on a related note, do you have a command for converting HTML5 animations into webp or mp4 videos?

      • By fireattack 2021-03-016:12

        I just noticed you have one for "Create single-image video with audio".

        This seemingly easy task is actually pretty hard to get right with FFMPEG.

        Just leave a few notes here if anyone want to use that.

        Video part

        Chroma sampling

        Without any `pix_fmt` argument, FFMPEG defaults to 4:4:4 instead of typical 4:2:0. Which has very limited support (for example, Firefox doesn't support it.)

        To fix: add `pix_fmt yuv420p`, or chain a `format=yuv420p` vf at the end to your other vf(s).

        Color space

        FFMPEG by default uses BT.601 when converting your RGB images into YUV. This is an issue if your image / output video is in HD resolution. Almost all video players (including browsers) would assume BT.709 for anything >=720P. This causes color to shift in playback(255,0,0 would become 255,24,0).

        To fix: add `-vf zscale=matrix=709`.

        Note: there are some other video filters can do the same. The most famous being good ol' `scale` (based on libswscale). However, it has a notorious bug that would cause the color to shift on its own (becomes yellow) if the input is in BGR (all the `.bmp`s). See: https://trac.ffmpeg.org/ticket/979 So stick with better `zscale`.

        Framerate etc.

        You can set framerate with `-r` to a small number for both input (reading the same image X times per second) and output (since it's a still image, you can get away with very low framerate. `-tune stillimage` should also be used for (default) x264 encoder.

        In summary:

        ffmpeg -loop 1 -r 1 -i image.png -i audio.wav -r 1 -shortest -vf zscale=matrix=709,format=yuv420p -c:v libx264 -tune stillimage output_video.mp4

        Audio part - length mismatch bug

        Even if we ignore all the image/video troubles above, `ffmpeg -loop 1 -i image.png -i sound.mp3 -shortest video.mp4` still doesn't work well. "-shortest" argument has a long-standing bug (https://trac.ffmpeg.org/ticket/5456) that is the output video would be longer than your input audio (by quite a few seconds, worse if using -r 1). There are some workarounds (listed in the ticket) but they don't eliminate the issue entirely.

        Your best bet (if the length match is crucial) is to just convert the output video again and use -t to cut to the proper length.

      • By dddw 2021-03-017:29

        I have one that is pretty usefull to me, which I use to convert MTS files from my Sony camera to mp4.

        # batch convert MTS files into mp4 files for f in .MTS; do avconv -i "$f" -deinterlace -vcodec libx264 -pass 1 "${f%.MTS}.mp4";done

    • By aq3cn 2021-03-0114:04

      there are many such syntax generator websites for simple video conversion like tasks. see:

      https://www.mrfdev.com/ffmpeg-command-generator

      http://www.mackinger.at/ffmpeg/

      https://marceauka.github.io/ffmpeg-generator/#

    • By neolog 2021-03-010:48

  • By jonplackett 2021-02-2820:272 reply

    I switched to ffmpegging my gifs a year ago and haven't looked back. It's a bit annoying to begin with but now so much easier than using some 3rd rate program or having to upload everything to EZGif. It's worth the pain!

    • By devadvance 2021-02-2820:361 reply

      Author here. This is the same journey I went through and I 100% agree! It can be intimidating at first, but FFmpeg is a a worthwhile utility to begin learning.

      I've also added some shell functions[0] to my dotfiles to make it a bit easier to use when switching between several different machines.

      [0] https://gist.github.com/devadvance/03d3c8f57b3e0254fb989e946...

      • By jonplackett 2021-02-2822:19

        You've made a really handy cheat sheet, thanks! Bookmarked it for future use!

        And yeah, it's great, and not just for gifs. Just quickly re-encoding something in a different format / container is so much easier than faffing around opening a proper program.

        Took a while to not get annoyed with it though and figure out annoying watch-outs like -pix_fmt yuv420p, which I now finally have memorised.

    • By cm2187 2021-03-011:53

      If you start from .png files I struggled to get ffmpeg to produce a high quality gif, and had much more luck with imagemagick.

  • By shmerl 2021-03-012:53

    I found that gifski makes great quality animated gifs. ffmpeg is a mess to use for that. You still need ffmpeg to generate individual frames from a video, but that's a relatively easy step in comparison to that cumbersome set up of dithering for gif generation.

    https://gif.ski

HackerNews