When seeking in a long HLS stream (>26.5 hours), the 33-bit MPEG-TS PTS clock wraps, causing the raw DTS in seeked segments to be lower than the seek target. The seek packet filter used plain subtraction, so ts_diff was always negative and every packet was dropped, producing empty output.
Fix by using av_compare_mod() in the 90kHz timebase (matching the existing compare_ts_with_wrapdetect logic) instead of a microsecond diff. Note: the analysis and code was generated mostly by Claude Code. I've updated the Trac ticket (https://trac.ffmpeg.org/ticket/7673) with a way to reproduce the issue, which this patch fixes. I've also used the patch on my actual usecase, a 48-hour long stream from Twitch. --- libavformat/hls.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/libavformat/hls.c b/libavformat/hls.c index b03201c690..f9083bc75f 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -2544,11 +2544,11 @@ static AVRational get_timebase(struct playlist *pls) return pls->ctx->streams[pls->pkt->stream_index]->time_base; } -static int compare_ts_with_wrapdetect(int64_t ts_a, struct playlist *pls_a, - int64_t ts_b, struct playlist *pls_b) +static int compare_ts_with_wrapdetect(int64_t ts_a, AVRational tb_a, + int64_t ts_b, AVRational tb_b) { - int64_t scaled_ts_a = av_rescale_q(ts_a, get_timebase(pls_a), MPEG_TIME_BASE_Q); - int64_t scaled_ts_b = av_rescale_q(ts_b, get_timebase(pls_b), MPEG_TIME_BASE_Q); + int64_t scaled_ts_a = av_rescale_q(ts_a, tb_a, MPEG_TIME_BASE_Q); + int64_t scaled_ts_b = av_rescale_q(ts_b, tb_b, MPEG_TIME_BASE_Q); return av_compare_mod(scaled_ts_a, scaled_ts_b, 1LL << 33); } @@ -2626,9 +2626,8 @@ static int hls_read_packet(AVFormatContext *s, AVPacket *pkt) } tb = get_timebase(pls); - ts_diff = av_rescale_rnd(pls->pkt->dts, AV_TIME_BASE, - tb.den, AV_ROUND_DOWN) - - pls->seek_timestamp; + ts_diff = compare_ts_with_wrapdetect(pls->pkt->dts, tb, + pls->seek_timestamp, AV_TIME_BASE_Q); if (ts_diff >= 0 && (pls->seek_flags & AVSEEK_FLAG_ANY || pls->pkt->flags & AV_PKT_FLAG_KEY)) { pls->seek_timestamp = AV_NOPTS_VALUE; @@ -2649,7 +2648,7 @@ static int hls_read_packet(AVFormatContext *s, AVPacket *pkt) int64_t mindts = minpls->pkt->dts; if (dts == AV_NOPTS_VALUE || - (mindts != AV_NOPTS_VALUE && compare_ts_with_wrapdetect(dts, pls, mindts, minpls) < 0)) + (mindts != AV_NOPTS_VALUE && compare_ts_with_wrapdetect(dts, get_timebase(pls), mindts, get_timebase(minpls)) < 0)) minplaylist = i; } } -- 2.48.1 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
