#!/usr/bin/env bash set -euo pipefail # Usage: nvenc_compress.sh [target_size_mb] VIDEO="$1" TARGET_MB="${2:-9}" TARGET_BYTES=$((TARGET_MB * 1024 * 1024)) if [[ ! -f "$VIDEO" ]]; then echo "Error: file not found: $VIDEO" exit 1 fi BASENAME="${VIDEO##*/}" BASENAME="${BASENAME%.*}" OUTDIR="$(dirname "$VIDEO")" OUTFILE="$OUTDIR/${BASENAME}_compressed.mp4" # nvenc cq range: 0 (best/largest) to 51 (worst/smallest) # We binary search this range to hit the target file size LO=0 HI=51 BEST_DIFF=999999999 BEST_CQ=23 MAX_ITERATIONS=20 echo "Target size: ${TARGET_MB}MB (${TARGET_BYTES} bytes)" echo "Encoding with nvenc (h264_nvenc)..." echo "" for ((i=0; i/dev/null if [[ ! -f "$TMPFILE" ]]; then echo "Error: ffmpeg failed at cq=$CQ" rm -f "$TMPFILE" break fi FILE_SIZE=$(stat -c%s "$TMPFILE" 2>/dev/null || stat -f%z "$TMPFILE" 2>/dev/null) DIFF=$(( FILE_SIZE - TARGET_BYTES )) ABS_DIFF=${DIFF#-} echo " Size: $(( FILE_SIZE / 1024 / 1024 ))MB (diff: $(( DIFF / 1024 / 1024 ))MB)" if (( ABS_DIFF < BEST_DIFF )); then BEST_DIFF=$ABS_DIFF BEST_CQ=$CQ cp "$TMPFILE" "$OUTFILE" fi rm -f "$TMPFILE" # If within 1% of target, we're close enough if (( ABS_DIFF < TARGET_BYTES / 100 )); then echo "" echo "Within tolerance! Stopping." break fi # Binary search direction: # Higher cq = smaller file, lower cq = larger file if (( FILE_SIZE > TARGET_BYTES )); then # File too big, need higher cq (smaller) LO=$(( CQ + 1 )) else # File too small, need lower cq (larger) HI=$(( CQ - 1 )) fi if (( LO > HI )); then echo "" echo "Range exhausted. Stopping." break fi done echo "" echo "Done! Best cq=$BEST_CQ, final size: $(( BEST_DIFF / 1024 / 1024 ))MB from target" echo "Output: $OUTFILE"