PR #25810 opened by MattCrossleyTR
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25810
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25810.patch

Mirror HLS demuxer's sleep mechanism from `reload_playlist`.

Dash demuxer would attempt to open fragments that do not yet exist in manifest 
and burn through
allowed reloads before fragment is written.

Can be tested with this command producing a live stream:
```
ffmpeg -re -f lavfi -i testsrc -t 30 \
  -c:v libx264 -preset veryfast -b:v 800k \
  -c:a aac -b:a 128k \
  -f dash -seg_duration 4 \
  -window_size 5 -extra_window_size 2 \
  -use_template 1 -use_timeline 1 \
  -remove_at_exit 0 \
  live.mpd
```
And this one consuming the live stream:
```
ffmpeg -i live.mpd -y out.mp4
```

Against master the consumer process will fail nearly immediately trying to 
fetch segments that don't yet exist.
Against this branch the process runs until the livestream is complete, 
consuming all segments, then exits.

The fix works by checking the `minimumUpdatePeriod` in the manifest, which the 
[DASH-IF 
guidelines](https://dashif.org/Guidelines-TimingModel/#timing-mpd-updates-theend)
state should be removed once live content has ended. Whilst the attribute is 
present `get_current_fragment` will
sleep and refresh the manifest until new segments are added.

Signed-off-by: Matthew Crossley <[email protected]>


>From 7680e963036e20c46695ccf8d5e9cec9d3c4cbc9 Mon Sep 17 00:00:00 2001
From: Matthew Crossley <[email protected]>
Date: Fri, 6 Nov 2026 12:11:26 +0000
Subject: [PATCH] avformat/dashdec: pace fragment-open retries to avoid
 exhausting max reloads on live content

Mirror HLS demuxer's sleep mechanism in `reload_playlist`.

Demuxer would attempt to open fragments that do not yet exist in manifest and 
burn through
allowed reloads before fragment is written.

Signed-off-by: Matthew Crossley <[email protected]>
---
 libavformat/dashdec.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/libavformat/dashdec.c b/libavformat/dashdec.c
index 00f91fc205a..bb5676462e8 100644
--- a/libavformat/dashdec.c
+++ b/libavformat/dashdec.c
@@ -1591,6 +1591,7 @@ static int refresh_manifest(AVFormatContext *s)
     int n_subtitles = c->n_subtitles;
     struct representation **subtitles = c->subtitles;
     char *base_url = c->base_url;
+    int64_t minimum_update_period = c->minimum_update_period;
 
     c->base_url = NULL;
     c->n_videos = 0;
@@ -1599,6 +1600,7 @@ static int refresh_manifest(AVFormatContext *s)
     c->audios = NULL;
     c->n_subtitles = 0;
     c->subtitles = NULL;
+    c->minimum_update_period = -1;
     ret = parse_manifest(s, s->url, NULL);
     if (ret)
         goto finish;
@@ -1661,6 +1663,8 @@ finish:
         av_free(base_url);
     else
         c->base_url  = base_url;
+    if (ret)
+        c->minimum_update_period = minimum_update_period;
 
     if (c->subtitles)
         free_subtitle_list(c);
@@ -1715,6 +1719,13 @@ static struct fragment *get_current_fragment(struct 
representation *pls)
         }
     }
     if (c->is_live) {
+        int64_t reload_interval;
+        int64_t last_load;
+reload:
+        reload_count++;
+        if (reload_count > c->max_reload)
+            return NULL;
+
         min_seq_no = calc_min_seg_no(pls->parent, pls);
         max_seq_no = calc_max_seg_no(pls, c);
 
@@ -1726,6 +1737,18 @@ static struct fragment *get_current_fragment(struct 
representation *pls)
             pls->cur_seq_no = calc_cur_seg_no(pls->parent, pls);
         } else if (pls->cur_seq_no > max_seq_no) {
             av_log(pls->parent, AV_LOG_VERBOSE, "new fragment: min[%"PRId64"] 
max[%"PRId64"]\n", min_seq_no, max_seq_no);
+            if (c->minimum_update_period != -1) {
+                /* If our current place is ahead of the max sequences in the 
manifest
+                 * then sleep for half the update period time and refresh */
+                reload_interval = c->minimum_update_period * AV_TIME_BASE / 2;
+                last_load = av_gettime_relative();
+                while (av_gettime_relative() - last_load < reload_interval) {
+                    if (ff_check_interrupt(c->interrupt_callback))
+                        return NULL;
+                    av_usleep(100*1000);
+                }
+                goto reload;
+            }
         }
         seg = av_mallocz(sizeof(struct fragment));
         if (!seg) {
-- 
2.54.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to