Communitygithub.com

Localisation vidéo : doublage chinois à voix clonée

Remplacez la voix anglaise d'une vidéo par un doublage chinois cloné sur l'orateur d'origine, sur une timeline identique : même image, même durée, musique conservée, sous-titres bilingues incrustés, avec contrôles de longueur, relecture à froid et écoute.

Qu'est-ce que Localisation vidéo : doublage chinois à voix clonée ?

Recette Localisation vidéo, étape 3 (le doublage), issue de ChHsiching/video-dubbing-skill. Elle lit la vidéo brute et un passage de sous-titres bilingues, puis produit une seconde version sans toucher à la première. L'agent traduit pour le doublage — phrases complètes calibrées sur un budget de caractères par cue — et applique les contrôles : longueur, relecture à froid, écoute et revue après incrustation. La CLI `cook dub` fait le travail déterministe : Demucs garde la musique, IndexTTS2 clone la voix, chaque réplique est ajustée à sa fenêtre d'origine par atempo, ffmpeg incruste les sous-titres ZH+EN. Résultat : un MP4 doublé de durée identique et des SRT zh/en.

Compatible avec✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/ChHsiching/video-dubbing-skill/tree/HEAD/skills/video-dubbing

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Remplacer les voix originales anglaises d'une vidéo par un doublage chinois sur une chronologie identique : la vidéo n'est jamais ré-étalonnée — chaque image conserve son horodatage d'origine et la version doublée a exactement la durée de la vidéo brute. L'audio synthétisé de chaque réplique est inséré dans sa propre fenêtre d'origine (début de la réplique → début de la réplique suivante) avec un atempo par réplique ; une synthèse plus rapide ou plus lente aboutit toutes deux dans la fenêtre. Le résultat est une deuxième version — même image à la même vitesse, audio chinois, sous-titres bilingues ZH+EN incrustés.

Cette compétence effectue les deux parties créatives que la CLI ne peut pas faire : traduire pour le doublage (phrases complètes écrites dans un budget de caractères, pas la fragmentation des sous-titres) et exécuter les contrôles de qualité (vérification de longueur, relecture à froid, vérification auditive, vérification post-incrustation). L'exécution déterministe (Demucs, IndexTTS2, assemblage, réétalonnage, ffmpeg) est gérée par la sous-commande cook dub de la CLI cook. Tous les scripts d'étape vivent dans le paquet cook (stages/dub/) ; chaque invocation ci-dessous est une commande cook. pip install -U video-cook met tout à jour en une seule fois.

Quand utiliser cette compétence

Vous avez une vidéo qui possède déjà :

  • Un fichier vidéo brut (<output-root>/raw/<name>.raw.mp4) — l'original, avec des voix anglaises.
  • Une exécution de sous-titres bilingues de video-subtitle — spécifiquement transcript/<name>.en.full.srt (la transcription anglaise en phrases complètes, fusionnée à partir des fragments whisperX) et transcript/translations.txt.

Vous voulez une version doublée en chinois. Si vous ne les avez pas encore, exécutez d'abord video-download puis video-subtitle — cette compétence lit leurs sorties.

Ce que vous produisez

Trois produits sont livrés : cooked/<name>.dubbed.mp4 (vidéo brute inchangée, doublage chinois, sous-titres bilingues incrustés — durée identique à la brute), cloud-srt/zh.dub.srt + en.dub.srt (sous-titres de téléchargement). Tout le reste sont des fichiers de travail sous dubbed/ — l'arborescence annotée ci-dessous les cartographie tous.

L'exécution n'est pas terminée tant que les vérifications de l'étape 6 ne sont pas passées.

Disposition des répertoires

Cette compétence ajoute dubbed/ (répertoire de travail) et écrit les produits finaux dans cooked/ et cloud-srt/ :

