srt/vtt字幕解析与生成需手动处理时间戳、跳过非字幕行、使用crlf+utf-8 bom编码、截断毫秒防浮点误差。

解析 SRT 字幕时,时间戳格式不匹配就直接崩
常见错误是用 DateTime.Parse 直接转 "00:01:23,456",但 SRT 的毫秒分隔符是逗号,而 .NET 默认认点号;更糟的是有些文件用分号(老版规范),或缺前导零。一解析就抛 FormatException。
正确做法是手写解析逻辑,别依赖通用时间解析:
- 用
string.Split拆开"-->"两边,再对每段按":"和","或";"分割 - 小时、分钟、秒转
int,毫秒部分用int.TryParse(..., out var ms)防逗号/分号混用 - 构造
TimeSpan:new TimeSpan(0, hours, minutes, seconds, ms),别碰DateTime
示例片段:
var parts = line.Split(new[] { " --> " }, StringSplitOptions.None);
var startParts = Regex.Split(parts[0].Trim(), @"[:;,]");
// 然后逐段 int.TryParse
VTT 解析要小心头部的 WEBVTT 声明和注释行
很多人直接 File.ReadAllLines 后从第 0 行开始 parse,结果把 WEBVTT、空行、NOTE 行当成了字幕块,导致索引错乱、ID 错位。
VTT 是有明确起始标识的文本格式,必须跳过非字幕内容:
- 逐行读,遇到第一个符合
^\d+$的行才开始当作序号(可选),下一行才是时间轴 - 时间轴行必须含
-->且前后都有有效时间格式,否则跳过 - 字幕正文以空行结束;遇到新序号或 EOF 才收尾当前条目
- 别假设每条都带序号——VTT 允许省略,SRT 则强制有
生成 SRT/VTT 时,换行和编码不处理好,播放器直接拒载
Windows 记事本打开正常,PotPlayer/VLC 却显示乱码或只读第一行?大概率是用了 \n 换行 + UTF-8 无 BOM。SRT/VTT 规范要求 CRLF(\r\n),且多数播放器(尤其旧版)只认 UTF-8 with BOM。
写文件时两个关键点不能漏:
- 用
Encoding.UTF8.GetBytes+File.WriteAllBytes,或指定new StreamWriter(path, false, new UTF8Encoding(true))(true表示带 BOM) - 每行结尾必须是
"\r\n",别用Environment.NewLine——它在 Linux/macOS 是\n,会坏掉 - SRT 序号后必须跟
\r\n,时间行后也必须跟\r\n,字幕正文末尾不能多一个空行
时间精度差异会让字幕快进或延迟几帧
SRT 只支持毫秒(三位),VTT 支持毫秒甚至微秒(但实际只取三位)。如果你从视频帧时间(比如 23.976 fps 下的 TimeSpan.FromTicks)直接 ToString() 写入,可能生成 00:01:23.456789 这种非法格式,部分播放器截断、部分报错。
统一做截断处理:
- 提取总毫秒数:
(int)timeSpan.TotalMilliseconds % 1000 - 避免四舍五入——字幕对齐靠的是向下取整,否则 999.8ms 会进到下一秒,造成跳断
- VTT 中时间推荐用
hh:mm:ss.fff格式输出,SRT 同理,但分隔符用,
真正麻烦的是跨格式转换:SRT 转 VTT 时,别把 ,456 直接换成 .456 就完事,得确认原始时间源有没有被 double 转换污染过——浮点误差叠一次就偏 1~2ms,连播 10 分钟可能偏半秒。








