From bc3cc0a6af44adc63caf4e5097fcfebd7a7475b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= Date: Wed, 23 Jul 2025 20:04:53 +0200 Subject: [PATCH] avformat/lrcdec: support arbitrary precision timestamp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- libavformat/lrcdec.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/libavformat/lrcdec.c b/libavformat/lrcdec.c index 68c44bce97..7941c02c5d 100644 --- a/libavformat/lrcdec.c +++ b/libavformat/lrcdec.c @@ -78,7 +78,9 @@ static int64_t count_ts(const char *p) static int64_t read_ts(const char *p, int64_t *start) { int64_t offset = 0; - uint64_t mm, ss, cs; + uint64_t mm; + double ss; + char prefix[3]; while(p[offset] == ' ' || p[offset] == '\t') { offset++; @@ -86,14 +88,14 @@ static int64_t read_ts(const char *p, int64_t *start) 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 { + int ret = sscanf(p, "%2[[-]%"SCNu64":%lf]", prefix, &mm, &ss); + if (ret != 3 || prefix[0] != '[') { return 0; } + *start = (mm * 60 + ss) * AV_TIME_BASE; + if (prefix[1] == '-') { + *start = - *start; + } do { offset++; } while(p[offset] && p[offset-1] != ']'); @@ -164,7 +166,7 @@ static int lrc_read_header(AVFormatContext *s) if(!st) { 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; st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codecpar->codec_id = AV_CODEC_ID_TEXT;