From 02b6fa099f31d554cbd062f2315d7366677fffca 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 (cherry picked from commit bc3cc0a6af44adc63caf4e5097fcfebd7a7475b4) Signed-off-by: Michael Niedermayer --- libavformat/lrcdec.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/libavformat/lrcdec.c b/libavformat/lrcdec.c index f43e9dccf5..e4e13f57a8 100644 --- a/libavformat/lrcdec.c +++ b/libavformat/lrcdec.c @@ -77,7 +77,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++; @@ -85,14 +87,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] != ']'); @@ -163,7 +165,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;