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]
