]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/rtspdec.c
Merge remote branch 'qatar/master'
[ffmpeg] / libavformat / rtspdec.c
index cdcef3843097237c2492be992a5d90d63ff08cf9..5833a5209ac4fce07e1ef2585debb21e8a236d0c 100644 (file)
@@ -28,6 +28,7 @@
 #include "os_support.h"
 #include "rtsp.h"
 #include "rdt.h"
+#include "url.h"
 
 //#define DEBUG
 //#define DEBUG_RTP_TCP
@@ -60,28 +61,26 @@ static int rtsp_read_play(AVFormatContext *s)
             cmd[0] = 0;
         } else {
             snprintf(cmd, sizeof(cmd),
-                     "Range: npt=%0.3f-\r\n",
-                     (double)rt->seek_timestamp / AV_TIME_BASE);
+                     "Range: npt=%"PRId64".%03"PRId64"-\r\n",
+                     rt->seek_timestamp / AV_TIME_BASE,
+                     rt->seek_timestamp / (AV_TIME_BASE / 1000) % 1000);
         }
         ff_rtsp_send_cmd(s, "PLAY", rt->control_uri, cmd, reply, NULL);
         if (reply->status_code != RTSP_STATUS_OK) {
             return -1;
         }
-        if (rt->transport == RTSP_TRANSPORT_RTP) {
+        if (rt->transport == RTSP_TRANSPORT_RTP &&
+            reply->range_start != AV_NOPTS_VALUE) {
             for (i = 0; i < rt->nb_rtsp_streams; i++) {
                 RTSPStream *rtsp_st = rt->rtsp_streams[i];
                 RTPDemuxContext *rtpctx = rtsp_st->transport_priv;
                 AVStream *st = NULL;
-                if (!rtpctx)
+                if (!rtpctx || rtsp_st->stream_index < 0)
                     continue;
-                if (rtsp_st->stream_index >= 0)
-                    st = s->streams[rtsp_st->stream_index];
-                if (reply->range_start != AV_NOPTS_VALUE) {
-                    if (st)
-                        rtpctx->range_start_offset =
-                            av_rescale_q(reply->range_start, AV_TIME_BASE_Q,
-                                         st->time_base);
-                }
+                st = s->streams[rtsp_st->stream_index];
+                rtpctx->range_start_offset =
+                    av_rescale_q(reply->range_start, AV_TIME_BASE_Q,
+                                 st->time_base);
             }
         }
     }
@@ -89,6 +88,24 @@ static int rtsp_read_play(AVFormatContext *s)
     return 0;
 }
 
+/* pause the stream */
+static int rtsp_read_pause(AVFormatContext *s)
+{
+    RTSPState *rt = s->priv_data;
+    RTSPMessageHeader reply1, *reply = &reply1;
+
+    if (rt->state != RTSP_STATE_STREAMING)
+        return 0;
+    else if (!(rt->server_type == RTSP_SERVER_REAL && rt->need_subscription)) {
+        ff_rtsp_send_cmd(s, "PAUSE", rt->control_uri, NULL, reply, NULL);
+        if (reply->status_code != RTSP_STATUS_OK) {
+            return -1;
+        }
+    }
+    rt->state = RTSP_STATE_PAUSED;
+    return 0;
+}
+
 int ff_rtsp_setup_input_streams(AVFormatContext *s, RTSPMessageHeader *reply)
 {
     RTSPState *rt = s->priv_data;
@@ -121,7 +138,7 @@ int ff_rtsp_setup_input_streams(AVFormatContext *s, RTSPMessageHeader *reply)
     ret = ff_sdp_parse(s, (const char *)content);
     av_freep(&content);
     if (ret < 0)
-        return AVERROR_INVALIDDATA;
+        return ret;
 
     return 0;
 }
@@ -169,7 +186,7 @@ int ff_rtsp_tcp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st,
     RTSPStream *rtsp_st;
 
 #ifdef DEBUG_RTP_TCP
