moviepy (Composition vidéo Python)
Idéal pour les vidéos courtes et scriptées, et pour placer du texte exact sur des séquences. Pour les vidéos longues, lourdes en design et réutilisables, préférez Remotion.
| Utilisez moviepy quand | Utilisez Remotion quand |
|---|---|
| Le projet est un script Python unique | Vous avez besoin de composants React et d'un système de design |
| Superposition de texte sur des clips existants ou générés par IA | Animations graphiques et diagrammes complexes |
| Éditions par lots sur plusieurs fichiers | L'aperçu avec rechargement à chaud est important |
| Aucune chaîne d'outils Node disponible | Vidéos longues et modélisées |
Configuration
pip install "moviepy>=2" pillow
# ou : uv add moviepy pillow
Cette compétence cible moviepy 2.x. Son API diffère de la 1.x : les importations viennent directement de moviepy, et les méthodes sont with_*/subclipped/resized, pas set_*/subclip/resize.
Bases
from moviepy import (VideoFileClip, AudioFileClip, ImageClip, TextClip,
CompositeVideoClip, CompositeAudioClip, concatenate_videoclips, vfx, afx)
clip = VideoFileClip("in.mp4").subclipped(5, 20) # extrait de 15 s
clip = clip.resized(height=1080) # conserve les proportions
clip = clip.with_effects([vfx.FadeIn(0.5), vfx.FadeOut(0.5)])
joined = concatenate_videoclips([clip, VideoFileClip("b.mp4")], method="compose")
joined.write_videofile("out/result.mp4", fps=30, codec="libx264", audio_codec="aac")
Appelez toujours .close() sur les clips dans les scripts longs, ou utilisez-les dans un bloc with, pour libérer les descripteurs de fichier.
Superposition de texte (texte déterministe sur séquence)
title = (TextClip(font="C:/Windows/Fonts/arial.ttf", # un chemin de fichier de police réel
text="Dr. Jane Doe\nChief Scientist",
font_size=56, color="white",
stroke_color="black", stroke_width=2,
method="caption", size=(900, None))
.with_start(1.0).with_duration(4.0)
.with_position(("left", 860))
.with_effects([vfx.CrossFadeIn(0.3), vfx.CrossFadeOut(0.3)]))
final = CompositeVideoClip([clip, title])
Remarques :
TextClipa besoin d'un chemin de fichier de police (TTF/OTF). Incluez la police de la marque dans le projet.- Les temps des clips sont en secondes, relatifs au début du composite.
- Pour un texte fortement stylisé (pilules arrondies, dégradés), générez un PNG avec Pillow et utilisez
ImageClip. - Gardez le texte dans la zone de sécurité : au moins 5 % de chaque bord.
Audio
voice = AudioFileClip("voiceover.mp3")
music = AudioFileClip("music.mp3").with_effects([afx.MultiplyVolume(0.12), afx.AudioFadeOut(2)])
music = music.with_duration(voice.duration + 1)
final = clip.with_audio(CompositeAudioClip([music, voice.with_start(0.5)]))
Laissez la voix off déterminer la chronologie : définissez la durée du clip sur voice.duration + padding, pas l'inverse.
Motif ancré à l'audio
scenes = [("scene1.mp3", "intro.png"), ("scene2.mp3", "chart.png")]
parts = []
for audio_path, image_path in scenes:
a = AudioFileClip(audio_path)
v = ImageClip(image_path).with_duration(a.duration + 0.6).with_audio(a)
parts.append(v)
concatenate_videoclips(parts).write_videofile("out/explainer.mp4", fps=30)
Effet Ken Burns sur images fixes
img = ImageClip("photo.jpg").with_duration(6)
img = img.resized(lambda t: 1.0 + 0.04 * t).with_position("center")
CompositeVideoClip([img], size=(1920, 1080)).write_videofile("out/kb.mp4", fps=30)
Performance
- Prévisualisez avec
fps=12etpreset="ultrafast"; effectuez le rendu final à 30 ips. write_videofile(..., threads=4).- Évitez les lambdas Python par image sur les longs clips. Prétraitez avec FFmpeg si possible.
Pièges
| Problème | Cause et correctif |
|---|---|
ImportError: cannot import name 'editor' | moviepy 2 a supprimé moviepy.editor ; importez depuis moviepy |
AttributeError: set_duration | Utilisez with_duration ; idem pour with_start, with_position |
| Plantage du clip texte | Fournissez un chemin de fichier de police réel |
| Audio désynchronisé après assemblage | Assurez-vous que tous les clips partagent le même fps ; appliquez l'audio après la concaténation |
| Rendu lent | Réduisez la résolution pour les brouillons ; évitez les lambdas resized volumineuses |