---
name: video-dubbing
description: "Translate video/audio into another language with dubbed voice and synchronized subtitles. 完整流水线：抽音轨(16kHz) -> ASR -> AI 翻译 -> 分段 TTS 配音 -> 合并音轨 -> 烧录硬字幕，翻译字幕与配音共用原始时间戳，保证音画同步。触发词：视频翻译、视频配音、给视频配音、翻译字幕、生成外语配音、双语字幕、字幕同步、dub a video、translate a video、add foreign-language voiceover、dubbed subtitles。Use when the user asks to translate a video, dub a video, generate foreign-language voiceover, or add translated subtitles with dubbed audio. Do NOT use when：只需转录不需要翻译/配音（改用 video-minutes 或 whisper）、只需本机文字转语音出音频（改用 mlx-tts）、要求保留原背景音并做专业混音（需额外的 Demucs 人声分离，本技能默认不做）。"
---

# video-dubbing: 视频翻译配音与字幕同步

## Purpose

把一段视频整体本地化为另一种语言：识别原语音、翻译、用 TTS 生成目标语言配音，在**保持原始
时间戳**的前提下合成音轨并把译文硬字幕烧进画面。产出是可直接发布的单文件视频，配音与字幕
天然同步，不需要二次对轴。

## When to Use

- 用户要求把视频翻译成另一种语言，并要配音（不只是字幕）。
- 需要给视频加目标语言配音 + 同步字幕（双语或纯译文）。
- 触发词：视频翻译、视频配音、翻译字幕、生成外语配音、双语字幕、dub a video、translate a video、
  foreign-language voiceover。
- 任何 ASR -> 翻译 -> TTS -> 视频合成的工作流。

## When NOT to Use

- 只需转录、不需要翻译或配音 -> 交给 `video-minutes` 或直接 whisper。
- 只需把文字合成为音频、不涉及视频 -> 交给 `mlx-tts`。
- 需要保留原背景音乐/音效并做专业混音（人声分离）-> 本技能默认不做 Demucs，需另行处理。
- 视频无音轨或音质极差到无法识别。

## Workflow

端到端推荐直接用编排脚本 `<skill>/scripts/dub.py`（见 `## Scripts`），它会依次执行下面各步并
在翻译处暂停等待 AI 翻译。手动执行时按以下步骤：

1. **抽音轨（16kHz 单声道）**：
   `ffmpeg -y -i input.mp4 -ar 16000 -ac 1 -c:a pcm_s16le audio16k.wav`
2. **ASR 转录**（要**逐段准确时间戳**）：
   `whisper audio16k.wav --model large-v3-turbo --language <源语言> --output_format srt --output_dir .`
   产出 `audio16k.srt`，时间戳与原视频天然对齐。想要更好的中文识别可改装 Qwen3-ASR
   （`pip install qwen-asr`）并用 `<skill>/scripts/qwen3_asr.py`。
3. **翻译字幕（由 AI 完成）**：读 SRT，逐段翻译。**每个 SRT 段输出一行译文，严格保持顺序**。
   先数清段数（如 27 段 -> 27 行），存为 `translated.txt`，继续前核对行数一致。
4. **生成配音**：
   `python3 <skill>/scripts/dub_segments.py audio16k.srt translated.txt dubbing.wav subtitle_synced.srt --lang <目标语言>`
   脚本会：用首段作音色参考保证**音色一致**；**保留原始时间戳**让字幕与画面同步；只对溢出槽位
   的段做变速（atempo 0.88–1.20）；把相邻小于 1s 的间隔桥接起来让听感自然。
5. **合并配音音轨到视频**：

   ```bash
   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.mp4
   ```

   然后确认音轨已被替换：
   `ffprobe -v error -show_entries stream=codec_type -of csv=p=0 output_temp.mp4`（应显示 `video, audio`）。
6. **烧录硬字幕**：
   `python3 <skill>/scripts/burn_subtitles.py output_temp.mp4 subtitle_synced.srt output_final.mp4`
   把译文字幕永久渲染进画面。
7. **清理（可选）**：删除 `audio16k.wav`、`audio16k.srt`、`translated.txt`、`dubbing.wav`、
   `subtitle_synced.srt`、`output_temp.mp4` 等中间产物。

## Decision Rules

