1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2025-08-04 22:03:09 +02:00

avformat/lrcdec: support arbitrary precision timestamp

Apparently files with milliseconds exist in the wild. And since it cost
nothing to support arbitrary number of digits, extend format to support
that.

Depending on number of digits, the time base of fractional part is
changing. Most LRCs use 2 digits and centiseconds base, but subs with 3
digits and miliseconds exist too.

Set internal time base to AV_TIME_BASE, which in parcitice allows to
hold microseconds with 6 digits. Totally artificial, but who knows maybe
someone wants that.

Fixes: #11677

Signed-off-by: Kacper Michajłow <kasper93@gmail.com>
This commit is contained in:
Kacper Michajłow
2025-07-23 20:04:53 +02:00
parent e916f55c91
commit bc3cc0a6af

View File

@ -78,7 +78,9 @@ static int64_t count_ts(const char *p)
static int64_t read_ts(const char *p, int64_t *start) static int64_t read_ts(const char *p, int64_t *start)
{ {
int64_t offset = 0; int64_t offset = 0;
uint64_t mm, ss, cs; uint64_t mm;
double ss;
char prefix[3];
while(p[offset] == ' ' || p[offset] == '\t') { while(p[offset] == ' ' || p[offset] == '\t') {
offset++; offset++;
@ -86,14 +88,14 @@ static int64_t read_ts(const char *p, int64_t *start)
if(p[offset] != '[') { if(p[offset] != '[') {
return 0; return 0;
} }
if(sscanf(p, "[-%"SCNu64":%"SCNu64".%"SCNu64"]", &mm, &ss, &cs) == 3) { int ret = sscanf(p, "%2[[-]%"SCNu64":%lf]", prefix, &mm, &ss);
/* Just in case negative pts, players may drop it but we won't. */ if (ret != 3 || prefix[0] != '[') {
*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; return 0;
} }
*start = (mm * 60 + ss) * AV_TIME_BASE;
if (prefix[1] == '-') {
*start = - *start;
}
do { do {
offset++; offset++;
} while(p[offset] && p[offset-1] != ']'); } while(p[offset] && p[offset-1] != ']');
@ -164,7 +166,7 @@ static int lrc_read_header(AVFormatContext *s)
if(!st) { if(!st) {
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
} }
avpriv_set_pts_info(st, 64, 1, 1000); avpriv_set_pts_info(st, 64, 1, AV_TIME_BASE);
lrc->ts_offset = 0; lrc->ts_offset = 0;
st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE;
st->codecpar->codec_id = AV_CODEC_ID_TEXT; st->codecpar->codec_id = AV_CODEC_ID_TEXT;