[FFmpeg-devel] [PATCH] RTSP-MS 8/15: fix RTSP-MS UDP (was: disallow UDP/RTSP-MS)

Ronald S. Bultje rsbultje
Sun Jan 25 20:14:10 CET 2009


Hi,

On Tue, Jan 6, 2009 at 12:07 AM, Ronald S. Bultje <rsbultje at gmail.com> wrote:
> I haven't gotten UDP/RTSP-MS to work yet, so this patch explicitely
> disallows anything else than TCP/RTSP-MS.

Attached patch fixes this, I think. Negotiation succeeds, the data is
slightly different than for TCP but that will be handled in a
different patch.

The patch is dirty, in a way, because for UDP in RTSP-MS:
- the server expects the RTX stream to be SETUP'ed first, even if it's
not the first in the SDP. (For TCP, we ignore the RTX.)
- right now I create a RTSPStream+AVStream pair for the RTX stream. I
could in theory just create a AVStream-less RTSPStream since the
client doesn't need this, it's just for the session.
- we should use two ports for the RTX, and then the next (one) for all
data streams, so:

SETUP x.y.z/x.asf/rtx
Transport: client_port=[x]-[x+1]

OK

SETUP x.y.z/x.asf/stream=1
Transport: client_port=[x+2]

OK

SETUP x.y.z/x.asf/stream=2
Transport: client_port=[x+2]

OK

(etc. for stream=3-n)

This is what wireshark dumps of MS sessions give me and it works, so I
kept it simple for now. I tried different orders or port numbers but
it all fails at the second or third SETUP with either a 500 (Internal
Server Error) or a 461 (Unsupported Transport).

Ronald
-------------- next part --------------
Index: ffmpeg-svn/libavformat/rtsp.c
===================================================================
--- ffmpeg-svn.orig/libavformat/rtsp.c	2009-01-24 14:19:22.000000000 -0500
+++ ffmpeg-svn/libavformat/rtsp.c	2009-01-25 09:17:45.000000000 -0500
@@ -392,6 +392,8 @@
             codec_type = CODEC_TYPE_AUDIO;
         } else if (!strcmp(st_type, "video")) {
             codec_type = CODEC_TYPE_VIDEO;
+        } else if (!strcmp(st_type, "application")) {
+            codec_type = CODEC_TYPE_DATA;
         } else {
             s1->skip_media = 1;
             return;
@@ -886,7 +888,7 @@
                     int lower_transport, const char *real_challenge)
 {
     RTSPState *rt = s->priv_data;
-    int j, i, err, interleave = 0;
+    int rtx, j, i, err, interleave = 0;
     RTSPStream *rtsp_st;
     RTSPHeader reply1, *reply = &reply1;
     char cmd[2048];
@@ -904,12 +906,38 @@
     for(j = RTSP_RTP_PORT_MIN, i = 0; i < rt->nb_rtsp_streams; ++i) {
         char transport[2048];
 
+        /**
+         * WMS serves all UDP data over a single connection, the RTX, which
+         * isn't necessarily the first in the SDP but has to be the first
+         * to be set up, else the second/third SETUP will fail with a 461.
+         */
+        if (lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
+             rt->server_type == RTSP_SERVER_WMS) {
+            if (i == 0) {
+                /* rtx first */
+                for (rtx = 0; rtx < rt->nb_rtsp_streams; rtx++) {
+                    int len = strlen(rt->rtsp_streams[rtx]->control_url);
+                    if (len >= 4 &&
+                        !strcmp(rt->rtsp_streams[rtx]->control_url + len - 4, "/rtx"))
+                        break;
+                }
+                if (rtx == rt->nb_rtsp_streams)
+                    return -1; /* no RTX found */
+                rtsp_st = rt->rtsp_streams[rtx];
+            } else
+                rtsp_st = rt->rtsp_streams[i > rtx ? i : i - 1];
+        } else
         rtsp_st = rt->rtsp_streams[i];
 
         /* RTP/UDP */
         if (lower_transport == RTSP_LOWER_TRANSPORT_UDP) {
             char buf[256];
 
+            if (rt->server_type == RTSP_SERVER_WMS && i > 1) {
+                port = reply->transports[0].client_port_min;
+                goto have_port;
+            }
+
             /* first try in specified port range */
             if (RTSP_RTP_PORT_MIN != 0) {
                 while(j <= RTSP_RTP_PORT_MAX) {
@@ -930,18 +958,23 @@
 
         rtp_opened:
             port = rtp_get_local_port(rtsp_st->rtp_handle);
+        have_port:
             snprintf(transport, sizeof(transport) - 1,
                      "%s/UDP;", trans_pref);
             if (rt->server_type != RTSP_SERVER_REAL)
                 av_strlcat(transport, "unicast;", sizeof(transport));
             av_strlcatf(transport, sizeof(transport),
                      "client_port=%d", port);
-            if (rt->transport == RTSP_TRANSPORT_RTP)
+            if (rt->transport == RTSP_TRANSPORT_RTP &&
+                !(rt->server_type == RTSP_SERVER_WMS && i > 0))
                 av_strlcatf(transport, sizeof(transport), "-%d", port + 1);
         }
 
         /* RTP/TCP */
         else if (lower_transport == RTSP_LOWER_TRANSPORT_TCP) {
+            if (rt->server_type == RTSP_SERVER_WMS &&
+                s->streams[rtsp_st->stream_index]->codec->codec_type == CODEC_TYPE_DATA)
+                continue;
             snprintf(transport, sizeof(transport) - 1,
                      "%s/TCP;", trans_pref);
             if (rt->server_type != RTSP_SERVER_REAL)
@@ -1014,7 +1047,7 @@
                 /* XXX: also use address if specified */
                 snprintf(url, sizeof(url), "rtp://%s:%d",
                          host, reply->transports[0].server_port_min);
-                if (rtp_set_remote_url(rtsp_st->rtp_handle, url) < 0) {
+                if (i < 2 && rtp_set_remote_url(rtsp_st->rtp_handle, url) < 0) {
                     err = AVERROR_INVALIDDATA;
                     goto fail;
                 }
@@ -1278,11 +1311,13 @@
         fd_max = -1;
         for(i = 0; i < rt->nb_rtsp_streams; i++) {
             rtsp_st = rt->rtsp_streams[i];
+            if (rtsp_st->rtp_handle) {
             /* currently, we cannot probe RTCP handle because of blocking restrictions */
             rtp_get_file_handles(rtsp_st->rtp_handle, &fd1, &fd2);
             if (fd1 > fd_max)
                 fd_max = fd1;
             FD_SET(fd1, &rfds);
+            }
         }
         tv.tv_sec = 0;
         tv.tv_usec = 100 * 1000;
@@ -1290,6 +1325,7 @@
         if (n > 0) {
             for(i = 0; i < rt->nb_rtsp_streams; i++) {
                 rtsp_st = rt->rtsp_streams[i];
+                if (rtsp_st->rtp_handle) {
                 rtp_get_file_handles(rtsp_st->rtp_handle, &fd1, &fd2);
                 if (FD_ISSET(fd1, &rfds)) {
                     ret = url_read(rtsp_st->rtp_handle, buf, buf_size);
@@ -1298,6 +1334,7 @@
                         return ret;
                     }
                 }
+                }
             }
         }
     }



More information about the ffmpeg-devel mailing list