Files
RoadTripsGenerator/Scripts/bench_crf.sh
T
FabriceandClaude Opus 5.5 97b936fd3e Refonte : templates, balades, photos web, aperçus, carte globale
- Mise en page sortie du Python : Scripts/templates/ (Jinja2 + CSS/JS
  communs copiés dans assets/ de chaque voyage)
- Voyages rangés dans un sous-dossier (Balades/…) : rubriques sur
  l'accueil, 2 plus récents par rubrique, pages voyages.html et
  balades.html
- prepare_web.py : photos allégées (photos_web/) et images d'aperçu
  des vidéos (apercus/)
- Voyage d'une seule journée : la page du voyage est la carte du jour
- Carte globale de l'accueil (OpenStreetMap) : voyages du site + cartes
  Google My Maps récupérées (mymaps.txt, _mymaps/), moto par voyage
  (moto.txt)
- KML par voyage pour My Maps
- compress.sh : réencode une sortie illisible (encodage interrompu) ;
  repli automatique sur l'autre qualité dans la page
- Corrections : CSV vide (voyage sans photo), racine de genere_site.sh,
  fichiers ._ de macOS
- README réécrit, commentaires allégés

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mf2kATMtqVABHSYdxJMnim
2026-10-09 11:08:01 +00:00

177 lines
7.0 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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_HEVC / CRF_H264 de compress.sh sur TES images.
#
# 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" "--------------------------------------------------------"
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