Sent the wrong patches, use these instead.
Also, my github rtsp-tunneling branch has been updated.

On 5 June 2010 14:59, Josh Allmann <[email protected]> wrote:
> On 5 June 2010 12:01, Ronald S. Bultje <[email protected]> wrote:
>> Hi,
>>
>> On Sat, Jun 5, 2010 at 4:28 AM, Josh Allmann <[email protected]> 
>> wrote:
>>> Fixed that, and other minor errors (s/handler/handle, spelling fixes
>>> in the proper commit, etc). Soc repo has been updated as well.
>> [..]
>>> +    if (!s->init) {
>>> +        int ret = http_open_cnx(h);
>>> +        if (ret != 0) {
>>> +            av_free (s);
>>
>> The av_free(s) should be removed in read/write, otherwise subsequent
>> calls to read/write (or close) will/might crash.
>
> Fixed.
>
>>
>>> +/**
>>> + * 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);
>>
>> You shouldn't omit them if missing from the "custom" header. The
>> expected behaviour if custom header is "Accept: bla\r\n" is that the
>> default Host is kept (same for the others). Also, please document that
>> the caller is required to maintain trailing "\r\n" in the custom
>> header. Assert this in the implementation. Also document that "\0"
>> resets the custom header.
>>
>
> Fixed on all counts.
> I was wrong earlier; adding in the default headers don't break stuff,
> so we don't need to omit anything.
>
>>> @@ -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 ||
>>
>> is_chunked && (ret = url_write... More generally, feel free to unroll this 
>> into:
>> if (is_chunked){
>> snprintf();
>> url_write();
>> }
>> url_write();
>> if (is_chunked)
>> url_write();
>>
>
> Fixed. The code is not as tight now, but a little less gnarly.
>
>> How does the caller or callee define the length of the data if it's
>> not chunked? We need some defined way of getting that, otherwise this
>> will break depending on the receiving server implementation.
>>
>> #4 is fine, if Luca is OK (or Martin), please apply.
>>
>>> +    /** RTSP transport mode, such as plain or tunneled. */
>>> +    int mode;
>>
>> enum RTSPMode mode. RTSPMode is also a little generic, but I don't
>> really have suggestions for a better name. Luca?
>> RTSPProtocolConnectionMode?
>
> Changed to RTSPControlTransport
>
>>
>> I think #6 is OK, again Luca/Martin for second review and then it can
>> be applied.
>>
>> Ronald
>> _______________________________________________
>> FFmpeg-soc mailing list
>> [email protected]
>> https://lists.mplayerhq.hu/mailman/listinfo/ffmpeg-soc
>>
>
From 25a81e29ed5607ea775aec607dd7cbf8017eb03c Mon Sep 17 00:00:00 2001
From: Josh Allmann <[email protected]>
Date: Fri, 4 Jun 2010 09:31:39 -0700
Subject: [PATCH 5/5] Added in RTSP tunneling over HTTP.

---
 libavformat/rtsp.c |   73 +++++++++++++++++++++++++++++++++++++++++++++++++--
 libavformat/rtsp.h |   12 ++++++++
 2 files changed, 82 insertions(+), 3 deletions(-)

diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c
index fb0747d..b478dec 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,13 +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->control_transport == RTSP_MODE_TUNNEL) {
+        av_base64_encode(base64buf, sizeof(base64buf), buf, strlen(buf));
+        out_buf = base64buf;
+    }
+
     dprintf(s, "Sending:\n%s--\n", buf);
 
-    url_write(rt->rtsp_hd_out, buf, strlen(out_buf));
+    url_write(rt->rtsp_hd_out, out_buf, strlen(out_buf));
     if (send_content_length > 0 && send_content)
         url_write(rt->rtsp_hd_out, send_content, send_content_length);
     rt->last_cmd_time = av_gettime();
@@ -1477,6 +1489,7 @@ int ff_rtsp_connect(AVFormatContext *s)
     if (!ff_network_init())
         return AVERROR(EIO);
 redirect:
+    rt->control_transport = 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 +1519,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->control_transport = RTSP_MODE_TUNNEL;
             } else {
                 /* Write options back into the buffer, using memmove instead
                  * of strcpy since the strings may overlap. */
@@ -1525,7 +1541,7 @@ redirect:
         /* 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) {
+        if (!lower_transport_mask || rt->control_transport == RTSP_MODE_TUNNEL) {
             av_log(s, AV_LOG_ERROR, "Unsupported lower transport method, "
                                     "only UDP and TCP are supported for output.\n");
             err = AVERROR(EINVAL);
@@ -1539,6 +1555,56 @@ redirect:
     ff_url_join(rt->control_uri, sizeof(rt->control_uri), "rtsp", NULL,
                 host, port, "%s", path);
 
+    if (rt->control_transport == 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 +1612,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 9d8e53b..095d577 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 RTSPControlTransport {
+    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
@@ -282,6 +291,9 @@ typedef struct RTSPState {
     /** Additional output handle, used when input and output are done
      * separately, eg for HTTP tunneling. */
     URLContext *rtsp_hd_out;
+
+    /** RTSP transport mode, such as plain or tunneled. */
+    enum RTSPControlTransport control_transport;
 } RTSPState;
 
 /**
-- 
1.7.0.4

From ec6ad739addcd33d829cd1bac3ea63d2f11d2936 Mon Sep 17 00:00:00 2001
From: Josh Allmann <[email protected]>
Date: Sat, 5 Jun 2010 14:42:04 -0700
Subject: [PATCH 2/5] Added in capability to write custom HTTP headers.

---
 libavformat/http.c |   45 +++++++++++++++++++++++++++++++++++----------
 libavformat/http.h |   50 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 85 insertions(+), 10 deletions(-)
 create mode 100644 libavformat/http.h

diff --git a/libavformat/http.c b/libavformat/http.c
index 68ad2ce..d3861ab 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,23 @@ 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;
+    int len = strlen(headers);
+
+    if (len && strcmp("\r\n", headers+len-2))
+        av_log(NULL, AV_LOG_ERROR, "No trailing CRLF found in HTTP header.\n");
+
+    snprintf(s->headers, sizeof(s->headers), "%s", headers);
+}
 
 /* return non zero if error */
 static int http_open_cnx(URLContext *h)