- 想一键跑完 -> 用 `dub.py`；只想重跑某一步（如已有 SRT）-> 用 `dub.py --srt existing.srt` 跳步。
- ASR 引擎：默认 `--asr whisper`（`large-v3-turbo`）；中文识别要求高 -> `--asr qwen3`。
- 不需要硬字幕 -> `dub.py --no-burn`（只到音轨合并）。
- 目标语言由 `--target-lang` 决定（默认 `zh`）；`dub_segments.py` 的 TTS 语言由 `--lang` 决定。
- 翻译必须由 AI 完成且与 SRT 段严格 1:1；行数不符时脚本直接报错退出，不要绕过。
- 字幕没出现/中文变方框 -> 用 `burn_subtitles.py`（moviepy 渲染，自动找中文字体），不要依赖
  ffmpeg 的 `subtitles=`（libass 缺失时会静默失败）。
- 配音时长溢出槽位 -> 依赖脚本的分段 atempo，不要对整条音轨做全局变速。

## Constraints

- **时间戳必须复用 ASR 原始结果**，禁止对配音重新 ASR 取时间。
- **译文行数必须等于 SRT 段数**（1:1），否则中止。
- **合并音轨必须显式 `-map 0:v:0 -map 1:a:0`**，否则会保留原音轨。
- ASR 必须用 `large-v3-turbo`（或 `turbo`），不要退回 `base`/`tiny`。
- 变速只在段级别进行，范围 0.88–1.20x；禁止全局 atempo。
- 默认不做背景音乐人声分离；用户要求时应显式说明需要额外处理。

## Verification

交付前逐项确认：

- [ ] `translated.txt` 行数与 SRT 段数完全一致。
- [ ] `dubbing.wav` 与 `subtitle_synced.srt` 均已生成。
- [ ] `ffprobe` 显示最终视频同时含 video 与 audio 流，且音频确实被替换。
- [ ] 字幕已硬烧进画面（不是外部软字幕），中文无方框。
- [ ] 配音与画面在若干随机点抽查时间戳对齐。
- [ ] 未删除用户提供的源文件。

## Output

- **Outcome**：一个本地化后的视频文件（默认 `output_final.mp4`，`dub.py` 下为
  `<视频名>_<目标语言>.mp4`），含目标语言配音与硬字幕；另可保留 `subtitle_synced.srt`。
- **Done when**：音轨已替换、字幕已烧录、音画在抽查点同步、ffprobe 校验通过。
- **Evidence**：最终文件路径；SRT 段数与译文行数；ffprobe 的流清单；抽查的同步时间点。

## References

按需加载，不要预先全读：

- `references/pipeline-design.md` — 需要解释或调整流水线行为（为何保留时间戳、分段变速、
  默认不做人声分离、产物与依赖清单）时读。
- `references/troubleshooting.md` — 实际报错、音画不同步、字幕没出现或中文变方框时读。

## Scripts

- `<skill>/scripts/dub.py` — 端到端编排。用法
  `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]`。
  运行到翻译步时会生成 `to_translate.txt` 并要求 AI 翻译成 `translated.txt`，然后重跑继续；
  返回最终视频路径与字幕路径。
- `<skill>/scripts/dub_segments.py` — 分段 TTS 配音 + 时间戳对齐。用法
  `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]`。
  返回对齐后的 `dubbing.wav` 与 `subtitle_synced.srt`；译文行数不匹配时以退出码 1 中止。
- `<skill>/scripts/burn_subtitles.py` — 用 moviepy 烧录硬字幕。用法
  `python3 <skill>/scripts/burn_subtitles.py input.mp4 subtitles.srt output.mp4 [--font <path>] [--font-size 28]`。
  返回烧好字幕的视频；`--font` 缺省时自动探测中文字体。
- `<skill>/scripts/qwen3_asr.py` — whisper 兼容的 Qwen3-ASR CLI，中文识别更佳。用法
  `python3 <skill>/scripts/qwen3_asr.py audio.wav [--model 0.6B|1.7B] [--language zh] [-f srt|vtt|txt|json|tsv|all] [-o 输出目录] [--device cuda:0|mps|cpu] [--dtype float16|bfloat16|float32]`。
  返回指定格式的字幕/文本文件。模型别名：`turbo/tiny/base/small -> Qwen3-ASR-0.6B`，
  `medium/large -> Qwen3-ASR-1.7B`。

## Troubleshooting

- 配音没被替换 / 还是原声 -> 合并 ffmpeg 时漏了 `-map 0:v:0 -map 1:a:0`。
- 字幕没出现或中文方框 -> 改用 `burn_subtitles.py`，并用 `--font` 指定中文字体。
- 译文行数与 SRT 段数不符 -> 脚本会报错退出，先补齐到 1:1。
- 完整错误清单见 `references/troubleshooting.md`。

## Related Skills

- `mlx-tts` — 提供底层 `mlx_audio.tts.generate`，本技能的配音节依赖它。
- `video-minutes` — 视频转结构化纪要；只需转录/总结时改用它。
