从写代码,到创作下一幕

探索 字节跳动 - 火山方舟 的 AI 编程与视频创作活动。

火山方舟 Agent Plan 与 Coding Plan 活动,价格 ¥9.9 起

Agent Plan & Coding Plan

一站体验多款热门模型,为 AI 编程与智能体开发提供更多选择。新用户可联系(微信: goo_lvyouyou)免费体验 9.9 agent plan。

查看套餐优惠
Seedance 2.5 视频创作活动:30 秒视频、多模态参考、局部编辑

Seedance 2.5

让创意,跃然成片。探索 30 秒视频、多模态参考与局部编辑,把脑海中的画面变成下一支作品。

探索视频创作

视频配音

查看 Markdown

此应用使用 Grok API 将视频中的对白译成另一种语言并配音。它将语音转文本、结构化翻译输出和文本转语音串联起来,最后使用 ffmpeg 将配音混入视频。

提供视频后即可获得另一种语言的配音版。每句配音从原句的起点开始,在原句时段内说完,各说话者使用不同的声音,原有背景音保留。网页并排播放原片和配音版,附双语转录和每句对白的时长对比条。

你将学到

  • 转录语音时获取每个词的起止时间,区分说话者并为每人分配声音

  • 为每句对白划定时段和长度预算,以结构化输出接收逐句翻译

  • 依据语音合成返回的字符时间戳测量录音长度,请 Grok 缩短超时的译句并重新录制

  • 每句翻译完成就开始并行录音,使用 ffmpeg 将译音与原声混合

  • 通过服务器发送事件从 Node 服务器向网页实时传送进度,并在关闭页面时取消任务

运行示例

需要 Node.js 22.13 或更高版本,以及 ffmpeg。将 API 密钥保存在 .env(仓库根目录),或导出环境变量 XAI_API_KEY。

Bash

cd examples/video-dubbing/typescript
npm install
npm run web

打开 http://localhost:3000,选择语言,点击 Dub the sample clip,也可选择或拖入自己的 MP4 或 MOV 文件。页面类似配音工作台:转录稿逐行显示对白、说话者和对应时段,译文随后在旁边逐步出现,配音预览窗上方会显示 Grok 的推理。时长条对比译音和原声;超出时段的部分显示为橙色,缩句重录后时长条缩短,旧译文会被划去。混音完成后两段视频同步播放。可在 Original 和 Dub 之间切换收听,观察两种语言的词随播放进度依次高亮。点击某句可跳转,点击 Stop 可取消。

在终端配音时,传入视频和语言代码:

Bash

npm start -- ./your-video.mp4 fr

不带参数时,默认将 sample-clip.mp4 配成墨西哥西班牙语。示例长 35 秒,内容是两位朋友在屋顶观星,由 Grok Imagine 静态画面、两种内置声音和轻柔的合成背景音通过 ffmpeg 合成。两个版本都将文件保存到 output/<video>-<language>/,包括用于转录的音频、每句的最终录音、script.json(包含每句的所有版本及相应时间戳),以及 dubbed.mp4。

示例实测一次需要 15 至 45 秒,API 繁忙时可能更久,花费约 0.01 至 0.03 美元。12 句对白中通常有一至三句需要缩短。Grok 的费用来自 usage.cost_usd。语音 API 不报告单个请求的费用,应用据转录秒数与合成字符数估算其余支出,采用的费率见公开价格。

配音按说话者首次发言的顺序分配内置声音。若要保留各人自己的声音,可将其克隆为自定义声音,再将其 ID 写入 VOICES,位于文件 src/dub.ts。通过 API 创建自定义声音需要 Enterprise 套餐。

工作原理

共享代码位于 src/dub.ts 和 src/fit.ts。dubVideo() 执行以下步骤,将各文件保存到 output/<video>-<language>/,在每一步开始时报告进度,并立即报告已完成的结果:

  1. extractAudio() 使用 ffmpeg 从视频中提取 16 kHz 单声道 FLAC 音频,接着 transcribe() 将其发送至 client.voice.transcribe(),设置 diarize: true。返回的数据包含每个词的起止时间和说话者编号。启用 diarize 时,API 从上传文件名识别音频格式,因此音频要以带文件名的 File 发送。若改用 Blob(由 openAsBlob() 返回),则会被当作不支持的格式而遭拒绝,格式名为 blob。

  2. splitLines() 将词分组成句。说话者变化、句子结束或出现停顿时另起一句。每句的时段从首词开始,到下一句开始前为止,且最多只延伸至末词结束后 0.3 秒。

  3. translateLines() 从 grok-4.7 流式接收结构化译文。每句附可用秒数和字符预算,通常每秒约 17 个字符,中文、日文和韩文则每秒约 6 至 7 个。短于 1.2 秒的句子按 1.2 秒计算预算,否则 Grok 会省略必要的词。请求还标明每位说话者配男声还是女声,让译文中需与说话者性别一致的词与声音匹配。JSON 流中的 json 事件返回截至当前的译句,每句完成后立即开始录音。应用采用低推理强度:默认强度下 Grok 会先计算所有句长才动笔,这个示例花了六分钟。

  4. fitLine(),位于文件 src/fit.ts。它逐句录音,使用 client.voice.speak() 和 with_timestamps: true,以获取音频和每个字符的起止时间。停顿计在其前面的空格或标点上,因此语音时长从第一个字母算至最后一个字母。若比时段长出 5% 以上,shortenLine() 会将译句发回 Grok 并重新录音,最多重录两次。字符时间戳可确定时段用尽时已经说了多少,程序据此要求 Grok 按比例删去余下部分并额外缩短 5%。如果规定精确字符数,Grok 会花数秒统计字母。若依然超时,则用 speed 加快录制,最高 1.15 倍。每次录音长度有波动,即使调快也可能比上次长,因此保留最短的版本。

  5. mixDub() 用 ffmpeg 将原声音量降至四分之一,再将录音放在相应句子的起点。每段录音会按其开头的静音时长提前放置,使第一个词与原句的首词对齐。

程序每次并发录制六句。配音会集中发出大量请求,因此 SDK 客户端遇到速率限制时最多重试五次,而非常规的两次;若 Grok 在输出任何内容前失败,则通过以下选项重发请求:retryBeforeOutput。SDK 不会自行重发连接中断的语音请求,因此每句录音最多尝试三次。

src/server.ts 为网页运行 dubVideo()。EventSource 只能发送 GET 请求,因此页面先将自选视频上传至 /api/videos,再打开 /api/dub 并传入返回的 ID,通过服务器发送事件接收各步骤的进度。服务器仅提供本次运行保存的文件,并按字节范围提供配音视频,以支持浏览器跳转。如果页面关闭或用户点击 Stop,服务器会中止所有 API 调用。public/index.html 用原生 HTML 和 JavaScript 展示事件。原视频作为时间基准,配音与它同步播放,未被选中收听时保持静音。原视频依据转录的逐词时间戳高亮,配音版则依据语音合成的逐字符时间戳高亮。src/index.ts 在终端执行相同的工作,输出每句对白及其时间信息。