update script

This commit is contained in:
2026-02-20 20:43:28 -08:00
parent 8ac3d517fe
commit e1338113b5

View File

@@ -3,37 +3,68 @@
set -euo pipefail set -euo pipefail
usage() { usage() {
cat <<'EOF' cat << 'USAGE'
Usage: Usage:
scripts/mkv-to-readme-video.sh <input.mkv> scripts/mkv-to-readme-video.sh [--force] <input.mkv>
Description: Description:
Generates two browser-friendly files next to the input file: Generates two browser-friendly files next to the input file:
- <name>.mp4 (H.264 + AAC, prefers NVIDIA GPU if available) - <name>.mp4 (H.264 + AAC, prefers NVIDIA GPU if available)
- <name>.webm (AV1/VP9 + Opus, prefers NVIDIA GPU if available) - <name>.webm (AV1/VP9 + Opus, prefers NVIDIA GPU if available)
EOF - <name>.gif (palette-optimised, 15 fps)
Options:
-f, --force Overwrite existing output files
Encoding profile:
- Crop: 1920x1080 at x=760 y=180
- MP4: H.264 + AAC
- WebM: AV1/VP9 + Opus at 30 fps
USAGE
} }
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then force=0
usage input=""
exit 0
while [[ $# -gt 0 ]]; do
case "$1" in
-h|--help)
usage
exit 0
;;
-f|--force)
force=1
;;
-*)
echo "Error: unknown option: $1" >&2
usage
exit 1
;;
*)
if [[ -n "$input" ]]; then
echo "Error: expected exactly one input file." >&2
usage
exit 1
fi
input="$1"
;;
esac
shift
done
if [[ -z "$input" ]]; then
usage
exit 1
fi fi
if [[ $# -ne 1 ]]; then if ! command -v ffmpeg > /dev/null 2>&1; then
usage echo "Error: ffmpeg is not installed or not in PATH." >&2
exit 1 exit 1
fi fi
if ! command -v ffmpeg >/dev/null 2>&1; then
echo "Error: ffmpeg is not installed or not in PATH." >&2
exit 1
fi
input="$1"
if [[ ! -f "$input" ]]; then if [[ ! -f "$input" ]]; then
echo "Error: input file not found: $input" >&2 echo "Error: input file not found: $input" >&2
exit 1 exit 1
fi fi
dir="$(dirname "$input")" dir="$(dirname "$input")"
@@ -42,46 +73,96 @@ base="${filename%.*}"
mp4_out="$dir/$base.mp4" mp4_out="$dir/$base.mp4"
webm_out="$dir/$base.webm" webm_out="$dir/$base.webm"
gif_out="$dir/$base.gif"
overwrite_flag="-n"
if [[ "$force" -eq 1 ]]; then
overwrite_flag="-y"
fi
if [[ "$force" -eq 0 ]]; then
for output in "$mp4_out" "$webm_out" "$gif_out"; do
if [[ -e "$output" ]]; then
echo "Error: output exists: $output (use --force to overwrite)" >&2
exit 1
fi
done
fi
has_encoder() { has_encoder() {
local encoder="$1" local encoder="$1"
ffmpeg -hide_banner -encoders 2>/dev/null | grep -qE "[[:space:]]${encoder}[[:space:]]" ffmpeg -hide_banner -encoders 2> /dev/null | grep -qE "[[:space:]]${encoder}[[:space:]]"
} }
crop_vf="crop=1920:1080:760:180"
webm_vf="${crop_vf},fps=30"
gif_vf="${crop_vf},fps=15,scale=960:-1:flags=lanczos,split[s0][s1];[s0]palettegen=max_colors=128[p];[s1][p]paletteuse=dither=bayer:bayer_scale=3"
echo "Generating MP4: $mp4_out" echo "Generating MP4: $mp4_out"
if has_encoder "h264_nvenc"; then if has_encoder "h264_nvenc"; then
echo "Using GPU encoder for MP4: h264_nvenc" echo "Trying GPU encoder for MP4: h264_nvenc"
ffmpeg -y -i "$input" \ if ffmpeg "$overwrite_flag" -i "$input" \
-c:v h264_nvenc -preset p5 -cq 20 \ -vf "$crop_vf" \
-profile:v high -pix_fmt yuv420p \ -c:v h264_nvenc -preset p6 -rc:v vbr -cq:v 20 -b:v 0 \
-movflags +faststart \ -pix_fmt yuv420p -movflags +faststart \
-c:a aac -b:a 160k \ -c:a aac -b:a 160k \
"$mp4_out" "$mp4_out"; then
:
else
echo "GPU MP4 encode failed; retrying with CPU encoder: libx264"
ffmpeg "$overwrite_flag" -i "$input" \
-vf "$crop_vf" \
-c:v libx264 -preset slow -crf 20 \
-profile:v high -level 4.1 -pix_fmt yuv420p \
-movflags +faststart \
-c:a aac -b:a 160k \
"$mp4_out"
fi
else else
echo "Using CPU encoder for MP4: libx264" echo "Using CPU encoder for MP4: libx264"
ffmpeg -y -i "$input" \ ffmpeg "$overwrite_flag" -i "$input" \
-c:v libx264 -preset slow -crf 20 \ -vf "$crop_vf" \
-profile:v high -level 4.1 -pix_fmt yuv420p \ -c:v libx264 -preset slow -crf 20 \
-movflags +faststart \ -profile:v high -level 4.1 -pix_fmt yuv420p \
-c:a aac -b:a 160k \ -movflags +faststart \
"$mp4_out" -c:a aac -b:a 160k \
"$mp4_out"
fi fi
echo "Generating WebM: $webm_out" echo "Generating WebM: $webm_out"
if has_encoder "av1_nvenc"; then if has_encoder "av1_nvenc"; then
echo "Using GPU encoder for WebM: av1_nvenc" echo "Trying GPU encoder for WebM: av1_nvenc"
ffmpeg -y -i "$input" \ if ffmpeg "$overwrite_flag" -i "$input" \
-c:v av1_nvenc -preset p5 -cq 30 -b:v 0 \ -vf "$webm_vf" \
-c:a libopus -b:a 128k \ -c:v av1_nvenc -preset p6 -cq:v 34 -b:v 0 \
"$webm_out" -c:a libopus -b:a 96k \
"$webm_out"; then
:
else
echo "GPU WebM encode failed; retrying with CPU encoder: libvpx-vp9"
ffmpeg "$overwrite_flag" -i "$input" \
-vf "$webm_vf" \
-c:v libvpx-vp9 -crf 34 -b:v 0 \
-row-mt 1 -threads 8 \
-c:a libopus -b:a 96k \
"$webm_out"
fi
else else
echo "Using CPU encoder for WebM: libvpx-vp9" echo "Using CPU encoder for WebM: libvpx-vp9"
ffmpeg -y -i "$input" \ ffmpeg "$overwrite_flag" -i "$input" \
-c:v libvpx-vp9 -crf 32 -b:v 0 \ -vf "$webm_vf" \
-c:a libopus -b:a 128k \ -c:v libvpx-vp9 -crf 34 -b:v 0 \
"$webm_out" -row-mt 1 -threads 8 \
-c:a libopus -b:a 96k \
"$webm_out"
fi fi
echo "Generating GIF: $gif_out"
ffmpeg "$overwrite_flag" -i "$input" \
-vf "$gif_vf" \
"$gif_out"
echo "Done." echo "Done."
echo "MP4: $mp4_out" echo "MP4: $mp4_out"
echo "WebM: $webm_out" echo "WebM: $webm_out"
echo "GIF: $gif_out"