FFmpeg 播放 mp3 和 LRC 时音乐歌词不同步?
2021年9月19日 · 709 字 · 2 分钟
NO. | 歌曲 | 歌词 |
---|---|---|
1 | 🎵 see you again | 📝 |
2 | 🎵 那些年 | 📝 |
上面两首歌和其对应的歌词,在用 ffmpeg/ffplay 播放的时候,发现第一首两者同步,第二首音乐和歌词不同步。播放命令如下
ffplay -vf subtitles=filename=xxxx.lrc xxxx.mp3
第二首歌和歌词都是从网易云音乐下载的,按理说,两者是匹配的。我用网易云音乐听,两者非常同步。文件没有问题,难道是 ffmpeg/ffplay 的问题?
后来分析了 FFmpeg 中有关 lrc 歌词解码/解析的部分代码。发现问题所在:
从代码(libavformat/lrcdec.c)看,ffmpeg 只能正确处理 [mm:ss.SS] 格式的时间点。
static int64_t read_ts(const char *p, int64_t *start)
{
int64_t offset = 0;
uint64_t mm, ss, cs;
while(p[offset] == ' ' || p[offset] == '\t') {
offset++;
}
if(p[offset] != '[') {
return 0;
}
if(sscanf(p, "[-%"SCNu64":%"SCNu64".%"SCNu64"]", &mm, &ss, &cs) == 3) {
/* Just in case negative pts, players may drop it but we won't. */
*start = -(int64_t) (mm*60000 + ss*1000 + cs*10);
} else if(sscanf(p, "[%"SCNu64":%"SCNu64".%"SCNu64"]", &mm, &ss, &cs) == 3) {
*start = mm*60000 + ss*1000 + cs*10;
} else {
return 0;
}
do {
offset++;
} while(p[offset] && p[offset-1] != ']');
return offset;
}
歌词文件 1 中,时间点格式为[mm:ss.SS]
[00:10.61]It's been a long day without you, my friend
[00:17.61]And I'll tell you all about it when I see you again
......
歌词文件 2 中,时间点格式为[mm:ss.SSS]
[00:17.904]又回到最初的起点
[00:20.912]记忆中你青涩的脸
......
我又查了下lrc
格式的wiki
介绍:LRC (file format),文中有如下描述:
The Line Time Tags are in the format [mm:ss.xx] where mm is minutes, ss is seconds and xx is hundredths of a second.
这么看,应该是歌词文件没有遵守lrc
的格式。
当然,如果你要做个播放器,最好还是兼容一下。上述代码可以稍作修改
static int64_t read_ts(const char *p, int64_t *start) {
int64_t offset = 0;
uint64_t mm;
float ss;
while (p[offset] == ' ' || p[offset] == '\t') {
offset++;
}
if (p[offset] != '[') {
return 0;
}
if (sscanf(p, "[-%" SCNu64":%f]", &mm, &ss) == 2) {
/* Just in case negative pts, players may drop it but we won't. */
*start = -(int64_t) (mm * 60000 + (uint64_t) (ss * 1000));
} else if (sscanf(p, "[%" SCNu64":%f]", &mm, &ss) == 2) {
*start = mm * 60000 + (uint64_t) (ss * 1000);
} else {
return 0;
}
do {
offset++;
} while (p[offset] && p[offset - 1] != ']');
return offset;
}
网易云音乐歌词下载地址:https://music.163.com/api/song/media?id=<123456>