<output-root>/
├── raw/                            ← de video-download (cette compétence le lit)
│   └── <name>.raw.mp4
├── transcript/                     ← de video-subtitle (cette compétence lit + ajoute)
│   ├── <name>.en.full.srt          ← anglais en phrases complètes (source du script de doublage)
│   ├── translations_dub.txt        ← cette compétence écrit : une ligne chinoise par réplique
│   └── <name>.zh.dub.srt           ← cette compétence écrit
├── cooked/                         ← les vidéos finales vivent ici
│   ├── <name>.cooked.bar.mp4       ← de video-subtitle (inchangé)
│   └── <name>.dubbed.mp4           ← produit de cette compétence
├── cloud-srt/                      ← les sous-titres de téléchargement vivent ici
│   ├── zh.srt / en.srt             ← de video-subtitle (inchangé)
│   └── zh.dub.srt / en.dub.srt     ← sous-titres de téléchargement de cette compétence
└── dubbed/                         ← répertoire de travail de cette compétence
    ├── _reference/
    │   └── ref.wav
    └── _full/
        ├── _segments/              ← cache IndexTTS2 par réplique
        ├── dub.wav                 ← le doublage sur l'horloge d'origine
        ├── dubbing.srt             ← fichier de travail (ZH, avant raccourcissement)
        ├── dubbing.short.srt       ← fichier de travail (ZH, sortie raccourcie)
        ├── dubbing.merged.srt      ← fichier de travail (ZH, après raccourcissement ; copié vers cloud-srt)
        ├── dubbing.en.srt          ← fichier de travail (EN en phrases complètes)
        ├── dubbing.en.short.srt / dubbing.en.merged.srt  ← ses sorties de raccourcissement et fusion
        ├── dubbing.bilingual.srt   ← fichier de travail (union bilingue ; ce qui est incrusté)
        ├── dubbing.cooked.ass     ← fichier de travail (sortie ass, copiée vers burn.ass)
        └── burn.ass                ← le ASS réellement incrusté

Règle : dubbed/ est le répertoire de travail ; cooked/<name>.dubbed.mp4 et cloud-srt/{zh,en}.dub.srt sont les produits. Ne touchez jamais à raw/, transcript/<name>.zh.srt, cooked/<name>.cooked.mp4, ou cloud-srt/{zh,en}.srt — ceux-ci appartiennent à video-subtitle. Si cette compétence échoue à mi-chemin, la livraison bilingue cuite est toujours complète.

Le pipeline

Deux étapes après le travail créatif : synth puis assemble, invoquées via cook :

cook dub synth    <root> <name> --python <indextts-venv>/Scripts/python.exe
cook dub assemble <root> <name> --python <indextts-venv>/Scripts/python.exe [--keep-subs]
# ou les deux :
cook dub full <root> <name> --python <indextts-venv>/Scripts/python.exe

Les étapes ci-dessous décrivent ce que chaque étape fait en interne (afin que vous puissiez vérifier les sorties et diagnostiquer les échecs) ; les commandes cook dub <stage> sont la façon de les exécuter.

Étape 0 — Résoudre les environnements

Il y a deux environnements Python en jeu, et les confondre est le mode d'échec que cette étape vise à éviter :

  • L'environnement de cook (Python système ou ~/.venvs/video-tools/) — où la CLI cook réside, avec whisperX/yt-dlp/torch pour le pipeline de sous-titres.
  • L'environnement d'IndexTTS2 (~/Git/index-tts/.venv) — un venv séparé contenant indextts, torch, demucs, et whisperx (le pipeline de doublage ajoute les deux derniers par-dessus le fichier de verrouillage en amont). Ces dépendances sont lourdes et isolées intentionnellement ; n'essayez pas de les installer dans l'environnement de cook.

cook exécute chaque étape de doublage comme un sous-processus sous le venv IndexTTS2 via --python, donc from indextts import ... s'y résout. Chaque commande cook dub dans cette compétence prend --python <indextts-venv>/Scripts/python.exe. Résolvez le chemin du venv une fois (par défaut ~/Git/index-tts/.venv) et réutilisez-le pour toute l'exécution.

0a. Vérifiez que les deux environnements sont accessibles :

<cook-venv>/Scripts/cook doctor                                    # whisperX/yt-dlp/ffmpeg
<indextts-venv>/Scripts/python -c "from indextts.infer_v2_5 import IndexTTS2; import demucs, whisperx; print('ok')"   # indextts (v2.5) + demucs + whisperx

0b. Contrainte mono-thread. IndexTTS2 doit s'exécuter en mono-thread (OMP_NUM_THREADS=1), sinon il produit un audio de mauvaise qualité. cook définit cela en interne avant d'importer torch, donc vous n'avez pas besoin de l'exporter vous-même.

Terminé lorsque le doctor de cook signale que whisperX/yt-dlp/ffmpeg sont installés, que le venv IndexTTS2 importe indextts (v2.5) + demucs + whisperx, et que vous connaissez le chemin absolu vers <indextts-venv>/Scripts/python.exe à passer comme --python.

Étape 1 — Séparer les voix de la vidéo brute

L'audio original est une piste mixte (voix + BGM + SFX). Demucs le sépare afin que nous puissions extraire une référence propre et vérifier le BGM plus tard.

