给 Opus 5.5 视频项目加配音和字幕:按实测时长对齐旁白与句子字幕

在 Opus 5.5 生成的 Remotion 项目中对齐旁白与句子字幕。获取可运行的 MP4、WAV、SRT 和源码,附时间检查方法与漂移修正。

浅色纸面上的节拍器线稿,鼠尾草绿背景,配橙色条块和 Opus 5.5 标题

要给 Opus 5.5 视频加配音和字幕,就要把音频时间当作项目数据来处理。 先制作或录制旁白,测量时长,把每句话映射到时间线上,然后一起渲染音频和字幕。只让模型“把字幕对上”而不给它实际的时间数据,是不够的。

本教程使用与我们 产品演示教程 相同的真实截图项目。你可以直接从可下载文件开始,不必先读完那篇文章。本文的目标是一个带旁白的 30 秒 MP4,配有清晰可读的句子字幕、一份可编辑的时间数据源和一个独立的 SRT——而不是一组新的提示词,也不是未经验证的自动配音承诺。

观看并检查音频示例

Remotion 实际导出文件,使用英文合成参考语音。这个声音有意只作为对时工具,不代表专业旁白品质。字幕按整句显示,并留有阅读停留时间。

下载 完整项目、带旁白的 MP4、参考 WAV 和 英文 SRT。五个语种的文章共用这个英文示例;我们并不把它当作五个本地化配音作品。

实际的模型调用是在官方 Claude Code 中使用 claude-opus-5-5 生成 Remotion 代码。它收到的是文件名和文字形式的场景说明,而不是图片像素或录音。随后我们提供了真实的原始截图,用 eSpeak NG 生成参考语音,修正代码并在本地渲染。这种分工是本教程的核心:Opus 写代码;语音引擎生成音频;Remotion 输出最终文件。

选择合适的对时工作流

常见的起点有两种。如果脚本和场景时长还能调整,先录制或合成已确认的配音,再让画面配合它的节奏。如果视频必须放进已确定的 30 秒时长,就先定义场景窗口,把放不自然的句子改短。

本例走的是第二条路线。它有五个现成场景和五个短句。每段音频必须落在分配给它的字幕窗口内;参考音频脚本会拒绝超出结束时间的片段。这项检查能在渲染前就发现一类真实存在的同步错误。

起始素材推荐做法需要重点检查的风险
已确认的连续旁白测量/转写旁白,再围绕实际语音放置画面和字幕根据字数猜测句子时间
固定时长的产品视频为每个场景写短句;逐条测量录音为了保住固定切点而加快语速或截断句子
已有带语音的视频从实际音轨获取时间戳,再进行审核把自动转写当作经过验证的字幕文件
多语言版本每种语言重新录制并重新对时口播时长变化后仍沿用英文时间

Remotion 的 字幕文档 介绍了字幕的导入、显示和导出。本项目有意使用一个小型 JSON 句子时间表,让时间一目了然、便于审核。它不运行自动转写或强制对齐。

先用提供的声音,再替换成你的配音

运行项目前先安装 Node.js 和 npm。下文可选的终端媒体检查还需要另行 安装 FFmpeg(包括 ffprobe);npm ci 不会安装这个命令行工具。不使用这些可选检查命令,也可以通过项目自带的 npm 脚本完成渲染。

解压压缩包,在根目录运行项目:

npm ci
npm start

选择 DemoNarrated。压缩包中已包含 public/narration.wav,所以渲染时不需要安装语音引擎,也不需要购买配音服务。检查开头附近的第一句、13 秒左右的文档句,以及 27 秒附近的最后一句。

Remotion Studio 实际界面,显示带旁白的合成、字幕和音频时间线

带 WAV 音轨的真实项目预览。可见的波形只能证明项目中有音频,不能说明发音质量或逐词对齐。

如需复现参考语音,请按照你所用系统的官方说明安装 eSpeak NG,然后运行:

python3 scripts/make_audio.py
npm run render:narrated

我们使用的是 eSpeak NG 1.52.0、en-us 语音,语速设置为每分钟 190 词。这种基于共振峰的声音有意听起来是合成的,适合在确定最终旁白前测试时间线;这个数字只是工具设置,不保证每句话的语速完全一致。

