LRC 纯 Kotlin 解析引擎
为什么需要自研 LRC 引擎
字幕互转管线里 SRT/VTT/ASS 都走 FFmpeg 兼容路线,但 LRC 是例外:
FFmpeg 不原生支持 LRC 格式。——support-matrix.md
所以 ZenConverter 写了一套纯 Kotlin 的 LRC 解析器和生成器,不依赖任何 native 库,不依赖 FFmpeg,理论上在任何 Android 设备上都能跑。
这套引擎是 ZenConverter 字幕路线的唯一非 FFmpeg 组件。
LRC 格式简介
LRC 是音频歌词领域最常见的格式(视频字幕领域用 SRT/VTT/ASS)。最简单的 LRC 长这样:
[ti:歌曲标题]
[ar:艺术家]
[al:专辑]
[by:歌词制作者]
[offset:500]
[00:12.00]第一句歌词
[00:15.50]第二句歌词
[00:20.00][00:45.00]第三句歌词(多时间戳)
特点:
- 时间戳格式
[mm:ss.xx](分:秒.百分秒); - 支持一行多个时间戳(
[00:20.00][00:45.00] 同一句歌词在两个时间点出现); - 支持
[offset:xxx]全局偏移; - 支持元数据标签
[ti:](标题)、[ar:](艺术家)、[al:](专辑)、[by:](制作者)。
解析引擎的能力
时间戳解析
支持三种时间戳精度:
| 格式 | 示例 | 说明 |
|---|---|---|
[mm:ss.xx] | [01:23.45] | 百分秒精度 |
[mm:ss.xxx] | [01:23.456] | 毫秒精度 |
[mm:ss] | [01:23] | 秒精度 |
多时间戳
同一行可以有多个时间戳:[00:20.00][00:45.00][01:30.10] 同一句歌词在三处出现。解析器会把每个时间戳拆成独立的 cue,最终 SRT/VTT/ASS 输出里会有三个独立的 cue 文本相同但时间不同。
[offset:] 偏移
[offset:500] 表示所有时间戳整体向后偏移 500 毫秒(-500 表示向前偏移)。解析器会在读取完所有时间戳后,统一加上偏移量。
编码处理
先用 UTF-8 解码整份歌词。如果解码失败(检测到无效的 UTF-8 序列),回退用 GB18030 解码——覆盖绝大多数 GBK 编码的中文歌词。GB18030 是 GBK 的超集,可以正确处理 GBK 编码的所有中文字符。
无时间戳的行
LRC 里可能出现没有时间戳的歌词行(某些编辑器会在行尾漏加时间戳)。解析器会直接忽略这些行,不会报错也不会输出——因为没有时间戳的歌词在时间轴上没有意义。
生成引擎的桥接角色
LRC 生成引擎的核心角色是桥接:
LRC → SRT
生成 SRT 是 ZenConverter LRC 引擎的主要输出路径:
- SRT 格式有明确的开始/结束时间(LRC 只有开始时间),所以用上一个 cue 的时间作为当前 cue 的结束时间;
- LRC 多时间戳行会被拆成多个独立的 SRT cue;
[offset:]偏移在解析阶段就被应用,SRT 输出的时间已经是偏移后的。
SRT → LRC
反向桥接也走这个引擎:
- 先由 FFmpeg 把 VTT/ASS 等转成 SRT;
- 再由 Kotlin 引擎把 SRT 转成 LRC;
- SRT 的
hh:mm:ss,SSS格式被转换成[mm:ss.xx]格式; - SRT 有明确结束时间,但 LRC 不保留结束时间——直接丢弃。
已知边界
- LRC 行内多个时间戳被合并成一句 SRT:这是正确行为——多时间戳意味着"同一句歌词在多个时间点出现",SRT 里应该有多个 cue;
- LRC 没有结束时间:任何从 LRC 转出来的格式,结尾那段的结束时间只能用上一个 cue 或文件末尾来估算;
- LRC 样式和定位不保留:LRC 本身就没有样式/定位格式(不像 ASS/VTT),转换到其他格式时也不会有;
- TXT 输入不支持:如果你的文件是纯 TXT 格式(没有
[mm:ss.xx]时间戳),ZenConverter 不会去猜哪些行是歌词——直接判定为无效。
为什么要自研而不是等 FFmpeg 支持
技术原因已经清楚了——FFmpeg 原生 demuxer/muxer 里没有 LRC,添加一条 LRC demuxer/muxer 路线的工作量和写一个纯 Kotlin 解析器差不多,而且纯 Kotlin 实现没有 native 库依赖,32 位 ARM 设备也能跑。
ZenConverter 的设计原则是:能纯 Kotlin 就纯 Kotlin,只在必要时引入 native 库(FFmpeg、PDFBox、office2pdf、woff2、NCNN)。
相关页面
- 四种字幕歌词格式互转管线 —— SRT/VTT/ASS 走 FFmpeg,只有 LRC 走这个引擎
- 音频格式互转 —— MP3/Opus/FLAC 本身支持嵌入歌词,和 LRC 转换有交集