rtspdec: Retry with TCP if UDP failed

Signed-off-by: Janne Grunau <janne-ffmpeg@jannau.net>
(cherry picked from commit 2762a7a28b)
This commit is contained in:
Martin Storsjö 2011-01-10 12:45:24 +02:00 committed by Michael Niedermayer
parent 2afd30bf7a
commit 4f40ec0552
3 changed files with 56 additions and 2 deletions

View File

@ -1291,7 +1291,7 @@ int ff_rtsp_connect(AVFormatContext *s)
int port, err, tcp_fd; int port, err, tcp_fd;
RTSPMessageHeader reply1 = {0}, *reply = &reply1; RTSPMessageHeader reply1 = {0}, *reply = &reply1;
int lower_transport_mask = 0; int lower_transport_mask = 0;
char real_challenge[64]; char real_challenge[64] = "";
struct sockaddr_storage peer; struct sockaddr_storage peer;
socklen_t peer_len = sizeof(peer); socklen_t peer_len = sizeof(peer);
@ -1515,6 +1515,8 @@ redirect:
} }
} while (err); } 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->state = RTSP_STATE_IDLE;
rt->seek_timestamp = 0; /* default is to start stream at position zero */ rt->seek_timestamp = 0; /* default is to start stream at position zero */
return 0; return 0;

View File

@ -248,6 +248,9 @@ typedef struct RTSPState {
* of RTSPMessageHeader->real_challenge */ * of RTSPMessageHeader->real_challenge */
enum RTSPServerType server_type; enum RTSPServerType server_type;
/** the "RealChallenge1:" field from the server */
char real_challenge[64];
/** plaintext authorization line (username:password) */ /** plaintext authorization line (username:password) */
char auth[128]; char auth[128];
@ -313,6 +316,16 @@ typedef struct RTSPState {
/** Filter incoming UDP packets - receive packets only from the right /** Filter incoming UDP packets - receive packets only from the right
* source address and port. */ * source address and port. */
int filter_source; int filter_source;
/**
* A mask with all requested transport methods
*/
int lower_transport_mask;
/**
* The number of returned packets
*/
uint64_t packets;
} RTSPState; } RTSPState;
/** /**

View File

@ -229,6 +229,20 @@ found:
*prtsp_st = rtsp_st; *prtsp_st = rtsp_st;
return len; 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) static int rtsp_read_packet(AVFormatContext *s, AVPacket *pkt)
{ {
RTSPState *rt = s->priv_data; RTSPState *rt = s->priv_data;
@ -236,6 +250,7 @@ static int rtsp_read_packet(AVFormatContext *s, AVPacket *pkt)
RTSPMessageHeader reply1, *reply = &reply1; RTSPMessageHeader reply1, *reply = &reply1;
char cmd[1024]; char cmd[1024];
retry:
if (rt->server_type == RTSP_SERVER_REAL) { if (rt->server_type == RTSP_SERVER_REAL) {
int i; int i;
@ -295,8 +310,32 @@ static int rtsp_read_packet(AVFormatContext *s, AVPacket *pkt)
} }
ret = ff_rtsp_fetch_packet(s, 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; return ret;
}
rt->packets++;
/* send dummy request to keep TCP connection alive */ /* send dummy request to keep TCP connection alive */
if ((av_gettime() - rt->last_cmd_time) / 1000000 >= rt->timeout / 2) { if ((av_gettime() - rt->last_cmd_time) / 1000000 >= rt->timeout / 2) {