GIFs are great! Maybe not as a video format: It's actually one of the most inefficient ways to store video that exists. But it's also one of the most compatible ways of showing a video. Simply because you can play back the video in almost any software. Be it browser, Slack or e-mail. They're especially good as graphical help when submitting PRs.
For this very reason whenever I want to share a screen recording I usually convert it to a GIF. Unless I really need a high quality or high framerate recording.
On Linux this is very easy. Since you can make the screenshot grabber use any
script you want you can simply make a script which uses ffmpeg
to record the
screen, and store it both as a high quality video and convert it into a GIF
that's ready to be shared. Mine looks something like this:
#!/bin/bash
slop=$(slop -f "%x %y %w %h %g %i") || exit 1
read -r x y w h g id < <(echo $slop)
out_path="/home/benedicte/Screenshots"
output_filename=$(date +'recording_%Y-%m-%d_%H%M%S')
# record in high quality
ffmpeg -video_size "${w}x${h}" -framerate 60 -f x11grab -i "$display+$x,$y" \
-c:v libx264 -preset slow -crf 18 "$out_path/$output_filename.mp4"
# generate color pallet
ffmpeg -i "$out_path/$output_filename.mp4" \
-filter_complex "fps=10,scale=500:-1:flags=lanczos,palettegen=stats_mode=full" \
"/tmp/$output_filename-palette.png"
# scaling: /2 means divide size by two, make sure it's the same to preserve
# aspect ratio
ffmpeg -i "$out_path/$output_filename.mp4" -i "/tmp/$output_filename-palette.png" \
-filter_complex "fps=10,scale=iw/2:ih/2:-1:flags=lanczos[scaled], [scaled] paletteuse=dither=sierra2_4a" \
-loop 0 \
"$out_path/$output_filename.gif"
Notice: This will only work under X11. In Wayland you need to do something else.
On macOS though, if you don't want to use custom software, only the built-in
screen recording (Command + Shift + 5
) you have no options other than
outputting the standard h264-video in a mov
container.
However you can use Automator to create a folder action on your Screenshots folder. And in turn make Automator call your encode script. This it what we'll be setting up in this post.
1 Set up your screenshots directory
The very first thing we need to do is set our screenshots folder. By default this is the desktop on macOs. However that's impractical because if you're anything like me you probably take a lot of screenshots and screen recordings. These files will clutter up your desktop (hiding that beautiful wallpaper). But it will also make our script run a lot unnccessarily.
You change the default folder by bringing up the screenshot HUD with the standard hotkey
Command + Shift + 5
You then click "Options", "Save to" and "Choose location". Just like this:
Then this location will be remembered and used by default for all your later recordings.
2 Make an encode script
Now we need a script that can receive the filename of the standard recording, and then encode all the other versions we want.
Mine looks like this:
#!/bin/bash
infile=$1
ffmpeg=/Users/benedicte/.homebrew/bin/ffmpeg
home="/Users/benedicte"
out_path="$HOME/Screenshots"
# isolate the file extension from the file name
xbase=${infile##*/}
file_extension=${xbase##*.}
filename_no_extension=${xbase%.*}
output_filename="$filename_no_extension"
# generate gif pallet
$ffmpeg -i "$infile" \
-filter_complex "fps=10,scale=500:-1:flags=lanczos,palettegen=stats_mode=full" \
"/tmp/$output_filename-palette.png"
# generate gif
$ffmpeg -i "$infile" -i "/tmp/$output_filename-palette.png" \
-filter_complex "fps=10,scale=iw/2:ih/2:-1:flags=lanczos[scaled], [scaled] paletteuse=dither=sierra2_4a" \
-loop 0 \
"$out_path/$output_filename.gif"
# compress to mp4 container
$ffmpeg -i "$infile" \
-c:v libx264 -preset slow -crf 18 "$out_path/$output_filename.mp4"
This gives me both a GIF and a more compressed h264-video in an mp4
container.
Which is a bit more compatible than Apple's default mov
.
Put this script somewhere where you can execute it. You might need to run chmod u+x
on it. I've put mine in my binary folder:
/Users/benedicte/.local/bin/encode_screenshot
3 Create Automator folder action
The last thing you need is to make the Automator folder action which actually executes this script every time a new recording is made.
Open the Automator app and on the "Create new"-screen click "Folder action". Like this:
Then choose the source directory to be the screenshots directory you selected earlier:
Add a "Run shell script" step by dragging it from the library:
Then make Automator send the filenames as arguments, not as input to stdin
. We
could have taken it from stdin
but that would have meant that we should
slightly rewrite the encode_screenshot
script from earlier.
Next we add some code code which calls our encode script only if the new file
added has the .mov
extension:
for f in "$@"
do
if [[ "$f" = ".mov" ]]; then
/Users/benedicte/.local/bin/encode_screenshot $f
fi
done
This assures we don't call the script for normal screenshots. Only for recordings. This is how it should look:
Then you save the folder action by hitting Command + s
. Automator prompts you
for a name:
And after that you're good to go!
Now, whenever you record something with Command + Shift + 5
a small cogwheel
will show up while the folder action calls your script and performs the
encoding.
And when it's gone you'll find your GIF right there in the screenshots directory! Ready to be used in Slack or a PR!