rtspsrc: Retry SETUP with non-compliant URL resolution on "Bad Request" and "Not...
authorSebastian Dröge <sebastian@centricular.com>
Thu, 6 Oct 2022 12:02:22 +0000 (15:02 +0300)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Fri, 7 Oct 2022 09:12:00 +0000 (09:12 +0000)
Various RTSP servers/cameras assume base and control URL to be simply
appended instead of being resolved according to the relative URL
resolution algorithm as mandated by the RTSP specification.

To work around this, try using such a non-compliant control URL if the
server didn't like the URL used in the first SETUP request.

Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1447
Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/922

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3127>

subprojects/gst-plugins-good/gst/rtsp/gstrtspsrc.c

index a6eec43..fe34dd2 100644 (file)
@@ -7402,6 +7402,7 @@ gst_rtspsrc_setup_streams_start (GstRTSPSrc * src, gboolean async)
     GstRTSPConnInfo *conninfo;
     gchar *transports;
     gint retry = 0;
+    gboolean tried_non_compliant_url = FALSE;
     guint mask = 0;
     gboolean selected;
     GstCaps *caps;
@@ -7594,6 +7595,47 @@ gst_rtspsrc_setup_streams_start (GstRTSPSrc * src, gboolean async)
           continue;
         else
           goto retry;
+      case GST_RTSP_STS_BAD_REQUEST:
+      case GST_RTSP_STS_NOT_FOUND:
+        /* There are various non-compliant servers that don't require control
+         * URLs that are not resolved correctly but instead are just appended.
+         * See e.g.
+         *   https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/922
+         *   https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1447
+         */
+        if (!tried_non_compliant_url && stream->control_url
+            && !g_str_has_prefix (stream->control_url, "rtsp://")) {
+          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);
+
+          tried_non_compliant_url = TRUE;
+
+          goto retry;
+        }
+
+        /* fall through */
       default:
         /* cleanup of leftover transport and move to the next stream */
         gst_rtspsrc_stream_free_udp (stream);