@@ -137,6 +149,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);
 
@@ -251,31 +264,43 @@ static int http_connect(URLContext *h, const char *path, const char *hoststr,
     HTTPContext *s = h->priv_data;
     int post, err;
     char line[1024];
+    char headers[1024];
     char *authstr = NULL;
     int64_t off = s->off;
+    int len = 0;
 
 
     /* send http header */
     post = h->flags & URL_WRONLY;
     authstr = ff_http_auth_create_response(&s->auth_state, auth, path,
                                         post ? "POST" : "GET");
+
+     /* set default headers if needed */
+     if(!strstr(s->headers, "\r\nUser-Agent:"))
+        len += snprintf(headers+len, sizeof(headers)-len, "User-Agent: %s\r\n", LIBAVFORMAT_IDENT);
+    if(!strstr(s->headers, "\r\nAccept:"))
+        len = snprintf(headers, sizeof(headers), "Accept: */*\r\n");
+    if(!strstr(s->headers, "\r\nRange:"))
+        len += snprintf(headers+len, sizeof(headers)-len, "Range: bytes=%"PRId64"\r\n", s->off);
+    if(!strstr(s->headers, "\r\nConnection:"))
+        len += snprintf(headers+len, sizeof(headers)-len, "Connection: close\r\n");
+    if(!strstr(s->headers, "\r\nHost:"))
+        len += snprintf(headers+len, sizeof(headers)-len, "Host: %s\r\n", hoststr);
+
+    /* now add in custom headers */
+    snprintf(headers+len, sizeof(headers)-len, "%s", s->headers);
+
     snprintf(s->buffer, sizeof(s->buffer),
              "%s %s HTTP/1.1\r\n"
-             "User-Agent: %s\r\n"
-             "Accept: */*\r\n"
-             "Range: bytes=%"PRId64"-\r\n"
-             "Host: %s\r\n"
              "%s"
-             "Connection: close\r\n"
+             "%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" : "",
+             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..2cb1f2c
--- /dev/null
+++ b/libavformat/http.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ * A trailing CRLF ("\r\n") is required for custom headers.
+ * Passing in an empty header string ("\0") will reset to defaults.
+ *
+ * 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
+ *
+ * If seeking is needed with custom headers, Range will need
+ * to be manually specified before each request.
+ *
+ * @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 53b7a7846b583e20929ebf11de8f8f1feacac7c7 Mon Sep 17 00:00:00 2001
From: Josh Allmann <[email protected]>
Date: Sat, 5 Jun 2010 14:43:18 -0700
Subject: [PATCH 3/5] Added support for disabling chunked transfer encoding.

Conflicts:

	libavformat/http.c
---
 libavformat/http.c |   22 +++++++++++++++++-----
 libavformat/http.h |    8 ++++++++
 2 files changed, 25 insertions(+), 5 deletions(-)

diff --git a/libavformat/http.c b/libavformat/http.c
index d3861ab..79fe939 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,
@@ -65,6 +66,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)
 {
@@ -147,6 +153,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';
@@ -298,7 +305,7 @@ static int http_connect(URLContext *h, const char *path, const char *hoststr,
              "\r\n",
              post ? "POST" : "GET",
              path,
-             post ? "Transfer-Encoding: chunked\r\n" : "",
+             post && s->is_chunked ? "Transfer-Encoding: chunked\r\n" : "",
              headers,
              authstr ? authstr : "");
 
@@ -400,7 +407,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;
@@ -421,11 +428,16 @@ 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)
+                return ret;
+        }
+
+        if ((ret = url_write(s->hd, buf, size)) < 0)
+            return ret;
 
