返回博客
AI配音Google CloudFFmpeg音视频处理

换掉 TTS 引擎后才发现,API 调用只是开始

从 Kokoro 迁移到 Google Chirp 3 HD 后,真正的挑战不是调用 API,而是让生成的语音精确嵌入原视频的时间轴。本文记录 Katto 配音系统的完整技术实现。

2026年9月13日

换掉 TTS 引擎后才发现,API 调用只是开始

Katto 的 AI 配音功能已经上线一段时间。创作者可以选择一个短视频片段,指定目标语言,系统返回翻译后的配音版本。最初的实现基于 Kokoro,支持 8 种语言。

最近我把主力语音引擎换成了 Google Cloud Text-to-Speech 的 Chirp 3 HD。目标看起来很明确:提升音质,增加语种。现在 Katto 编辑器里可以选择 19 种配音语言和 12 个精选音色。

我原本以为这主要是个 API 替换工作。

结果完全不是。

生成一句自然的语音很容易。让这句话精确地填进另一个说话人留下的时间槽,才是配音的真正难题。

如果原说话人用了 2.4 秒,翻译后的语音需要 3.2 秒,再好的 TTS 模型也救不了这个片段。要么语音挤到下一句,要么字幕飘移,要么只能加速到听起来很赶。

TTS 请求本身,反而是整个系统里最简单的部分。

最终的处理流水线

缓存的词级时间戳
        |
        v
固定时间槽的短语片段
        |
        v
长度感知的翻译
        |
        v
Google Chirp 3 HD 逐短语合成
        |
        v
基于 FFmpeg 的有界音频对齐
        |
        +----> 同源片段生成的翻译字幕
        |
        v
最终 MP4 封装

每个阶段的存在,都是因为更简单的版本在某个地方失败了。

1. 把原始时间轴当作数据保留

Katto 的转录流程已经输出词级时间戳。我不会把整段文本一次性送去翻译和合成,而是先分组成短语。

短语的结束点出现在句子标点、超过 0.6 秒的停顿,或者长度即将超过 6 秒的时候。每个片段保留原始的起止时间。这些数字成为后续所有阶段的约束条件。

对全文一次性合成可能听起来更流畅,但会丢失把语音放回视频时间轴所需的锚点。短语级合成在保留自然语调的同时,也保留了有用的时间边界。

2. 翻译要考虑发音时长,不只是语义

书面翻译正确,不等于配音翻译可用。有些语言表达同样的意思需要更多音节。逐字翻译可能保留了所有细节,但因为塞不进时间槽而无法使用。

对每组短语,我让 Claude Haiku 生成口语化的翻译,要求更短的措辞和更少的音节。返回结果保留每个源片段的索引。

这个提示词是音频系统的一部分。它的任务不只是语言准确性,还要减少后续的时间拉伸量。

这仍然是启发式方法。LLM 无法保证时长,因为选定的音色也会影响节奏。音频层会实际测量生成的 WAV 文件。以目标语言和源片段为键的进程内缓存,让 worker 存活期间的重复渲染可以复用翻译结果。

3. 逐短语调用合成接口

每个翻译后的短语作为独立请求发送到 Google Cloud Text-to-Speech REST API,输出 24 kHz LINEAR16 格式音频。音色名称遵循 Google 文档规定的 locale-Chirp3-HD-speaker 格式。

Google 支持的 Chirp 3 HD 语种比 Katto 当前开放的更多。我刻意把产品限制在 19 种语言,这些语言走通了完整路径:UI、locale 映射、字体、字幕和降级逻辑。API 声称支持某个语言,不代表周边产品能正确处理它。

4. 在不破坏音质的前提下让语音适配时间槽

合成后,我会比较生成时长和原始槽位:

target_duration = segment["end"] - segment["start"]
ratio = generated_duration / target_duration

如果语音稍长,用 FFmpeg 的 atempo 滤镜在保持音高的同时加速。加速上限设为 1.3 倍。

这个上限很重要。早期版本用 1.6 倍,更多短语能塞进去,但有些音色听起来不自然地仓促。完美对齐没有意义,如果结果让人不舒服。

每个调整后的短语放置在主轨道的原始偏移位置。短语音之间留下自然停顿。较长短语得到有界修正。这解决不了所有病态翻译,但执行了更有用的规则:保持可懂度优先于追求数学上的完美对齐。

5. 让语音和字幕共享同一个时钟

合成响应给我音频,但不给新语音的可靠词级时间戳。编造词级时间会让字幕看起来精确,实际上是错的。

因此配音片段使用短语级字幕,从用于语音的同一批翻译片段生成。它们的起止时间已经和音频放置位置匹配。

渲染器还会选择覆盖目标文字的字体。拉丁字体不够用于日语、中文、印地语或阿拉伯语。片头标题和 AI 钩子走相同的本地化路径,屏幕不会说一种语言显示另一种。

生产环境的常规问题也很重要

不是每个精选音色在我测试的每个 locale 都能用。如果选定音色不可用,Katto 用该性别的已知默认音色重试一次。编辑器的实时预览调用同一个 Google 引擎。用另一个模型的样本会让用户选择一个他们永远收不到的音色。

生产 API 密钥限制为 VPS 的 IPv4 地址,但 VPS 访问 Google 时优先用 IPv6。合法请求被拒绝,直到我强制 TTS 调用走 IPv4。API、密钥和代码都对,网络路径不对。

配音生成独立的视频变体。如果翻译、合成、字幕渲染或封装失败,原始片段保持完整。对于最初支持的 8 种语言,当 Google 路径被禁用或未配置时,Kokoro 仍可作为后备方案。

什么变了,什么没变

可见的结果是配音语言从 8 种扩展到 19 种,加上可选音色和实时预览。

更深层的改进是架构层面的。翻译、语音、字幕、叠加层和视频渲染现在共享一个时间单位:短语片段。

系统不克隆原说话人,不做唇形同步,不编造生成的词级时间戳。很长的翻译仍然可能超出理想槽位。这些限制好过声称流水线无法兑现的精度。

我以为自己在换语音引擎。结果是收紧了媒体流水线几乎每个阶段之间的契约。

API 调用是简单的部分。让结果属于原始时间轴,才是真正的工作。

Katto 把长视频切成短竖屏片段,现在可以把这些片段配音成 19 种语言。如果你在做多语言视频,我很想知道你如何在不让音色听起来很赶的前提下处理时间对齐。

参考资料

Google Cloud Text-to-Speech:Chirp 3 HD 音色

准备好把你的视频变成爆款短片了吗?

Katto 自动将你的长视频剪辑、加字幕并重新构图,转换为短视频内容。

免费试用 Katto
换掉 TTS 引擎后才发现,API 调用只是开始 | Katto