From 268a25b9797d4abf9822ff897a169bdad52ffe0f Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Fri, 25 Nov 2022 03:57:38 +1100 Subject: [PATCH] hlsdemux2: Use partial segment for playlist update interval When playing LL-HLS playlists in LL-HLS mode, update the playlist more often (on the partial segment interval) or else we end up downloading them in bursts and playing further from the live edge than intended. Part-of: --- .../adaptivedemux2/hls/gsthlsdemux-stream.c | 52 +++++++++++++++++++ .../adaptivedemux2/hls/gsthlsdemux-stream.h | 3 ++ .../ext/adaptivedemux2/hls/gsthlsdemux.c | 21 ++------ 3 files changed, 60 insertions(+), 16 deletions(-) diff --git a/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux-stream.c b/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux-stream.c index 2c4e6eb4b8..cbfdc032ab 100644 --- a/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux-stream.c +++ b/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux-stream.c @@ -1675,6 +1675,58 @@ lost_sync: } } +GstClockTime +gst_hls_demux_stream_get_playlist_reload_interval (GstHLSDemuxStream * stream) +{ + GstHLSMediaPlaylist *playlist = stream->playlist; + + if (playlist == NULL) + return GST_CLOCK_TIME_NONE; /* No playlist yet */ + + if (!gst_hls_media_playlist_is_live (playlist)) + return GST_CLOCK_TIME_NONE; /* Not live playback */ + + /* Use the most recent segment (or part segment) duration, as per + * https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis-11#section-6.3.4 + */ + GstClockTime target_duration = GST_CLOCK_TIME_NONE; + GstClockTime min_reload_interval = playlist->targetduration / 2; + + if (playlist->segments->len) { + GstM3U8MediaSegment *last_seg = + g_ptr_array_index (playlist->segments, playlist->segments->len - 1); + + target_duration = last_seg->duration; + + if (stream->llhls_enabled && last_seg->partial_segments) { + GstM3U8PartialSegment *last_part = + g_ptr_array_index (last_seg->partial_segments, + last_seg->partial_segments->len - 1); + + target_duration = last_part->duration; + if (GST_CLOCK_TIME_IS_VALID (playlist->partial_targetduration)) { + min_reload_interval = playlist->partial_targetduration / 2; + } else { + min_reload_interval = target_duration / 2; + } + } + } else if (stream->llhls_enabled + && GST_CLOCK_TIME_IS_VALID (playlist->partial_targetduration)) { + target_duration = playlist->partial_targetduration; + min_reload_interval = target_duration / 2; + } else if (playlist->version > 5) { + target_duration = playlist->targetduration; + } + + if (playlist->reloaded && target_duration > min_reload_interval) { + GST_DEBUG_OBJECT (stream, + "Playlist didn't change previously, returning lower update interval"); + target_duration = min_reload_interval; + } + + return target_duration; +} + static GstFlowReturn gst_hls_demux_stream_update_rendition_playlist (GstHLSDemux * demux, GstHLSDemuxStream * stream) diff --git a/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux-stream.h b/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux-stream.h index 0df4fdd01e..3ca4a44860 100644 --- a/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux-stream.h +++ b/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux-stream.h @@ -165,6 +165,9 @@ gst_hls_demux_stream_seek (GstAdaptiveDemux2Stream * stream, gboolean forward, GstFlowReturn gst_hls_demux_stream_update_media_playlist (GstHLSDemuxStream * stream, gchar ** uri, GError ** err); +GstClockTime +gst_hls_demux_stream_get_playlist_reload_interval (GstHLSDemuxStream * stream); + void gst_hls_demux_stream_clear_pending_data (GstHLSDemuxStream * hls_stream, gboolean force); diff --git a/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux.c b/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux.c index f5c453d2ad..c400e409fc 100644 --- a/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux.c +++ b/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux.c @@ -745,7 +745,7 @@ gst_hls_demux_is_live (GstAdaptiveDemux * demux) GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux); gboolean is_live = FALSE; - if (hlsdemux->main_stream) + if (hlsdemux->main_stream && hlsdemux->main_stream->playlist) is_live = gst_hls_media_playlist_is_live (hlsdemux->main_stream->playlist); return is_live; @@ -1258,22 +1258,11 @@ gst_hls_demux_get_manifest_update_interval (GstAdaptiveDemux * demux) { GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux); GstClockTime target_duration = 5 * GST_SECOND; + GstHLSDemuxStream *main_stream = hlsdemux->main_stream; - if (hlsdemux->main_stream && hlsdemux->main_stream->playlist) { - GstHLSMediaPlaylist *playlist = hlsdemux->main_stream->playlist; - - if (playlist->version > 5) { - target_duration = hlsdemux->main_stream->playlist->targetduration; - } else if (playlist->segments->len) { - GstM3U8MediaSegment *last_seg = - g_ptr_array_index (playlist->segments, playlist->segments->len - 1); - target_duration = last_seg->duration; - } - if (playlist->reloaded && target_duration > (playlist->targetduration / 2)) { - GST_DEBUG_OBJECT (demux, - "Playlist didn't change previously, returning lower update interval"); - target_duration /= 2; - } + if (main_stream) { + target_duration = + gst_hls_demux_stream_get_playlist_reload_interval (main_stream); } GST_DEBUG_OBJECT (demux, "Returning update interval of %" GST_TIME_FORMAT,