正式投放时,请使用你有权发布的录音或语音输出。仔细听产品名、缩写、标点处的停顿以及每句话的最后一个词。文字稿正确并不能说明声音是否自然。本文的实测检查针对的是时长、位置和可见字幕,不是对发音或表现的人工评审。

WAV、字幕和 SRT 共用一份时间表

打开 scripts/make_audio.py。其中的 LINES 数组是参考数据源:每一项包含开始时间、字幕结束时间和文本。运行脚本会生成 30 秒的 WAV、src/captions.json、public/captions.en.srt 和 audio-timing.json。合成直接导入生成的 JSON,避免在视频代码里再维护第二份手动编辑的字幕列表。

下表中的句子保留英文原文,因为它们正是各语种文章共用的英文音轨里实际说出的内容;括号内的中文仅为释义,方便理解。实测的参考片段如下:

句子(英文原声)开始WAV 片段时长片段结束字幕结束
A clear product video starts with a clear brief.(清晰的产品视频,始于清晰的简报。)0.35 秒2.664 秒3.014 秒3.60 秒
Show the real interface. Here, we begin with the model catalog.(展示真实界面。这里先从模型目录开始。)4.35 秒3.681 秒8.031 秒9.80 秒
Then show where a viewer can find the documentation.(然后展示观众在哪里能找到文档。)11.35 秒2.917 秒14.267 秒16.80 秒
Connect each scene to an actual page, such as this API reference.(让每个场景都对应一个真实页面,比如这个 API 参考。)18.35 秒3.743 秒22.093 秒23.80 秒
Keep the message simple. Plan, build, and verify.(信息保持简单:规划、构建、验证。)25.35 秒3.537 秒28.887 秒29.50 秒

这些时长包含生成片段末尾的尾随采样,并不是对单个音素的测量。字幕有意在语音结束后继续显示;文档那一句在 WAV 片段结束后还有约 2.53 秒的额外阅读时间。如果你想让字幕更紧凑,请在检查实际旁白后缩短这段停留。

脚本会在每段前后填充静音,并把音频放在表中列出的绝对开始时间。它不会为了塞进窗口而加快过长的句子。如果修改后的句子放不下,脚本会明确报错,提示你在渲染前缩短句子或调整结束时间。

连续的替换录音需要不同的准备步骤。导出一个完整时长的 public/narration.wav,然后编辑 src/captions.json 和 SRT,使其与实际录音匹配。之后不要再运行 make_audio.py,除非你打算用参考语音覆盖那份录音。把原始录音和生成的示例分别保存为不同的版本。

小心地把秒换算成帧

合成以 30 fps 运行。11.35 秒的字幕落在两个视频帧之间。最终代码用 Math.floor(start * fps) 计算第一个可见帧,因此这句话出现在第 340 帧,约 11.333 秒——略早于语音开始。它没有入场淡入,不会遮住第一个说出的词;在最后六帧有一个短暂的淡出。

const first = Math.floor(caption.start * fps);
const last = Math.round(caption.end * fps);
const visible = frame >= first && frame < last;

这段代码说明的是最终的可见性规则;完整组件还设置了文本排版和结尾淡出。帧取整是正常现象。不要根据 30 fps 的画面时间线宣称音频达到了采样级对齐。

所提供的 Remotion 4.0.424 项目从 remotion 导入 Audio,并用 staticFile 解析 WAV。当前 Remotion 文档把这个较旧的 HTML5 组件称为 Html5Audio,并建议在新的音频集成中使用更新的媒体组件。复现本压缩包时请保持其固定版本;不要把当前文档中的 API 变化和一次未加说明的包升级混在一起。

让字幕清晰可读,又不隐藏文字

横屏合成为字幕提供了一条与截图分开的深色色带。在文档和 API 场景中,场景标题位于左侧,句子字幕位于右侧。竖屏版把图片和字幕垂直堆叠;其布局参数见 竖屏视频教程。

我们的英文字幕在横屏中使用 28 像素文字,在竖屏中使用 30 像素。这些是本项目的取值,不是社交平台的通用规则。所选的句子长度能放进已检查过的布局,更长的译文则未必。

模型最初的代码用 CSS 行数截断(line-clamping)把文字限制在两行内。我们删除了这条规则,因为编辑后它可能悄悄隐藏第三行。字幕过长时,正确的修法是拆分或改写句子、扩大空间或调整布局——而不是让缺失的文字变得不可见。

