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
