mirror of
https://github.com/kristoferssolo/solorice.git
synced 2026-02-04 06:32:03 +00:00
151 lines
3.3 KiB
Bash
Executable File
151 lines
3.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# any2av1mkv - Convert provided files to MKV with AV1 video (VAAPI on AMD),
|
|
# keeping ALL audio tracks, subtitles (including PGS), and attachments.
|
|
#
|
|
# Default is bitrate-controlled VBR, tuned for 1080p and "not inflating".
|
|
#
|
|
# Usage:
|
|
# any2av1mkv input1.mkv input2.mp4 "weird name.avi"
|
|
# any2av1mkv * # skips directories
|
|
#
|
|
# Options:
|
|
# -d, --dry-run print ffmpeg command(s) only
|
|
# --no-skip overwrite output if it already exists
|
|
# --cqp use constant-quality mode instead of VBR
|
|
# --audio-encode aac re-encode ALL audio tracks to AAC (default: copy)
|
|
# -h, --help
|
|
#
|
|
# Env vars:
|
|
# DEV=/dev/dri/renderD128
|
|
#
|
|
# VBR mode (default):
|
|
# B=3500k target video bitrate (1080p 10-bit starting point)
|
|
# MAX=5000k max video bitrate
|
|
# BUF=10000k VBV buffer
|
|
#
|
|
# CQP mode (with --cqp):
|
|
# QP=42 higher = smaller / lower quality (try 40-46 for 1080p)
|
|
|
|
DEV="${DEV:-/dev/dri/renderD128}"
|
|
|
|
B="${B:-1500k}"
|
|
MAX="${MAX:-2200k}"
|
|
BUF="${BUF:-4400k}"
|
|
|
|
QP="${QP:-46}"
|
|
|
|
dry_run=0
|
|
skip_existing=1
|
|
audio_mode="acc" # or "copy"
|
|
use_cqp=0
|
|
|
|
args=()
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
-d | --dry-run)
|
|
dry_run=1
|
|
shift
|
|
;;
|
|
--no-skip)
|
|
skip_existing=0
|
|
shift
|
|
;;
|
|
--cqp)
|
|
use_cqp=1
|
|
shift
|
|
;;
|
|
--audio-encode)
|
|
[[ "${2:-}" == "aac" ]] || {
|
|
echo "Error: --audio-encode only supports: aac" >&2
|
|
exit 1
|
|
}
|
|
audio_mode="aac"
|
|
shift 2
|
|
;;
|
|
-h | --help)
|
|
sed -n '1,220p' "$0"
|
|
exit 0
|
|
;;
|
|
--)
|
|
shift
|
|
args+=("$@")
|
|
break
|
|
;;
|
|
*)
|
|
args+=("$1")
|
|
shift
|
|
;;
|
|
esac
|
|
done
|
|
|
|
command -v ffmpeg >/dev/null 2>&1 || {
|
|
echo "Error: ffmpeg not found." >&2
|
|
exit 1
|
|
}
|
|
|
|
if [[ ${#args[@]} -eq 0 ]]; then
|
|
echo "No input files. Provide file names/globs (e.g. *.mkv, *)."
|
|
exit 2
|
|
fi
|
|
|
|
for f in "${args[@]}"; do
|
|
[[ -e "$f" ]] || {
|
|
echo "Skip (missing): $f"
|
|
continue
|
|
}
|
|
[[ -f "$f" ]] || {
|
|
echo "Skip (not a file): $f"
|
|
continue
|
|
}
|
|
|
|
base="${f##*/}"
|
|
stem="${base%.*}"
|
|
out_dir="$(dirname -- "$f")"
|
|
out="${out_dir}/${stem}.av1.mkv"
|
|
|
|
if [[ $skip_existing -eq 1 && -e "$out" ]]; then
|
|
echo "Skip (exists): $out"
|
|
continue
|
|
fi
|
|
|
|
echo "Transcoding: $f -> $out"
|
|
|
|
if [[ "$audio_mode" == "aac" ]]; then
|
|
aopts=(-c:a aac -b:a 192k)
|
|
else
|
|
aopts=(-c:a copy)
|
|
fi
|
|
|
|
# Video options:
|
|
# - Use p010le to preserve 10-bit sources (and avoid 8-bit nv12 forcing).
|
|
# - If your source is 8-bit, VAAPI will still handle it; p010le is generally safe.
|
|
if [[ $use_cqp -eq 1 ]]; then
|
|
vopts=(-c:v av1_vaapi -rc_mode CQP -qp "$QP")
|
|
else
|
|
vopts=(-c:v av1_vaapi -rc_mode VBR -b:v "$B" -maxrate "$MAX" -bufsize "$BUF")
|
|
fi
|
|
|
|
cmd=(
|
|
ffmpeg -hide_banner -nostdin -y
|
|
-vaapi_device "$DEV"
|
|
-i "$f"
|
|
-map 0
|
|
-vf 'format=p010le,hwupload'
|
|
"${vopts[@]}"
|
|
"${aopts[@]}"
|
|
-c:s copy
|
|
-c:t copy
|
|
-c:d copy
|
|
"$out"
|
|
)
|
|
|
|
if [[ $dry_run -eq 1 ]]; then
|
|
printf '%q ' "${cmd[@]}"
|
|
printf '\n'
|
|
else
|
|
"${cmd[@]}"
|
|
fi
|
|
done
|