From 6d0c0d5d298e72eff880ede18f4194bfee4b9b47 Mon Sep 17 00:00:00 2001 From: Thibault Saunier <tsaunier@igalia.com> Date: Wed, 11 Dec 2024 22:00:56 -0300 Subject: [PATCH] adaptivedemux2: Expose a `max-retries` property So the user can configure what is the maximum number of time HTTP requests can be performed Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8128> --- .../docs/gst_plugins_cache.json | 14 +++++++ .../adaptivedemux2/gstadaptivedemux-private.h | 6 ++- .../adaptivedemux2/gstadaptivedemux-stream.c | 8 ++-- .../ext/adaptivedemux2/gstadaptivedemux.c | 37 ++++++++++++++++++- .../ext/adaptivedemux2/gstadaptivedemux.h | 1 + .../hls/gsthlsdemux-playlist-loader.c | 3 +- 6 files changed, 63 insertions(+), 6 deletions(-) diff --git a/subprojects/gst-plugins-good/docs/gst_plugins_cache.json b/subprojects/gst-plugins-good/docs/gst_plugins_cache.json index f856f950ab..16f90e9837 100644 --- a/subprojects/gst-plugins-good/docs/gst_plugins_cache.json +++ b/subprojects/gst-plugins-good/docs/gst_plugins_cache.json @@ -1404,6 +1404,20 @@ "type": "guint64", "writable": true }, + "max-retries": { + "blurb": "Maximum number of retries for HTTP requests (-1=infinite)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "3", + "max": "2147483647", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gint", + "writable": true + }, "min-bitrate": { "blurb": "Minimum bitrate to use when switching to alternates (bits/s)", "conditionally-available": false, diff --git a/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux-private.h b/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux-private.h index b80a92ad3c..b72219bf11 100644 --- a/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux-private.h +++ b/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux-private.h @@ -36,7 +36,6 @@ G_BEGIN_DECLS #define NUM_LOOKBACK_FRAGMENTS 3 -#define MAX_DOWNLOAD_ERROR_COUNT 3 /* Internal, so not using GST_FLOW_CUSTOM_SUCCESS_N */ #define GST_ADAPTIVE_DEMUX_FLOW_SWITCH (GST_FLOW_CUSTOM_SUCCESS_2 + 2) @@ -164,6 +163,11 @@ struct _GstAdaptiveDemuxPrivate * Head is the period being outputted, or to be outputted first * Tail is where new streams get added */ GQueue *periods; + + /* The maximum number of times HTTP request can be required before considering + * failed */ + gint max_retries; + }; static inline gboolean gst_adaptive_demux_scheduler_lock(GstAdaptiveDemux *d) diff --git a/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux-stream.c b/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux-stream.c index 2aa23bb5c8..7c1bf82837 100644 --- a/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux-stream.c +++ b/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux-stream.c @@ -1212,6 +1212,7 @@ on_download_error (DownloadRequest * request, DownloadRequestState state, request->state, last_status_code, stream->download_error_count, live, stream->download_error_retry); + gint max_retries = gst_adaptive_demux_max_retries (demux); if (!stream->download_error_retry && ((last_status_code / 100 == 4 && live) || last_status_code / 100 == 5)) { /* 4xx/5xx */ @@ -1255,7 +1256,7 @@ on_download_error (DownloadRequest * request, DownloadRequestState state, } } - if (++stream->download_error_count >= MAX_DOWNLOAD_ERROR_COUNT) { + if (max_retries >= 0 && ++stream->download_error_count >= max_retries) { /* looks like there is no way of knowing when a live stream has ended * Have to assume we are falling behind and cause a manifest reload */ GST_DEBUG_OBJECT (stream, "Converting error of live stream to EOS"); @@ -1271,7 +1272,7 @@ on_download_error (DownloadRequest * request, DownloadRequestState state, return; } else { /* retry same segment */ - if (++stream->download_error_count > MAX_DOWNLOAD_ERROR_COUNT) { + if (max_retries >= 0 && ++stream->download_error_count > max_retries) { gst_adaptive_demux2_stream_error (stream); return; } @@ -2007,7 +2008,8 @@ gst_adaptive_demux2_stream_load_a_fragment (GstAdaptiveDemux2Stream * stream) default: if (ret <= GST_FLOW_ERROR) { GST_WARNING_OBJECT (demux, "Error while downloading fragment"); - if (++stream->download_error_count > MAX_DOWNLOAD_ERROR_COUNT) { + gint max_retries = gst_adaptive_demux_max_retries (demux); + if (max_retries >= 0 && ++stream->download_error_count > max_retries) { gst_adaptive_demux2_stream_error (stream); return FALSE; } diff --git a/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux.c b/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux.c index 40b4706cfb..92d52147d3 100644 --- a/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux.c +++ b/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux.c @@ -113,6 +113,7 @@ GST_DEBUG_CATEGORY_EXTERN (adaptivedemux2_debug); #define GST_CAT_DEFAULT adaptivedemux2_debug #define DEFAULT_FAILED_COUNT 3 +#define DEFAULT_MAX_RETRIES 3 #define DEFAULT_CONNECTION_BITRATE 0 #define DEFAULT_BANDWIDTH_TARGET_RATIO 0.8f @@ -133,6 +134,7 @@ enum { PROP_0, PROP_CONNECTION_SPEED, + PROP_MAX_RETRIES, PROP_BANDWIDTH_TARGET_RATIO, PROP_CONNECTION_BITRATE, PROP_MIN_BITRATE, @@ -288,6 +290,11 @@ gst_adaptive_demux_set_property (GObject * object, guint prop_id, GST_OBJECT_LOCK (demux); switch (prop_id) { + case PROP_MAX_RETRIES: + demux->priv->max_retries = g_value_get_int (value); + GST_DEBUG_OBJECT (demux, "Maximum retries set to %u", + demux->priv->max_retries); + break; case PROP_CONNECTION_SPEED: demux->connection_speed = g_value_get_uint (value) * 1000; GST_DEBUG_OBJECT (demux, "Connection speed set to %u", @@ -339,6 +346,9 @@ gst_adaptive_demux_get_property (GObject * object, guint prop_id, GST_OBJECT_LOCK (demux); switch (prop_id) { + case PROP_MAX_RETRIES: + g_value_set_int (value, demux->priv->max_retries); + break; case PROP_CONNECTION_SPEED: g_value_set_uint (value, demux->connection_speed / 1000); break; @@ -506,6 +516,20 @@ gst_adaptive_demux_class_init (GstAdaptiveDemuxClass * klass) G_PARAM_READABLE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_STATIC_STRINGS)); + /** + * GstAdaptiveDemux2:max-retries: + * + * Maximum number of times HTTP request can be retried before considering + * the request as failed (-1=infinite) + * + * Since: 1.26 + */ + g_object_class_install_property (gobject_class, PROP_MAX_RETRIES, + g_param_spec_int ("max-retries", "Maximum Retries", + "Maximum number of retries for HTTP requests (-1=infinite)", + -1, G_MAXUINT, DEFAULT_MAX_RETRIES, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_element_class_add_static_pad_template (gstelement_class, &gst_adaptive_demux_audiosrc_template); gst_element_class_add_static_pad_template (gstelement_class, @@ -588,6 +612,7 @@ gst_adaptive_demux_init (GstAdaptiveDemux * demux, demux->current_level_time_video = DEFAULT_CURRENT_LEVEL_TIME_VIDEO; demux->current_level_time_audio = DEFAULT_CURRENT_LEVEL_TIME_AUDIO; + demux->priv->max_retries = DEFAULT_MAX_RETRIES; gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad); @@ -3004,7 +3029,7 @@ gst_adaptive_demux_manifest_update_cb (GstAdaptiveDemux * demux) } else { demux->priv->update_failed_count++; - if (demux->priv->update_failed_count <= DEFAULT_FAILED_COUNT) { + if (demux->priv->update_failed_count <= demux->priv->max_retries) { GST_WARNING_OBJECT (demux, "Could not update the playlist, flow: %s", gst_flow_get_name (ret)); } else { @@ -3956,3 +3981,13 @@ gst_adaptive_demux_get_loop (GstAdaptiveDemux * demux) { return gst_adaptive_demux_loop_ref (demux->priv->scheduler_task); } + +gint +gst_adaptive_demux_max_retries (GstAdaptiveDemux * self) +{ + GST_OBJECT_LOCK (self); + gint res = self->priv->max_retries; + GST_OBJECT_UNLOCK (self); + + return res; +} diff --git a/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux.h b/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux.h index b0ed01868e..50956206f1 100644 --- a/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux.h +++ b/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux.h @@ -481,6 +481,7 @@ gdouble gst_adaptive_demux_play_rate (GstAdaptiveDemux *demux); void gst_adaptive_demux2_manual_manifest_update (GstAdaptiveDemux * demux); GstAdaptiveDemuxLoop *gst_adaptive_demux_get_loop (GstAdaptiveDemux *demux); +gint gst_adaptive_demux_max_retries (GstAdaptiveDemux *self); G_END_DECLS diff --git a/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux-playlist-loader.c b/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux-playlist-loader.c index e5da0ba371..763c1bb4a6 100644 --- a/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux-playlist-loader.c +++ b/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux-playlist-loader.c @@ -470,7 +470,8 @@ static void handle_download_error (GstHLSDemuxPlaylistLoader * pl, GstHLSDemuxPlaylistLoaderPrivate * priv) { - if (++priv->download_error_count > MAX_DOWNLOAD_ERROR_COUNT) { + gint max_retries = gst_adaptive_demux_max_retries (priv->demux); + if (max_retries >= 0 && ++priv->download_error_count > max_retries) { GST_DEBUG_OBJECT (pl, "Reached %d download failures on URI %s. Reporting the failure", priv->download_error_count, priv->loading_playlist_uri);