Five patches in this series, addressing comments from everyone.

My soc repo is also updated. I've pulled against the latest ffmpeg
trunk, so we can use the av_base64_size macro and the interleaving fix
Martin made.

http://github.com/j0sh/ffmpeg-soc/tree/rtsp-tunneling

On 3 June 2010 11:51, Ronald S. Bultje <[email protected]> wrote:
> Hi,
>
> On Wed, Jun 2, 2010 at 6:59 PM, Josh Allmann <[email protected]> wrote:
>> First three are related to http, the last adds actual tunnelling
>> support to rtsp.
>
> HTTP doesn't need the new flag, you can always open delayed.

Done. Also, after talking with Martin about this on IRC, I also
special-cased the size parameter to force a header fetch. However, I
can just add a separate ff_http_connect function along the lines of my
first patchset if that's preferable.

>
> For RTSP/HTTP.
>
>
>> +    /* base64 encode rtsp if tunnelling */
>> +    if (rt->rtsp_hd_out != rt->rtsp_hd) {
>> +        if (!av_base64_encode(base64buf, sizeof(base64buf), buf, 
>> strlen(buf))) {
>> +            av_log(s, AV_LOG_ERROR, "Unable to base64 encode RTSP.\n");
>> +            return;
>> +        }
>> +        out_buf = base64buf;
>> +    }
>> +
>
> I don't like the if at the top, I'd add a rtsp_protocol_mode with an
> enum (like the transport enums in rtsp.h), using
> RTSP_PROTOCOL_MODE_PLAIN or RTSP_PROTOCOL_MODE_HTTP. You can also call
> it tunnel_mode or so.

Done.

>
>> -    url_write(rt->rtsp_hd, buf, strlen(buf));
>> +    url_write(rt->rtsp_hd_out, out_buf, strlen(out_buf));
>>      if (send_content_length > 0 && send_content)
>> -        url_write(rt->rtsp_hd, send_content, send_content_length);
>> +        url_write(rt->rtsp_hd_out, send_content, send_content_length);
>
> I'd prefer if you'd do the patch that splits rtsp_hd into hd_in/out 
> separately.
>
> +                 "Content-Length: 32767\r\n"
> +                 "Expires: Sun, 9 Jan 1972 00:00:00 GMT\r\n",
>
> ??

So quoth the spec. They're there to prevent proxies from caching stuff.

>
> The rest is pretty, well done!
>

Thanks!
From 86b80893a90a45b6e582015422c79fd4804a62e5 Mon Sep 17 00:00:00 2001
From: Josh Allmann <[email protected]>
Date: Thu, 3 Jun 2010 13:49:45 -0700
Subject: [PATCH 1/6] Modified behavior of http_open to implicitly delay connection
 establishment until http_read, http_write or http_seek has been
 called.

---
 libavformat/http.c |   30 +++++++++++++++++++++++++-----
 1 files changed, 25 insertions(+), 5 deletions(-)

