rtspsrc: expose property for forcing usage of non-compliant URLs

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7346>
This commit is contained in:
Mathieu Duponchelle 2024-07-03 16:03:47 +02:00 committed by GStreamer Marge Bot
parent c29f2e8632
commit 6500fc7666
3 changed files with 77 additions and 21 deletions

View file

@ -21407,6 +21407,18 @@
"type": "GstStructure", "type": "GstStructure",
"writable": true "writable": true
}, },
"force-non-compliant-url": {
"blurb": "Revert to old non-compliant method of constructing URLs",
"conditionally-available": false,
"construct": false,
"construct-only": false,
"controllable": false,
"default": "false",
"mutable": "null",
"readable": true,
"type": "gboolean",
"writable": true
},
"ignore-x-server-reply": { "ignore-x-server-reply": {
"blurb": "Whether to ignore the x-server-ip-address server header reply", "blurb": "Whether to ignore the x-server-ip-address server header reply",
"conditionally-available": false, "conditionally-available": false,

View file

@ -314,6 +314,7 @@ gst_rtsp_backchannel_get_type (void)
#define DEFAULT_ONVIF_RATE_CONTROL TRUE #define DEFAULT_ONVIF_RATE_CONTROL TRUE
#define DEFAULT_IS_LIVE TRUE #define DEFAULT_IS_LIVE TRUE
#define DEFAULT_IGNORE_X_SERVER_REPLY FALSE #define DEFAULT_IGNORE_X_SERVER_REPLY FALSE
#define DEFAULT_FORCE_NON_COMPLIANT_URL FALSE
enum enum
{ {
@ -365,6 +366,7 @@ enum
PROP_IS_LIVE, PROP_IS_LIVE,
PROP_IGNORE_X_SERVER_REPLY, PROP_IGNORE_X_SERVER_REPLY,
PROP_EXTRA_HTTP_REQUEST_HEADERS, PROP_EXTRA_HTTP_REQUEST_HEADERS,
PROP_FORCE_NON_COMPLIANT_URL,
}; };
#define GST_TYPE_RTSP_NAT_METHOD (gst_rtsp_nat_method_get_type()) #define GST_TYPE_RTSP_NAT_METHOD (gst_rtsp_nat_method_get_type())
@ -1117,6 +1119,26 @@ gst_rtspsrc_class_init (GstRTSPSrcClass * klass)
"Extra headers to append to HTTP requests when in tunneled mode", "Extra headers to append to HTTP requests when in tunneled mode",
GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstRTSPSrc:force-non-compliant-url
*
* There are various non-compliant servers that don't require control URLs
* that are not resolved correctly but instead are just appended.
*
* As some of these servers will nevertheless reply OK to SETUP requests
* even if they didn't handle URIs correctly, this property can be set to
* revert to the old non-compliant method for constructing URLs.
*
* Since: 1.24.7
*/
g_object_class_install_property (gobject_class,
PROP_FORCE_NON_COMPLIANT_URL,
g_param_spec_boolean ("force-non-compliant-url",
"Force non-compliant URL",
"Revert to old non-compliant method of constructing URLs",
DEFAULT_FORCE_NON_COMPLIANT_URL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/** /**
* GstRTSPSrc::handle-request: * GstRTSPSrc::handle-request:
* @rtspsrc: a #GstRTSPSrc * @rtspsrc: a #GstRTSPSrc
@ -1548,6 +1570,7 @@ gst_rtspsrc_init (GstRTSPSrc * src)
src->group_id = GST_GROUP_ID_INVALID; src->group_id = GST_GROUP_ID_INVALID;
src->prop_extra_http_request_headers = src->prop_extra_http_request_headers =
gst_structure_new_empty ("extra-http-request-headers"); gst_structure_new_empty ("extra-http-request-headers");
src->force_non_compliant_url = DEFAULT_FORCE_NON_COMPLIANT_URL;
/* get a list of all extensions */ /* get a list of all extensions */
src->extensions = gst_rtsp_ext_list_get (); src->extensions = gst_rtsp_ext_list_get ();
@ -1908,6 +1931,9 @@ gst_rtspsrc_set_property (GObject * object, guint prop_id, const GValue * value,
gst_structure_new_empty ("extra-http-request-headers"); gst_structure_new_empty ("extra-http-request-headers");
} }
break; break;
case PROP_FORCE_NON_COMPLIANT_URL:
rtspsrc->force_non_compliant_url = g_value_get_boolean (value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -2084,6 +2110,9 @@ gst_rtspsrc_get_property (GObject * object, guint prop_id, GValue * value,
case PROP_EXTRA_HTTP_REQUEST_HEADERS: case PROP_EXTRA_HTTP_REQUEST_HEADERS:
gst_value_set_structure (value, rtspsrc->prop_extra_http_request_headers); gst_value_set_structure (value, rtspsrc->prop_extra_http_request_headers);
break; break;
case PROP_FORCE_NON_COMPLIANT_URL:
g_value_set_boolean (value, rtspsrc->force_non_compliant_url);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -7577,6 +7606,31 @@ gst_rtspsrc_setup_streams_end (GstRTSPSrc * src, gboolean async)
return GST_RTSP_OK; return GST_RTSP_OK;
} }
static void
try_non_compliant_url (GstRTSPSrc * src, GstRTSPStream * stream)
{
const gchar *base;
base = get_aggregate_control (src);
g_free (stream->conninfo.location);
/* Make sure to not accumulate too many `/` */
if ((g_str_has_suffix (base, "/")
&& !g_str_has_suffix (stream->control_url, "/"))
|| (!g_str_has_suffix (base, "/")
&& g_str_has_suffix (stream->control_url, "/"))
)
stream->conninfo.location = g_strconcat (base, stream->control_url, NULL);
else if (g_str_has_suffix (base, "/")
&& g_str_has_suffix (stream->control_url, "/"))
stream->conninfo.location =
g_strconcat (base, stream->control_url + 1, NULL);
else
stream->conninfo.location =
g_strconcat (base, "/", stream->control_url, NULL);
}
/* Perform the SETUP request for all the streams. /* Perform the SETUP request for all the streams.
* *
* We ask the server for a specific transport, which initially includes all the * We ask the server for a specific transport, which initially includes all the
@ -7640,7 +7694,7 @@ gst_rtspsrc_setup_streams_start (GstRTSPSrc * src, gboolean async)
GstRTSPConnInfo *conninfo; GstRTSPConnInfo *conninfo;
gchar *transports; gchar *transports;
gint retry = 0; gint retry = 0;
gboolean tried_non_compliant_url = FALSE; gboolean tried_non_compliant_url;
guint mask = 0; guint mask = 0;
gboolean selected; gboolean selected;
GstCaps *caps; GstCaps *caps;
@ -7722,6 +7776,14 @@ gst_rtspsrc_setup_streams_start (GstRTSPSrc * src, gboolean async)
if (!protocol_masks[mask]) if (!protocol_masks[mask])
goto no_protocols; goto no_protocols;
if (src->force_non_compliant_url) {
try_non_compliant_url (src, stream);
tried_non_compliant_url = TRUE;
} else {
tried_non_compliant_url = FALSE;
}
retry: retry:
GST_DEBUG_OBJECT (src, "protocols = 0x%x, protocol mask = 0x%x", protocols, GST_DEBUG_OBJECT (src, "protocols = 0x%x, protocol mask = 0x%x", protocols,
protocol_masks[mask]); protocol_masks[mask]);
@ -7846,30 +7908,11 @@ gst_rtspsrc_setup_streams_start (GstRTSPSrc * src, gboolean async)
*/ */
if (!tried_non_compliant_url && stream->control_url if (!tried_non_compliant_url && stream->control_url
&& !gst_uri_is_valid (stream->control_url)) { && !gst_uri_is_valid (stream->control_url)) {
const gchar *base;
gst_rtsp_message_unset (&request); gst_rtsp_message_unset (&request);
gst_rtsp_message_unset (&response); gst_rtsp_message_unset (&response);
gst_rtspsrc_stream_free_udp (stream); gst_rtspsrc_stream_free_udp (stream);
g_free (stream->conninfo.location); try_non_compliant_url (src, stream);
base = get_aggregate_control (src);
/* Make sure to not accumulate too many `/` */
if ((g_str_has_suffix (base, "/")
&& !g_str_has_suffix (stream->control_url, "/"))
|| (!g_str_has_suffix (base, "/")
&& g_str_has_suffix (stream->control_url, "/"))
)
stream->conninfo.location =
g_strconcat (base, stream->control_url, NULL);
else if (g_str_has_suffix (base, "/")
&& g_str_has_suffix (stream->control_url, "/"))
stream->conninfo.location =
g_strconcat (base, stream->control_url + 1, NULL);
else
stream->conninfo.location =
g_strconcat (base, "/", stream->control_url, NULL);
tried_non_compliant_url = TRUE; tried_non_compliant_url = TRUE;

View file

@ -281,6 +281,7 @@ struct _GstRTSPSrc {
gboolean is_live; gboolean is_live;
gboolean ignore_x_server_reply; gboolean ignore_x_server_reply;
GstStructure *prop_extra_http_request_headers; GstStructure *prop_extra_http_request_headers;
gboolean force_non_compliant_url;
/* state */ /* state */
GstRTSPState state; GstRTSPState state;