On 7 June 2010 08:16, Ronald S. Bultje <[email protected]> wrote:
> Hi,
>
> #1:
>
> On Sun, Jun 6, 2010 at 10:10 PM, Josh Allmann <[email protected]>
> wrote:
>> + if (ret != 0) {
>> + return ret;
>> + }
>
> Superfluous {}.
>
Removed.
>> + /* A size of zero can be used to force
>> + * initializaton of the connection. */
>> + if (!size)
>> + return 0;
>
> Eh... I'm not sure I like that.
>
Left as per IRC discussion.
> #2:
>
>> +static inline int has_header(const char *str, const char *header)
>> +{
>> + return av_stristart(str, header+2, &str) || av_stristr(str, header);
>> +}
>
> av_stristart(a, b, NULL) should work also. Why header+2 (I know it's
> because of \r\n, but please document that because we'll forget...)?
>
> #5:
>
>> 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);
>
> Cosmetic.
Removed.
>
> The rest looks nice, I hope we can apply in the next round.
>
*dances*
Luca, Martin, any more comments?
Josh
From 3585a19bd98c81479dce8c7b139c364dab186101 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 | 26 +++++++++++++++++++++-----
1 files changed, 21 insertions(+), 5 deletions(-)
diff --git a/libavformat/http.c b/libavformat/http.c
index 4e2152f..855c67a 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,17 @@ 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)
+ 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 +379,12 @@ 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)
+ 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 aa2034a9bd0d80777523fb61f6cd1f8df0c57799 Mon Sep 17 00:00:00 2001
From: Josh Allmann <[email protected]>
Date: Sat, 5 Jun 2010 14:42:04 -0700
Subject: [PATCH 2/6] Added in capability to write custom HTTP headers.
---
libavformat/http.c | 51 +++++++++++++++++++++++++++++++++++++++++----------
libavformat/http.h | 42 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 83 insertions(+), 10 deletions(-)
create mode 100644 libavformat/http.h
diff --git a/libavformat/http.c b/libavformat/http.c
index 855c67a..ef66984 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");
+
+ av_strlcpy(s->headers, headers, sizeof(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);
@@ -245,37 +258,55 @@ static int process_line(URLContext *h, char *line, int line_count,
return 1;
}
+static inline int has_header(const char *str, const char *header)
+{
+ /* header+2 to skip over CRLF prefix. (make sure you have one!) */
+ return av_stristart(str, header+2, NULL) || av_stristr(str, header);
+}
+
static int http_connect(URLContext *h, const char *path, const char *hoststr,
const char *auth, int *new_location)
{
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(!has_header(s->headers, "\r\nUser-Agent: "))
+ len += av_strlcatf(headers+len, sizeof(headers)-len, "User-Agent: %s\r\n", LIBAVFORMAT_IDENT);
+ if(!has_header(s->headers, "\r\nAccept: "))
+ len += av_strlcpy(headers+len, "Accept: */*\r\n", sizeof(headers)-len);
+ if(!has_header(s->headers, "\r\nRange: "))
+ len += av_strlcatf(headers+len, sizeof(headers)-len, "Range: bytes=%"PRId64"\r\n", s->off);
+ if(!has_header(s->headers, "\r\nConnection: "))
+ len += av_strlcpy(headers+len, "Connection: close\r\n", sizeof(headers)-len);
+ if(!has_header(s->headers, "\r\nHost: "))
+ len += av_strlcatf(headers+len, sizeof(headers)-len, "Host: %s\r\n", hoststr);
+
+ /* now add in custom headers */
+ av_strlcpy(headers+len, s->headers, sizeof(headers)-len);
+
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..64dd21f
--- /dev/null
+++ b/libavformat/http.h
@@ -0,0 +1,42 @@
+/*
+ * 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 can be overriden by custom values,
+ * otherwise they will be set to their defaults.
+ * -User-Agent
+ * -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 c98a09efaac646d20a13cdd9c13a815e80a4893a Mon Sep 17 00:00:00 2001
From: Josh Allmann <[email protected]>
Date: Sat, 5 Jun 2010 14:43:18 -0700
Subject: [PATCH 3/6] 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 ef66984..df57c42 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)
av_strlcpy(s->headers, headers, sizeof(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';
@@ -304,7 +311,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 : "");
@@ -405,7 +412,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;
@@ -425,11 +432,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 64dd21f..6e2e8fa 100644
--- a/libavformat/http.h
+++ b/libavformat/http.h
@@ -39,4 +39,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 95cf8e831898e356403887707cdffa6bca12456e Mon Sep 17 00:00:00 2001
From: Josh Allmann <[email protected]>
Date: Fri, 4 Jun 2010 09:31:39 -0700
Subject: [PATCH 5/6] Added in RTSP tunneling over HTTP.
---
libavformat/rtsp.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++--
libavformat/rtsp.h | 12 ++++++++
2 files changed, 81 insertions(+), 3 deletions(-)
diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c
index fb0747d..2d5d147 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)
@@ -1030,9 +1035,15 @@ void ff_rtsp_send_cmd_with_content_async(AVFormatContext *s,
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 +1488,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 +1518,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 +1540,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 +1554,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 +1611,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