起因
Apple TV+ 出品的《小小世界》(Tiny World)是一部极度精美的微观自然纪录片,4K 画质令人叹为观止。视频自带简体中文字幕,对我来说看字幕完全没问题——但孩子还不识字,没有配音就没法看。
官方无中文配音,于是我决定自己动手:用 AI 把字幕读出来,配上中国人最熟悉的纪录片声音——赵忠祥。
整体架构
系统以视频文件和字幕文件为输入,输出一个含中文配音音轨的新 MKV,全程本地运行,无需联网。
每个步骤独立成脚本,中间产物落盘,可以从任意步骤重跑。
关键模块设计
🎙️ 音色克隆
Qwen3-TTS-1.7B ICL 模式:提供 16 秒赵忠祥参考音频 + 精确转录,模型即可用该音色合成任意文本。
⏱️ 语速控制
游标推后策略:TTS 以自然语速生成,字幕间停顿自动消化累积偏移,保持从容旁白感。
🎧 背景音增益
动态 RMS 匹配:实测两路信号 RMS,自动计算增益,混音结果配音略高于背景。
✅ ASR 验证
闭环自检:Qwen3-ASR 转写回文字做字符匹配,匹配率 < 0.5 自动重新生成。
音色克隆细节
TTS 引擎选用阿里巴巴开源的 Qwen3-TTS-1.7B-Base,通过 ICL(In-Context Learning) 模式实现声音克隆:向模型提供一段约 16 秒的参考音频和对应的精确转录文本,模型即可用该音色合成任意文本。
参考音频来自赵忠祥先生的《人与自然·鳄鱼最后的晚宴》片段,经 Demucs 去除背景音乐后截取。TTS 服务以 OpenAI 兼容 API 形式运行在本地(port 8880),由主程序在流水线开始时自动启动、结束后自动关闭。
游标推后策略
字幕的显示时间窗口(平均 2.8 秒)往往比 TTS 自然语速所需时间短。传统做法是用变速(atempo)把音频压进窗口,但这会导致语速异常快,失去旁白该有的从容感。
本项目采用游标推后策略:TTS 以自然语速生成,若某条音频超出对应字幕窗口,后续字幕的音频统一顺延,字幕间的较长停顿则自动消化累积偏移,使音画整体保持对齐:
动态 RMS 匹配
Demucs 分离出的背景音轨振幅比原始音频低 40–70%,直接混音会让背景音显得很弱。系统在混音前实测两路信号的 RMS,动态计算增益系数:
这样无论背景音的原始电平如何,混音结果总能保持配音略高于背景的层次感。
ASR 闭环自检
每条 TTS 生成后,用 Qwen3-ASR-0.6B 转写回文字,与原字幕做字符集匹配。匹配率低于 0.5 或检测到静音,则标记为失败,可用 --retry 参数自动删除并重新生成。这形成了一个生成→验证→修复的闭环。
批量并行处理
单视频处理完成后,把全季都处理了是自然而然的需求。系统支持批量模式:
uv run main.py --batch input/s1/
执行逻辑:
nvidia-smi自动检测 GPU 数量 N- 启动 N 个 TTS 服务实例(各占一个端口:8880、8881…)
- 视频按 GPU 轮转分配,
ProcessPoolExecutor并行处理 - 每个视频用独立子目录隔离中间产物,互不干扰
GPU 绑定通过 CUDA_VISIBLE_DEVICES 环境变量实现,每个子进程只能看到分配给它的一张卡,Demucs、TTS、ASR 全部在该卡上运行。
性能数据
单集(30 分钟,~185 条字幕)处理耗时:
| 步骤 | 耗时 | 速度 |
|---|---|---|
| Demucs 人声分离 | 20 秒 | 90× 实时 |
| TTS 生成 | 3.5 分钟 | RTF ≈ 0.41 |
| ASR 验证 | 43 秒 | — |
| 拼装 + 混音 + 封包 | < 10 秒 | — |
| 合计 | ~5.5 分钟 |
输出 4K 原画质 MKV(~1.5GB),可选用全 GPU 流水线(NVDEC + scale_cuda + NVENC)压缩至 1080p(11.4× 实时,~2.5 分钟)。
技术栈
| 组件 | 选型 |
|---|---|
| TTS 引擎 | Qwen3-TTS-1.7B-Base(阿里开源) |
| TTS 服务 | faster-qwen3-tts(OpenAI 兼容 API) |
| 声音克隆 | ICL 模式 + 赵忠祥《人与自然》参考音频 |
| 人声分离 | Demucs htdemucs(Meta 开源) |
| ASR 验证 | Qwen3-ASR-0.6B(阿里开源) |
| 视频处理 | ffmpeg(NVDEC + NVENC 全 GPU 流水线) |
| 包管理 | uv |
| 并行调度 | ProcessPoolExecutor + CUDA_VISIBLE_DEVICES |
一个延伸思考
有人会问:有了 AI,为什么还需要字幕?直接把英文音频翻译成中文不就好了?
这里有一个被低估的问题:视觉信息对语音内容有消歧作用。
- 同音词:
bear(熊)vsbare(裸露)——画面一眼明确,纯音频无法区分 - 多义词:
"The pride moves across the plain"中pride= 狮群 or 骄傲,plain= 平原 or 朴素——看到画面是狮子,答案立刻清晰
对于纪录片里大量的物种名、地名,ASR 转写后可能已经面目全非,翻译也跟着错。解决这个问题需要引入多模态 LLM(视频帧 + 音频转写同时输入),成本远高于直接使用人工字幕。
注:参考音频为赵忠祥先生的真实配音片段,仅用于个人学习研究目的。