makemkv-workstation

Log | Files | Refs | README

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