[FFmpeg-cvslog] rtspdec: Retry with TCP if UDP failed

Martin Storsjö git
Wed Jan 26 04:01:15 CET 2011


ffmpeg | branch: master | Martin Storsj? <martin at martin.st> | Mon Jan 10 12:45:24 2011 +0200| [4f40ec0552fd1247c67580f145290c8ed835c6c4] | committer: Michael Niedermayer

rtspdec: Retry with TCP if UDP failed

Signed-off-by: Janne Grunau <janne-ffmpeg at jannau.net>
(cherry picked from commit 2762a7a28b261a505a9002b92d4f7c04eeaacc1b)

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=4f40ec0552fd1247c67580f145290c8ed835c6c4
---

 libavformat/rtsp.c    |    4 +++-
 libavformat/rtsp.h    |   13 +++++++++++++
 libavformat/rtspdec.c |   41 ++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 56 insertions(+), 2 deletions(-)

diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c
index dddaaf4..ca9ce7c 100644
--- a/libavformat/rtsp.c
+++ b/libavformat/rtsp.c
@@ -1291,7 +1291,7 @@ int ff_rtsp_connect(AVFormatContext *s)
     int port, err, tcp_fd;
     RTSPMessageHeader reply1 = {0}, *reply = &reply1;
     int lower_transport_mask = 0;
-    char real_challenge[64];
+    char real_challenge[64] = "";
     struct sockaddr_storage peer;
     socklen_t peer_len = sizeof(peer);
 
@@ -1515,6 +1515,8 @@ redirect:
         }
     } while (err);
 
+    rt->lower_transport_mask = lower_transport_mask;
+    av_strlcpy(rt->real_challenge, real_challenge, sizeof(rt->real_challenge));
     rt->state = RTSP_STATE_IDLE;
     rt->seek_timestamp = 0; /* default is to start stream at position zero */
     return 0;
diff --git a/libavformat/rtsp.h b/libavformat/rtsp.h
index 6dc64b1..62bd3a2 100644
--- a/libavformat/rtsp.h
+++ b/libavformat/rtsp.h
@@ -248,6 +248,9 @@ typedef struct RTSPState {
      * of RTSPMessageHeader->real_challenge */
     enum RTSPServerType server_type;
 
+    /** the "RealChallenge1:" field from the server */
+    char real_challenge[64];
+
     /** plaintext authorization line (username:password) */
     char auth[128];
 
@@ -313,6 +316,16 @@ typedef struct RTSPState {
     /** Filter incoming UDP packets - receive packets only from the right
      * source address and port. */
     int filter_source;
+
+    /**
+     * A mask with all requested transport methods
+     */
+    int lower_transport_mask;
+
+    /**
+     * The number of returned packets
+     */
+    uint64_t packets;
 } RTSPState;
 
 /**
diff --git a/libavformat/rtspdec.c b/libavformat/rtspdec.c
index b910d4c..6a4b4af 100644
--- a/libavformat/rtspdec.c
+++ b/libavformat/rtspdec.c
@@ -229,6 +229,20 @@ found:
     *prtsp_st = rtsp_st;
     return len;
 }
+
+static int resetup_tcp(AVFormatContext *s)
+{
+    RTSPState *rt = s->priv_data;
+    char host[1024];
+    int port;
+
+    av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, NULL, 0,
+                 s->filename);
+    ff_rtsp_undo_setup(s);
+    return ff_rtsp_make_setup_request(s, host, port, RTSP_LOWER_TRANSPORT_TCP,
+                                      rt->real_challenge);
+}
+
 static int rtsp_read_packet(AVFormatContext *s, AVPacket *pkt)
 {
     RTSPState *rt = s->priv_data;
@@ -236,6 +250,7 @@ static int rtsp_read_packet(AVFormatContext *s, AVPacket *pkt)
     RTSPMessageHeader reply1, *reply = &reply1;
     char cmd[1024];
 
+retry:
     if (rt->server_type == RTSP_SERVER_REAL) {
         int i;
 
@@ -295,8 +310,32 @@ static int rtsp_read_packet(AVFormatContext *s, AVPacket *pkt)
     }
 
     ret = ff_rtsp_fetch_packet(s, pkt);
-    if (ret < 0)
+    if (ret < 0) {
+        if (ret == FF_NETERROR(ETIMEDOUT) && !rt->packets) {
+            if (rt->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
+                rt->lower_transport_mask & (1 << RTSP_LOWER_TRANSPORT_TCP)) {
+                RTSPMessageHeader reply1, *reply = &reply1;
+                av_log(s, AV_LOG_WARNING, "UDP timeout, retrying with TCP\n");
+                if (rtsp_read_pause(s) != 0)
+                    return -1;
+                // TEARDOWN is required on Real-RTSP, but might make
+                // other servers close the connection.
+                if (rt->server_type == RTSP_SERVER_REAL)
+                    ff_rtsp_send_cmd(s, "TEARDOWN", rt->control_uri, NULL,
+                                     reply, NULL);
+                rt->session_id[0] = '\0';
+                if (resetup_tcp(s) == 0) {
+                    rt->state = RTSP_STATE_IDLE;
+                    rt->need_subscription = 1;
+                    if (rtsp_read_play(s) != 0)
+                        return -1;
+                    goto retry;
+                }
+            }
+        }
         return ret;
+    }
+    rt->packets++;
 
     /* send dummy request to keep TCP connection alive */
     if ((av_gettime() - rt->last_cmd_time) / 1000000 >= rt->timeout / 2) {




More information about the ffmpeg-cvslog mailing list