cook dub separate <output-root> <name> [--model htdemucs] --python <indextts-venv>/Scripts/python.exe

Demucs vit dans le venv IndexTTS2, donc --python pointe là-bas. Utilisez htdemucs (modèle unique, ~3GB de RAM), pas htdemucs_ft (sac de 4 modèles, ~20GB de RAM — OOM sur des machines de 32GB). La qualité est légèrement inférieure mais adéquate pour l'extraction de référence.

En mode avant-plan (par défaut), cook déplace les pistes séparées vers dubbed/vocals.wav + dubbed/no_vocals.wav automatiquement ; en mode --detach, vous les déplacez vous-même après l'apparition du marqueur de fin.

Terminé lorsque dubbed/vocals.wav ET dubbed/no_vocals.wav existent tous deux avec une durée correspondant à la brute ±0,5s.

Étape 2 — Extraire le clip de référence

IndexTTS2 a besoin d'un clip propre de 14 à 30 secondes du locuteur original — il lit au maximum les 15 premières secondes, donc une fenêtre pleine capacité est préférable à une fenêtre courte. IndexTTS2 clone la prosodie, pas seulement le timbre : le rythme de délivrance de la fenêtre devient le rythme de délivrance de tout le doublage. Le sélecteur par défaut prend le discours continu le plus long, qui tend à sélectionner le passage le plus lent et le plus délibéré — souvent faux. Préférez le scanner :

cook dub scan-reference <output-root> <name> \
    [--full-band] [--python <indextts-venv>/Scripts/python.exe]

