Convert videos to GIFs with ffmpeg
2024-03-15
Shell script to convert videos to high-quality GIFs with optional boomerang loop effect. Uses ffmpeg’s palettegen for optimal colors.
#!/bin/sh
# We divide by this SCALE value (higher is smaller output, lower is better quality)
SCALE_DEFAULT="2.5"
SCALE="$SCALE_DEFAULT"
FPS_DEFAULT="15"
FPS="$FPS_DEFAULT"
# Parse arguments
while [ $# -gt 0 ]; do
case "$1" in
-s)
SCALE="$2"
shift 2
;;
-f)
FPS="$2"
shift 2
;;
-l)
LOOP_FLAG=1
shift
;;
*)
VIDEO="$1"
shift
;;
esac
done
if [ -z "$VIDEO" ]; then
echo "Usage: $0 [-s scale] [-f fps] [-l] <video>"
echo "Default scale: $SCALE_DEFAULT"
echo "Default fps: $FPS_DEFAULT"
exit 1
fi
TMPDIR=${TMPDIR:-/tmp}
TMP_PREFIX="giffify_$(basename "$VIDEO" | sed 's/[^a-zA-Z0-9_-]/_/g')_$$"
make_gif() {
echo "Making gif from $1"
ffmpeg -v quiet -i "$1" -vf "fps=${FPS},scale=iw/${SCALE}:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" "$OUTPUT"
}
reverse_and_trim() {
echo "Reversing and trimming $1"
ffmpeg -v quiet -hwaccel vaapi -hwaccel_device /dev/dri/renderD128 -i "$1" \
-vf "reverse" -c:v h264 -an "$TMPDIR/${TMP_PREFIX}_reversed_full.mp4"
ffmpeg -v quiet -ss 0.5 -i "$TMPDIR/${TMP_PREFIX}_reversed_full.mp4" -c copy "$TMPDIR/${TMP_PREFIX}_r.mp4"
rm -f "$TMPDIR/${TMP_PREFIX}_reversed_full.mp4"
}
make_gif_reversed() {
echo "Making reversed gif from ${1%.*}.mp4"
ffmpeg -v quiet -i "$TMPDIR/${TMP_PREFIX}_r.mp4" -vf "fps=${FPS},scale=iw/${SCALE}:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" "$TMPDIR/${TMP_PREFIX}_r.gif"
}
combine_gifs() {
echo "Combining gifs for $1"
ffmpeg -v quiet -i "$TMPDIR/${TMP_PREFIX}.gif" -i "$TMPDIR/${TMP_PREFIX}_r.gif" \
-filter_complex "[0:v][1:v]concat=n=2:v=1:a=0,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" \
"loop_${1%.*}.gif"
}
if [ "$LOOP_FLAG" = "1" ]; then
OUTPUT="$TMPDIR/${TMP_PREFIX}.gif"
(make_gif "$VIDEO") &
(reverse_and_trim "$VIDEO") &
wait
make_gif_reversed "$VIDEO"
combine_gifs "$VIDEO"
rm -f "$TMPDIR/${TMP_PREFIX}.gif" "$TMPDIR/${TMP_PREFIX}_r.mp4" "$TMPDIR/${TMP_PREFIX}_r.gif"
else
OUTPUT="${VIDEO%.*}.gif"
echo "Outputting to $OUTPUT"
make_gif "$VIDEO"
fi
Usage:
giffify video.mp4- convert to GIFgiffify -l video.mp4- convert with boomerang loopgiffify -s 2 -f 20 video.mp4- custom scale (smaller=better) and FPS