PR #23942 opened by Kacper Michajłow (kasper93) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23942 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23942.patch
From 5abb6c7f17f4b7d33f0d16bce1c29cc4f0d6364a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= <[email protected]> Date: Wed, 8 Jul 2026 07:41:15 +0200 Subject: [PATCH 1/2] avformat/hls: measure playlist reload interval from load start RFC 8216 6.3.4 measures reload waits from the time the client began loading the playlist, not from when the load finished. --- libavformat/hls.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libavformat/hls.c b/libavformat/hls.c index e8533aa93f..e6772292b4 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -849,6 +849,7 @@ static int parse_playlist(HLSContext *c, const char *url, struct segment **prev_segments = NULL; int prev_n_segments = 0; int64_t prev_start_seq_no = -1; + int64_t load_start = av_gettime_relative(); if (is_http && !in && c->http_persistent && c->playlist_pb) { in = c->playlist_pb; @@ -1159,10 +1160,10 @@ static int parse_playlist(HLSContext *c, const char *url, free_segment_dynarray(prev_segments, prev_n_segments); av_freep(&prev_segments); } - if (pls) - pls->last_load_time = av_gettime_relative(); fail: + if (pls) + pls->last_load_time = load_start; av_free(new_url); if (close_in) ff_format_io_close(c->ctx, &in); -- 2.52.0 From 32be7f395e9360349a672dc63b3826c068c46acc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= <[email protected]> Date: Wed, 8 Jul 2026 07:42:58 +0200 Subject: [PATCH 2/2] avformat/hls: refresh stale playlist when seeking Seeking used only the loaded segment list. Live and EVENT playlists can gain segments after loading, and sliding-window playlists can also expire them, so a seek target may lie outside the loaded window even when it is within the actual presentation. Refresh the target playlist before resolving the seek when the target may fall outside the window. Rate-limited to one-half the target duration, the minimum reload interval of RFC 8216 6.3.4. --- libavformat/hls.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/libavformat/hls.c b/libavformat/hls.c index e6772292b4..5b82c9b7df 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -2945,9 +2945,6 @@ static int hls_read_seek(AVFormatContext *s, int stream_index, if ((flags & AVSEEK_FLAG_BYTE) || (c->ctx->ctx_flags & AVFMTCTX_UNSEEKABLE)) return AVERROR(ENOSYS); - first_timestamp = c->first_timestamp == AV_NOPTS_VALUE ? - 0 : c->first_timestamp; - seek_timestamp = av_rescale_q_rnd(timestamp, s->streams[stream_index]->time_base, AV_TIME_BASE_Q, AV_ROUND_DOWN); @@ -2966,6 +2963,29 @@ static int hls_read_seek(AVFormatContext *s, int stream_index, if (!seek_pls) return AVERROR(EIO); + /* Live and EVENT playlists may have gained segments since the last load, + * and sliding-window playlists may also have expired some. Refresh before + * resolving a seek that may fall outside the loaded window, rate limited + * to one-half the target duration (RFC 8216 6.3.4). */ + if (!seek_pls->finished) { + int64_t elapsed = av_gettime_relative() - seek_pls->last_load_time; + int64_t start = c->first_timestamp == AV_NOPTS_VALUE ? + 0 : c->first_timestamp; + int64_t end = start; + int need_refresh; + for (i = 0; i < seek_pls->n_segments; i++) + end += seek_pls->segments[i]->duration; + need_refresh = seek_timestamp >= end; + if (seek_pls->type == PLS_TYPE_UNSPECIFIED) + need_refresh |= seek_timestamp < start + elapsed + + seek_pls->target_duration; + if (need_refresh && elapsed >= seek_pls->target_duration / 2) + parse_playlist(c, seek_pls->url, seek_pls, NULL); + } + + first_timestamp = c->first_timestamp == AV_NOPTS_VALUE ? + 0 : c->first_timestamp; + duration = s->duration == AV_NOPTS_VALUE ? 0 : s->duration; -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
