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
