]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/rtsp.c
Add a lowercase parameter to ff_data_to_hex
[ffmpeg] / libavformat / rtsp.c
index fafd27c05654393016f3973071b92178fd76526a..f466574758584568d88a3112520e788b223c52e4 100644 (file)
@@ -584,7 +584,13 @@ void ff_rtsp_close_streams(AVFormatContext *s)
                 if (s->oformat) {
                     AVFormatContext *rtpctx = rtsp_st->transport_priv;
                     av_write_trailer(rtpctx);
-                    url_fclose(rtpctx->pb);
+                    if (rt->lower_transport == RTSP_LOWER_TRANSPORT_TCP) {
+                        uint8_t *ptr;
+                        url_close_dyn_buf(rtpctx->pb, &ptr);
+                        av_free(ptr);
+                    } else {
+                        url_fclose(rtpctx->pb);
+                    }
                     av_metadata_free(&rtpctx->streams[0]->metadata);
                     av_metadata_free(&rtpctx->metadata);
                     av_free(rtpctx->streams[0]);
@@ -644,11 +650,20 @@ static void *rtsp_rtp_mux_open(AVFormatContext *s, AVStream *st,
     av_free(rtpctx->streams[0]->codec);
     rtpctx->streams[0]->codec = st->codec;
 
-    url_fdopen(&rtpctx->pb, handle);
+    if (handle) {
+        url_fdopen(&rtpctx->pb, handle);
+    } else
+        url_open_dyn_packet_buf(&rtpctx->pb, RTSP_TCP_MAX_PACKET_SIZE);
     ret = av_write_header(rtpctx);
 
     if (ret) {
-        url_fclose(rtpctx->pb);
+        if (handle) {
+            url_fclose(rtpctx->pb);
+        } else {
+            uint8_t *ptr;
+            url_close_dyn_buf(rtpctx->pb, &ptr);
+            av_free(ptr);
+        }
         av_free(rtpctx->streams[0]);
         av_free(rtpctx);
         return NULL;
@@ -861,7 +876,7 @@ void ff_rtsp_parse_line(RTSPMessageHeader *reply, const char *buf)
 }
 
 /* skip a RTP/TCP interleaved packet */
-static void rtsp_skip_packet(AVFormatContext *s)
+void ff_rtsp_skip_packet(AVFormatContext *s)
 {
     RTSPState *rt = s->priv_data;
     int ret, len, len1;
@@ -917,7 +932,7 @@ int ff_rtsp_read_reply(AVFormatContext *s, RTSPMessageHeader *reply,
                 if (return_on_interleaved_data) {
                     return 1;
                 } else
-                    rtsp_skip_packet(s);
+                    ff_rtsp_skip_packet(s);
             } else if (ch != '\r') {
                 if ((q - buf) < sizeof(buf) - 1)
                     *q++ = ch;
@@ -959,6 +974,11 @@ int ff_rtsp_read_reply(AVFormatContext *s, RTSPMessageHeader *reply,
     else
         av_free(content);
 
+    if (rt->seq != reply->seq) {
+        av_log(s, AV_LOG_WARNING, "CSeq %d expected, %d received.\n",
+            rt->seq, reply->seq);
+    }
+
     /* EOS */
     if (reply->notice == 2101 /* End-of-Stream Reached */      ||
         reply->notice == 2104 /* Start-of-Stream Reached */    ||
@@ -1014,9 +1034,7 @@ void ff_rtsp_send_cmd(AVFormatContext *s,
                       const char *cmd, RTSPMessageHeader *reply,
                       unsigned char **content_ptr)
 {
-    ff_rtsp_send_cmd_async(s, cmd);
-
-    ff_rtsp_read_reply(s, reply, content_ptr, 0);
+    ff_rtsp_send_cmd_with_content(s, cmd, reply, content_ptr, NULL, 0);
 }
 
 void ff_rtsp_send_cmd_with_content(AVFormatContext *s,
@@ -1296,10 +1314,9 @@ static int rtsp_read_play(AVFormatContext *s)
     return 0;
 }
 
-static int rtsp_setup_input_streams(AVFormatContext *s)
+static int rtsp_setup_input_streams(AVFormatContext *s, RTSPMessageHeader *reply)
 {
     RTSPState *rt = s->priv_data;
-    RTSPMessageHeader reply1, *reply = &reply1;
     char cmd[1024];
     unsigned char *content = NULL;
     int ret;
@@ -1435,9 +1452,11 @@ redirect:
         port = RTSP_DEFAULT_PORT;
 
     /* search for options */
-    option_list = strchr(path, '?');
+    option_list = strrchr(path, '?');
     if (option_list) {
-        filename = strchr(s->filename, '?');
+        /* Strip out the RTSP specific options, write out the rest of
+         * the options back into the same string. */
+        filename = option_list;
         while (option_list) {
             /* move the option pointer */
             option = ++option_list;
@@ -1447,14 +1466,17 @@ redirect:
 
             /* handle the options */
             if (!strcmp(option, "udp")) {
-                lower_transport_mask = (1<< RTSP_LOWER_TRANSPORT_UDP);
+                lower_transport_mask |= (1<< RTSP_LOWER_TRANSPORT_UDP);
             } else if (!strcmp(option, "multicast")) {
-                lower_transport_mask = (1<< RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
+                lower_transport_mask |= (1<< RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
             } else if (!strcmp(option, "tcp")) {
-                lower_transport_mask = (1<< RTSP_LOWER_TRANSPORT_TCP);
+                lower_transport_mask |= (1<< RTSP_LOWER_TRANSPORT_TCP);
             } else {
-                strcpy(++filename, option);
-                filename += strlen(option);
+                /* 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 = '&';
             }
         }
@@ -1465,11 +1487,12 @@ redirect:
         lower_transport_mask = (1 << RTSP_LOWER_TRANSPORT_NB) - 1;
 
     if (s->oformat) {
-        /* Only UDP output is supported at the moment. */
-        lower_transport_mask &= 1 << RTSP_LOWER_TRANSPORT_UDP;
+        /* Only UDP or TCP - UDP multicast isn't supported. */
+        lower_transport_mask &= (1 << RTSP_LOWER_TRANSPORT_UDP) |
+                                (1 << RTSP_LOWER_TRANSPORT_TCP);
         if (!lower_transport_mask) {
             av_log(s, AV_LOG_ERROR, "Unsupported lower transport method, "
-                                    "only UDP is supported for output.\n");
+                                    "only UDP and TCP are supported for output.\n");
             err = AVERROR(EINVAL);
             goto fail;
         }
@@ -1490,10 +1513,13 @@ redirect:
                     NULL, 0, NI_NUMERICHOST);
     }
 
+    /* Construct the URI used in request; this is similar to s->filename,
+     * but with authentication credentials removed and RTSP specific options
+     * stripped out. */
+    ff_url_join(rt->control_uri, sizeof(rt->control_uri), "rtsp", NULL,
+                host, port, "%s", path);
     /* request options supported by the server; this also detects server
      * type */
-    av_strlcpy(rt->control_uri, s->filename,
-               sizeof(rt->control_uri));
     for (rt->server_type = RTSP_SERVER_RTP;;) {
         snprintf(cmd, sizeof(cmd),
                  "OPTIONS %s RTSP/1.0\r\n", rt->control_uri);
@@ -1531,7 +1557,7 @@ redirect:
     }
 
     if (s->iformat)
-        err = rtsp_setup_input_streams(s);
+        err = rtsp_setup_input_streams(s, reply);
     else
         err = rtsp_setup_output_streams(s, host);
     if (err)
@@ -1647,7 +1673,9 @@ static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st,
             if (tcp_fd != -1 && FD_ISSET(tcp_fd, &rfds)) {
                 RTSPMessageHeader reply;
 
-                ff_rtsp_read_reply(s, &reply, NULL, 0);
+                ret = ff_rtsp_read_reply(s, &reply, NULL, 0);
+                if (ret < 0)
+                    return ret;
                 /* XXX: parse message */
                 if (rt->state != RTSP_STATE_STREAMING)
                     return 0;