如何让 ASS 字幕中的单词一次出现一个?

How to make words in ASS subtitles appear one at a time?

我正在尝试将字幕刻录到视频中,这样它们就可以逐字显示,而不是一次全部出现。

我的意思是,一个词会出现,然后另一个词旁边会出现,依此类推。最终线路会清除,然后重复。

示例:

我想我可以创建一个 Advanced Substation Alpha 文件,其中字幕共享相同的结束时间但不同的开始时间,但是 FFMPEG 在渲染文件时似乎不能很好地处理:

[Script Info]
; Script generated by FFmpeg/Lavc57.107.100
ScriptType: v4.00+
PlayResX: 384
PlayResY: 288

[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
Style: Default,Arial,16,&Hffffff,&Hffffff,&H0,&H0,0,0,0,0,100,100,0,0,1,1,0,2,10,10,10,0

[Events]
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
Dialogue: 0,0:00:00.00,0:00:03.46,Default,,0,0,0,,I'm
Dialogue: 0,0:00:01.00,0:00:03.46,Default,,0,0,0,,a
Dialogue: 0,0:00:01.50,0:00:03.46,Default,,0,0,0,,subtitle

想法是 I'm 会出现,然后 1 秒后 a 会出现在它旁边,半秒后 subtitle 会出现

您走在正确的轨道上,但您现在正在做的是创建新的 文本。事实上,它们会并排显示,但它们会垂直堆叠,这不是您想要的。

具有重复文本的多个事件

要将单词添加到 same 行,您需要在下一个单词必须出现时停止上一个对话事件,并在下一个对话事件中重复整个可见文本:

Dialogue: 0,0:00:00.00,0:00:01.00,Default,,0,0,0,,I'm
Dialogue: 0,0:00:01.00,0:00:01.50,Default,,0,0,0,,I'm a
Dialogue: 0,0:00:01.50,0:00:03.46,Default,,0,0,0,,I'm a subtitle

如果是居中或(对于从左到右书写的语言)右对齐文本,或者如果您的文本太长而自动换行并分几行显示,您需要指定每次都是整个文本,因此对齐和环绕计算在每个事件上都以相同的方式工作,但是通过将其完全透明,使文本的不可见部分实际上不可见:

Dialogue: 0,0:00:00.00,0:00:01.00,Default,,0,0,0,,I'm {\alpha&HFF}a subtitle
Dialogue: 0,0:00:01.00,0:00:01.50,Default,,0,0,0,,I'm a {\alpha&HFF}subtitle
Dialogue: 0,0:00:01.50,0:00:03.46,Default,,0,0,0,,I'm a subtitle

这是通常的做法。

带有覆盖标签的单个事件

或者,如果您的文本没有 border/outline 并且没有阴影 (示例视频中不是这种情况), 您可以通过设置待唱文字颜色(SecondaryColour)至全透明:

Dialogue: 0,0:00:00.00,0:00:03.46,Default,,0,0,0,,{a&HFF\k100}I'm {\k50}a {\k196}subtitle

如果您确实有边框或阴影(如示例视频中所示),那么单纯的卡拉 OK 是不够的,因为您还想修改 border/shadow 颜色。你可以使用 ASS 的通用动画标签 \t:

Dialogue: 0,0:00:00.00,0:00:03.46,Default,,0,0,0,,I'm {\alpha&HFF\t(1000,1000,\alpha0)}a {\alpha&HFF\t(1500,1500,\alpha0)}subtitle

在这里,对于除第一个单词之外的每个单词,我在事件开始时将所有 alpha 值设置为完全透明,然后在单词出现时立即将其切换为完全不透明。

关于从右到左文本的注意事项

问题中没有任何迹象表明您打算将其用于除从左到右的英文文本之外的任何内容,但这仍然值得谨慎。 (您甚至可能认为现在很自然地认为这种区别无关紧要。不幸的是,由于过去的一些错误决定和习惯,它仍然如此。)

如果您使用从右到左的文本(例如阿拉伯语或希伯来语)尝试这些方法中的任何一种,但第一种最简单的方法没有覆盖标签,您会发现 VSFilter 和 libass,两个主要的 ASS 渲染器,以不同的方式显示文本:libass 将使用相同的词序,就好像你有一个没有任何标签的单行,但 VSFilter 将在覆盖标签处拆分文本并重新排序部分,以便前面的部分始终到 剩下后面的部分。

即使在没有任何覆盖标签的最简单情况下,如果您的文本以某些标点符号(或其他方向中性字符)开头或结尾,它们也不会与文本的自然方向匹配并显示为反转。

目前对此没有合适的“解决方案”,但您可以通过在覆盖标签周围插入 Unicode 双向控制字符来解决差异,使 libass 匹配 VSFilter 的顺序(not 自然文本顺序)并强制任何 start/end-of-line 标点符号从右到左。

当然,如果您只是刻录字幕而不打算分发字幕文件,那么您不必担心它们在其他渲染器中的外观。 FFmpeg 使用 libass。然而,libass 的行为可能会在未来的某个时候进行调整以匹配 VSFilter,因为 VSFilter 传统上拥有最大的市场份额(从 libass 甚至不存在的时候开始)和大部分(如果不是全部的话)阿拉伯语字幕存在的文件实际上依赖于它对从右到左文本的错误处理,并要求它产生正确的输出。