Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@dantuck
Forked from lisamelton/encode.sh
Created March 13, 2017 00:03
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 dantuck/9863c29cdf965b2fe8642e645993688b to your computer and use it in GitHub Desktop.
Save dantuck/9863c29cdf965b2fe8642e645993688b to your computer and use it in GitHub Desktop.
This is the shell script I use to drive HandBrakeCLI to re-encode video files in a format suitable for playback on Apple TV, Roku 3, iOS, OS X, etc.
#!/bin/bash
# encode.sh
#
# Copyright (c) 2013 Don Melton
#
# This version published on June 7, 2013.
#
# Re-encode video files in a format suitable for playback on Apple TV, Roku 3,
# iOS, OS X, etc.
#
# Input is assumed to be a single file readable by HandBrakeCLI and mediainfo,
# e.g. just about any .mkv, .avi, .mpg, etc. file.
#
# The script automatically calculates output video bitrate based on input. For
# Blu-ray Disc-quality input that's always 5000 Kbps. For DVD-quality input
# that's always 1800 Kbps. For other files that will vary.
#
# The script also automatically calculates video frame rates and audio channel
# configuration.
#
# If the input contains a VobSub (DVD-style) or PGS (Blu-ray Disc-style)
# subtitle, then it is burned into the video.
#
# Optional frame rate overrides and soft subtitles in .srt format are read
# from separate fixed locations in the `$frame_rates_location` and
# `$subtitles_location` variables defined below. Edit this script to redefine
# them.
#
# If your input file is named "foobar.mkv" then the optional frame rate file
# should be named "foobar.txt". And all it should contain is the frame rate
# number, e.g. "25" followed by a carriage return.
#
# If your input file is named "foobar.mkv" then the optional soft subtitle
# file should be named "foobar.srt".
#
# Output is an MP4 container with H.264 video, AAC audio and possibly AC-3
# audio if the input has more than two channels.
#
# No scaling or cropping is performed on the output. This is a good thing.
#
# The output .mp4 file and a companion .log file are written to the current
# directory.
#
# This script depends on two separate command line tools:
#
# HandBrakeCLI http://handbrake.fr/
# mediainfo http://mediainfo.sourceforge.net/
#
# Make sure both are in your `$PATH` or redefine the variables below.
#
# Usage:
#
# ./encode.sh [input file]
#
die() {
echo "$program: $1" >&2
exit ${2:-1}
}
escape_string() {
echo "$1" | sed "s/'/'\\\''/g;/ /s/^\(.*\)$/'\1'/"
}
readonly program="$(basename "$0")"
readonly input="$1"
if [ ! "$input" ]; then
die 'too few arguments'
fi
handbrake="HandBrakeCLI"
mediainfo="mediainfo"
frame_rates_location="/path/to/Frame Rates"
subtitles_location="/path/to/Subtitles"
# My advice is: do NOT change these HandBrake options. I've encoded over 300
# Blu-ray Discs, 30 DVDs and numerous other files with these settings and
# they've never let me down.
handbrake_options="--markers --large-file --encoder x264 --encopts vbv-maxrate=25000:vbv-bufsize=31250:ratetol=inf --crop 0:0:0:0 --strict-anamorphic"
width="$(mediainfo --Inform='Video;%Width%' "$input")"
height="$(mediainfo --Inform='Video;%Height%' "$input")"
if (($width > 1280)) || (($height > 720)); then
max_bitrate="5000"
elif (($width > 720)) || (($height > 576)); then
max_bitrate="4000"
else
max_bitrate="1800"
fi
min_bitrate="$((max_bitrate / 2))"
bitrate="$(mediainfo --Inform='Video;%BitRate%' "$input")"
if [ ! "$bitrate" ]; then
bitrate="$(mediainfo --Inform='General;%OverallBitRate%' "$input")"
bitrate="$(((bitrate / 10) * 9))"
fi
if [ "$bitrate" ]; then
bitrate="$(((bitrate / 5) * 4))"
bitrate="$((bitrate / 1000))"
bitrate="$(((bitrate / 100) * 100))"
if (($bitrate > $max_bitrate)); then
bitrate="$max_bitrate"
elif (($bitrate < $min_bitrate)); then
bitrate="$min_bitrate"
fi
else
bitrate="$min_bitrate"
fi
handbrake_options="$handbrake_options --vb $bitrate"
frame_rate="$(mediainfo --Inform='Video;%FrameRate_Original%' "$input")"
if [ ! "$frame_rate" ]; then
frame_rate="$(mediainfo --Inform='Video;%FrameRate%' "$input")"
fi
frame_rate_file="$(basename "$input")"
frame_rate_file="$frame_rates_location/${frame_rate_file%\.[^.]*}.txt"
if [ -f "$frame_rate_file" ]; then
handbrake_options="$handbrake_options --rate $(cat "$frame_rate_file")"
elif [ "$frame_rate" == '29.970' ]; then
handbrake_options="$handbrake_options --rate 23.976"
else
handbrake_options="$handbrake_options --rate 30 --pfr"
fi
channels="$(mediainfo --Inform='Audio;%Channels%' "$input" | sed 's/[^0-9].*$//')"
if (($channels > 2)); then
handbrake_options="$handbrake_options --aencoder ca_aac,copy:ac3"
elif [ "$(mediainfo --Inform='General;%Audio_Format_List%' "$input" | sed 's| /.*||')" == 'AAC' ]; then
handbrake_options="$handbrake_options --aencoder copy:aac"
fi
if [ "$frame_rate" == '29.970' ]; then
handbrake_options="$handbrake_options --detelecine"
fi
srt_file="$(basename "$input")"
srt_file="$subtitles_location/${srt_file%\.[^.]*}.srt"
if [ -f "$srt_file" ]; then
subtitle_format="$(mediainfo --Inform='Text;%Format%' "$input" | sed q)"
if [ "$subtitle_format" == 'VobSub' ] || [ "$subtitle_format" == 'PGS' ]; then
handbrake_options="$handbrake_options --subtitle 1 --subtitle-burned"
else
tmp=""
trap '[ "$tmp" ] && rm -rf "$tmp"' 0
trap '[ "$tmp" ] && rm -rf "$tmp"; exit 1' SIGHUP SIGINT SIGQUIT SIGTERM
tmp="/tmp/${program}.$$"
mkdir -m 700 "$tmp" || exit 1
temporary_srt_file="$tmp/subtitle.srt"
cp "$srt_file" "$temporary_srt_file" || exit 1
handbrake_options="$handbrake_options --srt-file $(escape_string "$temporary_srt_file") --srt-codeset UTF-8 --srt-lang eng --srt-default 1"
fi
fi
output="$(basename "$input")"
output="${output%\.[^.]*}.mp4"
echo "Encoding: $input" >&2
time "$handbrake" \
$handbrake_options \
--input "$input" \
--output "$output" \
2>&1 | tee -a "${output}.log"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment