Skip to content

Instantly share code, notes, and snippets.

@deseven
Last active January 12, 2025 17:54
Show Gist options
  • Save deseven/f3dc4ae7141babeeac860a4305c34122 to your computer and use it in GitHub Desktop.
Save deseven/f3dc4ae7141babeeac860a4305c34122 to your computer and use it in GitHub Desktop.
a wrapper for quick web-friendly video convertions using ffmpeg, intended for macOS
#!/bin/bash
# a wrapper for quick web-friendly video convertions using ffmpeg
# mostly intended to be used on macOS (hence videotoolbox hardware acceleration)
# info & updates: https://gist.github.com/deseven/f3dc4ae7141babeeac860a4305c34122
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m'
DEFAULT_QUALITY_H264=23
DEFAULT_QUALITY_H265=28
DEFAULT_QUALITY_HARDWARE=52
DEFAULT_CODEC="h264"
DEFAULT_HALF_RES="no"
DEFAULT_SILENT="no"
DEFAULT_KEEP_SOURCE="no"
DEFAULT_HARDWARE="no"
DEFAULT_EXTRA_ARGS=""
while getopts hkq:c:HsA: flag; do
case "$flag" in
h) half_res=yes;;
k) keep_source=yes;;
s) silent=yes;;
q) quality=$OPTARG;;
c) codec=$OPTARG;;
H) hardware=yes;;
A) extra_args=$OPTARG;;
esac
done
shift $((OPTIND - 1))
if [ -z "$1" ]; then
echo -e "${RED}syntax: $0 file_path [file_path...]${NC}"
echo -e "${BLUE}-h ${PURPLE}to use half resolution (default no)"
echo -e "${BLUE}-k ${PURPLE}to keep the source file (default no)"
echo -e "${BLUE}-s ${PURPLE}to remove the audio stream (default no)"
echo -e "${BLUE}-q ${PURPLE}to set the quality (default $DEFAULT_QUALITY_H264 for h264, $DEFAULT_QUALITY_H265 for h265, $DEFAULT_QUALITY_HARDWARE for hardware)"
echo -e "${BLUE}-c ${PURPLE}to set the codec (default $DEFAULT_CODEC, options: h264, h265)"
echo -e "${BLUE}-H ${PURPLE}to enable hardware encoding (default no)"
echo -e "${BLUE}-A ${PURPLE}to pass additional ffmpeg arguments (default none)${NC}"
exit 1
fi
if [ -z "$half_res" ]; then
half_res=$DEFAULT_HALF_RES
fi
if [ -z "$silent" ]; then
silent=$DEFAULT_SILENT
fi
if [ -z "$keep_source" ]; then
keep_source=$DEFAULT_KEEP_SOURCE
fi
if [ -z "$codec" ]; then
codec=$DEFAULT_CODEC
fi
if [ -z "$hardware" ]; then
hardware=$DEFAULT_HARDWARE
fi
if [ -z "$extra_args" ]; then
extra_args=$DEFAULT_EXTRA_ARGS
fi
if [ -z "$quality" ]; then
if [ "$hardware" == "yes" ]; then
quality=$DEFAULT_QUALITY_HARDWARE
else
if [ "$codec" == "h265" ]; then
quality=$DEFAULT_QUALITY_H265
else
quality=$DEFAULT_QUALITY_H264
fi
fi
fi
if [ "$silent" == "yes" ]; then
audio_arg="-an"
else
audio_arg="-c:a aac -b:a 192k -ac 2"
fi
if [ "$half_res" == "yes" ]; then
res="-vf scale='bitand(oh*dar,65534)':'bitand(ih/2,65534)',setsar=1"
else
res=""
fi
if [ "$hardware" == "yes" ]; then
if [ "$codec" == "h265" ]; then
codec_opts="-c:v hevc_videotoolbox -q:v $quality -pix_fmt yuv420p -movflags faststart -tag:v hvc1"
else
codec_opts="-c:v h264_videotoolbox -q:v $quality -pix_fmt yuv420p -movflags faststart"
fi
else
if [ "$codec" == "h265" ]; then
codec_opts="-c:v libx265 -crf $quality -pix_fmt yuv420p -movflags faststart -tag:v hvc1"
else
codec_opts="-c:v libx264 -crf $quality -profile:v baseline -level 3.0 -pix_fmt yuv420p -movflags faststart"
fi
fi
results=()
for input_file in "$@"; do
name=$(basename -- "$input_file")
ext="${name##*.}"
name="${name%.*}"
dir=$(dirname "$input_file")
echo -e "${BLUE}file: ${PURPLE}$name.$ext${NC}"
echo -e "${BLUE}half_res: ${PURPLE}$half_res${NC}"
echo -e "${BLUE}silent: ${PURPLE}$silent${NC}"
echo -e "${BLUE}keep_source: ${PURPLE}$keep_source${NC}"
echo -e "${BLUE}quality: ${PURPLE}$quality${NC}"
echo -e "${BLUE}codec: ${PURPLE}$codec${NC}"
echo -e "${BLUE}hardware: ${PURPLE}$hardware${NC}"
echo -e "${BLUE}extra_args: ${PURPLE}$extra_args${NC}"
echo "Running \`ffmpeg -hide_banner -loglevel error -stats -i \"$input_file\" $res $audio_arg $codec_opts $extra_args \"$dir/$name-1.mp4\"\`"
if nice -n 8 ffmpeg -hide_banner -loglevel error -stats -i "$input_file" $res $audio_arg $codec_opts $extra_args "$dir/$name-1.mp4"; then
if [ -s "$dir/$name-1.mp4" ]; then
if [ "$keep_source" == "no" ]; then
rm -f "$input_file"
mv "$dir/$name-1.mp4" "$dir/$name.mp4"
results+=("${GREEN}SUCCESS: ${CYAN}$dir/$name.mp4${NC}")
else
results+=("${GREEN}SUCCESS: ${CYAN}$dir/$name-1.mp4${NC}")
fi
else
results+=("${RED}FAILED: ${CYAN}$input_file${NC}")
fi
else
results+=("${RED}FAILED: ${CYAN}$input_file${NC}")
fi
done
echo ""
echo -e "${YELLOW}Conversion Summary:${NC}"
for result in "${results[@]}"; do
echo -e "$result"
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment