The AppGini Blog
A few tips and tricks to make your coding life a tiny bit better.

Convert MP4 Videos to Optimized GIFs with One Simple Bash Script

As part of my journey documenting AppGini’s features, I often find myself recording quick, focused screen captures—just a few seconds highlighting a specific feature. These short clips are perfect for explaining how a certain button works or demonstrating a new workflow. I love sharing these bite-sized tutorials in our newsletter, but there’s always been one catch: embedding MP4 videos in emails just doesn’t work.

My go-to workaround has been to convert those MP4s into animated GIFs—GIFs play effortlessly in almost every email client and browser. Naturally, I turned to the web for solutions, but most online MP4-to-GIF converters left me frustrated. They were slow, imposed file size limits, added unsightly watermarks, and rarely gave me control over the GIF’s quality or dimensions.

That’s when I thought: I bet I could make a better tool myself—one that’s fast, flexible, and watermark-free. Armed with FFmpeg, a bit of Bash scripting, and a desire for more control, I set out to build my own MP4-to-GIF converter. It turned out to be easier—and more powerful—than I expected.

Why Use FFmpeg for GIF Conversion?

FFmpeg is a powerful, open-source video toolkit found on almost every Linux server and available for Windows and macOS. It can convert, resize, and optimize almost any video or audio format, including turning videos into GIFs.

It’s tempting to just run ffmpeg -i video.mp4 out.gif, but I quickly discovered that the results were usually huge and had poor color quality. Since GIFs are limited to just 256 colors, a little extra care is needed to get good-looking, efficient GIFs. That’s why, in my script, I added a step to generate a custom color palette based on the video itself—this gives much better results.

The Script

Here’s the Bash script I ended up with. Save it as mp42gif.sh and make it executable with:

1
chmod +x mp42gif.sh
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#!/bin/bash

set -e

if [ $# -lt 1 ] || [ $# -gt 3 ]; then
  echo "Usage: $0 input.mp4 [fps] [width]"
  exit 1
fi

input="$1"
fps="${2:-5}"
width="${3:-}"

dir="$(dirname "$input")"
base="$(basename "$input" .mp4)"
output="$dir/$base.gif"
palette="$dir/$base-palette.png"

# Construct scale filter if width is provided
if [ -n "$width" ]; then
  scale="scale=$width:-1"
  vf_palette="fps=$fps,$scale,palettegen"
  vf_gif="fps=$fps,$scale[x];[x][1:v]paletteuse"
else
  vf_palette="fps=$fps,palettegen"
  vf_gif="fps=$fps[x];[x][1:v]paletteuse"
fi

# Generate palette
ffmpeg -hide_banner -loglevel error -y -i "$input" -vf "$vf_palette" -frames:v 1 "$palette"

# Create GIF using palette
ffmpeg -hide_banner -loglevel error -y -i "$input" -i "$palette" -filter_complex "$vf_gif" "$output"

# Remove palette file
rm -f "$palette"

echo "GIF created: $output (FPS: $fps${width:+, Width: $width})"

How It Works

  1. Palette Generation
    First, the script generates a color palette from the video itself. This extra step helps the GIF use the best possible set of 256 colors, so the result looks much closer to the original video and comes out smaller.

  2. GIF Creation
    Next, it uses that palette to create a high-quality GIF at the frame rate and width you choose.

  3. Cleanup
    The script deletes the temporary palette file so you don’t have to worry about leftover files.

  4. Minimal Output
    You’ll only see a single line confirming your GIF’s creation—no verbose FFmpeg logs cluttering up your terminal.

Usage Examples

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Default: 5 FPS, original size
./mp42gif.sh myvideo.mp4

# 12 FPS, original size
./mp42gif.sh myvideo.mp4 12

# 10 FPS, 320px wide
./mp42gif.sh myvideo.mp4 10 320

# 8 FPS, 480px wide
./mp42gif.sh myvideo.mp4 8 480

The output GIF will appear next to your MP4 with the same name, but a .gif extension.

Example: Input Video and Output GIF

To give you a concrete idea, here’s a sample input video and the resulting animated GIF created by the script. The video is a very short screencast demonstrating how to access DataTalk’s reports menu inside an AppGini application.

Input Video (MP4):

Dimensions: 912x614, duration: 4 seconds, frame rate: 30 FPS, size: ~1MB

Output GIF, no scaling:

1
./mp42gif.sh datatalk-reports-menu.mp4

Output GIF, no scaling Dimensions: 912x614, duration: 4 seconds, frame rate: 5 FPS, size: 534KB

Output GIF, scaled to 500px width:

1
./mp42gif.sh datatalk-reports-menu.mp4 5 500

Output GIF, scaled to 500px width Dimensions: 500x337, duration: 4 seconds, frame rate: 5 FPS, size: 199KB

Tips for Great GIFs

  • Lower FPS = smaller file: I find 5–10 is usually enough for screencasts, and up to 15 for smoother action.
  • Smaller width = smaller file: 320–480px is a good range for including in emails. 640px is better for web pages.
  • Trim unwanted video before conversion if needed:
    ffmpeg -ss 00:00:01 -t 4 -i input.mp4 ...

Requirements

  • FFmpeg installed (sudo apt install ffmpeg on Ubuntu).
  • Bash shell (Linux, macOS, or WSL on Windows).

Final Thoughts

For me, this little script has become a real timesaver. I no longer have to hunt for online converters or settle for big, awkward GIFs with watermarks. Every time I need to share a quick screen recording in an email or newsletter, I just run this script and get a clean, optimized GIF—no extra steps, no surprises.

If you also find yourself needing to convert video snippets to GIFs for your workflow, feel free to use or tweak this script however you like. And if you come up with improvements, or if you have questions or ideas for new features (like trimming, cropping, or batch processing), I’d be genuinely interested to hear from you.

Thanks for reading, and happy GIF-making!