# Many DVDs released in Australia are sped up from 24fps to 25fps.
# This script reverses the procedure, correcting the audio pitch.
-# The video framerate is adjusted without re-encoding. The audio is
-# slowed, and encoded as AAC, preserving surround sound.
+# - The video framerate is adjusted without re-encoding.
+# - The audio is slowed, and encoded as AAC, preserving surround sound.
+# - Chapters and subtitles are also adjusted to match the new timing.
-if [ -z "$1" -o -z "$2" ]; then
+if [ -z "$1" ] || [ -z "$2" ]; then
echo "Usage: $0 infile outfile"
exit 1
fi
set -o pipefail -eux
-FORCEFPS="24"
-SLOWFILTER="-filter asetrate=46080,aresample=osr=48000:resampler=soxr"
+OLDFPS="25"
+NEWFPS="24"
+SLOWFILTER=("-filter" "asetrate=46080,aresample=osr=48000:resampler=soxr")
-function mux_replace_audio {
+function main {
+ local infile="$1"
+ local outfile="$2"
+
+ local tmpdir=""
+ tmpdir="$(mktemp -d "${TMPDIR:-/var/tmp}/pal-XXXXXXXX")"
+ local audiofile="${tmpdir}/audiofile.m4a"
+
+ encode_audio "$infile" "$audiofile"
+ remux_file "$infile" "$audiofile" "$outfile"
+
+ rm -rf "$tmpdir"
+}
+
+function encode_audio {
+ ffmpeg \
+ -i "$1" \
+ -vn \
+ "${SLOWFILTER[@]}" \
+ -c:a libfdk_aac -vbr 3 \
+ "$2"
+}
+
+function remux_file {
local infile="$1"
local audiofile="$2"
local outfile="$3"
- local audiodelay="$(get_minimum_timestamp "$infile" "audio")"
- local videodelay="$(get_minimum_timestamp "$infile" "video")"
- local videotrackid="$(get_track_id "$infile" "video")"
+ local audiodelay=""
+ audiodelay="$(get_minimum_timestamp "$infile" "audio")"
+
+ local videodelay=""
+ videodelay="$(get_minimum_timestamp "$infile" "video")"
+
+ local videotrackid=""
+ videotrackid="$(get_track_id "$infile" "video")"
+
+ local suboptions=()
+ local subtitletrackid=""
+ while read -r subtitletrackid; do
+ suboptions+=("--sync" "${subtitletrackid}:0,${OLDFPS}/${NEWFPS}")
+ done < <(get_track_id "$infile" "subtitles")
mkvmerge \
-o "${outfile}" \
- --default-duration "${videotrackid}:${FORCEFPS}fps" \
+ --default-duration "${videotrackid}:${NEWFPS}fps" \
--sync "${videotrackid}:$((videodelay / 1000000))" \
+ --chapter-sync "0,${OLDFPS}/${NEWFPS}" \
+ "${suboptions[@]}" \
--no-audio "$infile" \
--sync "0:$((audiodelay / 1000000))" \
"$audiofile"
}
function get_minimum_timestamp {
- mkvmerge -F json -i "$1" | jq -r ".tracks[] | select(.type == \"$2\") | .properties.minimum_timestamp"
-}
-
-function encode_audio {
- ffmpeg \
- -i "$1" \
- -vn \
- $SLOWFILTER \
- -c:a libfdk_aac -vbr 3 \
- "$2"
+ mkvmerge -i -F json "$1" | jq -r ".tracks[] | select(.type == \"$2\") | .properties.minimum_timestamp"
}
-function convert_file {
- local infile="$1"
- local outfile="$2"
- local audiofile="${tmpdir}/audiofile.m4a"
-
- encode_audio "$infile" "$audiofile"
- mux_replace_audio "$infile" "$audiofile" "$outfile"
-}
-
-
-infile="$1"
-outfile="$2"
-tmpdir="$(mktemp -d "${TMPDIR:-/var/tmp}/pal-XXXXXXXX")"
-convert_file "$infile" "$outfile"
-rm -rf "$tmpdir"
+main "$@"