手里只有蓝光碟,电脑读不了碟,字幕时间轴又对不上——这个场景不需要光驱。 用一部片 10 分钟、三个时间点、一条命令,把偏移和漂移一次算清。 下面这套流程已经在 G5300 上跑通,工具是单文件 Python,无依赖、离线可用。
错位分三种,只有前两种能靠算法解决。判错了会白忙一场。
碟片总时长(碟盒背面或碟机信息页)和字幕末条时间比一下。
| 现象 | 判定 | 怎么办 |
|---|---|---|
| 两者相差 < 1 分钟 | 基本对齐,或轻微平移 | 1 个锚点 |
| 碟片比字幕长 4%~5% | B 类 · PAL 加速 | --ratio 1.0416667 一键解 |
| 碟片比字幕长很多(>10 分钟) | 大概率不同剪辑版 | 先换字幕,别调 |
| 片长几乎相同但对不上 | A 类 · 整体平移 | 1 个锚点 |
记三个点,看差值怎么变——差值恒定是 A 类,线性变大是 B 类,某处突然跳变是 C 类。
--force)——
这时候正确的做法是换一份对应版本的字幕,而不是继续拟合。
顺序很重要:先在字幕里挑句子,再去看片。
字幕放 U 盘根目录(物理碟只认根目录)。Mac 上留一份同样的文件,命名如 星际穿越.chs.srt。
片头 3~6 分钟一句、片中一句(避开打斗和纯音乐)、最后一段对白一句。 注意是最后一段对白,不是字幕文件的最后一条——最后一条往往已经进了 credits,碟上根本没有对应画面。
./bdsub.py find 星际穿越.srt 库珀
# → [ 128] 00:04:38,000 --> 00:04:40,500
把三句的字幕时间码抄下来:① 04:38 ② 52:30 ③ 1:51:40
碟机进正片后,听到台词出口的瞬间按暂停 → 调出 OSD 读已播时间 → 记成 碟=字 的形式。
三个点重复三次,得到 --anchor 4:47=4:38 这样的三行。
按暂停会慢 0.3~0.8 秒,但三次都慢同样的量,这个恒定误差会被偏移量吸收。 所以单点误差 1 秒以内都无所谓,别为了 0.1 秒反复倒带。
./bdsub.py fit 星际穿越.srt \
--anchor 4:47=4:38 \
--anchor 54:38=52:30 \
--anchor 1:56:16=1:51:40 \
--dry-run
锚点数 3
缩放 a 1.041580 (+4.1580%)
偏移 b -2.708 s
残差 +0.15s -0.27s +0.12s (RMS 0.191s)
判定 B 类 · 速率漂移 ≈ PAL 加速 24→25 (+4.167%)
残差 RMS < 1 秒 → 可用。确认无误后去掉 --dry-run,加 --out 星际穿越.chs.fixed.srt 出文件。
方向只有一种正确写法:碟片时刻=字幕时刻。
写反了 a 会变成 0.77 这种数字,工具会直接提示。
拷到 U 盘根目录,把原件移走(不移走的话字幕菜单里两个文件并排,容易选错),重放检查三点:片头、片中、片尾。 任一点偏差 > 2 秒,说明那个锚点采错了,重采那一个点再跑一次。
--anchor 4:47=4:38 --ratio 1.0416667
和 bdsub.py 同一套算法、同一个阈值,结果应完全一致。算完可直接复制命令。
这一类有物理上限,方法也必须换。
锚点法的误差来自「按暂停的反应延迟」,约 ±0.5 秒。要修的量若只有 0.2~0.4 秒, 测量误差比被测量还大,算出来的是噪声——一个「看起来精确」的错数,改完反而更糟。
| 情况 | 处理 |
|---|---|
| 字幕比声音早 0.3 秒内 | 不要改。观众是听着声音读字,眼睛需要提前量,字幕略早是行业惯例 |
| 字幕比声音晚 0.2 秒内 | 多数人可接受 |
| 字幕比声音晚超过 0.3 秒 | 值得改 |
| 方向在不同段落不一致 | 不是固定偏移,是字幕本身的质量问题,整体平移会拆东墙补西墙 |
参考阈值:唇音同步的可察觉窗口是「声音超前 45 ms ~ 滞后 125 ms」(ITU-R BT.1359-1)。 字幕比唇音同步更宽容,因为它走阅读通道,不是唇形匹配。
./bdsub.py sweep 星际穿越.srt --from -0.4 --to 0.4 --step 0.1
生成 9 个文件,一次全拷到 U 盘根目录:
星际穿越_0.0s.srt ← 原时间轴,留作基准
星际穿越_m0.1s.srt m0.2s m0.3s m0.4s ← 字幕往前提
星际穿越_p0.1s.srt p0.2s p0.3s p0.4s ← 字幕往后推
播放到选定片段,用遥控器【字幕】键在菜单里逐一切换,挑最贴的那个。 这一步的全部价值,是把 N 次「改文件 → 拷 U 盘 → 插碟 → 重播」压成 1 次。 单次往返 3 分钟,9 次就是半小时。
23.976 fps 一帧 = 41.7 ms,碟机字幕渲染还有 1~2 帧延迟。 所以 ±0.1 秒(约 2.4 帧)就是实际可达的极限,做到这儿就收工。
--from -0.4 可以,
--range -0.4:0.4 会被当成选项名而报错。
两件事都不是简单的「改个后缀」。
工具直接支持 .ass / .ssa,所有命令都能用,不需要先转换。
关键是写回方式:只替换 [Events] 里每条 Dialogue: 的 Start / End 两个字段,
其余字节原样保留——样式表、字体、颜色、Comment: 行、BOM、CRLF 都不动。
如果按「重新生成」的方式写回,样式全丢。
实测:一次校正后全文件仅 4 行变动,且变动只发生在时间字段上。时间格式自动按 ASS 规范输出 H:MM:SS.cc。
| 字幕类型 | 建议 |
|---|---|
| 纯对白,只有字体/颜色 | 保留 ASS,样式能用就用 |
带 \pos 强行定位、\move 滚动 | convert 成 SRT,碟机渲染常常不认,位置会飘 |
| 动漫特效字幕、屏幕字 | 转 SRT 后这些内容会混进对白里,不如换一份普通字幕 |
./bdsub.py convert 字幕.ass 字幕.srt
纯标准库单文件,macOS / Linux / Windows 通用,不需要装任何依赖。把 python3 换成 py -3 即可:
py -3 bdsub.py list 字幕.srt --tail 5
py -3 bdsub.py fit 字幕.srt --anchor 4:47=4:38 --anchor 54:38=52:30 --dry-run
路径含空格或中文要加引号:py -3 bdsub.py fit "D:\字幕\星际穿越.srt" ...
极老的英文控制台可能把中文显示成 ?,那只是显示问题,不影响计算和输出文件。
知道它做不到什么,比知道它能做什么更重要。
| 项 | 说明 |
|---|---|
| 支持格式 | SRT / ASS / SSA。SUB(VobSub 图形)、IDX、PGS 不在范围内 |
| 编码 | 自动识别 UTF-8 / GBK / BIG5(按常用字命中率择优),输出保持原编码,--enc 可强制 |
| 不改帧率标记 | 只动时间戳,这正是我们需要的 |
| 遥控器做不到的 | 时移能做整体平移;速率缩放和分段只能靠本工具 |
| 结构性错位 | 无解。不同剪辑版之间不存在线性变换 |
| 片源 | 必须有字幕文件。这里全程不需要读碟、不需要光驱 |
出现以下任一情况,说明手工锚点已经不划算,再考虑 UHD 光驱 + MakeMKV:
| 信号 | 含义 |
|---|---|
| 要校正的片子 > 20 部 | 人工成本超过硬件成本 |
| 对白极稀疏(纯音乐、纪录片) | 锚点难找,误采率高 |
| 遇到 C 类且必须救 | 需要拿碟内 PGS 时间轴当 reference,走 pgs2ref.py + alass |
否则,一部片 10 分钟的人工成本,比千元光驱加每部片一小时的读盘时间划算得多。 物理碟版本是永久固定的,调好一次终身复用——这是相对流媒体的实质优势。
三个文件都是纯文本加标准库,下载后可直接离线使用。
curl -O https://geziyichen.fun/bdsub/bdsub.py
curl -O https://geziyichen.fun/bdsub/pgs2ref.py
curl -O https://geziyichen.fun/bdsub/bdsub-sop.md
./bdsub.py find 字幕.srt 台词片段 # 查台词在字幕里的时间码
./bdsub.py list 字幕.srt --tail 5 # 看结尾几条(确认末条是否已进 credits)
./bdsub.py list 字幕.srt --from 5:00 --to 6:30
./bdsub.py fit 字幕.srt --anchor 碟=字 --anchor 碟=字 --dry-run
./bdsub.py fit 字幕.srt --anchor 碟=字 --ratio 1.0416667
./bdsub.py fit 字幕.srt --anchor ... --keep-duration # 只移起点不改显示时长
./bdsub.py check a.srt b.srt # 对比两份字幕,判断是否同版本
./bdsub.py convert 字幕.ass 字幕.srt # ASS → SRT(去特效标签)
./bdsub.py sweep 字幕.srt --from -0.4 --to 0.4 --step 0.1
时间格式接受 1:51:40、01:51:40,000、111:40,会自动补零。
把 .srt 换成 .ass / .ssa,其余命令完全一样。