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>
This commit is contained in:
Thibault Saunier 2024-12-11 22:00:56 -03:00 committed by GStreamer Marge Bot
parent ba4a260c07
commit 6d0c0d5d29
6 changed files with 63 additions and 6 deletions

View File

@ -1404,6 +1404,20 @@
"type": "guint64", "type": "guint64",
"writable": true "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": { "min-bitrate": {
"blurb": "Minimum bitrate to use when switching to alternates (bits/s)", "blurb": "Minimum bitrate to use when switching to alternates (bits/s)",
"conditionally-available": false, "conditionally-available": false,

View File

@ -36,7 +36,6 @@
G_BEGIN_DECLS G_BEGIN_DECLS
#define NUM_LOOKBACK_FRAGMENTS 3 #define NUM_LOOKBACK_FRAGMENTS 3
#define MAX_DOWNLOAD_ERROR_COUNT 3
/* Internal, so not using GST_FLOW_CUSTOM_SUCCESS_N */ /* Internal, so not using GST_FLOW_CUSTOM_SUCCESS_N */
#define GST_ADAPTIVE_DEMUX_FLOW_SWITCH (GST_FLOW_CUSTOM_SUCCESS_2 + 2) #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 * Head is the period being outputted, or to be outputted first
* Tail is where new streams get added */ * Tail is where new streams get added */
GQueue *periods; 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) static inline gboolean gst_adaptive_demux_scheduler_lock(GstAdaptiveDemux *d)

View File

@ -1212,6 +1212,7 @@ on_download_error (DownloadRequest * request, DownloadRequestState state,
request->state, last_status_code, request->state, last_status_code,
stream->download_error_count, live, stream->download_error_retry); 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) if (!stream->download_error_retry && ((last_status_code / 100 == 4 && live)
|| last_status_code / 100 == 5)) { || last_status_code / 100 == 5)) {
/* 4xx/5xx */ /* 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 /* 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 */ * Have to assume we are falling behind and cause a manifest reload */
GST_DEBUG_OBJECT (stream, "Converting error of live stream to EOS"); GST_DEBUG_OBJECT (stream, "Converting error of live stream to EOS");
@ -1271,7 +1272,7 @@ on_download_error (DownloadRequest * request, DownloadRequestState state,
return; return;
} else { } else {
/* retry same segment */ /* 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); gst_adaptive_demux2_stream_error (stream);
return; return;
} }
@ -2007,7 +2008,8 @@ gst_adaptive_demux2_stream_load_a_fragment (GstAdaptiveDemux2Stream * stream)
default: default:
if (ret <= GST_FLOW_ERROR) { if (ret <= GST_FLOW_ERROR) {
GST_WARNING_OBJECT (demux, "Error while downloading fragment"); 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); gst_adaptive_demux2_stream_error (stream);
return FALSE; return FALSE;
} }

View File

@ -113,6 +113,7 @@ GST_DEBUG_CATEGORY_EXTERN (adaptivedemux2_debug);
#define GST_CAT_DEFAULT adaptivedemux2_debug #define GST_CAT_DEFAULT adaptivedemux2_debug
#define DEFAULT_FAILED_COUNT 3 #define DEFAULT_FAILED_COUNT 3
#define DEFAULT_MAX_RETRIES 3
#define DEFAULT_CONNECTION_BITRATE 0 #define DEFAULT_CONNECTION_BITRATE 0
#define DEFAULT_BANDWIDTH_TARGET_RATIO 0.8f #define DEFAULT_BANDWIDTH_TARGET_RATIO 0.8f
@ -133,6 +134,7 @@ enum
{ {
PROP_0, PROP_0,
PROP_CONNECTION_SPEED, PROP_CONNECTION_SPEED,
PROP_MAX_RETRIES,
PROP_BANDWIDTH_TARGET_RATIO, PROP_BANDWIDTH_TARGET_RATIO,
PROP_CONNECTION_BITRATE, PROP_CONNECTION_BITRATE,
PROP_MIN_BITRATE, PROP_MIN_BITRATE,
@ -288,6 +290,11 @@ gst_adaptive_demux_set_property (GObject * object, guint prop_id,
GST_OBJECT_LOCK (demux); GST_OBJECT_LOCK (demux);
switch (prop_id) { 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: case PROP_CONNECTION_SPEED:
demux->connection_speed = g_value_get_uint (value) * 1000; demux->connection_speed = g_value_get_uint (value) * 1000;
GST_DEBUG_OBJECT (demux, "Connection speed set to %u", 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); GST_OBJECT_LOCK (demux);
switch (prop_id) { switch (prop_id) {
case PROP_MAX_RETRIES:
g_value_set_int (value, demux->priv->max_retries);
break;
case PROP_CONNECTION_SPEED: case PROP_CONNECTION_SPEED:
g_value_set_uint (value, demux->connection_speed / 1000); g_value_set_uint (value, demux->connection_speed / 1000);
break; break;
@ -506,6 +516,20 @@ gst_adaptive_demux_class_init (GstAdaptiveDemuxClass * klass)
G_PARAM_READABLE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_READABLE | GST_PARAM_MUTABLE_PLAYING |
G_PARAM_STATIC_STRINGS)); 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_element_class_add_static_pad_template (gstelement_class,
&gst_adaptive_demux_audiosrc_template); &gst_adaptive_demux_audiosrc_template);
gst_element_class_add_static_pad_template (gstelement_class, 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_video = DEFAULT_CURRENT_LEVEL_TIME_VIDEO;
demux->current_level_time_audio = DEFAULT_CURRENT_LEVEL_TIME_AUDIO; 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); gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
@ -3004,7 +3029,7 @@ gst_adaptive_demux_manifest_update_cb (GstAdaptiveDemux * demux)
} else { } else {
demux->priv->update_failed_count++; 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_WARNING_OBJECT (demux, "Could not update the playlist, flow: %s",
gst_flow_get_name (ret)); gst_flow_get_name (ret));
} else { } else {
@ -3956,3 +3981,13 @@ gst_adaptive_demux_get_loop (GstAdaptiveDemux * demux)
{ {
return gst_adaptive_demux_loop_ref (demux->priv->scheduler_task); 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;
}

View File

@ -481,6 +481,7 @@ gdouble gst_adaptive_demux_play_rate (GstAdaptiveDemux *demux);
void gst_adaptive_demux2_manual_manifest_update (GstAdaptiveDemux * demux); void gst_adaptive_demux2_manual_manifest_update (GstAdaptiveDemux * demux);
GstAdaptiveDemuxLoop *gst_adaptive_demux_get_loop (GstAdaptiveDemux *demux); GstAdaptiveDemuxLoop *gst_adaptive_demux_get_loop (GstAdaptiveDemux *demux);
gint gst_adaptive_demux_max_retries (GstAdaptiveDemux *self);
G_END_DECLS G_END_DECLS

View File

@ -470,7 +470,8 @@ static void
handle_download_error (GstHLSDemuxPlaylistLoader * pl, handle_download_error (GstHLSDemuxPlaylistLoader * pl,
GstHLSDemuxPlaylistLoaderPrivate * priv) 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, GST_DEBUG_OBJECT (pl,
"Reached %d download failures on URI %s. Reporting the failure", "Reached %d download failures on URI %s. Reporting the failure",
priv->download_error_count, priv->loading_playlist_uri); priv->download_error_count, priv->loading_playlist_uri);