Skip to content

Instantly share code, notes, and snippets.

@FarisHijazi
Last active September 26, 2021 10:01
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save FarisHijazi/4ba8d9768eddc6f218ecd21824c24909 to your computer and use it in GitHub Desktop.
Save FarisHijazi/4ba8d9768eddc6f218ecd21824c24909 to your computer and use it in GitHub Desktop.
segment videos into video or GIF segments using ffmpeg
#!/bin/bash
# https://gist.github.com/FarisHijazi/4ba8d9768eddc6f218ecd21824c24909
#TODO: fix directory naming, name it something related to the file
# argparsing from: https://stackoverflow.com/a/39376824/7771202
# usage function
function usage()
{
cat << HEREDOC
Usage: $progname [--num NUM] [-t|--segduration INT] [--gif] [--yes] [--verbose] [--dry-run]
optional arguments:
-h, --help show this help message and exit
-n, --num NUM increase this value to make it output less of the video (default: 20)
-t, --segduration NUM segment/gif duration in seconds (default: 3)
-g, --gif create gifs instead of video segments?
-y, --yes overwrite files
-v, --verbose increase the verbosity of the bash script
to apply on multiple videos in a folder
find /path/to/videofolder/ -name "*.mp4" -not -name "*.seg.*" | xargs -P \$(nproc --all) -I{} sh -c 'sh vidsplit.sh {} --gif --verbose'
HEREDOC
}
# initialize variables
progname=$(basename $0)
verbose=0
dryrun=0
gif=0
num_str=40
segduration=3
yes=0
# use getopt and store the output into $OPTS
# note the use of -o for the short options, --long for the long name options
# and a : for any option that takes a parameter
OPTS=$(getopt -a -o "hn:t:g,y,v" --long "help,num:,segduration:,gif,yes,verbose,dry-run" -n "$progname" -- "$@")
if [ $? != 0 ] ; then echo "Error in command line arguments." >&2 ; usage; exit 1 ; fi
eval set -- "$OPTS"
while true; do
# uncomment the next line to see how shift is working
# echo "\$1:\"$1\" \$2:\"$2\""
case "$1" in
-h | --help ) usage; exit; ;;
-n | --num ) num_str="$2"; shift 2 ;;
-t | --segduration ) segduration="$2"; shift 2 ;;
-g | --gif ) gif=$((gif + 1)); shift ;;
-y | --yes ) yes=$((yes + 1)); shift ;;
-v | --verbose ) verbose=$((verbose + 1)); shift ;;
-- ) shift; break ;;
* ) break ;;
esac
done
input=$1
if [ -z "$input" ]; then
echo "infile not passed"
usage
exit 1
fi
if [ ! -f "$input" ]; then
echo "Cannot access '$input': No such file or directory"
exit 1
fi
# echo dirname: $(dirname "$input")
cd "$(dirname $input)" # || echo "unable to cd" && exit 1
input=$(basename "$input")
fullduration=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$input")
segduration=3
skipsec=$(echo "$fullduration/($segduration*$num_str)" | bc)
if (( $verbose > 0 )); then
# print out all the parameters we read in
cat <<EOM
1=$1
num=$num_str
time=$segduration
gif=$gif
yes=$yes
skipsec=$skipsec
verbose=$verbose
EOM
fi
if (( $yes > 0 )); then
yes=y
else
yes=n
fi
if (( $gif > 0 )); then
seq $skipsec | xargs -I{} sh -c "echo {}*$num_str*$segduration|bc -l" -- {} | xargs -P $(nproc --all) -I{} sh -c "mkdir -p gifs; ffmpeg -hide_banner -loglevel error -$yes -ss {} -t $segduration -i \"$input\" -vf \"fps=10,scale=320:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse\" -loop 0 gifs/\"${input%.*}.{}.seg.gif\" && echo \"${input%.*}.{}.seg.gif\"" -- {} | tqdm --desc "segmenting video" --total $skipsec --unit gif >/dev/null
else
seq $skipsec | xargs -I{} sh -c "echo {}*$num_str*$segduration|bc -l" -- {} | xargs -P $(nproc --all) -I{} sh -c "mkdir -p segments; ffmpeg -hide_banner -loglevel error -$yes -ss {} -t $segduration -i \"$input\" -loop 0 segments/\"${input%.*}.{}.seg.mp4\" && echo \"${input%.*}.{}.seg.mp4\"" -- {} | tqdm --desc "segmenting video" --total $skipsec --unit file >/dev/null
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment