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]

Reply via email to