修改文字时,按预期的显示尺寸检查第一条、最长一条和最后一条字幕。系统字体回退可能改变换行;压缩包不保证在每个操作系统上排版完全一致。如果需要固定的品牌字体,请打包一款授权合适的字体,在渲染前加载,并重复上述检查。

让 Opus 做有边界的时间修改

测量完你自己的配音后,这个改编提示词会很有用。请用真实时间替换占位符;它不是一次额外的模型测试。

只更新现有的 DemoNarrated 合成。
保留已确认的截图、30 fps 和当前的场景顺序。
替换后的旁白为 public/narration.wav。
以下是实测的句子区间(单位:秒):
[粘贴开始时间、结束时间和准确的口播文本]

只使用一个字幕数据源。保留每一个说出的词。
每句字幕在第一个词说出之前或同时出现;说明帧取整方式。
不要虚构逐词时间戳或自动转写结果。
只在我明确给出的位置保留阅读停留时间。
不要用行数截断(line-clamping)隐藏溢出文字。
如果某句跨越了场景切点,请指出,而不是悄悄截断音频。
返回修改过的文件、时间假设和需要检查的帧。

修改后,先把文字与旁白对照,再核查画面。如果某句在描述 API 页面,而画面上还是模型目录,那么两个文件各自都可能没问题,合在一起的故事却是错的。请修正共享的场景时间表或录音;仅调整字幕偏移,无法修复旁白与画面不匹配的问题。

导出并诊断实际文件

npm run render:narrated
ffprobe -v error -show_entries stream=codec_name,codec_type,duration,sample_rate \
  -show_entries format=duration -of json out/narrated.mp4

渲染出的示例包含一条 H.264 视频流和一条 AAC 音频流。视频时间线为 30 秒;由于编码器填充,压缩音频报告的流/容器时长可能略有不同。我们的参考 WAV 正好 30 秒。请检查可听内容和同步情况,不要把 AAC 末尾的少量多余时长误判为场景时长错误。

症状可能要检查的地方如何修改
整个 MP4 没有声音合成、静音标志、WAV 路径和流元数据使用 render:narrated,确认音频素材存在,并确保渲染时没有被静音。
每句都晚了同样的时间开头的静音或共享的起始偏移修正这个统一偏移,并再次检查第一句和最后一句。
越往后偏差越大错误的时长假设、音频速度或源时间线测量实际录音;不要根据估算的字数逐条修补字幕。
某句跨过了切点该句的时长与场景边界缩短或重录该句,或延长场景及所有相关的时间。
屏幕上少了词文字换行和固定尺寸的字幕框拆分句子或调整布局尺寸;绝不隐藏溢出。
预览有声音,最终导出却没有最终文件和渲染命令检查 MP4 的音频流,而不只是看 Studio 里的波形。
SRT 与烧录字幕不一致最后编辑的数据源与重新生成的顺序从同一份时间表重新生成;使用替换录音时,则有意识地同时更新两者。

交付前,开着声音完整播放导出文件,检查每句的开始和结束,并检查上传到发布平台后的版本。烧录字幕始终存在于画面像素中;独立的 SRT 则取决于平台是否支持并启用。本例两者都提供,但不声称其中任何一种已上传到社交渠道。

把音频工作与模型访问分开看

Opus 5.5 模型条目 标明了与这个编码工作流相关的模型。本例不能证明 Ofox 提供 TTS,也不能说明视频渲染的计费方式;其记录的模型调用使用的是官方 Claude Code,音频是在本地生成的。

整体制作流程请看 Opus 视频主指南,素材选择请看 截图演示教程,发布到移动优先的格式之前请看 竖屏改编教程。可靠的交付物应包括最终 MP4、WAV、匹配的字幕文件,以及生成它们的确切项目版本。

常见问题

旁白是 Opus 5.5 生成的吗?
不是。Opus 生成的是视频项目代码。本例使用明确标注为合成音的 eSpeak NG 参考语音,再由 Remotion 把 WAV 与视频合成在一起。
这些字幕是逐词同步的吗?
不是。本例使用五条按时间表显示的句子字幕,每段音频结束后还留有额外的阅读时间。逐词高亮需要真实的逐词时间戳,并需单独验证。
可以只替换配音而不重新生成视频设计吗?
可以。替换音频并更新字幕时间使其匹配,保留已确认的画面即可。如果新配音超出场景或项目时长,导出前需修改共享的时间线。