diff --git a/libavformat/http.c b/libavformat/http.c
index 4e2152f..3d79869 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -45,6 +45,7 @@ typedef struct {
     int64_t off, filesize;
     char location[URL_SIZE];
     HTTPAuthState auth_state;
+    int init;
 } HTTPContext;
 
 static int http_connect(URLContext *h, const char *path, const char *hoststr,
@@ -65,6 +66,7 @@ static int http_open_cnx(URLContext *h)
     HTTPContext *s = h->priv_data;
     URLContext *hd = NULL;
 
+    s->init = 1;
     proxy_path = getenv("http_proxy");
     use_proxy = (proxy_path != NULL) && !getenv("no_proxy") &&
         av_strstart(proxy_path, "http://";, NULL);
@@ -123,7 +125,6 @@ static int http_open_cnx(URLContext *h)
 static int http_open(URLContext *h, const char *uri, int flags)
 {
     HTTPContext *s;
-    int ret;
 
     h->is_streamed = 1;
 
@@ -135,13 +136,11 @@ static int http_open(URLContext *h, const char *uri, int flags)
     s->filesize = -1;
     s->chunksize = -1;
     s->off = 0;
+    s->init = 0;
     memset(&s->auth_state, 0, sizeof(s->auth_state));
     av_strlcpy(s->location, uri, URL_SIZE);
 
-    ret = http_open_cnx(h);
-    if (ret != 0)
-        av_free (s);
-    return ret;
+    return 0;
 }
 static int http_getc(HTTPContext *s)
 {
@@ -322,6 +321,19 @@ static int http_read(URLContext *h, uint8_t *buf, int size)
     HTTPContext *s = h->priv_data;
     int len;
 
+    if (!s->init) {
+        int ret = http_open_cnx(h);
+        if (ret != 0) {
+            av_free (s);
+            return ret;
+        }
+    }
+
+    /* A size of zero can be used to force
+     * initializaton of the connection. */
+    if (!size)
+        return 0;
+
     if (s->chunksize >= 0) {
         if (!s->chunksize) {
             char line[32];
@@ -369,6 +381,14 @@ static int http_write(URLContext *h, const uint8_t *buf, int size)
     char crlf[] = "\r\n";
     HTTPContext *s = h->priv_data;
 
+    if (!s->init) {
+        int ret = http_open_cnx(h);
+        if (ret != 0) {
+            av_free (s);
+            return ret;
+        }
+    }
+
     if (s->chunksize == -1) {
         /* headers are sent without any special encoding */
         return url_write(s->hd, buf, size);
-- 
1.7.0.4

From 78ff5f1969416cb588b1d6c8ea92f37895498cb8 Mon Sep 17 00:00:00 2001
From: Josh Allmann <[email protected]>
Date: Thu, 3 Jun 2010 13:55:02 -0700
Subject: [PATCH 2/6] Added in capability to write custom HTTP headers.

---
 libavformat/http.c |   31 +++++++++++++++++++++++--------
 libavformat/http.h |   45 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 68 insertions(+), 8 deletions(-)
 create mode 100644 libavformat/http.h

diff --git a/libavformat/http.c b/libavformat/http.c
index 3d79869..175555d 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -25,6 +25,7 @@
 #include <strings.h>
 #include "internal.h"
 #include "network.h"
+#include "http.h"
 #include "os_support.h"
 #include "httpauth.h"
 
@@ -46,12 +47,18 @@ typedef struct {
     char location[URL_SIZE];
     HTTPAuthState auth_state;
     int init;
+    unsigned char headers[BUFFER_SIZE];
 } HTTPContext;
 
 static int http_connect(URLContext *h, const char *path, const char *hoststr,
                         const char *auth, int *new_location);
 static int http_write(URLContext *h, const uint8_t *buf, int size);
 
+void ff_http_set_headers(URLContext *h, const char *headers)
+{
+    HTTPContext *s = h->priv_data;
+    snprintf(s->headers, sizeof(s->headers), "%s", headers);
+}
 
 /* return non zero if error */
 static int http_open_cnx(URLContext *h)
@@ -137,6 +144,7 @@ static int http_open(URLContext *h, const char *uri, int flags)
     s->chunksize = -1;
     s->off = 0;
     s->init = 0;
+    *s->headers = '\0';
     memset(&s->auth_state, 0, sizeof(s->auth_state));
     av_strlcpy(s->location, uri, URL_SIZE);
 
@@ -259,23 +267,30 @@ static int http_connect(URLContext *h, const char *path, const char *hoststr,
     post = h->flags & URL_WRONLY;
     authstr = ff_http_auth_create_response(&s->auth_state, auth, path,
                                         post ? "POST" : "GET");
-    snprintf(s->buffer, sizeof(s->buffer),
-             "%s %s HTTP/1.1\r\n"
-             "User-Agent: %s\r\n"
+    if (!strlen(s->headers)) {
+    snprintf(s->headers, sizeof(s->headers),
              "Accept: */*\r\n"
              "Range: bytes=%"PRId64"-\r\n"
              "Host: %s\r\n"
-             "%s"
              "Connection: close\r\n"
+             "\r\n",
+             s->off,
+             hoststr);
+    }
+
+    snprintf(s->buffer, sizeof(s->buffer),
+             "%s %s HTTP/1.1\r\n"
+             "User-Agent: %s\r\n"
+             "%s"
+             "%s"
              "%s"
              "\r\n",
              post ? "POST" : "GET",
              path,
              LIBAVFORMAT_IDENT,
-             s->off,
-             hoststr,
-             authstr ? authstr : "",
-             post ? "Transfer-Encoding: chunked\r\n" : "");
+             post ? "Transfer-Encoding: chunked\r\n" : "",
+             s->headers,
+             authstr ? authstr : "");
 
     av_freep(&authstr);
     if (http_write(h, s->buffer, strlen(s->buffer)) < 0)
diff --git a/libavformat/http.h b/libavformat/http.h
new file mode 100644
index 0000000..7393ae0
--- /dev/null
+++ b/libavformat/http.h
@@ -0,0 +1,45 @@
+/*
+ * HTTP definitions
+ * Copyright (c) 2010 Josh Allmann
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef AVFORMAT_HTTP_H
+#define AVFORMAT_HTTP_H
+
+/**
+ * Sets custom HTTP headers. Note this overwrites all default options.
+ *
+ * The following headers will always be set, no matter what:
+ *  -HTTP verb, path, HTTP version
+ *  -User-Agent
+ *  -Transfer-Encoding (if applicable)
+ *  - Authorization (if applicable)
+ *
+ * The following headers are set by default, and will be overwritten if
+ * custom headers are set. Be sure to re-specify them if needed.
+ *  -Accept
+ *  -Range
+ *  -Host
+ *  -Connection
+ *
+ * @param h URL context for this HTTP connection
+ * @param is_chunked 0 to disable chunking, nonzero otherwise.
+ */
+void ff_http_set_headers(URLContext *h, const char *headers);
+
+#endif /* AVFORMAT_HTTP_H */
-- 
1.7.0.4

From 7942643fb619cde8efbf9a7380d6c073d64ed9ae Mon Sep 17 00:00:00 2001
From: Josh Allmann <[email protected]>
Date: Thu, 3 Jun 2010 15:12:11 -0700
Subject: [PATCH 3/6] Added support for disabling chunked transfer encoding.

---
 libavformat/http.c |   14 +++++++++++---
 libavformat/http.h |    8 ++++++++
 2 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/libavformat/http.c b/libavformat/http.c
index 175555d..9be921b 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -48,6 +48,7 @@ typedef struct {
     HTTPAuthState auth_state;
     int init;
     unsigned char headers[BUFFER_SIZE];
+    int is_chunked;
 } HTTPContext;
 
 static int http_connect(URLContext *h, const char *path, const char *hoststr,
@@ -60,6 +61,11 @@ void ff_http_set_headers(URLContext *h, const char *headers)
     snprintf(s->headers, sizeof(s->headers), "%s", headers);
 }
 
+void ff_http_set_chunked_transfer_encoding(URLContext *h, int is_chunked)
+{
+    ((HTTPContext*)h->priv_data)->is_chunked = is_chunked;
+}
+
 /* return non zero if error */
 static int http_open_cnx(URLContext *h)
 {
@@ -142,6 +148,7 @@ static int http_open(URLContext *h, const char *uri, int flags)
     h->priv_data = s;
     s->filesize = -1;
     s->chunksize = -1;
+    s->is_chunked = 1;
     s->off = 0;
     s->init = 0;
     *s->headers = '\0';
@@ -288,7 +295,7 @@ static int http_connect(URLContext *h, const char *path, const char *hoststr,
              post ? "POST" : "GET",
              path,
              LIBAVFORMAT_IDENT,
-             post ? "Transfer-Encoding: chunked\r\n" : "",
+             post && s->is_chunked ? "Transfer-Encoding: chunked\r\n" : "",
              s->headers,
              authstr ? authstr : "");
 
@@ -391,7 +398,7 @@ static int http_read(URLContext *h, uint8_t *buf, int size)
 /* used only when posting data */
 static int http_write(URLContext *h, const uint8_t *buf, int size)
 {
-    char temp[11];  /* 32-bit hex + CRLF + nul */
+    char temp[11] = "";  /* 32-bit hex + CRLF + nul */
     int ret;
     char crlf[] = "\r\n";
     HTTPContext *s = h->priv_data;
@@ -413,11 +420,12 @@ static int http_write(URLContext *h, const uint8_t *buf, int size)
      * signal EOF */
     if (size > 0) {
         /* upload data using chunked encoding */
+        if(s->is_chunked)
         snprintf(temp, sizeof(temp), "%x\r\n", size);
 
         if ((ret = url_write(s->hd, temp, strlen(temp))) < 0 ||
             (ret = url_write(s->hd, buf, size)) < 0 ||
-            (ret = url_write(s->hd, crlf, sizeof(crlf) - 1)) < 0)
+            (s->is_chunked && (ret = url_write(s->hd, crlf, sizeof(crlf) - 1)) < 0))
             return ret;
     }
     return size;
diff --git a/libavformat/http.h b/libavformat/http.h
index 7393ae0..e754c7e 100644
--- a/libavformat/http.h
+++ b/libavformat/http.h
@@ -42,4 +42,12 @@
  */
 void ff_http_set_headers(URLContext *h, const char *headers);
 
+/**
+ * Enables or disables chunked transfer encoding. (default is enabled)
+ *
+ * @param h URL context for this HTTP connection
+ * @param is_chunked 0 to disable chunking, nonzero otherwise.
+ */
+void ff_http_set_chunked_transfer_encoding(URLContext *h, int is_chunked);
+
 #endif /* AVFORMAT_HTTP_H */
-- 
1.7.0.4

From 6a2eaead2dd6ffa38cbd13ad9b8e4b6db64aaf41 Mon Sep 17 00:00:00 2001
From: Josh Allmann <[email protected]>
Date: Thu, 3 Jun 2010 14:10:46 -0700
Subject: [PATCH 4/6] Adds in a second RTSP handle for outgoing messages.
 Done in preparation for RTSP over HTTP.

---
 libavformat/rtsp.c    |   21 +++++++++++++++------
 libavformat/rtsp.h    |   11 +++++++++++
 libavformat/rtspenc.c |    4 ++--
 3 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c
index 6dbd796..b1112fd 100644
--- a/libavformat/rtsp.c
+++ b/libavformat/rtsp.c
@@ -1032,9 +1032,9 @@ void ff_rtsp_send_cmd_with_content_async(AVFormatContext *s,
 
     dprintf(s, "Sending:\n%s--\n", buf);
 
-    url_write(rt->rtsp_hd, buf, strlen(buf));
+    url_write(rt->rtsp_hd_out, out_buf, strlen(out_buf));
     if (send_content_length > 0 && send_content)
-        url_write(rt->rtsp_hd, send_content, send_content_length);
+        url_write(rt->rtsp_hd_out, send_content, send_content_length);
     rt->last_cmd_time = av_gettime();
 }
 
@@ -1454,12 +1454,19 @@ static int rtsp_setup_output_streams(AVFormatContext *s, const char *addr)
     return 0;
 }
 
+void ff_rtsp_close_connections(AVFormatContext *s)
+{
+    RTSPState *rt = s->priv_data;
+    if (rt->rtsp_hd_out != rt->rtsp_hd) url_close(rt->rtsp_hd_out);
+    url_close(rt->rtsp_hd);
+}
+
 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;
-    URLContext *rtsp_hd;
+    URLContext *rtsp_hd, *rtsp_hd_out;
     int port, err, tcp_fd;
     RTSPMessageHeader reply1 = {}, *reply = &reply1;
     int lower_transport_mask = 0;
@@ -1538,7 +1545,9 @@ redirect:
         err = AVERROR(EIO);
         goto fail;
     }
+    rtsp_hd_out = rtsp_hd;
     rt->rtsp_hd = rtsp_hd;
+    rt->rtsp_hd_out = rtsp_hd_out;
     rt->seq = 0;
 
     tcp_fd = url_get_file_handle(rtsp_hd);
@@ -1612,7 +1621,7 @@ redirect:
     return 0;
  fail:
     ff_rtsp_close_streams(s);
-    url_close(rt->rtsp_hd);
+    ff_rtsp_close_connections(s);
     if (reply->status_code >=300 && reply->status_code < 400 && s->iformat) {
         av_strlcpy(s->filename, reply->location, sizeof(s->filename));
         av_log(s, AV_LOG_INFO, "Status %d: Redirecting to %s\n",
@@ -1641,7 +1650,7 @@ static int rtsp_read_header(AVFormatContext *s,
     } else {
          if (rtsp_read_play(s) < 0) {
             ff_rtsp_close_streams(s);
-            url_close(rt->rtsp_hd);
+            ff_rtsp_close_connections(s);
             return AVERROR_INVALIDDATA;
         }
     }
@@ -1986,7 +1995,7 @@ static int rtsp_read_close(AVFormatContext *s)
     ff_rtsp_send_cmd_async(s, "TEARDOWN", rt->control_uri, NULL);
 
     ff_rtsp_close_streams(s);
-    url_close(rt->rtsp_hd);
+    ff_rtsp_close_connections(s);
     ff_network_close();
     return 0;
 }
diff --git a/libavformat/rtsp.h b/libavformat/rtsp.h
index 342f825..7701d27 100644
--- a/libavformat/rtsp.h
+++ b/libavformat/rtsp.h
@@ -278,6 +278,10 @@ typedef struct RTSPState {
 
     /** The synchronized start time of the output streams. */
     int64_t start_time;
+
+    /** Additional output handler, used when input and output are done
+     * separately, eg for HTTP tunnelling. */
+    URLContext *rtsp_hd_out;
 } RTSPState;
 
 /**
@@ -434,4 +438,11 @@ int ff_rtsp_connect(AVFormatContext *s);
  */
 void ff_rtsp_close_streams(AVFormatContext *s);
 
+/**
+ * Close all connection handles within the RTSP (de)muxer
+ *
+ * @param rt RTSP (de)muxer context
+ */
+void ff_rtsp_close_connections(AVFormatContext *rt);
+
 #endif /* AVFORMAT_RTSP_H */
diff --git a/libavformat/rtspenc.c b/libavformat/rtspenc.c
index 0761783..7dc6a83 100644
--- a/libavformat/rtspenc.c
+++ b/libavformat/rtspenc.c
@@ -57,7 +57,7 @@ static int rtsp_write_header(AVFormatContext *s)
 
     if (rtsp_write_record(s) < 0) {
         ff_rtsp_close_streams(s);
-        url_close(rt->rtsp_hd);
+        ff_rtsp_close_connections(s);
         return AVERROR_INVALIDDATA;
     }
     return 0;
@@ -162,7 +162,7 @@ static int rtsp_write_close(AVFormatContext *s)
     ff_rtsp_send_cmd_async(s, "TEARDOWN", rt->control_uri, NULL);
 
     ff_rtsp_close_streams(s);
-    url_close(rt->rtsp_hd);
+    ff_rtsp_close_connections(s);
     ff_network_close();
     return 0;
 }
-- 
1.7.0.4

From 3408ff3c79267f71c90ac4182808062bc6d81f85 Mon Sep 17 00:00:00 2001
From: Josh Allmann <[email protected]>
Date: Thu, 3 Jun 2010 14:49:30 -0700
Subject: [PATCH 5/6] Added in RTSP tunneling over HTTP.

---
 libavformat/rtsp.c |   72 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 libavformat/rtsp.h |   14 +++++++++-
 2 files changed, 84 insertions(+), 2 deletions(-)

diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c
index b1112fd..446c375 100644
--- a/libavformat/rtsp.c
+++ b/libavformat/rtsp.c
@@ -22,6 +22,7 @@
 #include "libavutil/base64.h"
 #include "libavutil/avstring.h"
 #include "libavutil/intreadwrite.h"
+#include "libavutil/random_seed.h"
 #include "avformat.h"
 
 #include <sys/time.h>
@@ -32,6 +33,7 @@
 #include "internal.h"
 #include "network.h"
 #include "os_support.h"
+#include "http.h"
 #include "rtsp.h"
 
 #include "rtpdec.h"
@@ -1008,8 +1010,11 @@ void ff_rtsp_send_cmd_with_content_async(AVFormatContext *s,
                                          int send_content_length)
 {
     RTSPState *rt = s->priv_data;
-    char buf[4096];
+    char buf[4096], *out_buf;
+    char base64buf[AV_BASE64_SIZE(sizeof(buf))];
 
+    /* Add in RTSP headers */
+    out_buf = buf;
     rt->seq++;
     snprintf(buf, sizeof(buf), "%s %s RTSP/1.0\r\n", method, url);
     if (headers)
@@ -1026,10 +1031,20 @@ void ff_rtsp_send_cmd_with_content_async(AVFormatContext *s,
             av_strlcat(buf, str, sizeof(buf));
         av_free(str);
     }
+
     if (send_content_length > 0 && send_content)
         av_strlcatf(buf, sizeof(buf), "Content-Length: %d\r\n", send_content_length);
     av_strlcat(buf, "\r\n", sizeof(buf));
 
+    /* base64 encode rtsp if tunneling */
+    if (rt->mode == RTSP_MODE_TUNNEL) {
+        if (!av_base64_encode(base64buf, sizeof(base64buf), buf, strlen(buf))) {
+            av_log(s, AV_LOG_ERROR, "Unable to base64 encode RTSP.\n");
+            return;
+        }
+        out_buf = base64buf;
+    }
+
     dprintf(s, "Sending:\n%s--\n", buf);
 
     url_write(rt->rtsp_hd_out, out_buf, strlen(out_buf));
@@ -1477,6 +1492,7 @@ int ff_rtsp_connect(AVFormatContext *s)
     if (!ff_network_init())
         return AVERROR(EIO);
 redirect:
+    rt->mode = RTSP_MODE_PLAIN;
     /* extract hostname and port */
     ff_url_split(NULL, 0, auth, sizeof(auth),
                  host, sizeof(host), &port, path, sizeof(path), s->filename);
@@ -1506,6 +1522,9 @@ redirect:
                 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->mode = RTSP_MODE_TUNNEL;
             } else {
                 /* Write options back into the buffer, using memmove instead
                  * of strcpy since the strings may overlap. */
@@ -1539,6 +1558,56 @@ redirect:
     ff_url_join(rt->control_uri, sizeof(rt->control_uri), "rtsp", NULL,
                 host, port, "%s", path);
 
+    if (rt->mode == RTSP_MODE_TUNNEL) {
+        /* set up initial handshake for tunneling */
+        char httpname[1024];
+        char sessioncookie[17];
+        char headers[1024];
+
+        ff_url_join(httpname, sizeof(httpname), "http", NULL, host, port, "%s", path);
+        snprintf(sessioncookie, sizeof(sessioncookie), "%08x%08x",
+                 av_get_random_seed(), av_get_random_seed());
+
+        /* GET requests */
+        if (url_open(&rtsp_hd, httpname, URL_RDONLY) < 0) {
+            err = AVERROR(EIO);
+            goto fail;
+        }
+
+        /* generate GET headers */
+        snprintf(headers, sizeof(headers),
+                 "x-sessioncookie: %s\r\n"
+                 "Accept: application/x-rtsp-tunnelled\r\n"
+                 "Pragma: no-cache\r\n"
+                 "Cache-Control: no-cache\r\n",
+                 sessioncookie);
+        ff_http_set_headers(rtsp_hd, headers);
+
+        /* complete the connection */
+        if (url_read(rtsp_hd, NULL, 0)) {
+            err = AVERROR(EIO);
+            goto fail;
+        }
+
+        /* POST requests */
+        if (url_open(&rtsp_hd_out, httpname, URL_WRONLY) < 0 ) {
+            err = AVERROR(EIO);
+            goto fail;
+        }
+
+        /* generate POST headers */
+        snprintf(headers, sizeof(headers),
+                 "x-sessioncookie: %s\r\n"
+                 "Content-Type: application/x-rtsp-tunnelled\r\n"
+                 "Pragma: no-cache\r\n"
+                 "Cache-Control: no-cache\r\n"
+                 "Content-Length: 32767\r\n"
+                 "Expires: Sun, 9 Jan 1972 00:00:00 GMT\r\n",
+                 sessioncookie);
+        ff_http_set_headers(rtsp_hd_out, headers);
+        ff_http_set_chunked_transfer_encoding(rtsp_hd_out, 0);
+
+    } else {
     /* open the tcp connexion */
     ff_url_join(tcpname, sizeof(tcpname), "tcp", NULL, host, port, NULL);
     if (url_open(&rtsp_hd, tcpname, URL_RDWR) < 0) {
@@ -1546,6 +1615,7 @@ redirect:
         goto fail;
     }
     rtsp_hd_out = rtsp_hd;
+    }
     rt->rtsp_hd = rtsp_hd;
     rt->rtsp_hd_out = rtsp_hd_out;
     rt->seq = 0;
diff --git a/libavformat/rtsp.h b/libavformat/rtsp.h
index 7701d27..68298c7 100644
--- a/libavformat/rtsp.h
+++ b/libavformat/rtsp.h
@@ -49,6 +49,15 @@ enum RTSPTransport {
     RTSP_TRANSPORT_NB
 };
 
+/**
+ * Transport mode for the RTSP data. This may be plain, or
+ * tunneled, which is done over HTTP.
+ */
+enum RTSPMode {
+    RTSP_MODE_PLAIN,   /**< Normal RTSP */
+    RTSP_MODE_TUNNEL   /**< RTSP over HTTP (tunneling) */
+};
+
 #define RTSP_DEFAULT_PORT   554
 #define RTSP_MAX_TRANSPORTS 8
 #define RTSP_TCP_MAX_PACKET_SIZE 1472
@@ -280,8 +289,11 @@ typedef struct RTSPState {
     int64_t start_time;
 
     /** Additional output handler, used when input and output are done
-     * separately, eg for HTTP tunnelling. */
+     * separately, eg for HTTP tunneling. */
     URLContext *rtsp_hd_out;
+
+    /** RTSP transport mode, such as plain or tunneled. */
+    int mode;
 } RTSPState;
 
 /**
-- 
1.7.0.4

From 599446a6d0a1789ed597624d0b59bd44fd8802a6 Mon Sep 17 00:00:00 2001
From: Josh Allmann <[email protected]>
Date: Fri, 4 Jun 2010 00:50:29 -0700
Subject: [PATCH 6/6] Propagated errors up ff_rtsp_send_cmd*

---
 libavformat/rtsp.c |   27 +++++++++++++++++----------
 libavformat/rtsp.h |   12 ++++++++----
 2 files changed, 25 insertions(+), 14 deletions(-)

diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c
index 446c375..7b439a5 100644
--- a/libavformat/rtsp.c
+++ b/libavformat/rtsp.c
@@ -1003,7 +1003,7 @@ int ff_rtsp_read_reply(AVFormatContext *s, RTSPMessageHeader *reply,
     return 0;
 }
 
-void ff_rtsp_send_cmd_with_content_async(AVFormatContext *s,
+int ff_rtsp_send_cmd_with_content_async(AVFormatContext *s,
                                          const char *method, const char *url,
                                          const char *headers,
                                          const unsigned char *send_content,
@@ -1040,7 +1040,7 @@ void ff_rtsp_send_cmd_with_content_async(AVFormatContext *s,
     if (rt->mode == RTSP_MODE_TUNNEL) {
         if (!av_base64_encode(base64buf, sizeof(base64buf), buf, strlen(buf))) {
             av_log(s, AV_LOG_ERROR, "Unable to base64 encode RTSP.\n");
-            return;
+            return AVERROR(EINVAL);
         }
         out_buf = base64buf;
     }
@@ -1051,23 +1051,25 @@ void ff_rtsp_send_cmd_with_content_async(AVFormatContext *s,
     if (send_content_length > 0 && send_content)
         url_write(rt->rtsp_hd_out, send_content, send_content_length);
     rt->last_cmd_time = av_gettime();
+
+    return 0;
 }
 
-void ff_rtsp_send_cmd_async(AVFormatContext *s, const char *method,
+int ff_rtsp_send_cmd_async(AVFormatContext *s, const char *method,
                             const char *url, const char *headers)
 {
-    ff_rtsp_send_cmd_with_content_async(s, method, url, headers, NULL, 0);
+    return ff_rtsp_send_cmd_with_content_async(s, method, url, headers, NULL, 0);
 }
 
-void ff_rtsp_send_cmd(AVFormatContext *s, const char *method, const char *url,
+int ff_rtsp_send_cmd(AVFormatContext *s, const char *method, const char *url,
                       const char *headers, RTSPMessageHeader *reply,
                       unsigned char **content_ptr)
 {
-    ff_rtsp_send_cmd_with_content(s, method, url, headers, reply,
+    return ff_rtsp_send_cmd_with_content(s, method, url, headers, reply,
                                   content_ptr, NULL, 0);
 }
 
-void ff_rtsp_send_cmd_with_content(AVFormatContext *s,
+int ff_rtsp_send_cmd_with_content(AVFormatContext *s,
                                    const char *method, const char *url,
                                    const char *header,
                                    RTSPMessageHeader *reply,
@@ -1077,17 +1079,22 @@ void ff_rtsp_send_cmd_with_content(AVFormatContext *s,
 {
     RTSPState *rt = s->priv_data;
     HTTPAuthType cur_auth_type;
+    int ret;
 
 retry:
     cur_auth_type = rt->auth_state.auth_type;
-    ff_rtsp_send_cmd_with_content_async(s, method, url, header,
-                                        send_content, send_content_length);
+    if ((ret = ff_rtsp_send_cmd_with_content_async(s, method, url, header,
+                                        send_content, send_content_length)))
+        return ret;
 
-    ff_rtsp_read_reply(s, reply, content_ptr, 0);
+    if ((ret = ff_rtsp_read_reply(s, reply, content_ptr, 0) ) < 0)
+        return ret;
 
     if (reply->status_code == 401 && cur_auth_type == HTTP_AUTH_NONE &&
         rt->auth_state.auth_type != HTTP_AUTH_NONE)
         goto retry;
+
+    return 0;
 }
 
 /**
diff --git a/libavformat/rtsp.h b/libavformat/rtsp.h
index 68298c7..b5d917f 100644
--- a/libavformat/rtsp.h
+++ b/libavformat/rtsp.h
@@ -357,8 +357,10 @@ extern int rtsp_rtp_port_max;
  * @param send_content if non-null, the data to send as request body content
  * @param send_content_length the length of the send_content data, or 0 if
  *                            send_content is null
+ *
+ * @return zero if success, nonzero otherwise
  */
-void ff_rtsp_send_cmd_with_content_async(AVFormatContext *s,
+int ff_rtsp_send_cmd_with_content_async(AVFormatContext *s,
                                          const char *method, const char *url,
                                          const char *headers,
                                          const unsigned char *send_content,
@@ -368,7 +370,7 @@ void ff_rtsp_send_cmd_with_content_async(AVFormatContext *s,
  *
  * @see rtsp_send_cmd_with_content_async
  */
-void ff_rtsp_send_cmd_async(AVFormatContext *s, const char *method,
+int ff_rtsp_send_cmd_async(AVFormatContext *s, const char *method,
                             const char *url, const char *headers);
 
 /**
@@ -384,8 +386,10 @@ void ff_rtsp_send_cmd_async(AVFormatContext *s, const char *method,
  * @param send_content if non-null, the data to send as request body content
  * @param send_content_length the length of the send_content data, or 0 if
  *                            send_content is null
+ *
+ * @return zero if success, nonzero otherwise
  */
-void ff_rtsp_send_cmd_with_content(AVFormatContext *s,
+int ff_rtsp_send_cmd_with_content(AVFormatContext *s,
                                    const char *method, const char *url,
                                    const char *headers,
                                    RTSPMessageHeader *reply,
@@ -398,7 +402,7 @@ void ff_rtsp_send_cmd_with_content(AVFormatContext *s,
  *
  * @see rtsp_send_cmd_with_content
  */
-void ff_rtsp_send_cmd(AVFormatContext *s, const char *method,
+int ff_rtsp_send_cmd(AVFormatContext *s, const char *method,
                       const char *url, const char *headers,
                       RTSPMessageHeader *reply, unsigned char **content_ptr);
 
-- 
1.7.0.4

_______________________________________________
FFmpeg-soc mailing list
[email protected]
https://lists.mplayerhq.hu/mailman/listinfo/ffmpeg-soc

Reply via email to