aboutsummaryrefslogtreecommitdiffstats
path: root/libavformat
diff options
context:
space:
mode:
authorMartin Storsjö <martin@martin.st>2011-01-10 12:45:24 +0200
committerJanne Grunau <janne-ffmpeg@jannau.net>2011-01-24 22:49:36 +0100
commit2762a7a28b261a505a9002b92d4f7c04eeaacc1b (patch)
tree51a37efaa522715ea75a6597b8e0dfa1de816f1f /libavformat
parente836b1b0859798488d8ba45a837dc27bac2ee99f (diff)
downloadffmpeg-2762a7a28b261a505a9002b92d4f7c04eeaacc1b.tar.gz
rtspdec: Retry with TCP if UDP failed
Signed-off-by: Janne Grunau <janne-ffmpeg@jannau.net>
Diffstat (limited to 'libavformat')
-rw-r--r--libavformat/rtsp.c4
-rw-r--r--libavformat/rtsp.h13
-rw-r--r--libavformat/rtspdec.c41
3 files changed, 56 insertions, 2 deletions
diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c
index dddaaf4237..ca9ce7cf21 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 6dc64b19ae..62bd3a2ecc 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 b910d4cdb9..6a4b4af2b3 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) {