mise à jours HEVC pour 1080p

This commit is contained in:
2026-08-17 23:50:11 +02:00
parent aed1467284
commit 5a04f159ca
6 changed files with 1139 additions and 167 deletions
+177
View File
@@ -0,0 +1,177 @@
#!/bin/bash
# =============================================================================
# CALIBRATION CRF — HEVC
#
# Encode un même extrait de rush à plusieurs CRF et mesure la qualité
# objective (VMAF si dispo, sinon SSIM) + la taille obtenue.
# Objectif : choisir CRF_HD / CRF_SD sur TES images plutôt qu'au doigt mouillé.
#
# Usage :
# ./bench_crf.sh rushs/GH011182.MP4 [start_sec] [duree_sec]
#
# Variables :
# CODEC=hevc palier 1080p HEVC (défaut)
# CODEC=h264 palier 720p H.264
# HEIGHT=1080 hauteur cible du test (1080 ou 720)
# CRFS="22 24 26 28 30 32"
# PRESET=medium
# ENCODER=cpu|vt (en mode vt, CRFS est interprété comme des valeurs -q:v)
# KEEP=1 conserve les fichiers encodés pour comparaison visuelle
#
# Les deux paliers du site se calibrent séparément — les échelles de CRF
# de x264 et x265 ne sont PAS comparables :
# ./bench_crf.sh rushs/GH011182.MP4 30 20 # 1080p HEVC
# CODEC=h264 HEIGHT=720 CRFS="20 22 24 26" ./bench_crf.sh rushs/GH011182.MP4 30 20
#
# Choisis un extrait REPRÉSENTATIF : du mouvement, de la végétation, du
# ciel dégradé. Un plan fixe sur un mur donnera un CRF trop optimiste.
# =============================================================================
set -uo pipefail
SRC="${1:?Usage: ./bench_crf.sh <fichier_rush> [start_sec] [duree_sec]}"
START="${2:-30}"
DUR="${3:-20}"
CODEC="${CODEC:-hevc}"
HEIGHT="${HEIGHT:-1080}"
if [ "$CODEC" = "h264" ]; then
CRFS="${CRFS:-18 20 22 24 26 28}"
else
CRFS="${CRFS:-22 24 26 28 30 32}"
fi
PRESET="${PRESET:-medium}"
ENCODER="${ENCODER:-cpu}"
KEEP="${KEEP:-0}"
[ -f "$SRC" ] || { echo "❌ Fichier introuvable : $SRC"; exit 1; }
WORK="$(mktemp -d "${TMPDIR:-/tmp}/bench_crf.XXXXXX")"
cleanup() { [ "$KEEP" = "1" ] || rm -rf "$WORK"; }
trap cleanup EXIT
# --- Détection de la métrique disponible -------------------------------------
FILTERS_LIST="$(ffmpeg -hide_banner -filters 2>/dev/null)"
if printf '%s' "$FILTERS_LIST" | grep -q "libvmaf"; then
METRIC="vmaf"
else
METRIC="ssim"
echo "️ libvmaf absent de ton ffmpeg → repli sur SSIM."
echo " (VMAF est bien plus parlant : brew install ffmpeg l'inclut normalement)"
fi
# --- Référence : extrait copié sans réencodage -------------------------------
REF="$WORK/ref.mp4"
echo "✂️ Extraction de la référence (${DUR}s à partir de ${START}s)…"
ffmpeg -nostdin -hide_banner -loglevel error -y \
-ss "$START" -i "$SRC" -t "$DUR" \
-map 0:v:0 -c copy -tag:v hvc1 "$REF" 2>/dev/null
if [ ! -s "$REF" ]; then
echo "⚠️ Copie directe impossible, réencodage sans perte visible de la référence…"
ffmpeg -nostdin -hide_banner -loglevel error -y \
-ss "$START" -i "$SRC" -t "$DUR" \
-map 0:v:0 -c:v libx265 -preset ultrafast -x265-params lossless=1 \
-tag:v hvc1 "$REF"
fi
# Si on teste une hauteur inférieure à la source, la référence de comparaison
# doit être à la MÊME définition que le test : on fabrique une référence scalée.
SRC_H=$(ffprobe -v error -select_streams v:0 -show_entries stream=height -of csv=p=0 "$REF" | head -1)
REF_CMP="$REF"
if [ "$SRC_H" != "$HEIGHT" ]; then
REF_CMP="$WORK/ref_${HEIGHT}.mp4"
echo "📐 Référence de comparaison rescalée en ${HEIGHT}p…"
ffmpeg -nostdin -hide_banner -loglevel error -y -i "$REF" \
-vf "scale=-2:${HEIGHT}:flags=lanczos" \
-c:v libx265 -preset ultrafast -x265-params lossless=1 -tag:v hvc1 "$REF_CMP"
fi
REF_DUR=$(ffprobe -v error -show_entries format=duration -of csv=p=0 "$REF" | cut -d. -f1)
REF_DUR=${REF_DUR:-$DUR}
echo
echo "🎯 Palier testé : ${HEIGHT}p en $(echo "$CODEC" | tr a-z A-Z)"
printf "%-6s %10s %12s %10s %10s\n" "CRF" "Taille" "Débit" "$(echo "$METRIC" | tr a-z A-Z)" "Encodage"
printf "%s\n" "--------------------------------------------------------"
BEST_LINE=""
for crf in $CRFS; do
OUT="$WORK/test_crf${crf}.mp4"
if [ "$CODEC" = "h264" ]; then
if [ "$ENCODER" = "vt" ]; then
VOPTS=(-c:v h264_videotoolbox -profile:v high -q:v "$crf" -allow_sw 1 -realtime 0)
else
VOPTS=(-c:v libx264 -preset "$PRESET" -profile:v high -level 4.0 -crf "$crf"
-g 120 -keyint_min 24)
fi
else
if [ "$ENCODER" = "vt" ]; then
VOPTS=(-c:v hevc_videotoolbox -profile:v main -q:v "$crf" -allow_sw 1 -realtime 0 -tag:v hvc1)
else
VOPTS=(-c:v libx265 -preset "$PRESET" -profile:v main -crf "$crf"
-x265-params "keyint=120:min-keyint=24:aq-mode=3" -tag:v hvc1)
fi
fi
T0=$(date +%s)
ffmpeg -nostdin -hide_banner -loglevel error -y -i "$REF" \
-map 0:v:0 "${VOPTS[@]}" \
-vf "scale=-2:${HEIGHT}:flags=lanczos" \
-pix_fmt yuv420p \
-color_primaries bt709 -color_trc bt709 -colorspace bt709 \
-an "$OUT" 2>/dev/null
T1=$(date +%s)
ENC_TIME=$((T1 - T0))
[ -s "$OUT" ] || { printf "%-6s %10s\n" "$crf" "ÉCHEC"; continue; }
BYTES=$(stat -f%z "$OUT" 2>/dev/null || stat -c%s "$OUT")
MB=$(awk -v b="$BYTES" 'BEGIN{printf "%.1f", b/1048576}')
KBPS=$(awk -v b="$BYTES" -v d="$REF_DUR" 'BEGIN{printf "%.0f", b*8/1000/d}')
# --- Mesure de qualité ---
if [ "$METRIC" = "vmaf" ]; then
SCORE=$(ffmpeg -nostdin -hide_banner -loglevel info -i "$OUT" -i "$REF_CMP" \
-lavfi "[0:v]setpts=PTS-STARTPTS[d];[1:v]setpts=PTS-STARTPTS[r];[d][r]libvmaf" \
-f null - 2>&1 | grep -oE "VMAF score: [0-9.]+" | tail -1 | grep -oE "[0-9.]+")
SCORE=$(awk -v s="${SCORE:-0}" 'BEGIN{printf "%.2f", s}')
else
SCORE=$(ffmpeg -nostdin -hide_banner -loglevel info -i "$OUT" -i "$REF_CMP" \
-lavfi "[0:v]setpts=PTS-STARTPTS[d];[1:v]setpts=PTS-STARTPTS[r];[d][r]ssim" \
-f null - 2>&1 | grep -oE "All:[0-9.]+" | tail -1 | cut -d: -f2)
SCORE=$(awk -v s="${SCORE:-0}" 'BEGIN{printf "%.4f", s}')
fi
printf "%-6s %9s M %9s k %10s %8s s\n" "$crf" "$MB" "$KBPS" "$SCORE" "$ENC_TIME"
done
echo
echo "📖 Comment lire ce tableau"
if [ "$METRIC" = "vmaf" ]; then
cat <<'EOF'
VMAF ≥ 95 : indiscernable de la source à distance normale
VMAF 90-95 : excellent, cible raisonnable pour un site de voyage
VMAF 85-90 : bon, quelques artefacts visibles en plein écran
VMAF < 85 : dégradation nette sur les scènes chargées
→ Prends le CRF le plus ÉLEVÉ qui reste au-dessus de ton seuil.
Le gain de taille entre deux CRF consécutifs s'écrase vite ;
dès que la courbe de qualité plonge, tu es allé trop loin.
EOF
else
cat <<'EOF'
SSIM ≥ 0.98 : très bon
SSIM 0.96-0.98 : correct pour du web
SSIM < 0.95 : dégradation visible
→ Prends le CRF le plus ÉLEVÉ qui reste au-dessus de ton seuil.
⚠️ SSIM est moins fiable que VMAF sur des images très texturées
(feuillage, eau, gravier) : vérifie AUSSI à l'œil avec KEEP=1.
EOF
fi
if [ "$KEEP" = "1" ]; then
echo
echo "📁 Fichiers conservés dans : $WORK"
echo " Compare à l'œil, en plein écran, sur les plans les plus chargés."
fi