Il classe les fenêtres fixes de 15s par taux de syllabes (filtré par densité et pause) et coupe les 3 premiers candidats (plus les copies pleine bande 48k avec --full-band). La densité n'est que la moitié de l'histoire — IndexTTS2 clone aussi la prosodie de la fenêtre, donc classez les candidats également par vivacité : pyin F0 std et gamme de demi-tons par fenêtre (une fenêtre plate double plat ; utilisez librosa.pyin, PAS detect_pitch_frequency, qui signale la voisation sur le silence). Authentifiez tout fichier de référence hérité avant de le réutiliser : un dérivé retraité conserve son embedding de locuteur et ses statistiques de hauteur mais perd la corrélation de forme d'onde, donc une corrélation proche de zéro ne signifie PAS "locuteur différent" — notez-le par rapport à un clip d'ancrage avec cook dub scan-reference --score <file> --anchor <anchor.wav> (l'audio réel du même locuteur atterrit près de 0,94 ; les synthèses dans la bande normale 0,66-0,76) et comparez les statistiques pyin. Quoi qu'il en soit : l'oreille de l'utilisateur choisit la référence, toujours — synthétisez les phrases pilotes une fois par candidat (Étape 3a), présélectionnez chaque prise avec un aller-retour ASR de petit modèle (les mots manquants signalent un charabia ; la sortie en chinois traditionnel signale un accent que la fenêtre transmet à la prise), notez avec cook dub scan-reference --score, puis remettez les wavs adaptés en volume à l'utilisateur.

Terminé lorsque dubbed/_reference/ref.wav existe, fait 14-30s, et n'a pas de silence > 0,3s (ffmpeg -af silencedetect).

Étape 3 — Traduire pour le doublage (l'agent fait cela)

C'est là que le doublage diverge des sous-titres. N'utilisez pas translations.txt (la traduction des sous-titres) — elle suit les coupes de fragments de whisperX, qui divisent les phrases. Le doublage a besoin de phrases complètes pour que le chinois sonne naturellement lorsqu'il est parlé.

Lisez <output-root>/transcript/<name>.en.full.srt (la transcription anglaise en phrases complètes). Traduisez chaque réplique vous-même, en écrivant dans transcript/translations_dub.txt — une ligne chinoise par réplique anglaise, ligne N = réplique N.

La règle du budget de caractères — le cœur de la traduction pour doublage. Le budget de chaque réplique est secondes de fenêtre × taux de parole normal, fixé avant que vous écriviez : la fenêtre est le début de la réplique jusqu'au début de la réplique suivante (fenêtre + pause suivante), le taux est mesuré, jamais supposé — cook dub measure-rate sur les pilotes que l'utilisateur a choisis (procédure : Étape 3a). Un taux supposé passe toutes les vérifications et double en secondes de silence : une conférence de 45 minutes budgétée à un taux supposé de 5,0 caractères/s contre un réel de 6,93 a laissé 83 répliques avec >2,5s de silence et a coûté une re-synthèse de 82 répliques. Écrivez dans le budget : légèrement au-dessus est acceptable, nettement en dessous ne l'est pas — une prise courte garde son rythme naturel et laisse une pause de respiration, donc un texte sous-budgétisé signifie du silence, et un texte sur-budgétisé signifie une compression audible. Re-calibrez sur tout changement de référence ou de facteur de durée : un budget calibré sur une référence retirée survit à toutes les vérifications et double toujours en silence. Synthétisez une sonde stratifiée (5 à 10 répliques typiques par locuteur dans différentes tranches de longueur) et revérifiez le script par rapport aux fenêtres aux taux mesurés — procédure dans REFERENCE.md → "Re-calibrage du taux". Comment remplir un budget légitimement (et ce que "remplir" n'est pas autorisé à inventer) : REFERENCE.md → "Remplir le budget de caractères".

Principes de traduction (au-delà du budget) :

  • Traduisez des pensées complètes, pas des fragments. L'anglais est déjà en phrases complètes ; votre réplique chinoise est une pensée complète.
  • Gardez les termes techniques en anglais là où les développeurs chinois le font — spec, plan, prototype, agent, token, skill, session, branch, route, etc. Voir REFERENCE.md → "Liste de rétention des termes".
  • Gardez l'anglais pour tout ce qui est affiché à l'écran — étiquettes d'interface, code, URL, noms de fichiers. Exemples dans REFERENCE.md → "Liste de rétention des termes".
  • Traduisez les concepts qui ont des noms chinois standards lorsqu'ils ne sont pas affichés à l'écran — les exemples travaillés se trouvent dans la liste de rétention des termes.
  • Le nombre de lignes doit être égal au nombre de répliques. La manière autorisée de changer les comptes est via build_merge.py de l'Étape 3a, qui réécrit les deux fichiers ensemble.

Ensuite, générez le SRT pré-assemblage (horodatages hérités de en.full.srt) :

cook dub make-srt <output-root> <name>

Auto-révision — deux passages, avant la vérification mécanique : lisez chaque ligne à voix haute dans votre tête comme une phrase parlée (est-ce que ça ressemble à quelque chose qu'une personne dirait ?) ; puis parcourez la liste de termes ci-dessous par rapport à chaque ligne (tout ce qui est à l'écran reste en anglais, les concepts standards vont en chinois). Ce sont vous qui vérifiez votre propre travail ; la révision du sous-agent ci-dessous est la lecture à froid.

Vérification de longueur — mécanique (pure arithmétique, prend une seconde) :

cook dub gate <output-root> <name> --rate <chars/s mesurés>

Elle recoupe chaque ligne par rapport à sa fenêtre de réplique de trois manières : lignes courtes (≤8 syllabes — le piège du rythme de narration d'IndexTTS2, réécrivez plus complètement ou laissez l'Étape 3a fusionner), dépassements de budget (parole estimée bien au-dessus de sa fenêtre — le texte doit être réduit — ou bien en dessous — la fenêtre devient du silence, remplissez-la), et le total de couverture (Σ parole estimée / Σ fenêtres — une traduction uniformément mince passe chaque vérification de ligne et double toujours en longs silences ; sain 90-105%). --rate est obligatoire (la valeur mesurée ; --self-measure la redérive des prises existantes). La sortie 1 liste les lignes et le verdict de couverture ; réécrivez et réexécutez jusqu'à ce qu'il réussisse. Une ligne hors budget est corrigée en réécrivant plus court ou en la fusionnant avec sa voisine via cook dub merge — jamais en la laissant être compressée par atempo.

Vérification de qualité — révision par sous-agent en étoile (obligatoire, avant la synthèse). La vérification auditive et cette révision sont les seules vérifications avant des heures de synthèse. Distribuez à un sous-agent avec accès en lecture à <name>.en.full.srt et translations_dub.txt, et demandez-lui de vérifier, pour chaque réplique :

  1. Précision de la traduction — le chinois transmet-il fidèlement l'anglais ? Pas de clauses omises, pas de contenu ajouté (rien que l'anglais ne dit pas), pas de mauvaises traductions.
  2. Orthographe des noms propres — noms (personnes, produits, entreprises) exactement comme la source les utilise. "Claude" pas "克劳德", "IndexTTS" pas "索引TTS", sauf si un nom chinois standard existe vraiment.
  3. Lisibilité TTS — IndexTTS2 prononcera-t-il cela naturellement ? Pas de séquences de caractères étranges, pas de voyelles orphelines...

Skills associés