-    dprintf(s, "tcp_read_packet:\n");
+    av_dlog(s, "tcp_read_packet:\n");
 #endif
 redo:
     for (;;) {
@@ -184,18 +201,18 @@ redo:
         if (rt->state != RTSP_STATE_STREAMING)
             return 0;
     }
-    ret = url_read_complete(rt->rtsp_hd, buf, 3);
+    ret = ffurl_read_complete(rt->rtsp_hd, buf, 3);
     if (ret != 3)
         return -1;
     id  = buf[0];
     len = AV_RB16(buf + 1);
 #ifdef DEBUG_RTP_TCP
-    dprintf(s, "id=%d len=%d\n", id, len);
+    av_dlog(s, "id=%d len=%d\n", id, len);
 #endif
     if (len > buf_size || len < 12)
         goto redo;
     /* get the data */
-    ret = url_read_complete(rt->rtsp_hd, buf, len);
+    ret = ffurl_read_complete(rt->rtsp_hd, buf, len);
     if (ret != len)
         return -1;
     if (rt->transport == RTSP_TRANSPORT_RDT &&
@@ -214,6 +231,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;
@@ -221,6 +252,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;
 
@@ -253,7 +285,7 @@ static int rtsp_read_packet(AVFormatContext *s, AVPacket *pkt)
             for (i = 0; i < rt->nb_rtsp_streams; i++) {
                 rule_nr = 0;
                 for (r = 0; r < s->nb_streams; r++) {
-                    if (s->streams[r]->priv_data == rt->rtsp_streams[i]) {
+                    if (s->streams[r]->id == i) {
                         if (s->streams[r]->discard != AVDISCARD_ALL) {
                             if (!first)
                                 av_strlcat(rt->last_subscription, ",",
@@ -280,12 +312,36 @@ static int rtsp_read_packet(AVFormatContext *s, AVPacket *pkt)
     }
 
     ret = ff_rtsp_fetch_packet(s, pkt);
-    if (ret < 0)
+    if (ret < 0) {
+        if (ret == AVERROR(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) {
-        if (rt->server_type == RTSP_SERVER_WMS) {
+        if (rt->server_type != RTSP_SERVER_REAL) {
             ff_rtsp_send_cmd_async(s, "GET_PARAMETER", rt->control_uri, NULL);
         } else {
             ff_rtsp_send_cmd_async(s, "OPTIONS", "*", NULL);
@@ -295,24 +351,6 @@ static int rtsp_read_packet(AVFormatContext *s, AVPacket *pkt)
     return 0;
 }
 
-/* pause the stream */
-static int rtsp_read_pause(AVFormatContext *s)
-{
-    RTSPState *rt = s->priv_data;
-    RTSPMessageHeader reply1, *reply = &reply1;
-
-    if (rt->state != RTSP_STATE_STREAMING)
-        return 0;
-    else if (!(rt->server_type == RTSP_SERVER_REAL && rt->need_subscription)) {
-        ff_rtsp_send_cmd(s, "PAUSE", rt->control_uri, NULL, reply, NULL);
-        if (reply->status_code != RTSP_STATUS_OK) {
-            return -1;
-        }
-    }
-    rt->state = RTSP_STATE_PAUSED;
-    return 0;
-}
-
 static int rtsp_read_seek(AVFormatContext *s, int stream_index,
                           int64_t timestamp, int flags)
 {
@@ -346,7 +384,7 @@ static int rtsp_read_close(AVFormatContext *s)
 #if 0
     /* NOTE: it is valid to flush the buffer here */
     if (rt->lower_transport == RTSP_LOWER_TRANSPORT_TCP) {
-        url_fclose(&rt->rtsp_gb);
+        avio_close(&rt->rtsp_gb);
     }
 #endif
     ff_rtsp_send_cmd_async(s, "TEARDOWN", rt->control_uri, NULL);
@@ -359,7 +397,7 @@ static int rtsp_read_close(AVFormatContext *s)
     return 0;
 }
 
-AVInputFormat rtsp_demuxer = {
+AVInputFormat ff_rtsp_demuxer = {
     "rtsp",
     NULL_IF_CONFIG_SMALL("RTSP input format"),
     sizeof(RTSPState),