MediaEncoder/reencode.sh
2025-02-20 20:19:51 -05:00

207 lines
4.0 KiB
Bash

#!/bin/sh
#
# Section: Argument parsing
#
options="sim run full"
if [ $# -ne 2 ]; then
echo "reencode <$( echo "$options" | sed 's/ /|/g' )> <directory>"
exit 1
fi
mode=""
for opt in $options; do
if [ "$opt" = "$1" ]; then
mode="$opt"
fi
done
if [ "$mode" = "" ]; then
echo "'$1' is not a valid option"
exit 1
fi
path="$2"
cd "$path"
if [ $? -ne 0 ]; then
echo "Path does not exist: $path"
exit 1
fi
echo "Searching for MKVs in $( pwd )"
#
# Section: Functions
#
do_ffprobe() {
ffprobe -v quiet -select_streams v:0 -show_entries $1 -of csv=p=0:nk=1 "$2"
}
get_codec() {
do_ffprobe stream=codec_name "$1"
}
get_bitrate() {
do_ffprobe format=bit_rate "$1"
}
get_resolution() {
do_ffprobe stream=height,width "$1"
}
file_size() {
du -sb "$1" | awk '{print $1}'
}
format_size() {
echo "$1" | numfmt --to=iec-i | awk '{print $1"B"}'
}
format_rate() {
echo "$1" | numfmt --to=si | awk '{print $1"bps"}'
}
encode_file() {
process=$( echo $1 | awk -v FPAT="([^' ]+)|'([^']+)'" '{print $1}' )
filesize=$( echo $1 | awk -v FPAT="([^' ]+)|'([^']+)'" '{print $2}' )
bitrate=$( echo $1 | awk -v FPAT="([^' ]+)|'([^']+)'" '{print $3}' )
codec=$( echo $1 | awk -v FPAT="([^' ]+)|'([^']+)'" '{print $4}' )
infile=$( echo $1 | awk -v FPAT="([^' ]+)|'([^']+)'" '{print $5}' | sed "s/^'\|'\$//g" )
outfile=$( echo $1 | awk -v FPAT="([^' ]+)|'([^']+)'" '{print $6}' | sed "s/^'\|'\$//g" )
if [ "$process" = "Ignore" ]; then
return 1
fi
tmpfile="$infile.bak"
ffmpeg -nostdin -hide_banner -i "$infile" -c:v hevc_nvenc -c:a copy -c:s copy -map 0 -vtag hvc1 output.mkv
if [ $? -ne 0 ]; then
echo "FFMPEG re-encode failed: $infile"
return 1
fi
mv "$infile" "$tmpfile"
if [ $? -ne 0 ]; then
echo "Failed to make backup file: $infile"
rm output.mkv
return 2
fi
mv output.mkv "$outfile"
if [ $? -ne 0 ]; then
echo "Failed final move to: $outfile"
mv -f "$tmpfile" "$infile"
rm output.mkv
return 2
fi
echo "Output file: $outfile"
rm "$tmpfile"
oldsize=$( format_size $filesize )
oldbitr=$( format_rate $bitrate )
newsize=$( format_size $( file_size "$outfile" ) )
newbitr=$( format_rate $( get_bitrate "$outfile" ) )
echo "Converted $infile:" >> summary.txt
echo "\t$oldsize ($oldbitr) => $newsize ($newbitr)\n" >> summary.txt
return 0
}
get_file_info() {
# Args:
# $1 - video file name
#
# Returns a single line:
# filesize bitrate codec
echo "$( file_size "$1" ) $( get_bitrate "$1" ) $( get_codec "$1" )"
}
select_file() {
# Arg:
# $1 - filename
# $2 - filesize
# $3 - bitrate
# $4 - codec
#
# Note: args line up with return values from get_file_info
#
# Echo "Ignore" or "Process" with an optional reason
file=$1
size=$2
bitrate=$3
codec=$4
#if [ "$codec" = "hevc" ]; then
# echo "Ignore Already HEVC"
# return
#fi
if [ $bitrate -lt 4000000 ]; then
echo "Ignore bitrate too low"
else
echo "Process"
fi
}
simulate_file() {
# Arg:
# $1 - video file name
#
# Prints out a line to simulate.txt formatted like so:
# process filesize bitrate codec infile outfile
fileinfo=$( get_file_info "$1" )
selected=$( select_file "$1" $fileinfo )
outputfile="${1%.*}.mkv"
reason=${selected#* }
selected=$( echo "$selected" | awk '{print $1}' )
if [ "$selected" = "Ignore" ]; then
echo "$selected $fileinfo '$1' '$reason'" >> simulation.txt
echo "Ignored $1"
echo "\t => $reason"
else
echo "$selected $fileinfo '$1' '$outputfile' '$reason'" >> simulation.txt
echo "Selected $1"
fi
}
#
# Section: Main code - do mode-specific stuff
#
if [ "$mode" != "run" ]; then
# if mode is not run (sim or full) then we're doing a simulation
rm -f simulation.txt
find -type f \( -name "*.mkv" -o -name "*.mp4" \) | while read file; do
simulate_file "$file"
done
fi
if [ "$mode" != "sim" ]; then
# if mode is not sim (run or full) then we're actually executing re-encodings
rm -f output.mkv
if [ ! -f "simulation.txt" ]; then
echo "No simulation file found. Cannot proceed."
exit 1
fi
cat simulation.txt | while read line; do
encode_file "$line"
if [ $? -eq 2 ]; then
exit 2
fi
done
fi