diff --git a/subprojects/gst-plugins-good/docs/gst_plugins_cache.json b/subprojects/gst-plugins-good/docs/gst_plugins_cache.json index 71d8f3b3bf..03a0476aff 100644 --- a/subprojects/gst-plugins-good/docs/gst_plugins_cache.json +++ b/subprojects/gst-plugins-good/docs/gst_plugins_cache.json @@ -21407,6 +21407,18 @@ "type": "GstStructure", "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": { "blurb": "Whether to ignore the x-server-ip-address server header reply", "conditionally-available": false, diff --git a/subprojects/gst-plugins-good/gst/rtsp/gstrtspsrc.c b/subprojects/gst-plugins-good/gst/rtsp/gstrtspsrc.c index fdde01f880..8aaad5d561 100644 --- a/subprojects/gst-plugins-good/gst/rtsp/gstrtspsrc.c +++ b/subprojects/gst-plugins-good/gst/rtsp/gstrtspsrc.c @@ -314,6 +314,7 @@ gst_rtsp_backchannel_get_type (void) #define DEFAULT_ONVIF_RATE_CONTROL TRUE #define DEFAULT_IS_LIVE TRUE #define DEFAULT_IGNORE_X_SERVER_REPLY FALSE +#define DEFAULT_FORCE_NON_COMPLIANT_URL FALSE enum { @@ -365,6 +366,7 @@ enum PROP_IS_LIVE, PROP_IGNORE_X_SERVER_REPLY, PROP_EXTRA_HTTP_REQUEST_HEADERS, + PROP_FORCE_NON_COMPLIANT_URL, }; #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", 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: * @rtspsrc: a #GstRTSPSrc @@ -1548,6 +1570,7 @@ gst_rtspsrc_init (GstRTSPSrc * src) src->group_id = GST_GROUP_ID_INVALID; src->prop_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 */ 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"); } break; + case PROP_FORCE_NON_COMPLIANT_URL: + rtspsrc->force_non_compliant_url = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -2084,6 +2110,9 @@ gst_rtspsrc_get_property (GObject * object, guint prop_id, GValue * value, case PROP_EXTRA_HTTP_REQUEST_HEADERS: gst_value_set_structure (value, rtspsrc->prop_extra_http_request_headers); break; + case PROP_FORCE_NON_COMPLIANT_URL: + g_value_set_boolean (value, rtspsrc->force_non_compliant_url); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -7577,6 +7606,31 @@ gst_rtspsrc_setup_streams_end (GstRTSPSrc * src, gboolean async) 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. * * 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; gchar *transports; gint retry = 0; - gboolean tried_non_compliant_url = FALSE; + gboolean tried_non_compliant_url; guint mask = 0; gboolean selected; GstCaps *caps; @@ -7722,6 +7776,14 @@ gst_rtspsrc_setup_streams_start (GstRTSPSrc * src, gboolean async) if (!protocol_masks[mask]) 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: GST_DEBUG_OBJECT (src, "protocols = 0x%x, protocol mask = 0x%x", protocols, protocol_masks[mask]); @@ -7846,30 +7908,11 @@ gst_rtspsrc_setup_streams_start (GstRTSPSrc * src, gboolean async) */ if (!tried_non_compliant_url && stream->control_url && !gst_uri_is_valid (stream->control_url)) { - const gchar *base; - gst_rtsp_message_unset (&request); gst_rtsp_message_unset (&response); gst_rtspsrc_stream_free_udp (stream); - g_free (stream->conninfo.location); - 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); + try_non_compliant_url (src, stream); tried_non_compliant_url = TRUE; diff --git a/subprojects/gst-plugins-good/gst/rtsp/gstrtspsrc.h b/subprojects/gst-plugins-good/gst/rtsp/gstrtspsrc.h index 2adfcba0f8..eae0376caa 100644 --- a/subprojects/gst-plugins-good/gst/rtsp/gstrtspsrc.h +++ b/subprojects/gst-plugins-good/gst/rtsp/gstrtspsrc.h @@ -281,6 +281,7 @@ struct _GstRTSPSrc { gboolean is_live; gboolean ignore_x_server_reply; GstStructure *prop_extra_http_request_headers; + gboolean force_non_compliant_url; /* state */ GstRTSPState state;