PR #25386 opened by danog URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25386 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25386.patch
A playlist whose streams all get discarded is only closed when that happens before the first packet, and even then the data read while probing stays buffered. If it's discarded later, e.g. when a player switches to another audio rendition: - the playlist keeps being read until the end of its current segment; - packets of the discarded streams are still returned; - when the streams are enabled again, it resumes with stale data and skips a segment; - an fMP4 playlist doesn't resume at all. This closes the playlist and drops its buffered data, as `hls_read_seek()` does, whenever it is no longer needed. It was tested with an API program that discards a rendition at 6 s and re-enables it at 12 s, on MPEG-TS, fMP4, live, muxed audio+video variants and WebVTT. No discarded packets are returned, playback resumes at the right segment, and output before the first packet is unchanged. The CLI can't toggle discard mid-stream, so there's no FATE test. Kodi carries this as a patch in https://github.com/xbmc/xbmc/pull/30047, where VideoPlayer discards the audio renditions it doesn't play; its maintainers asked for FFmpeg changes to go upstream. >From d91c9e9eb781af8ebecf832e1d45d5c757ac4e0b Mon Sep 17 00:00:00 2001 From: Daniil Gentili <[email protected]> Date: Fri, 23 Oct 2026 11:55:46 +0200 Subject: [PATCH] avformat/hls: stop playlists discarded during playback A playlist whose streams all get discarded is only closed when that happens before the first packet, and even then the data read while probing stays buffered. Discarded later, e.g. when a player switches to another audio rendition, the playlist keeps being read until the end of its current segment and packets of the discarded streams are still returned. When the streams are enabled again, it resumes with the stale data and skips a segment, and an fMP4 playlist does not resume at all. Close the playlist and drop its buffered data, as when seeking, whenever it is no longer needed. Signed-off-by: Daniil Gentili <[email protected]> --- libavformat/hls.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/libavformat/hls.c b/libavformat/hls.c index c68b5e88cf5..3f64c402507 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -2800,7 +2800,7 @@ static int hls_read_header(AVFormatContext *s) return 0; } -static int recheck_discard_flags(AVFormatContext *s, int first) +static int recheck_discard_flags(AVFormatContext *s) { HLSContext *c = s->priv_data; int i, changed = 0; @@ -2829,11 +2829,21 @@ static int recheck_discard_flags(AVFormatContext *s, int first) pls->seek_stream_index = -1; } av_log(s, AV_LOG_INFO, "Now receiving playlist %d, segment %"PRId64"\n", i, pls->cur_seq_no); - } else if (first && !cur_needed && pls->needed) { + } else if (!cur_needed && pls->needed) { + AVIOContext *const pb = &pls->pb.pub; + ff_format_io_close(pls->parent, &pls->input); pls->input_read_done = 0; ff_format_io_close(pls->parent, &pls->input_next); pls->input_next_requested = 0; + /* Drop buffered data as hls_read_seek() does; if needed again, + * the playlist restarts at another segment. */ + av_packet_unref(pls->pkt); + pb->buf_end = pb->buf_ptr = pb->buffer; + pb->pos = 0; + if (pls->ctx) + ff_read_frame_flush(pls->ctx); + pls->cur_init_section = NULL; if (pls->is_subtitle) avformat_close_input(&pls->ctx); pls->needed = 0; @@ -2914,7 +2924,7 @@ static int hls_read_packet(AVFormatContext *s, AVPacket *pkt) HLSContext *c = s->priv_data; int ret, i, minplaylist = -1; - recheck_discard_flags(s, c->first_packet); + recheck_discard_flags(s); c->first_packet = 0; for (i = 0; i < c->n_playlists; i++) { -- 2.54.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
