#!/bin/bash
# Usage info
show_help() {
cat << EOF
temptoanim converts temp.mkv to anim.gif
Usage: temptoanim [-h -s# -r# -k -g -e -o type -d working_dir]
-h display this help and exit
-s # i.e. Silentcast # - the number of instances of Silentcast
that are running
# must be 0, 1, or 2 (default is 0 meaning temptoanim was started
outside of the Silentcast application)
0: tries to convert ./temp.mkv (if working_dir is also
specified, it will be ignored)
1: tries to convert working_dir/silentcast/temp.mkv
2: tries to convert working_dir/silentcast/silentcast/temp.mkv
-r # i.e. rate # or fps (default is 8)
# is a natural number (2 to 120) that should match the
frames per second of temp.mkv for making or using png
images. A rate does not need to be specified if not using
png images at all, and will be ignored if specified. When
making anim.gif, png images are always necessary so that
if a rate is not specified, 8 will be used.
temptoanim doesn't verify the actual fps in temp.mkv.
-k keep all the png images that are created. Default is to
delete them unless '-o png' is used, in which case -k isn't
needed.
-g generate png images and use them to create the webm or mp4
video. No need to specifiy -g for a gif because png images
are required in that cast, but for webm or mp4, the default
is to use temp.mkv directly so that png images are not
generated or used.
-e existing png images will be used, so don't generate them. If
-g and -e are both used, exising images will be used unless
there are none, then they will be generated. The default for
making anim.gif is to delete any existing png images and
generate new ones from temp.mkv. For webm and mp4, the
default is to use temp.mkv directly so if you want to
edit frame by frame, you have to specify -g or -e for
frame png images to be used in creating the video.
-o type final desired output. Default is anim.gif. The recognized types are
png generates a series of png images: ew-???.png
ew-001.png ew-002.png .... ew-999.png
If more than 999 pngs, the first ones will
be overwritten
gif generates an animated gif named anim.gif.
ew-???.png images used will be deleted
unless -k is used.
webm generates a compressed video named anim.webm
from the uncompressed video temp.mkv unless
-e or -g is used, then it will create anim.webm
from png images. Those png images will be
deleted unless -k is used.
mp4 same as webm except it will be anim.mp4 that
is created.
All of these outputs are many times smaller than temp.mkv,
which is uncompressed, and sometimes hundreds of times smaller.
-d working_dir
defaults to the current directory and is where temptoanim
will expect to find the silentcast or silentcast/silentcast
directory
There are some dialogues that come up, and it's important to read
and understand them. View /usr/share/doc/silentcast/README.md with
a markdown viewer and get an animated gif demo made with silentcast,
as well as a step by step guide and a list of tips.
EOF
}
#defaults
castnum=""
anims_from="temp.mkv"
otype="gif" # default to making anim.gif if no -o type is specified
rm_png=true # this is whether or not to remove pngs after output is generated
use_pngs=false # default to making webm/mp4 from temp.mkv but if true, make from existing pngs instead
gen_pngs=false # generate pngs and make webm/mp4 from those if true
fps=8
cut=0
total_cut=0
group=0
count=0
check_for_temp() {
if ! [ -f temp.mkv ]
then
echo "temp.mkv not found, so can't generate anything from it" \
| yad --text-info --wrap --on-top --center --window-icon="$doc_dir/record$castnum".svg --title="Error" \
--text="SILENTCAST $castnum "
exit -1
fi
}
check_for_pngs() {
if ! [ -f ew-[0-9][0-9][0-9].png ]
then
echo "ew-???.png not found, so can't convert them to webm or mp4, use -g to generate pngs" \
| yad --text-info --wrap --on-top --center --window-icon="$doc_dir/record$castnum".svg \
--title="Error" --text="SILENTCAST $castnum "
exit -1
fi
}
mem_error() {
echo "Too many images for the available memory. Try closing other applications, creating a swap file, or removing unecessary images." |\
yad --text-info --wrap --on-top --center --window-icon="$doc_dir/record$castnum".svg --title="Error" \
--text="SILENTCAST $castnum "
(($? != 0)) && exit 1 #Cancel was clicked
}
check_for_anim() {
if ! [ -f anim.gif ]
then
mem_error
else
[ "$rm_png" = true ] && rm ew-[0-9][0-9][0-9].png
fi
xdotool key 'F5' # in testing, Dolphin used by KDE needs this sometimes
}
generate_pngs() {
find -maxdepth 1 -regex '\.\/ew-[0-9][0-9][0-9]\.png' -delete
check_for_temp
ffmpeg -i temp.mkv -r $fps ew-%03d.png \
| yad --progress --on-top --center --window-icon="$doc_dir/record$castnum".svg --text="SILENTCAST $castnum \n\
Creating images from temp.mkv" --pulsate --auto-close
xdotool key 'F5' # in testing, Dolphin used by KDE needs this sometimes
}
edit_pngs() {
cut=`yad --entry --on-top --center --window-icon="$doc_dir/record$castnum".svg \
--title="Prepare images before converting to animated gif or video" \
--text="SILENTCAST $castnum \n\
Manually delete or otherwise manipulate the images and click OK,\n\
Or \n\
Enter any positive integer less than the total number of images. It works like this:\n\
0 do nothing\n\
1 delete every other\n\
2 delete 2 out of every 3\n\
3 delete 3 out of every 4 ..."\
--entry-text="0"`
(($? != 0)) && exit 1 #Cancel was clicked
let group=$cut+1
let total_cut=$total_cut+$cut
if (($group > 1))
then
count=0
for f in ew-[0-9][0-9][0-9].png
do
let count++
if (($count % $group != 1))
then
rm $f
fi
done
fi
}
make_webm_from_pngs() {
ffmpeg -r $fps -i $silentcast_dir/ew-[0-9][0-9][0-9].png -c:v libvpx -qmin 0 -qmax 50 -crf 5 -b:v 749k \
$silentcast_dir/anim.webm \
| yad --progress --on-top --center --window-icon="$doc_dir/record$castnum".svg \
--text="SILENTCAST $castnum \nCreating anim.webm from ew-???.png" --pulsate --auto-close
}
make_mp4_from_pngs() {
ffmpeg -r $fps -i $silentcast_dir/ew-[0-9][0-9][0-9].png -pix_fmt yuv420p -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" \
$silentcast_dir/anim.mp4 \
| yad --progress --on-top --center --window-icon="$doc_dir/record$castnum".svg \
--text="SILENTCAST $castnum \nCreating anim.mp4 from ew-???.png" --pulsate --auto-close
}
make_webm_from_temp() {
ffmpeg -i $silentcast_dir/temp.mkv -c:v libvpx -qmin 0 -qmax 50 -crf 5 -b:v 749k $silentcast_dir/anim.webm \
| yad --progress --on-top --center --window-icon="$doc_dir/record$castnum".svg \
--text="SILENTCAST $castnum \nCreating anim.webm from temp.mkv" --pulsate --auto-close
}
make_mp4_from_temp() {
# -pix_fmt yuv420p was suggested by ffmpeg itself for max compatibility and -vf ... is because dim have to be even
ffmpeg -i $silentcast_dir/temp.mkv -pix_fmt yuv420p -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" $silentcast_dir/anim.mp4 \
| yad --progress --on-top --center --window-icon="$doc_dir/record$castnum".svg \
--text="SILENTCAST $castnum \nCreating anim.mp4 from temp.mkv" --pulsate --auto-close
}
generate_anim() {
vidtype=$1
[ "$use_pngs" = false ] && check_for_temp
[ "$gen_pngs" = true ] && generate_pngs
find -maxdepth 1 -name 'anim.$vidtype' -delete
if [ "$use_pngs" = true ] || [ "$gen_pngs" = true ]
then
check_for_pngs
if [ "$vidtype" = webm ]
then
make_webm_from_pngs
elif [ "$vidtype" = mp4 ]
then
make_mp4_from_pngs
fi
[ "$rm_pngs" = true ] && rm ew-[0-9][0-9][0-9].png
xdotool key 'F5' # in testing, Dolphin used by KDE needs this sometimes
else
check_for_temp
if [ "$vidtype" = webm ]
then
make_webm_from_temp
elif [ "$vidtype" = mp4 ]
then
make_mp4_from_temp
fi
fi
}
OPTIND=1
while getopts ":hs:r:kgeo:d:" opt
do
echo $OPTARG # I don't know why I have to echo $OPTARG to get it assigned, but I do
case $opt in
h)
show_help
exit 0
;;
s)
case $OPTARG in
1)
castnum=1
;;
2)
castnum=2
;;
[!012])
echo "Invalid Silentcast#: -s $OPTARG ('temptoanim -h' for help)" >&2
exit 1
;;
esac
;;
r)
fps=$OPTARG
if ! [[ "$fps" =~ ^[0-9]+$ ]] && (($fps<2 || $fps>120))
then
show_help
exit 0
fi
;;
k)
rm_png=false
;;
g)
gen_png=true
;;
e)
use_png=true # if both gen_png and use_png are true, existing pngs will be used if there are any
;;
o)
if [ "$OPTARG" = png ] || [ "$OPTARG" = gif ] || [ "$OPTARG" = webm ] || [ "$OPTARG" = mp4 ]
then
otype=$OPTARG
else
echo "Invalid output type: -o $OPTARG ('temptoanim -h' for help)" >&2
exit 1
fi
;;
d)
working_dir="$OPTARG"
;;
\?)
echo "Invalid option: -$OPTARG ('genffcom -h' for help)" >&2
exit 1
;;
:)
echo "Option -$OPTARG requires an argument. ('genffcom -h' for help)" >&2
exit 1
;;
esac
done
shift "$((OPTIND-1))" # get rid of everything just processed leaving anything left as $1
if [ "$1" != "" ]
then
show_help # shouldn't be anything else so show help if there is
exit 1
fi
if ! [ -d $working_dir/ ]
then
echo "$working_dir is not an existing directory, so the silentcast directory can't be there" \
| yad --text-info --wrap --on-top --center --window-icon="$doc_dir/record.svg" --title="Error" --text="SILENTCAST ? "
exit -1
fi
[ $castnum = 1 ] && cd $working_dir/silentcast
[ $castnum = 2 ] && cd $working_dir/silentcast/silentcast
[ "$use_png" = false ] && find -maxdepth 1 -regex '\.\/ew-[0-9][0-9][0-9]\.png' -delete
if [ "$XDG_CURRENT_DESKTOP" = "GNOME" ]
then
nautilus ./ & file_browserPID=$! # for some reason xdg-open doesn't work inside this script in Gnome
else
xdg-open ./
fi
case $otype in
png)
generate_pngs
;;
gif)
[ "$use_png" = false ] || ! [ -f ew-[0-9][0-9][0-9].png ] && generate_pngs
find -maxdepth 1 -name 'anim.gif' -delete
while ! [ -f anim.gif ]
do
edit_pngs
# try to make anim.gif from pngs
convert -adjoin -delay "$((total_cut + 1))"x"$fps" -layers optimize ew-[0-9][0-9][0-9].png anim.gif | \
yad --progress --on-top --center --title="convert" --window-icon="$doc_dir/record$castnum".svg \
--text="SILENTCAST $castnum \n\
Replacing images with anim.gif... (clicking Close below doesn't stop convert, \
so don't)" --pulsate --auto-close
check_for_anim
done
;;
*)
generate_anim $otype
;;
esac
! [ "$file_browserPID" = "" ] && kill $file_browserPID
cd -
# End of file: temptoanim