encode.sh (2886B)
1 #!/bin/bash 2 set -euo pipefail 3 4 SOFTWARE=0 5 6 usage() { 7 echo "Usage: encode <input.mkv> [output.mkv] [crf] [--software]" 8 echo "" 9 echo " input.mkv source file (required)" 10 echo " output.mkv destination file (default: input_x265.mkv)" 11 echo " crf quality level 18-28 (default: 22, lower = better quality)" 12 echo " --software use software x265 encoder (slower, higher quality)" 13 echo "" 14 echo "Examples:" 15 echo " encode movie.mkv" 16 echo " encode movie.mkv movie_encoded.mkv" 17 echo " encode movie.mkv movie_encoded.mkv 18" 18 echo " encode movie.mkv movie_encoded.mkv 18 --software" 19 exit 1 20 } 21 22 [[ $# -lt 1 ]] && usage 23 24 INPUT="$1" 25 OUTPUT="${2:-${INPUT%.*}_x265.mkv}" 26 CRF="${3:-22}" 27 28 for arg in "$@"; do 29 [[ "$arg" == "--software" ]] && SOFTWARE=1 30 done 31 32 if [[ ! -f "$INPUT" ]]; then 33 echo "Error: input file not found: $INPUT" 34 exit 1 35 fi 36 37 # Build stream maps — probe for English audio and subtitle tracks 38 MAPS="-map 0:v" 39 40 if ffprobe -v quiet -select_streams "a:m:language:eng" -show_streams "$INPUT" 2>/dev/null | grep -q "^index="; then 41 MAPS="$MAPS -map 0:a:m:language:eng" 42 else 43 MAPS="$MAPS -map 0:a" 44 fi 45 46 if ffprobe -v quiet -select_streams "s:m:language:eng" -show_streams "$INPUT" 2>/dev/null | grep -q "^index="; then 47 MAPS="$MAPS -map 0:s:m:language:eng" 48 fi 49 50 # Auto-detect SD content — hevc_vaapi can't handle BT.601/TV-range color space 51 # (standard DVD format). SD is small enough that software is faster and better quality. 52 if [[ $SOFTWARE -eq 0 ]]; then 53 HEIGHT=$(ffprobe -v quiet -select_streams v:0 \ 54 -show_entries stream=height -of default=noprint_wrappers=1:nokey=1 "$INPUT" 2>/dev/null | head -1) 55 if [[ -n "$HEIGHT" && "$HEIGHT" -le 576 ]]; then 56 echo "SD content detected (${HEIGHT}p) — switching to software encoder" 57 SOFTWARE=1 58 fi 59 fi 60 61 echo "Input: $INPUT" 62 echo "Output: $OUTPUT" 63 echo "CRF/QP: $CRF" 64 65 if [[ $SOFTWARE -eq 1 ]]; then 66 echo "Encoder: libx265 (software)" 67 echo "" 68 ffmpeg -probesize 100M -analyzeduration 100M \ 69 -i "$INPUT" \ 70 $MAPS \ 71 -c:v libx265 \ 72 -crf "$CRF" \ 73 -preset medium \ 74 -c:a copy \ 75 -c:s copy \ 76 "$OUTPUT" 77 else 78 echo "Encoder: hevc_vaapi (hardware)" 79 echo "" 80 ffmpeg -probesize 100M -analyzeduration 100M \ 81 -vaapi_device /dev/dri/renderD128 \ 82 -i "$INPUT" \ 83 $MAPS \ 84 -vf 'format=nv12,hwupload,scale_vaapi=format=nv12' \ 85 -c:v hevc_vaapi \ 86 -qp "$CRF" \ 87 -c:a copy \ 88 -c:s copy \ 89 "$OUTPUT" 90 fi 91 92 INSIZE=$(du -sh "$INPUT" | cut -f1) 93 OUTSIZE=$(du -sh "$OUTPUT" | cut -f1) 94 echo "" 95 echo "Done. $INPUT ($INSIZE) -> $OUTPUT ($OUTSIZE)" 96 97 if command -v notify &>/dev/null && [[ "${MAKEMKV_RIP:-0}" != "1" ]]; then 98 notify "Encode complete" "$(basename "$OUTPUT") — ${INSIZE} → ${OUTSIZE}" 99 fi