ffsubsync 解决一个很具体的问题:字幕和视频差了几秒。它不是靠人工拖动时间轴,而是从音频里提取语音活动,再跟字幕的时间轴做互相关,算出一个整体偏移量后平移整份字幕。

32 秒的音频跑一次不到 2 秒。但它有一个默认参数会在短音频上直接跑偏:同一份错位 3 秒的字幕,默认参数算出 -23.29 秒,把偏移范围限制到 10 秒以内才算对。

装完之后是一条命令

ffsubsync --version
ffsubsync 0.5.1

ffsubsync speech.wav -i bad.srt -o synced.srt --max-offset-seconds 10

第一个参数是音频或视频,-i 是待对齐的字幕,-o 是输出。它内部用 ffmpeg 抽音轨、用 webrtcvad 判断哪一段有人说话,再拿这个语音时间轴跟字幕时间轴对相关。

装上会带 numpy、scipy、webrtcvad 几个依赖,pip 一次装完。运行时不需要 GPU,也不需要联网。

造一份能复现的测试

手边没有现成的错位字幕,就自己造一份。用 ffmpeg 自带的 flite 合成 8 句英文语音,句子之间插 0.6 秒静音,拼成一段 31.96 秒的音频;再按真实的语音起止时间写一份正确字幕,然后把整份字幕整体后移 3 秒当成待修复的样本:

ffmpeg -f lavfi -i "flite=text='...':voice=slt" -ar 16000 -ac 1 l01.wav
ffmpeg -f concat -safe 0 -i list.txt -c copy speech.wav

合成音频 31.96 秒,1022958 字节
正确字幕最后一句结束于 31.96 秒,错位版整体 +3 秒

这样「正确答案」是已知的:理想情况下应该算出 -3.00 秒,把错位版平移回去。有了参照,后面的数字才有意义。

默认参数在这段音频上跑偏了

设置耗时(秒)算出的偏移(秒)相关得分与正确版行一致率(%)
默认(搜索 ±60 秒)2.19-23.2999512.5
限制 ±10 秒1.97-2.81262966.7
限制 ±5 秒2.02-2.81262966.7

默认参数把偏移算成 -23.29 秒,相关得分只有 995,对齐后跟正确字幕只有 12.5% 的行能对上。原因在于搜索范围:默认允许在正负 60 秒内找最佳匹配,而这段音频只有 31.96 秒,范围比音频本身还长,等于在一个几乎没有重叠的空间里滑,很容易滑到一个「碰巧得分也不低」的位置。

把范围收到 ±10 秒,偏移算成 -2.81 秒,与真值 -3.00 秒差 0.19 秒,相关得分跳到 2629,行一致率 66.7%。收到 ±5 秒结果完全一样,说明真值落在范围内之后,范围再收窄不影响结果。

0.19 秒的误差来自语音活动检测的边缘:它判断「有人说话」的起点比真实发音稍晚,整体平移量就偏了一点。对字幕来说 190 毫秒可以接受,观众几乎察觉不到。

已经对齐的字幕再跑一次

> ffsubsync speech.wav -i v_限制10秒.srt -o again.srt --max-offset-seconds 10
offset seconds: 0.01
score: 2630
耗时 1.99 秒

拿已经对齐的版本再跑一次,算出的偏移是 0.01 秒,得分 2630,比上一次的 2629 还高一点。说明这个算法在正确位置上是稳定的,来回跑不会把字幕越推越偏。

这个性质很重要:如果工具每次都随机偏个几百毫秒,反复对齐就会让字幕慢慢漂走。0.01 秒说明它是收敛的。

失败时会发生什么

> ffsubsync nofile.wav -i bad.srt -o x.srt
退出码 1,x.srt 没有被创建

> ffsubsync speech.wav -i broken.srt -o x2.srt
退出码 0,x2.srt 照样生成(内容不可用)

音频文件不存在时会失败退出,输出文件不生成,脚本里可以用退出码判断。

字幕文件格式不对时反而更麻烦:它不报错,退出码 0,照样写一个输出文件出来。因为解析不出有效的字幕条目,最后等于把空内容写了一遍。这种情况只能自己检查产物——比较输入输出条目数,或者看看输出文件是不是 0 条。

另外它的日志很啰嗦,默认会把每一步的 INFO 都打出来。脚本里调用建议加 --log-level warning,不然一大段无用的输出会混进你的管道。

什么时候值得用

整份字幕早或晚了几秒。这是它最擅长的场景:一个整体偏移量,一次平移解决,不足 2 秒跑完。

字幕来自不同版本。同一部片子的蓝光版和流媒体版时长不同,字幕要重新对,用它算偏移比手动拖准。

要处理分段错位。它算的是一个全局偏移,前半段对后半段错的字幕处理不了。这种要按段落切开分别对齐,或者人工修。

音频里几乎没人说话。音乐、环境音、纯解说的长静音,语音活动检测抽不出有效时间轴,相关就会失效。这种情况它不会告诉你「我算不准」,只会给一个偏移量。

还没测的两项:真实影视音频上的准确率 / 与 subsync 这类图形工具的对比。前者需要带已知偏移的电影片段,后者要装桌面程序逐帧比对。