Composition Vidéo — Assemblage, Audio, Encodage, Validation
FFmpeg est la couche de livraison, pas un outil de conception. Il doit recevoir des scènes déjà conçues et produire un master propre ainsi que des encodages spécifiques aux plateformes.
Consultez references/FFMPEG-COOKBOOK.md pour des commandes prêtes à copier et scripts/validate.sh pour une vérification avant livraison.
Règle zéro : sonder d’abord. Construire un graphe de filtres en se basant sur des propriétés de flux supposées est la cause la plus fréquente de rendu cassé.
ffprobe -v error -show_streams -show_format -of json input.mp4
1. Normaliser avant de combiner
Des entrées incompatibles provoquent saccades, silence, dérive et halos. Avant tout assemblage multi-source, faites en sorte que chaque entrée soit d’accord sur :
| Propriété | Cible |
|---|---|
| Résolution | master du projet (ex. 1920×1080) |
| Ratio d’aspect des pixels | 1:1 |
| Fréquence d’images | FPS du projet, constante |
| Base de temps | cohérente |
| Format de pixel | yuv420p pour la livraison, yuva444p10le/PNG pour l’alpha |
| Espace colorimétrique / transfert | un seul standard ; le marquer |
| Audio | 48 kHz, stéréo, codec cohérent |
ffmpeg -i in.mp4 -vf "scale=1920:1080:flags=lanczos,fps=30,setsar=1" \
-c:v libx264 -crf 14 -preset fast -pix_fmt yuv420p \
-c:a aac -ar 48000 -ac 2 -b:a 256k normalized.mp4
Maintenez les intermédiaires en haute qualité (CRF 12–16 ou ProRes). Encodez la version de livraison une seule fois.
2. Concaténation
Même codec, taille, fps, format de pixel et disposition audio → copie de flux, rapide et sans perte :
printf "file 'shot_01.mp4'\nfile 'shot_02.mp4'\n" > list.txt
ffmpeg -f concat -safe 0 -i list.txt -c copy final.mp4
Sinon → graphe de filtres :
ffmpeg -i a.mp4 -i b.mp4 -filter_complex \
"[0:v]scale=1920:1080,fps=30,setsar=1[v0]; \
[1:v]scale=1920:1080,fps=30,setsar=1[v1]; \
[v0][0:a][v1][1:a]concat=n=2:v=1:a=1[v][a]" \
-map "[v]" -map "[a]" -c:v libx264 -crf 16 -pix_fmt yuv420p -c:a aac final.mp4
Ne concaténez jamais par copie de flux des entrées non identiques. Cela « réussit » et produit une lecture cassée.
3. Incrustation, alpha et incrustation en incrusté
# élément transparent sur un fond
ffmpeg -i bg.mp4 -i logo.mov -filter_complex \
"[0:v][1:v]overlay=W-w-48:48:format=auto" -c:v libx264 -crf 16 out.mp4
# incrusté (PIP), source redimensionnée et arrondie
ffmpeg -i main.mp4 -i insert.mp4 -filter_complex \
"[1:v]scale=640:-2[pip];[0:v][pip]overlay=W-w-40:H-h-40" out.mp4
Règles pour l’alpha :
- H.264/MP4 ne peut pas transporter d’alpha. Utilisez une séquence PNG, ProRes 4444 ou WebM/VP9 avec alpha.
- Vérifiez l’alpha sur un fond contrasté après chaque étape.
- Surveillez les halos d’alpha prémultiplié ou non sur les bords sombres ; respectez la convention du moteur de rendu source.
4. Audio
# fond musical avec fondu d’entrée/sortie et ducking sous la voix
ffmpeg -i video.mp4 -i music.mp3 -i voice.wav -filter_complex \
"[1:a]volume=0.35,afade=t=in:st=0:d=1,afade=t=out:st=28:d=2[bed]; \
[2:a]volume=1.0[vo]; \
[bed][vo]sidechaincompress=threshold=0.08:ratio=6:attack=8:release=250[duck]; \
[duck][vo]amix=inputs=2:duration=first:dropout_transition=0[a]" \
-map 0:v -map "[a]" -c:v copy -c:a aac -b:a 192k out.mp4
# mesurer la loudness, puis normaliser
ffmpeg -i in.mp4 -af loudnorm=I=-14:TP=-1:LRA=11:print_format=json -f null -
ffmpeg -i in.mp4 -af loudnorm=I=-14:TP=-1:LRA=11 -c:v copy out.mp4
Les cibles varient selon la destination (-14 LUFS pour de nombreuses plateformes web, -23/-24 pour la diffusion). Mesurez, puis choisissez. Évitez de normaliser un fichier déjà dans la cible.
5. Sous‑titres
# incrustés (hard subs)
ffmpeg -i in.mp4 -vf "subtitles=captions.srt:force_style='FontName=Inter,FontSize=22,PrimaryColour=&H00FFFFFF,OutlineColour=&H80000000,BorderStyle=3,Outline=1,Shadow=0'" \
-c:v libx264 -crf 18 -c:a copy out.mp4
# sous‑titres logiciels (piste déplaçable)
ffmpeg -i in.mp4 -i captions.srt -c copy -c:s mov_text -metadata:s:s:0 language=eng out.mp4
Vérifiez les langues RTL : utilisez force_style avec une police compatible shaping, le bon Alignment, et inspectez une image rendue. Gardez les légendes dans les zones de sécurité et au‑dessus de l’interface de la plateforme.
6. Encodages spécifiques aux plateformes
# YouTube paysage, 1080p30
ffmpeg -i master.mov -c:v libx264 -preset slow -crf 18 -pix_fmt yuv420p \
-profile:v high -level 4.1 -movflags +faststart \
-c:a aac -b:a 192k -ar 48000 out_1080p.mp4
# vertical réseaux sociaux, 1080x1920
ffmpeg -i master.mov -vf "scale=1080:1920:force_original_aspect_ratio=increase,crop=1080:1920" \
-c:v libx264 -preset slow -crf 18 -pix_fmt yuv420p -movflags +faststart \
-c:a aac -b:a 192k out_vertical.mp4
# intermédiaire haute qualité pour composition ultérieure
ffmpeg -i master.mov -c:v prores_ks -profile:v 3 -pix_fmt yuv422p10le -c:a pcm_s24le master.mov
Vérifiez que l’encodeur existe : ffmpeg -encoders | grep -E "libx264|prores|nvenc". Les encodeurs matériels sont rapides mais souvent de moins bonne qualité par débit ; comparez avant de livrer.
7. Images, planches contact, GIF
# images à des instants donnés
ffmpeg -ss 00:00:03.5 -i in.mp4 -frames:v 1 frame.png
# planche contact
ffmpeg -i in.mp4 -vf "fps=1,scale=320:-1,tile=4x4" -frames:v 1 sheet.jpg
# GIF haute qualité (palettegen/paletteuse)
ffmpeg -i in.mp4 -vf "fps=15,scale=640:-1:flags=lanczos,palettegen" palette.png
ffmpeg -i in.mp4 -i palette.png -lavfi "fps=15,scale=640:-1:flags=lanczos[x];[x][1:v]paletteuse" out.gif
8. Validation (à ne pas sauter)
ffprobe -v error \
-show_entries format=duration,size,bit_rate,format_name \
-show_entries stream=index,codec_type,codec_name,width,height,r_frame_rate,avg_frame_rate,pix_fmt,channels,sample_rate,nb_frames \
-of json final.mp4
Vérifications automatisées :
# segments noirs (images noires accidentelles)
ffmpeg -i final.mp4 -vf "blackdetect=d=0.1:pix_th=0.05" -an -f null - 2>&1 | grep blackdetect || true
# segments figés (arrêt trop long)
ffmpeg -i final.mp4 -vf "freezedetect=n=0.003:d=2" -an -f null - 2>&1 | grep freeze || true
# présence audio et niveau de crête
ffmpeg -i final.mp4 -af volumedetect -f null - 2>&1 | grep -E "mean_volume|max_volume"
Inspectez ensuite la première image, la dernière, chaque transition et les images contenant du texte. Les chiffres prouvent que le fichier est bien formé ; ils ne prouvent pas qu’il a l’air correct.
9. Pièges de la précision à l’image
- Sources VFR (captures d’écran, téléphones) dérivent par rapport à une timeline CFR. Normalisez avec
fps=30et vérifiez la durée. - Décalage d’une image : N images à 30 fps dure exactement N/30 secondes ; un rendu de 300 images dure 10,0 s. Si la durée est de 9,97 s, une image a été perdue.
- Audio tronqué plus court que la vidéo → silence à la fin ; ajoutez du silence ou coupez délibérément.
- Vidéo de téléphone tournée contient une matrice d’affichage ;
-noautorotateseulement si vous voulez vraiment ignorer cette rotation. - Décalage de couleur après encodage : vérifiez les balises
color_primaries/transfer; un aperçu dans un navigateur n’est pas une référence fiable. - Encodages répétés dégradent la qualité ; conservez un master haute qualité et encodez à partir de lui.
10. Paquet de livraison
output/
final_1080p.mp4 # principal
final_vertical.mp4 # variante plateforme, si demandée
final_master.mov # ProRes/H.264 CRF 14, conservé pour futurs encodages
thumbnail.png # 1280x720 ou 1080x1920
contact-sheet.jpg
captions.srt
project-report.md # versions des outils, paramètres, vérifications effectuées
Rapportez les propriétés exactes de ffprobe ; ne les devinez jamais.