video-dubbing : Doublage vidéo, traduction et synchronisation des sous-titres
Objectif
Localiser entièrement une vidéo dans une autre langue : reconnaître la parole originale, la traduire, générer un doublage dans la langue cible via TTS, tout en conservant les timestamps d'origine, puis mixer la piste audio et incruster les sous-titres traduits directement dans l'image. Le résultat est un fichier vidéo unique prêt à être publié, où le doublage et les sous-titres sont naturellement synchronisés, sans besoin de ré-étalonnage.
Quand l'utiliser
- L'utilisateur demande de traduire une vidéo dans une autre langue avec doublage (pas seulement des sous-titres).
- Besoin d'ajouter un doublage dans la langue cible + des sous-titres synchronisés (bilingues ou traduction seule).
- Mots-clés : traduction vidéo, doublage vidéo, sous-titres traduits, doublage en langue étrangère, sous-titres bilingues, dub a video, translate a video, foreign-language voiceover.
- Tout flux de travail ASR -> traduction -> TTS -> composition vidéo.
Quand NE PAS l'utiliser
- Seulement une transcription, sans traduction ni doublage -> utiliser
video-minutesou Whisper directement. - Seulement une synthèse vocale à partir de texte, sans vidéo -> utiliser
mlx-tts. - Besoin de conserver la musique de fond / les effets sonores et de faire un mixage professionnel (séparation des voix) -> cette compétence ne fait pas de Demucs par défaut, nécessite un traitement séparé.
- Vidéo sans piste audio ou qualité audio trop mauvaise pour être reconnue.
Flux de travail
De bout en bout, la méthode recommandée est d'utiliser le script d'orchestration <skill>/scripts/dub.py (voir ## Scripts), qui exécute automatiquement les étapes suivantes et s'arrête à la traduction pour attendre l'IA. En exécution manuelle, suivez ces étapes :
-
Extraction audio (16 kHz mono) :
ffmpeg -y -i input.mp4 -ar 16000 -ac 1 -c:a pcm_s16le audio16k.wav -
Transcription ASR (avec timestamps précis par segment) :
whisper audio16k.wav --model large-v3-turbo --language <langue_source> --output_format srt --output_dir .Produitaudio16k.srt, les timestamps sont naturellement alignés avec la vidéo originale. Pour une meilleure reconnaissance du chinois, on peut utiliser Qwen3-ASR (pip install qwen-asr) avec<skill>/scripts/qwen3_asr.py. -
Traduction des sous-titres (par l'IA) : lire le SRT, traduire segment par segment. Chaque segment SRT donne une ligne de traduction, en respectant strictement l'ordre. Compter d'abord le nombre de segments (ex. 27 segments -> 27 lignes), sauvegarder dans
translated.txt, vérifier la correspondance du nombre de lignes avant de continuer. -
Génération du doublage :
python3 <skill>/scripts/dub_segments.py audio16k.srt translated.txt dubbing.wav subtitle_synced.srt --lang <langue_cible>Le script : utilise le premier segment comme référence de timbre pour garantir un timbre cohérent ; conserve les timestamps d'origine pour synchroniser sous-titres et image ; applique un changement de vitesse (atempo 0.88–1.20) uniquement aux segments qui dépassent le créneau ; relie les intervalles de moins de 1 seconde pour un rendu naturel. -
Fusion de la piste de doublage avec la vidéo :
ffmpeg -y -i input.mp4 -i dubbing.wav \ -map 0:v:0 -map 1:a:0 \ -c:v copy -c:a aac -b:a 192k -shortest output_temp.mp4Puis vérifier que la piste audio a bien été remplacée :
ffprobe -v error -show_entries stream=codec_type -of csv=p=0 output_temp.mp4(doit affichervideo, audio). -
Incrustation des sous-titres durs :
python3 <skill>/scripts/burn_subtitles.py output_temp.mp4 subtitle_synced.srt output_final.mp4Rend les sous-titres traduits en permanence dans l'image. -
Nettoyage (optionnel) : supprimer
audio16k.wav,audio16k.srt,translated.txt,dubbing.wav,subtitle_synced.srt,output_temp.mp4, etc.
Règles de décision
- Pour une exécution en un clic -> utiliser
dub.py; pour ne refaire qu'une étape (ex. SRT déjà existant) ->dub.py --srt existing.srtsaute l'étape. - Moteur ASR : par défaut
--asr whisper(large-v3-turbo) ; si reconnaissance chinoise exigeante ->--asr qwen3. - Pas besoin de sous-titres durs ->
dub.py --no-burn(s'arrête après la fusion audio). - La langue cible est définie par
--target-lang(défautzh) ; la langue TTS dedub_segments.pyest définie par--lang. - La traduction doit être faite par l'IA et strictement 1:1 avec les segments SRT ; si le nombre de lignes ne correspond pas, le script échoue immédiatement ; ne pas contourner.
- Si les sous-titres n'apparaissent pas ou que le chinois devient des carrés -> utiliser
burn_subtitles.py(rendu avec moviepy, détection automatique de la police chinoise) ; ne pas dépendre desubtitles=de ffmpeg (qui échoue silencieusement si libass manque). - Si la durée du doublage dépasse le créneau -> s'appuyer sur l'atempo segmenté du script, ne pas appliquer de changement de vitesse global sur toute la piste.
Contraintes
- Les timestamps doivent réutiliser les résultats ASR originaux, interdiction de refaire un ASR sur le doublage pour obtenir les timestamps.
- Le nombre de lignes de traduction doit être égal au nombre de segments SRT (1:1), sinon arrêt.
- La fusion audio doit explicitement utiliser
-map 0:v:0 -map 1:a:0, sinon la piste audio originale est conservée. - L'ASR doit utiliser
large-v3-turbo(outurbo), ne pas revenir àbase/tiny. - Le changement de vitesse se fait uniquement au niveau des segments, dans la plage 0.88–1.20x ; interdiction de l'atempo global.
- Par défaut, pas de séparation des voix de la musique de fond ; si l'utilisateur le demande, il faut explicitement indiquer qu'un traitement supplémentaire est nécessaire.
Vérification
Avant la livraison, vérifier chaque point :
- Le nombre de lignes dans
translated.txtcorrespond exactement au nombre de segments SRT. -
dubbing.wavetsubtitle_synced.srtont été générés. -
ffprobemontre que la vidéo finale contient à la fois un flux vidéo et un flux audio, et que l'audio a bien été remplacé. - Les sous-titres sont bien incrustés dans l'image (pas de sous-titres externes mous), le chinois n'a pas de carrés.
- Le doublage et l'image sont synchronisés à plusieurs points aléatoires vérifiés.
- Les fichiers sources fournis par l'utilisateur n'ont pas été supprimés.
Résultat
- Sortie : un fichier vidéo localisé (par défaut
output_final.mp4, avecdub.pyil s'agit de<nom_de_la_video>_<langue_cible>.mp4), contenant le doublage et les sous-titres durs dans la langue cible ;subtitle_synced.srtpeut être conservé en option. - Terminé quand : la piste audio a été remplacée, les sous-titres incrustés, l'audio et l'image synchronisés aux points de vérification, et ffprobe valide.
- Preuve : chemin du fichier final ; nombre de segments SRT et nombre de lignes de traduction ; liste des flux ffprobe ; points de synchronisation vérifiés.
Références
Charger à la demande, ne pas tout lire à l'avance :
references/pipeline-design.md— à lire lorsqu'il faut expliquer ou ajuster le comportement du pipeline (pourquoi conserver les timestamps, changement de vitesse segmenté, pas de séparation des voix par défaut, liste des artefacts et dépendances).references/troubleshooting.md— à lire en cas d'erreur réelle, de désynchronisation audio/vidéo, de sous-titres absents ou de carrés chinois.
Scripts
<skill>/scripts/dub.py— orchestration de bout en bout. Utilisation :python3 <skill>/scripts/dub.py input.mp4 --source-lang en --target-lang zh [--asr whisper|qwen3] [--srt existing.srt] [-o out.mp4] [--font-size 28] [--no-burn] [--keep-temp]. Lors de l'étape de traduction, il génèreto_translate.txtet demande à l'IA de produiretranslated.txt, puis continue ; il retourne le chemin de la vidéo finale et celui des sous-titres.<skill>/scripts/dub_segments.py— TTS segmenté + alignement des timestamps. Utilisation :python3 <skill>/scripts/dub_segments.py original.srt translated.txt out_dub.wav out_synced.srt [--lang zh] [--min-atempo 0.88] [--max-atempo 1.20] [--gap-bridge 1.0] [--keep-temp]. Retournedubbing.wavetsubtitle_synced.srtalignés ; si le nombre de lignes de traduction ne correspond pas, il s'arrête avec le code de sortie 1.<skill>/scripts/burn_subtitles.py— incrustation des sous-titres durs avec moviepy. Utilisation :python3 <skill>/scripts/burn_subtitles.py input.mp4 subtitles.srt output.mp4 [--font <chemin>] [--font-size 28]. Retourne la vidéo avec sous-titres incrustés ; si--fontest omis, détection automatique de la police chinoise.<skill>/scripts/qwen3_asr.py— CLI Qwen3-ASR compatible avec Whisper, meilleure reconnaissance du chinois. Utilisation :python3 <skill>/scripts/qwen3_asr.py audio.wav [--model 0.6B|1.7B] [--language zh] [-f srt|vtt|txt|json|tsv|all] [-o répertoire_sortie] [--device cuda:0|mps|cpu] [--dtype float16|bfloat16|float32]. Retourne les fichiers de sous-titres/texte dans le format spécifié. Alias de modèles :turbo/tiny/base/small -> Qwen3-ASR-0.6B,medium/large -> Qwen3-ASR-1.7B.
Dépannage
- Le doublage n'est pas remplacé / le son original est toujours présent -> la fusion ffmpeg a oublié
-map 0:v:0 -map 1:a:0. - Les sous-titres n'apparaissent pas ou le chinois devient des carrés -> utiliser
burn_subtitles.pyavec--fontpour spécifier une police chinoise. - Le nombre de lignes de traduction ne correspond pas au nombre de segments SRT -> le script échoue et s'arrête ; compléter d'abord pour obtenir un ratio 1:1.
- Liste complète des erreurs dans
references/troubleshooting.md.
Compétences associées
mlx-tts— fournit la fonction sous-jacentemlx_audio.tts.generate, dont dépend cette compétence pour le doublage.video-minutes— transformation d'une vidéo en résumé structuré ; à utiliser en remplacement si seule la transcription/résumé est nécessaire.