Automatiser les aperçus GIF animés en ligne de commande
Pour un répertoire de vidéos, générez un court GIF pour chaque fichier en conservant son chemin
relatif dans le répertoire de sortie. Le script Bash ci-dessous crée un aperçu des trois premières
secondes à 10 fps, préserve les fichiers existants et renvoie un statut d’échec si une conversion
échoue. Deux vidéos nommées demo.mp4 dans des dossiers différents obtiennent
des aperçus distincts.
Installer les outils Linux
Utilisez Bash, GNU findutils et coreutils, ainsi que FFmpeg avec ffprobe. Les
exemples ciblent Linux et un système de fichiers sensible à la casse qui prend en charge les liens
physiques ; macOS natif et PowerShell sortent du périmètre testé de ce guide. Utilisez des vidéos
SDR ordinaires à pixels carrés. Le mappage tonal HDR et la correction des vidéos anamorphiques
nécessitent une configuration de filtres distincte.
Ces exemples ont été testés avec FFmpeg 6.1.1 sous Ubuntu 24.04 et FFmpeg n9.0.1 sous Linux.
Sous Ubuntu ou Debian, installez les outils avec :
sudo apt-get update && sudo apt-get install ffmpeg bash findutils coreutils
Le paquet FFmpeg d’Ubuntu inclut les outils multimédias. Vérifiez les versions disponibles dans votre shell :
bash --version
ffmpeg -version
ffprobe -version
Choisir le GIF lorsque la destination l’exige
Le GIF est utile pour une illustration en boucle dans une documentation ou pour un système qui accepte les images mais ne peut pas intégrer de vidéo. Sa palette est limitée et il ne contient pas de son. Un GIF peut être beaucoup plus volumineux que sa source MP4 ; comparez donc les fichiers réels avant de l’utiliser pour des aperçus web. Si votre destination prend en charge la vidéo, conserver un court extrait vidéo peut offrir une meilleure qualité pour une taille moindre. La comparaison entre GIF et vidéo de Google illustre l’écart de taille potentiel.
Créer un aperçu de durée limitée
Placez une vidéo nommée input.mp4 dans votre répertoire de travail, puis
exécutez :
(
if [[ -e ./preview.gif || -L ./preview.gif ]]; then
printf 'Refusing existing output: ./preview.gif\n' >&2
exit 1
fi
ffmpeg -hide_banner -loglevel error -nostdin -n -xerror -abort_on empty_output \
-t 3 -i ./input.mp4 -map 0:v:0 \
-vf "fps=10,scale='min(320,iw)':-1:flags=lanczos,split[a][b];[a]palettegen[p];[b][p]paletteuse" \
-t 3 -frames:v 30 -loop 0 -f gif ./preview.gif
)
Cette commande sélectionne le premier flux vidéo, limite la largeur à 320 pixels sans agrandir les
entrées plus petites, et crée un GIF en boucle infinie. L’option -t 3
placée côté entrée limite le segment transmis aux filtres ; la durée de sortie et le plafond
d’images limitent l’aperçu à trois secondes et 30 images au maximum. Les entrées courtes
produisent des aperçus plus courts. Consultez les
règles des options d’entrée et de sortie de FFmpeg.
Le filtre split envoie les images mises à l’échelle à la fois vers palettegen
et paletteuse : l’un construit une palette à partir de l’extrait, l’autre
l’applique. Limiter l’entrée est important, car générer une palette pour toute la vidéo retarderait
la sortie et augmenterait la mise en mémoire tampon. La
documentation des filtres de palette décrit les réglages de couleur
et de tramage disponibles.
La vérification du shell signale un preview.gif existant comme un échec ;
-n indique également à FFmpeg de ne pas l’écraser. Certaines versions de
FFmpeg peuvent renvoyer zéro lorsqu’elles refusent d’écraser un fichier ; leur statut seul ne suffit
donc pas ici. -nostdin désactive la saisie interactive. Si la conversion
échoue après la création du fichier, elle peut laisser un GIF incomplet. Le script de traitement par
lots ci-dessous évite de publier une sortie partielle en convertissant d’abord vers un fichier
temporaire.
Inspectez un résultat réussi avec :
ffprobe -v error -select_streams v:0 -count_frames \
-show_entries stream=width,height,nb_read_frames:format=duration,size \
-of json ./preview.gif
Pour une entrée d’au moins trois secondes, attendez-vous à 30 images et à une durée de
3.000000 secondes. Ouvrez aussi le GIF : les métadonnées ne vous disent pas si
la scène d’ouverture choisie est utile.
Traiter le répertoire par lots sans perdre les noms de fichiers
Enregistrez ce script complet sous gif-previews.sh. Il traite récursivement les
fichiers réguliers se terminant par .mp4, sans tenir compte de la casse et
sans suivre les entrées de type lien symbolique. Il ajoute .gif au nom de
fichier relatif complet : videos/team/demo.mp4 devient gifs/team/demo.mp4.gif.
Conserver l’extension permet aussi de distinguer demo.mp4 de
demo.MP4 sur le système de fichiers pris en charge.
#!/usr/bin/env bash
set -euo pipefail
if (( $# > 2 )); then
printf 'Usage: bash gif-previews.sh [video-directory] [output-directory]\n' >&2
exit 1
fi
VIDEO_DIR=${1:-./videos}
OUTPUT_DIR=${2:-./gifs}
command -v ffmpeg >/dev/null
# Resolve both directory arguments from the caller's working directory.
start_dir=$PWD
cd -P -- "$VIDEO_DIR"
VIDEO_DIR=$PWD
cd -P -- "$start_dir"
mkdir -p -- "$OUTPUT_DIR"
cd -P -- "$OUTPUT_DIR"
OUTPUT_DIR=$PWD
cd -P -- "$VIDEO_DIR"
work=$(mktemp -d -- "$OUTPUT_DIR/.gif-preview.XXXXXX")
trap 'rm -rf -- "$work"' EXIT
trap 'exit 130' INT
trap 'exit 143' TERM
# Finish discovery first so a failed find cannot look like an empty successful batch.
find . -type f -iname '*.mp4' -print0 > "$work/files"
if [[ ! -s "$work/files" ]]; then
printf 'No MP4 files found.\n' >&2
exit 1
fi
generated=0
failed=0
while IFS= read -r -d '' video; do
output="$OUTPUT_DIR/${video#./}.gif"
if [[ -e "$output" || -L "$output" ]]; then
printf 'Refusing existing output: %q\n' "$output" >&2
failed=$((failed + 1))
continue
fi
if mkdir -p -- "${output%/*}" &&
ffmpeg -hide_banner -loglevel error -nostdin -y -xerror -abort_on empty_output \
-t 3 -i "$video" -map 0:v:0 \
-vf "fps=10,scale='min(320,iw)':-1:flags=lanczos,split[a][b];[a]palettegen[p];[b][p]paletteuse" \
-t 3 -frames:v 30 -loop 0 -f gif "$work/preview.gif" &&
ln -T -- "$work/preview.gif" "$output"; then
printf 'Generated: %q\n' "$output"
generated=$((generated + 1))
else
printf 'Failed: %q\n' "$video" >&2
failed=$((failed + 1))
fi
# Unlink the temporary name before reuse: published files share its inode.
rm -f -- "$work/preview.gif"
done < "$work/files"
printf 'Generated: %d; failed: %d\n' "$generated" "$failed"
if (( failed > 0 )); then
exit 1
fi
Exécutez-le depuis le répertoire qui contient votre dossier videos :
bash gif-previews.sh ./videos ./gifs
Le script préserve les espaces, les sauts de ligne, les tirets initiaux et les signes de
pourcentage littéraux dans les noms de fichiers. La découverte délimitée par des caractères nuls
préserve l’intégrité de chaque nom de fichier, et FFmpeg ne peut pas consommer l’entrée de la boucle
grâce à -nostdin. La découverte comme la conversion s’exécutent depuis le même
répertoire d’entrée résolu physiquement, y compris lorsque l’argument de répertoire contient un lien
symbolique suivi de ...
Les destinations existantes comptent comme des échecs ; elles ne sont jamais ignorées ni remplacées
silencieusement. La conversion utilise -y uniquement pour le fichier
temporaire privé. La commande GNU ln -T publie un GIF terminé sans
remplacer une destination apparue pendant la conversion. Le répertoire temporaire se trouve sur le
système de fichiers de sortie afin que les liens physiques puissent fonctionner. Utilisez une
arborescence de sortie que vous contrôlez, sans sous-répertoires liés symboliquement ni points de
montage imbriqués.
Un lot aux résultats mixtes conserve ses GIF réussis et continue après les échecs individuels, puis
se termine avec le statut 1. Un répertoire d’entrée vide se termine aussi avec le statut 1. Une
nouvelle exécution sur la même arborescence de sortie signale les fichiers existants comme des
échecs ; choisissez un nouveau répertoire de sortie pour régénérer tout le lot. Les échecs ordinaires
et les interruptions nettoient les fichiers temporaires, mais un arrêt forcé ou une coupure de
courant peut laisser un répertoire caché .gif-preview.*.
Ajuster le budget de taille et de qualité
Commencez avec les réglages de trois secondes, 320 pixels et 10 fps, puis inspectez des
extraits représentatifs. Des dimensions plus petites suppriment des détails ; une fréquence d’images
plus basse rend le mouvement moins fluide. Raccourcir l’extrait permet souvent d’économiser davantage
que d’ajuster les couleurs. Si vous modifiez la fréquence ou la durée, mettez à jour ensemble les
deux valeurs -t et le plafond -frames:v ; pour deux
secondes à 8 fps, utilisez un plafond de 16.
Le tramage paletteuse par défaut aide pour les dégradés, mais peut ajouter un
bruit visible. Son réglage documenté dither=bayer mérite d’être comparé sur vos
propres séquences. Ces réglages sacrifient détails, fluidité du mouvement et fidélité des couleurs
au profit de la taille ; aucun ne promet que le GIF battra un codec vidéo.
Diagnostiquer un lot en échec
- Sortie existante : choisissez un nouveau répertoire de sortie, ou supprimez délibérément uniquement les aperçus que vous voulez régénérer. Modifier les réglages de qualité n’écrase pas les anciens résultats.
- Vidéo invalide ou absence de flux vidéo : inspectez la source indiquée avec
ffprobe. Renommer un fichier corrompu en.mp4ne le répare pas. Le script vérifie le segment d’aperçu, pas l’état de la vidéo entière. - Aucune image ou ouverture peu utile : des entrées très courtes ou inhabituelles peuvent ne produire aucun aperçu ; le script traite une sortie vide comme un échec. Une ouverture noire nécessite un autre segment.
- Erreurs de système de fichiers ou de mémoire : vérifiez l’espace libre, les permissions de la sortie et la prise en charge des liens physiques. Réduisez la longueur du segment et les dimensions pour les sources volumineuses. Une limite de trois secondes pour l’extrait n’est pas une limite stricte de la mémoire du décodeur ni du temps d’exécution.
Utilisez les chemins de fichiers affichés pour examiner les échecs, puis vérifiez les GIF réussis avant de les ajouter à votre catalogue multimédia.
