Skip to content

Instantly share code, notes, and snippets.

@bennettscience
Last active September 8, 2017 18:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bennettscience/d22049cf37b524baff81c2622b76ceaa to your computer and use it in GitHub Desktop.
Save bennettscience/d22049cf37b524baff81c2622b76ceaa to your computer and use it in GitHub Desktop.
gifify hack
#!/bin/bash
set -euo pipefail
function printHelpAndExit {
echo 'Usage:'
echo ' gifify [options] filename'
echo ''
echo 'Options: (all optional)'
echo ' c CROP: The x and y crops, from the top left of the image, i.e. 640:480'
echo ' o OUTPUT: The basename of the file to be output (default "output")'
echo ' l LOOP: The number of times to loop the animnation. 0 (default)'
echo ' for infinity.'
echo ' r FPS@SPEED: With 60@1.5, output at 60FPS at a speed of 1.5x the'
echo ' source material. NOTE: It is best to keep FPSxSPEED'
echo ' t TEXT Add a caption to the bottom of the animation'
echo ' below approximately 60.'
echo ' p SCALE: Rescale the output, e.g. 320:240'
echo ' x: Remove the original file and resulting .gif once the script is complete'
echo ''
echo 'Example:'
echo ' gifify -c 240:80 -o my-gif my-movie.mov'
exit $1
}
function getLength() {
#Gets the length of the GIF for the resulting .srt needed for captions
ff=$(ffmpeg -i $filename 2>&1)
d="${ff#*Duration: }"
echo "${d%%,*}"
exit $1
}
crop=
output=
loop=0
fpsspeed='10@1'
scale=
OPTERR=0
while getopts 'c:o:l:p:r:s:t' opt; do
case $opt in
c) crop=$OPTARG;;
h) printHelpAndExit 0;;
o) output=$OPTARG;;
l) loop=$OPTARG;;
r) fpsspeed=$OPTARG;;
p) scale=$OPTARG;;
s) speed=$OPTARG;;
t) text=$OPTARG;;
*) printHelpAndExit 1;;
esac
done
shift $(( OPTIND - 1 ))
filename=$1
if [ -z ${output} ]; then
output=$filename
fi
if [ -z "$filename" ]; then printHelpAndExit 1; fi
if [ $crop ]; then
crop="crop=${crop}:0:0"
else
crop=
fi
if [ $scale ]; then
scale="scale=${scale}"
else
scale=
fi
if [ $scale ] || [ $crop ]; then
filter="-vf $scale$crop"
else
filter=
fi
# Throws an unbound variable here.
# If I specify -t with the script, the error is on $OPTARG in line 51
if [ $text ]; then
: > /tmp/subs.srt
(echo 1; echo "00:00:00,000 -->" $(getLength 1); echo $text) >> /tmp/subs.srt
text="-vf subtitles=/tmp/subs.srt"
else
text=
fi
# -delay uses time per tick (a tick defaults to 1/100 of a second), so 60fps ==
# -delay 1.666666 which is rounded to 2 because convert apparently stores this
# as an integer.
#
# To animate faster than 60fps, you must drop frames, meaning you must specify
# a lower -r. This is due to the GIF format as well as GIF renderers that cap
# frame delays < 3 to 3 or sometimes 10. Source:
# http://humpy77.deviantart.com/journal/Frame-Delay-Times-for-Animated-GIFs-214150546
echo 'Exporting movie...'
fps=$(echo $fpsspeed | cut -d'@' -f1)
speed=$(echo $fpsspeed | cut -d'@' -f2)
if [ ! -z "$speed" ]; then
speed=1
fi
delay=$(bc -l <<< "100/$fps/$speed")
temp=$(mktemp /tmp/tempfile.XXXXXXXXX)
ffmpeg -loglevel panic -i "$filename" $text $filter -r $fps -f image2pipe -vcodec ppm - >> $temp
echo 'Baking gif...'
cat $temp | convert +dither -layers Optimize -loop $loop -delay $delay - "${output}.gif"
echo "${output}.gif"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment