feat: pipeline stop motion (découverte, ffconcat, encodage, récapitulatif)

This commit is contained in:
herel committed 2026-08-31 21:15:00 +02:00
1 parent 51cb34a163
commit e298825aac
1 file changed
+57
+57
View File
@@ -53,3 +53,60 @@ if [ ! -d "$INPUT" ]; then
echo "Erreur : le dossier d'images '$INPUT' n'existe pas." >&2
exit 1
fi
IMAGES_ABS_DIR=$(cd "$INPUT" && pwd)
IMAGES=$(LC_ALL=C find "$IMAGES_ABS_DIR" -maxdepth 1 -type f \( -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.png' -o -iname '*.heic' \) | LC_ALL=C sort)
if [ -z "$IMAGES" ]; then
echo "Erreur : aucune image (jpg, jpeg, png, heic) trouvée dans '$INPUT'." >&2
exit 1
fi
COUNT=$(printf '%s\n' "$IMAGES" | wc -l | tr -d ' ')
if [ ! -d "$(dirname "$OUTPUT")" ]; then
echo "Erreur : le dossier de sortie '$(dirname "$OUTPUT")' n'existe pas." >&2
exit 1
fi
if [ -e "$OUTPUT" ] && [ "$ASSUME_YES" -ne 1 ]; then
read -r -p "'$OUTPUT' existe déjà. L'écraser ? [o/N] " reponse
case $reponse in
o|O|y|Y|oui|Oui) ;;
*) echo "Abandon." ; exit 0 ;;
esac
fi
OUT_DIR=$(cd "$(dirname "$OUTPUT")" && pwd)
OUT_NAME=$(basename "$OUTPUT")
LIST_FILE=$(mktemp "$OUT_DIR/.stopmotion.XXXXXX")
trap 'rm -f "$LIST_FILE"' EXIT
quote_ffconcat() {
local s=$1
s=${s//\\/\\\\}
s=${s//\'/\'\\\'\'}
printf "file '%s'\n" "$s"
}
DURATION=$(awk -v f="$FPS" 'BEGIN{printf "%.6f", 1/f}')
{
echo "ffconcat version 1.0"
while IFS= read -r img; do
quote_ffconcat "$img"
printf 'duration %s\n' "$DURATION"
done <<< "$IMAGES"
} > "$LIST_FILE"
if ! ffmpeg -y -hide_banner -loglevel error -stats \
-f concat -safe 0 -i "$LIST_FILE" \
-vf "scale=${SIZE}:${SIZE}:force_original_aspect_ratio=decrease:force_divisible_by=2" \
-r "$FPS" \
-c:v libx264 -pix_fmt yuv420p -movflags +faststart \
"$OUT_DIR/$OUT_NAME"; then
rm -f "$OUT_DIR/$OUT_NAME"
echo "Erreur : l'encodage ffmpeg a échoué." >&2
exit 1
fi
DURATION_VIDEO=$(awk -v c="$COUNT" -v f="$FPS" 'BEGIN{printf "%.2f", c/f}')
SIZE_HUMAN=$(du -h "$OUT_DIR/$OUT_NAME" | cut -f1 | tr -d ' ')
echo "Vidéo créée : $OUT_NAME ($COUNT images, ${FPS} fps, ${DURATION_VIDEO} s, ${SIZE_HUMAN})"