#!/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