]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/rtsp.c
Merge remote-tracking branch 'qatar/master'
[ffmpeg] / libavformat / rtsp.c
index c2a0d26e5eeefe3e82816c1b45e985fe0f6d599b..b28fb519cb347cfec15a60df57c48507ee32ee05 100644 (file)
@@ -73,7 +73,7 @@
 
 const AVOption ff_rtsp_options[] = {
     { "initial_pause",  "Don't start playing the stream immediately", OFFSET(initial_pause), AV_OPT_TYPE_INT, {0}, 0, 1, DEC },
-    FF_RTP_FLAG_OPTS(RTSPState, rtp_muxer_flags),
+    FF_RTP_FLAG_OPTS(RTSPState, rtp_muxer_flags)
     { "rtsp_transport", "RTSP transport protocols", OFFSET(lower_transport_mask), AV_OPT_TYPE_FLAGS, {0}, INT_MIN, INT_MAX, DEC|ENC, "rtsp_transport" }, \
     { "udp", "UDP", 0, AV_OPT_TYPE_CONST, {1 << RTSP_LOWER_TRANSPORT_UDP}, 0, 0, DEC|ENC, "rtsp_transport" }, \
     { "tcp", "TCP", 0, AV_OPT_TYPE_CONST, {1 << RTSP_LOWER_TRANSPORT_TCP}, 0, 0, DEC|ENC, "rtsp_transport" }, \
@@ -900,9 +900,13 @@ int ff_rtsp_read_reply(AVFormatContext *s, RTSPMessageHeader *reply,
     char buf[4096], buf1[1024], *q;
     unsigned char ch;
     const char *p;
-    int ret, content_length, line_count = 0;
+    int ret, content_length, line_count = 0, request = 0;
     unsigned char *content = NULL;
 
+start:
+    line_count = 0;
+    request = 0;
+    content = NULL;
     memset(reply, 0, sizeof(*reply));
 
     /* parse reply (XXX: use buffers) */
@@ -938,9 +942,15 @@ int ff_rtsp_read_reply(AVFormatContext *s, RTSPMessageHeader *reply,
         if (line_count == 0) {
             /* get reply code */
             get_word(buf1, sizeof(buf1), &p);
-            get_word(buf1, sizeof(buf1), &p);
-            reply->status_code = atoi(buf1);
-            av_strlcpy(reply->reason, p, sizeof(reply->reason));
+            if (!strncmp(buf1, "RTSP/", 5)) {
+                get_word(buf1, sizeof(buf1), &p);
+                reply->status_code = atoi(buf1);
+                av_strlcpy(reply->reason, p, sizeof(reply->reason));
+            } else {
+                av_strlcpy(reply->reason, buf1, sizeof(reply->reason)); // method
+                get_word(buf1, sizeof(buf1), &p); // object
+                request = 1;
+            }
         } else {
             ff_rtsp_parse_line(reply, p, rt, method);
             av_strlcat(rt->last_reply, p,    sizeof(rt->last_reply));
@@ -949,7 +959,7 @@ int ff_rtsp_read_reply(AVFormatContext *s, RTSPMessageHeader *reply,
         line_count++;
     }
 
-    if (rt->session_id[0] == '\0' && reply->session_id[0] != '\0')
+    if (rt->session_id[0] == '\0' && reply->session_id[0] != '\0' && !request)
         av_strlcpy(rt->session_id, reply->session_id, sizeof(rt->session_id));
 
     content_length = reply->content_length;
@@ -964,6 +974,44 @@ int ff_rtsp_read_reply(AVFormatContext *s, RTSPMessageHeader *reply,
     else
         av_free(content);
 
+    if (request) {
+        char buf[1024];
+        char base64buf[AV_BASE64_SIZE(sizeof(buf))];
+        const char* ptr = buf;
+
+        if (!strcmp(reply->reason, "OPTIONS")) {
+            snprintf(buf, sizeof(buf), "RTSP/1.0 200 OK\r\n");
+            if (reply->seq)
+                av_strlcatf(buf, sizeof(buf), "CSeq: %d\r\n", reply->seq);
+            if (reply->session_id[0])
+                av_strlcatf(buf, sizeof(buf), "Session: %s\r\n",
+                                              reply->session_id);
+        } else {
+            snprintf(buf, sizeof(buf), "RTSP/1.0 501 Not Implemented\r\n");
+        }
+        av_strlcat(buf, "\r\n", sizeof(buf));
+
+        if (rt->control_transport == RTSP_MODE_TUNNEL) {
+            av_base64_encode(base64buf, sizeof(base64buf), buf, strlen(buf));
+            ptr = base64buf;
+        }
+        ffurl_write(rt->rtsp_hd_out, ptr, strlen(ptr));
+
+        rt->last_cmd_time = av_gettime();
+        /* Even if the request from the server had data, it is not the data
+         * that the caller wants or expects. The memory could also be leaked
+         * if the actual following reply has content data. */
+        if (content_ptr)
+            av_freep(content_ptr);
+        /* If method is set, this is called from ff_rtsp_send_cmd,
+         * where a reply to exactly this request is awaited. For
+         * callers from within packet receiving, we just want to
+         * return to the caller and go back to receiving packets. */
+        if (method)
+            goto start;
+        return 0;
+    }
+
     if (rt->seq != reply->seq) {
         av_log(s, AV_LOG_WARNING, "CSeq %d expected, %d received.\n",
             rt->seq, reply->seq);
@@ -1074,7 +1122,7 @@ int ff_rtsp_send_cmd_with_content(AVFormatContext *s,
 {
     RTSPState *rt = s->priv_data;
     HTTPAuthType cur_auth_type;
-    int ret;
+    int ret, attempts = 0;
 
 retry:
     cur_auth_type = rt->auth_state.auth_type;
@@ -1085,9 +1133,11 @@ retry:
 
     if ((ret = ff_rtsp_read_reply(s, reply, content_ptr, 0, method) ) < 0)
         return ret;
+    attempts++;
 
-    if (reply->status_code == 401 && cur_auth_type == HTTP_AUTH_NONE &&
-        rt->auth_state.auth_type != HTTP_AUTH_NONE)
+    if (reply->status_code == 401 &&
+        (cur_auth_type == HTTP_AUTH_NONE || rt->auth_state.stale) &&
+        rt->auth_state.auth_type != HTTP_AUTH_NONE && attempts < 2)
         goto retry;
 
     if (reply->status_code > 400){
@@ -1297,7 +1347,7 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port,
             break;
         }
         case RTSP_LOWER_TRANSPORT_UDP_MULTICAST: {
-            char url[1024], namebuf[50];
+            char url[1024], namebuf[50], optbuf[20] = "";
             struct sockaddr_storage addr;
             int port, ttl;
 
@@ -1310,10 +1360,12 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port,
                 port      = rtsp_st->sdp_port;
                 ttl       = rtsp_st->sdp_ttl;
             }
+            if (ttl > 0)
+                snprintf(optbuf, sizeof(optbuf), "?ttl=%d", ttl);
             getnameinfo((struct sockaddr*) &addr, sizeof(addr),
                         namebuf, sizeof(namebuf), NULL, 0, NI_NUMERICHOST);
             ff_url_join(url, sizeof(url), "rtp", NULL, namebuf,
-                        port, "?ttl=%d", ttl);
+                        port, "%s", optbuf);
             if (ffurl_open(&rtsp_st->rtp_handle, url, AVIO_FLAG_READ_WRITE,
                            &s->interrupt_callback, NULL) < 0) {
                 err = AVERROR_INVALIDDATA;
@@ -1352,7 +1404,6 @@ int ff_rtsp_connect(AVFormatContext *s)
 {
     RTSPState *rt = s->priv_data;
     char host[1024], path[1024], tcpname[1024], cmd[2048], auth[128];
-    char *option_list, *option, *filename;
     int port, err, tcp_fd;
     RTSPMessageHeader reply1 = {0}, *reply = &reply1;
     int lower_transport_mask = 0;
@@ -1389,51 +1440,6 @@ redirect:
     if (port < 0)
         port = RTSP_DEFAULT_PORT;
 
-#if FF_API_RTSP_URL_OPTIONS
-    /* search for options */
-    option_list = strrchr(path, '?');
-    if (option_list) {
-        /* Strip out the RTSP specific options, write out the rest of
-         * the options back into the same string. */
-        filename = option_list;
-        while (option_list) {
-            int handled = 1;
-            /* move the option pointer */
-            option = ++option_list;
-            option_list = strchr(option_list, '&');
-            if (option_list)
-                *option_list = 0;
-
-            /* handle the options */
-            if (!strcmp(option, "udp")) {
-                lower_transport_mask |= (1<< RTSP_LOWER_TRANSPORT_UDP);
-            } else if (!strcmp(option, "multicast")) {
-                lower_transport_mask |= (1<< RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
-            } else if (!strcmp(option, "tcp")) {
-                lower_transport_mask |= (1<< RTSP_LOWER_TRANSPORT_TCP);
-            } else if(!strcmp(option, "http")) {
-                lower_transport_mask |= (1<< RTSP_LOWER_TRANSPORT_TCP);
-                rt->control_transport = RTSP_MODE_TUNNEL;
-            } else if (!strcmp(option, "filter_src")) {
-                rt->rtsp_flags |= RTSP_FLAG_FILTER_SRC;
-            } else {
-                /* Write options back into the buffer, using memmove instead
-                 * of strcpy since the strings may overlap. */
-                int len = strlen(option);
-                memmove(++filename, option, len);
-                filename += len;
-                if (option_list) *filename = '&';
-                handled = 0;
-            }
-            if (handled)
-                av_log(s, AV_LOG_WARNING, "Options passed via URL are "
-                                          "deprecated, use -rtsp_transport "
-                                          "and -rtsp_flags instead.\n");
-        }
-        *filename = 0;
-    }
-#endif
-
     if (!lower_transport_mask)
         lower_transport_mask = (1 << RTSP_LOWER_TRANSPORT_NB) - 1;
 
@@ -1844,7 +1850,7 @@ static int sdp_probe(AVProbeData *p1)
     return 0;
 }
 
-static int sdp_read_header(AVFormatContext *s, AVFormatParameters *ap)
+static int sdp_read_header(AVFormatContext *s)
 {
     RTSPState *rt = s->priv_data;
     RTSPStream *rtsp_st;
@@ -1930,8 +1936,7 @@ static int rtp_probe(AVProbeData *p)
     return 0;
 }
 
-static int rtp_read_header(AVFormatContext *s,
-                           AVFormatParameters *ap)
+static int rtp_read_header(AVFormatContext *s)
 {
     uint8_t recvbuf[1500];
     char host[500], sdp[500];
@@ -1969,6 +1974,9 @@ static int rtp_read_header(AVFormatContext *s,
             continue;
         }
 
+        if (RTP_PT_IS_RTCP(recvbuf[1]))
+            continue;
+
         payload_type = recvbuf[1] & 0x7f;
         break;
     }
@@ -2008,7 +2016,7 @@ static int rtp_read_header(AVFormatContext *s,
 
     rt->media_type_mask = (1 << (AVMEDIA_TYPE_DATA+1)) - 1;
 
-    ret = sdp_read_header(s, ap);
+    ret = sdp_read_header(s);
     s->pb = NULL;
     return ret;
 
@@ -2038,4 +2046,3 @@ AVInputFormat ff_rtp_demuxer = {
     .priv_class     = &rtp_demuxer_class
 };
 #endif /* CONFIG_RTP_DEMUXER */
-