Ich baue animierte Kinder-Cartoons, die gleichzeitig in fünf Sprachen erscheinen: Deutsch als Master, dann Englisch, Arabisch, Türkisch und Persisch. Die strategische Grundsatzentscheidung dahinter klingt unscheinbar, hat aber alles bestimmt: ein einziges Video pro Folge, identisch über alle fünf Sprachen, mit fünf Audio-Tracks über das YouTube-Multi-Audio-Feature. Nicht fünf Videos, nicht fünf Kanäle.
Warum klassische Lipsync-Tools sofort ausscheiden
Wav2Lip, Hedra, Sync.so, Higgsfield Lipsync Studio — sie alle haben dasselbe Problem für mein Konzept: Sie modifizieren das Video pro Sprache. Wenn der englische Mund anders aussieht als der deutsche, habe ich fünf verschiedene Videos und das 1-Video-Multi-Audio-Konzept ist tot. Dazu kommt: Die meisten sind auf echten Gesichtern trainiert, mein 3D-Pixar-Look ist für sie Glücksspiel.
Also akzeptiere ich Industry-Standard-Dub-Sync (~90–95% perzeptuelle Synchronität) und hole die Qualität über andere Hebel. Das Video bleibt unangetastet. Die Stimme passt sich an, nicht das Bild.
Erst messen: Wann spricht der Mund überhaupt?
Bevor man etwas angleichen kann, muss man wissen, wann der animierte Mund aktiv ist. Ich messe das nicht per Computer-Vision, sondern über Audio — und zwar über einen schönen Trick: Mein Video-Modell synchronisiert beim Generieren intern bereits eine Pseudo-Stimme zur Mundanimation. Bevor ich diese Pseudo-Stimme entferne, messe ich sie.
Der Schritt heißt bei mir Mouth-Timing-Detection:
- Demucs (
htdemucs) trennt den Vocals-Stem vom Rest. - RMS-Analyse im Vocals-Stem, 20-ms-Fenster, Threshold −45 dB.
- Erstes lautes Sample =
mouth_window_start_s, letztes =mouth_window_end_s.
Das funktioniert — aber es hat eine Falle. Bei einem meiner Lehrbeispiele (eine Figur sagt „Yusuf, mein Keks?") detektierte Demucs den Start bei 2,22s. Plausibilitätscheck: 2,22s > 4,086s / 2 → verdächtig. Der Grund: Bei −45 dB übersieht Demucs den weichen, halbvokalischen „Y"-Onset von „Yusuf" und erkennt erst das laute „u-suf". Der Frame-Check (ffmpeg extrahiert Einzelbilder) zeigte: Der Mund öffnet sich schon bei 1,30s. Override gesetzt, Window korrigiert von 1,68s auf 2,60s.
Wichtigste Regel hier: Nie einen Override per Heuristik schätzen. In einem Gegenbeispiel sah die Detection genauso verdächtig aus — aber der Frame-Check zeigte, dass die Figur wirklich erst spät spricht. Demucs hatte recht. Darum ist die visuelle Verifikation Pflicht.
Die Cascade: fünf Hebel in fester Reihenfolge
Wenn die Voice-Dauer nicht zum Mouth-Window passt, ziehe ich an Hebeln — in dieser Reihenfolge:
- Smart-Translation — übersetzen mit Ziel-Dauer als Constraint (nur Multi-Lang)
- Video-Atempo — Video stauchen/strecken, Range
[0.80, 1.20] - Voice-Atempo — Stimme dehnen/stauchen, Range
[0.85, 1.30] - Rephrase — umformulieren bei Restfehler
- Shorten/Lengthen — Skript kürzen oder erweitern
Reihenfolge ist kein Zufall: Video vor Voice. Bis ±20% Video-Tempo ist im Pixar-Stil unhörbar, jede Voice-Verfremdung dagegen sofort hörbar. Darum fasse ich die Char-Stimme zuletzt an.
Das Lehrbeispiel durchgerechnet
Das Window ist 2,60s. Der Algorithmus im Final-Cut-Mix:
voice_raw_de = 1,76s (TTS-Real-Output)
inverse_target = 2,60 / 1,76 = 1,477 → Video müsste 47,7% schneller
video_ratio = clamp(1,477, 0.80, 1.20) = 1,200 ← CAP
adjusted_window = 2,60 / 1,200 = 2,167s
voice_atempo = clamp(1,76/2,167, 0.85, 1.30) = 0,850 ← CAP
voice_dur = 1,76 / 0,85 = 2,071s
residual_pad = 2,167 − 2,071 = 0,096s ✓
96 ms Reststille, unter dem 0,3s-Threshold — wird von Ambient überdeckt, läuft durch.
Spannend wird der Vergleich zur englischen Spur. Die Smart-Translation wählte „Yusuf, my cookie?" — nur 1,40s, zu kurz. Hier kippt dieselbe Cascade ins Cap-Versagen: residual = 0,520s, über dem Threshold → needs_retrigger = true. Die Pipeline ruft die Übersetzung erneut auf, diesmal mit dem Hint „~30–40% länger". Das Sprachmodell liefert etwa „Yusuf, where's my cookie?", die Voice wird neu generiert, der Mismatch schrumpft auf ~0,1s. Maximal drei Iterationen, dann greife ich von Hand ein.
Was ich dabei gelernt habe
Der Algorithmus-Score ist nur Diagnostik, nie Beweis. In einem frühen Pilotschnitt hatte ein EN-Cut Sync-Scores von 82–96 — und klang trotzdem katastrophal, schlechter als die Version mit niedrigeren Scores. Mein Ohr ist der finale Judge. Eine „Verbesserung", die nur die Zahl hebt, ist keine.
Und die Smart-Translation? System-Prompt mit Char-Profilen und Werte-Kanon einmal cachen (Prompt-Caching) — ab Shot 2 zahle ich nur den User-Payload, ~90% Kostenersparnis. ~50 Shots in unter 30 Sekunden pro Sprache.