h264/h264

128 lines
2.5 KiB
Bash
Executable File

#! /bin/sh
set -e
usage () { cat <<EOD 1>&2; }
Usage: $0 [OPTIONS...] SRC [SRC...]
Re-encodes to h.264, preserving audio and subtitles.
Output will be written to \$SRC.h264.mp4
-height H Rescale to no taller than H
-1080p Rescale to no bigger than 1080p
-720p Rescale to no bigger than 720p
-480p Rescale to no bigger than 480p
-bitrate B Set average bitrate to B, overriding rescale setting or CRF
-crf C Set CRF to C, overriding rescale setting or bitrate
-swenc Software encode instead of hardware
EOD
height=ih
codec=h264_v4l2m2m
bitrate="-b:v 2048k"
while true; do
case "$1" in
-height|--height)
height=$2
shift 2
;;
-1080p|--1080p)
height=1080
bitrate="-b:v 2048k"
shift
;;
-720p|--720p)
height=720
bitrate="-b:v 1200k"
shift
;;
-480p|--480p)
height=480
bitrate="-b:v 512k"
shift
;;
-bitrate|--bitrate)
bitrateManual="-b:v $2"
shift 2
;;
-crf|--crf)
bitrateManual="-crf $2"
shift 2
;;
-swenc|--swenc)
codec=h264
shift
;;
-*)
usage
exit
;;
*)
break
;;
esac
done
if [ "$codec" = "h264" ]; then
bitrate="-crf 28"
fi
bitrate=${bitrateManual:-$bitrate}
log () {
echo "=== $*"
}
cmd () {
nice "$@"
}
# This got a height of 719 (n%2 must = 0)
#-vf "scale='min($width,iw)':'min($height,ih)':force_original_aspect_ratio=decrease,format=yuv420p" \
for fn in "$@"; do
base=${fn%.*}
filename=$(basename "$fn")
intermediate="$base.nut"
out="$base.h264.mkv"
[ -f "$out" ] && continue
case "$fn" in *.h264.mp4) continue ;; esac
# ffmpeg has some bizarro thing where the h264_v4l2m2m codec won't write to a mkv file,
# In addition, some subtitles interfere with it too.
# Solution: transcode video + audio into an intermediate file,
# then add back any subtitles.
log "$filename - Scale/Transcode"
cmd ffmpeg \
-hide_banner \
-loglevel warning \
-stats \
-i "$fn" \
-map 0:v \
-vf "scale=-2:'min($height,ih)':force_original_aspect_ratio=decrease,format=yuv420p" \
-c:v $codec \
$bitrate \
-map 0:a \
-c:a copy \
-num_capture_buffers 16 \
-num_output_buffers 32 \
-y \
"$intermediate"
log "$filename - Add subtitles"
cmd ffmpeg \
-hide_banner \
-loglevel warning \
-stats \
-i "$intermediate" \
-i "$fn" \
-map 0:v \
-map 0:a \
-map 1:s? \
-c copy \
-y \
"$out"
rm "$intermediate"
done