Home

ffmpeg GIF Maker Command (2023 Edition)

Introduction

I love making GIFs. It's one of my go-to hobbies when I've got enough energy to do something but don't want to code or do anything that requires much thinking.

My first step is to use DaVinci Resolve1 to create an mp4 that's clipped and cropped the way I want. Once that's done, I set the options in this script and run it to produce the GIF:

#!/bin/bash

################################################
# The Options 


################################################
# The input video file to use. I generally use
# the full path to the input file. Relative
# paths also work (e.g. just "hackers.mp4"
# if you're running the script from the same
# directory the .mp4 file is in)

INPUT_PATH="/Users/alan/Desktop/input.mp4"


################################################
# The GIF file to output to

OUTPUT_PATH="/Users/alan/Desktop/output.gif"


################################################
# How wide to make the GIF. (The height is
# set automatically in the command itself)

WIDTH=400


################################################
# How many Frames Per Second the GIF should be.
# I find 10-15 works great for most GIFs. The
# higher the number the bigger the GIF will 
# be though so it's something to pay 
# attention to

FRAMES_PER_SECOND=20


################################################
# How many colors to use in the color palette.
# The max number is 255. With the other options
# that are set in this script I rarely find
# it necessary to go that high to get a good
# looking GIF. As with FRAMES_PER_SECOND
# the high the number the bigger the GIF's
# file size will be. 

COLORS=70


################################################
# Optional time to start from in the input video. 
# I generally leave this blank since I've already 
# clipped the input video to where I want it, 
# but you can use something like:
#
# START_TIME="-ss 00:01:53.6"
#
# The format for the time is: 
#
# HOURS:MINUTES:SECONDS.SUBSECOND
#
# So, the above example will start
# at 1 minute 53.6 seconds into the video
# 
# Note that the GIF may not start at the exact
# time you specify because of the way keyframes
# work in videos. If you run into that you can 
# cut your input video to exactly what you want. 
# (There are ways to deal with keyframe offsets
# directly in ffmpeg, but that's not in scope
# for this script)

START_TIME=""


################################################
# Optional length for the GIF. I generally leave
# this blank since I've already cut my clips
# in DaVinci, but you can do something like 
# this:
#
# LENGTH="-t 2.3"
# 
# which will make a 2.3 second GIF. As with 
# START_TIME the length may not be exact because
# of the way video keyframes work. 

LENGTH=""


################################################
# Optional offset for cropdetect to cover videos 
# that start with totally black frames. I leave 
# it empty most of the time since I've done my
# clipping in DaVinci. To use it, change it
# to something like: 
#
# CROP_OFFSET="-ss 0.2"
#
# That will skip 0.2 seconds of the clip before 
# starting to detect the cropping. Just make 
# sure to keep the offset less than the total 
# length of your clip otherwise it'll miss the 
# cropping

CROP_OFFSET=""


################################################
# The "stat_mode" to use in "palettegen". 
# Options are "full" and "diff". Where "full" 
# optimizes for the overall scene and "diff" 
# optimizes for just what's moving. (I don't
# generally see much of a difference with 
# this one, but keep it around just in case)

STAT_MODE="diff"


################################################
# The scaler to use. The default is "bilinear" 
# but "lanczos" and "bicubic" generally produce
# better results.

SCALER="lanczos"


################################################
# The dithering option to use. I generally find 
# "sierra2_4a" (which is also the default) to be 
# a good balance of quality and output size. The 
# other options to explore are:
#
# "bayer:bayer_scale=0"
# "bayer:bayer_scale=1"
# "bayer:bayer_scale=2"
# "bayer:bayer_scale=3"
# "bayer:bayer_scale=4"
# "bayer:bayer_scale=5"
# "floyd_steinberg"
# "sierra2"
# "sierra2_4a"
# "sierra3"
# "burkes"
# "atkinson"
# "none"

DITHER="sierra2_4a"


################################################
# The "diff_mode" defines the zone to 
# process for parts of the scene that 
# move. The default is none, but setting
# to "rectangle" can help keep backgrounds
# from changing as the color palette changes
# during processing. Change to:
# 
# DIFF_MODE="none"
#
# if you want to turn it off. Setting it
# either way might not have much of an effect
# depending on the input video

DIFF_MODE="rectangle"


################################################
# The Command Itself
################################################
# This is what collections all the options
# from above and actually makes the GIF
################################################

ffmpeg -i "${INPUT_PATH}" ${CROP_OFFSET} \
-t 0.1 -vf cropdetect -f null - 2>&1 | \
awk '/crop/ { print $NF }' | \
tail -1 | xargs -I{CROP} \
ffmpeg -loglevel error -hide_banner \
-i "${INPUT_PATH}" $START_TIME $LENGTH \
-vf "{CROP},fps=${FRAMES_PER_SECOND},\
scale=${WIDTH}:-2:flags=${SCALER},split[s0][s1];\
[s0]palettegen=max_colors=${COLORS}:reserve_transparent=0[p];\
[s1][p]paletteuse=dither=${DITHER}:diff_mode=${DIFF_MODE}" \
-y "${OUTPUT_PATH}"

open ${OUTPUT_PATH}


The script uses ffmpeg2 which you'll need to have installed. This version runs on my mac and will probably work on must linux distros. I'm not sure what would need to be tweaked to run on windows. The first four lines (which remove any black bars from cropping) would likely need to be redone somehow.

Choosing what settings to use for the various options generally comes down to "it depends" based on the input video you're working with. The settings above are my defaults that work fine for me most of the time.

The three things I'm most likely to change are the WIDTH, FRAMES_PER_SECOND, and COLORS in order to balance the quality with the file size.

Some Details

Go Forth And Animate

A bunch of hours of research went into that command. For any given GIF it would be way easier to use one of the many online GIF makers. Except, most of those feel shady and gross with the number of ads on them. Plus, I like making things myself and with this script I can automate things so GIFs are made as soon as I export an mp4 from DaVinci.

That's a topic for a future post though. For now, running this when I need it works just fine.

~ fin ~

Footnotes

1 ⤴
DaVinci Resolve

This is one of those apps that I can't believe is free. It's serious prop level stuff. It's way more than what I need. Took a little youtubing to figure out how to do stuff. Totally worth the time spent.

2 ⤴
ffmpeg

"A complete, cross-platform solution to record, convert and stream audio and video."

This is the command line tool for messing with video. Also free, but way more cryptic to figure out.