-        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)
+        if (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 2cb1f2c..bac3be3 100644
--- a/libavformat/http.h
+++ b/libavformat/http.h
@@ -47,4 +47,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 25a81e29ed5607ea775aec607dd7cbf8017eb03c Mon Sep 17 00:00:00 2001
From: Josh Allmann <[email protected]>
Date: Fri, 4 Jun 2010 09:31:39 -0700
Subject: [PATCH 5/5] Added in RTSP tunneling over HTTP.

---
 libavformat/rtsp.c |   73 +++++++++++++++++++++++++++++++++++++++++++++++++--
 libavformat/rtsp.h |   12 ++++++++
 2 files changed, 82 insertions(+), 3 deletions(-)

diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c
index fb0747d..b478dec 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,13 +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->control_transport == RTSP_MODE_TUNNEL) {
+        av_base64_encode(base64buf, sizeof(base64buf), buf, strlen(buf));
+        out_buf = base64buf;
+    }
+
     dprintf(s, "Sending:\n%s--\n", buf);
 
-    url_write(rt->rtsp_hd_out, buf, strlen(out_buf));
+    url_write(rt->rtsp_hd_out, out_buf, strlen(out_buf));
     if (send_content_length > 0 && send_content)
         url_write(rt->rtsp_hd_out, send_content, send_content_length);
     rt->last_cmd_time = av_gettime();
@@ -1477,6 +1489,7 @@ int ff_rtsp_connect(AVFormatContext *s)
     if (!ff_network_init())
         return AVERROR(EIO);
 redirect:
+    rt->control_transport = 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 +1519,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->control_transport = RTSP_MODE_TUNNEL;
             } else {
                 /* Write options back into the buffer, using memmove instead
                  * of strcpy since the strings may overlap. */
@@ -1525,7 +1541,7 @@ redirect:
         /* 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) {
+        if (!lower_transport_mask || rt->control_transport == RTSP_MODE_TUNNEL) {
             av_log(s, AV_LOG_ERROR, "Unsupported lower transport method, "
                                     "only UDP and TCP are supported for output.\n");
             err = AVERROR(EINVAL);
@@ -1539,6 +1555,56 @@ redirect:
     ff_url_join(rt->control_uri, sizeof(rt->control_uri), "rtsp", NULL,
                 host, port, "%s", path);
 
+    if (rt->control_transport == 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 +1612,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 9d8e53b..095d577 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 RTSPControlTransport {
+    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
@@ -282,6 +291,9 @@ typedef struct RTSPState {
     /** Additional output handle, used when input and output are done
      * separately, eg for HTTP tunneling. */
     URLContext *rtsp_hd_out;
+
+    /** RTSP transport mode, such as plain or tunneled. */
+    enum RTSPControlTransport control_transport;
 } RTSPState;
 
 /**
-- 
1.7.0.4

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

Reply via email to