SRT/VTT/LRC/ASS 四向互转管线
四种格式的定位
| 格式 | 常见用途 | 引擎 |
|---|---|---|
| SRT | 视频字幕最通用的格式,几乎所有播放器都支持 | FFmpeg |
| VTT | Web 标准字幕格式(Web Video Text Tracks),浏览器原生支持 | FFmpeg |
| ASS | 高级字幕格式(Advanced SubStation Alpha),支持样式/定位/特效 | FFmpeg |
| LRC | 歌词格式,时间戳+歌词,最常见的音频歌词格式 | 纯 Kotlin(自研) |
四种格式覆盖了视频字幕和音频歌词两大场景。SRT/VTT/ASS 都是视频字幕生态里的,LRC 是音频歌词生态里的。
六种互转方向
ZenConverter 支持六种跨格式互转(不含同格式):
| 源 → 目标 | 引擎 | 关键处理 |
|---|---|---|
| SRT ↔ VTT / ASS | FFmpeg | 用 FFmpeg 的 subrip/webvtt/ass demuxer 和 muxer |
| VTT → LRC | FFmpeg → 纯 Kotlin | VTT → SRT(FFmpeg)→ LRC(Kotlin 自研) |
| LRC → SRT / VTT / ASS | 纯 Kotlin → FFmpeg | LRC → SRT(Kotlin 自研)→ 目标格式(FFmpeg) |
| ASS → SRT / VTT / LRC | FFmpeg / 纯 Kotlin | ASS 样式和定位被丢弃(LRC 只保留文字) |
所有走 FFmpeg 的路线都会在导出前探测 APK 里的 FFmpegKitNext AAR是否包含需要的 demuxer/muxer(srt、webvtt、ass)和 codec(subrip/webvtt/ass)。缺失就明确报错。
LRC 为什么需要自研引擎
FFmpeg 不原生支持 LRC 格式(LRC 是音频歌词格式,不是视频字幕格式)。所以 ZenConverter 写了纯 Kotlin 的 LRC 解析器和生成器。LRC 路线完全不依赖 FFmpeg。
不做同格式互转
这是一个故意的设计选择:ZenConverter 不提供"同格式互转"选项(比如 SRT → SRT)。原因是:
- 同格式互转没有实际意义(文件原样拷贝就行);
- 反而可能引入不必要的信息丢失(比如 LRC → LRC 多时间戳被简化)。
如果你有一个 SRT 想修正时间戳精度,直接用文本编辑器改就行。ZenConverter 做的是格式转换,不是字幕编辑。
已知边界
- 样式和定位被丢弃:ASS 的样式/定位/格式化、WebVTT 的 cue settings/inline markup,在转换到 SRT 或 LRC 时都会被丢弃。只保留文字内容和时间信息;
- LRC 没有结束时间:LRC 格式只有开始时间(
[mm:ss.xx]),没有结束时间。LRC → SRT 时会用下一个 cue 的开始时间合成结束时间; - 最大文件 8 MiB:字幕/歌词文件一次性读入内存,硬上限 8 MiB;
- UTF-8 优先 + GB18030 回退:先用 UTF-8 解码,如果失败再用 GB18030 回退——覆盖常见的 GBK 编码中文歌词;
- TXT 不支持输入/输出:如果你的字幕是纯 TXT 格式(没有任何时间戳),ZenConverter 处理不了——不是字幕格式。
SRT 的时间戳 vs LRC 的时间戳
| 格式 | 时间戳表达 | 结束时间 |
|---|---|---|
| SRT | hh:mm:ss,SSS | 明确有(用 --> 分隔) |
| VTT | hh:mm:ss.SSS | 明确有(用 --> 分隔) |
| ASS | hh:mm:ss.CC(百分秒) | 明确有 |
| LRC | [mm:ss.xx] | 没有,只有开始时间 |
LRC 只有开始时间这个事实,是 LRC → SRT/ASS/VTT 时需要合成结束时间的根本原因。
使用场景
| 场景 | 推荐转换 |
|---|---|
| 视频字幕 SRT 想在 Safari 浏览器里显示 | SRT → VTT |
| 从 MP3 提取 LRC 歌词想做成可编辑字幕 | LRC → SRT |
| ASS 字幕想去掉样式(比如给播放器自己加样式) | ASS → SRT |
相关页面
- LRC 纯 Kotlin 解析引擎 —— LRC 路线的自研引擎细节
- 音频元数据验证与修复 —— 很多音频格式本身支持嵌入歌词,和 LRC 转换有交集