Skip to content

Instantly share code, notes, and snippets.

@FabianBartl
Last active February 28, 2025 14:41
Show Gist options
  • Save FabianBartl/a4c88fe0922670ca1926c1447e61a4ca to your computer and use it in GitHub Desktop.
Save FabianBartl/a4c88fe0922670ca1926c1447e61a4ca to your computer and use it in GitHub Desktop.
Slowly re-encode high quality video files into H.265 format to reduce the file size while maintaining quality. The audio tracks are not re-encoded as this does not affect the file size as much as the video.
#!/bin/bash
# Directory containing the files to process
input_dir="$1"
# Iterate over all files in the directory
for file in "$input_dir"/*; do
if [ -f "$file" ]; then
echo "Processing file: $file"
bash /root/slow-reencode-to-h265.sh "$file" # absolute path (!) to the script below
fi
done
#!/bin/bash
# Input file
input_file="$1"
# Extract pixel format using ffprobe and trim any excess whitespace or lines
pix_fmt=$(ffprobe -hide_banner -v error -select_streams v:0 -show_entries stream=pix_fmt -of default=noprint_wrappers=1:nokey=1 "$input_file" 2>/dev/null | head -n 1 | xargs)
# Determine the appropriate profile based on the pixel format
if [[ "$pix_fmt" == *"yuv420p10le"* ]]; then
profile="main10"
else
profile="main"
fi
# Check if the video is interlaced using ffprobe
field_order=$(ffprobe -hide_banner -v error -select_streams v:0 -show_entries stream=field_order -of default=noprint_wrappers=1:nokey=1 "$input_file" 2>/dev/null | head -n 1)
# If the field order indicates interlacing (tt or bt), enable deinterlacing
if [[ "$field_order" == *"tt"* || "$field_order" == *"bt"* ]]; then
deinterlace_filter="-vf yadif"
else
deinterlace_filter=""
fi
# CRF 18-23: High quality, larger file sizes.
# CRF 24-27: Good balance of quality and file size.
# CRF 28-30: Smaller file size, but with a noticeable drop in quality.
crf=23 # With crf=23, a 40GB 1080p BluRay file is reduced to a file size of around 15GB.
# Display used settings.
echo "input_file='$input_file'"
echo "crf='$crf'"
echo "profile='$profile'"
echo "pix_fmt='$pix_fmt'"
echo "field_order='$field_order'"
echo "deinterlace_filter='$deinterlace_filter'"
# Create the "komp" subfolder if it doesn't exist
output_dir="$(dirname "$input_file")/komp"
mkdir -p "$output_dir"
# Run the ffmpeg command dynamically based on the input file's pixel format and profile,
# preserving all audio and subtitle tracks without re-encoding the audio.
ffmpeg -i "$input_file" \
-map 0:v -c:v libx265 -crf "$crf" -preset medium -profile:v "$profile" -pix_fmt "$pix_fmt" $deinterlace_filter \
-map 0:a -c:a copy \
-map 0:s:? -c:s copy \
"$output_dir/$(basename "${input_file%.*}") [crf"${crf}"].mkv"
# TODO: insert a pushover command to get notified when the conversion is finished
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment