On Sun, 17 Jun 2012, Samuel Pitoiset wrote:
This adds two protocols, but one of them is an internal implementation
detail just used as an abstraction layer/generalization in the code. The
RTMPT protocol implementation uses rtmphttp:// as an alternative to the
tcp:// protocol. This allows moving most of the lower level logic out
from the higher level generic rtmp code.
---
Changelog | 1 +
configure | 4 +
doc/protocols.texi | 8 ++
libavformat/Makefile | 2 +
libavformat/allformats.c | 2 +
libavformat/rtmphttp.c | 267 ++++++++++++++++++++++++++++++++++++++++++++++
libavformat/rtmpproto.c | 38 ++++++-
libavformat/version.h | 4 +-
8 files changed, 321 insertions(+), 5 deletions(-)
create mode 100644 libavformat/rtmphttp.c
diff --git a/Changelog b/Changelog
index b80ff88..4288aa3 100644
--- a/Changelog
+++ b/Changelog
@@ -25,6 +25,7 @@ version <next>:
be used with -of old.
- Indeo Audio decoder
- channelsplit audio filter
+- RTMPT protocol support
version 0.8:
diff --git a/configure b/configure
index 4bb2030..d614366 100755
--- a/configure
+++ b/configure
@@ -1511,6 +1511,10 @@ mmsh_protocol_select="http_protocol"
mmst_protocol_deps="network"
rtmp_protocol_deps="!librtmp_protocol"
rtmp_protocol_select="tcp_protocol"
+rtmphttp_protocol_deps="!librtmp_protocol"
+rtmphttp_protocol_select="http_protocol"
+rtmpt_protocol_deps="!librtmp_protocol"
+rtmpt_protocol_select="rtmphttp_protocol"
rtp_protocol_select="udp_protocol"
sctp_protocol_deps="network netinet_sctp_h"
tcp_protocol_deps="network"
diff --git a/doc/protocols.texi b/doc/protocols.texi
index 8492033..0b4f1b1 100644
--- a/doc/protocols.texi
+++ b/doc/protocols.texi
@@ -243,6 +243,14 @@ For example to read with @command{avplay} a multimedia
resource named
avplay rtmp://myserver/vod/sample
@end example
+@section rtmpt
+
+Real-Time Messaging Protocol tunneled through HTTP.
+
+The Real-Time Messaging Protocol tunneled through HTTP (RTMPT) is used
+for streaming multimedia content within HTTP requests to traverse
+firewalls.
+
@section rtmp, rtmpe, rtmps, rtmpt, rtmpte
Real-Time Messaging Protocol and its variants supported through
diff --git a/libavformat/Makefile b/libavformat/Makefile
index ca4f7a0..6262324 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -345,6 +345,8 @@ OBJS-$(CONFIG_MMST_PROTOCOL) += mmst.o mms.o
asf.o
OBJS-$(CONFIG_MD5_PROTOCOL) += md5proto.o
OBJS-$(CONFIG_PIPE_PROTOCOL) += file.o
OBJS-$(CONFIG_RTMP_PROTOCOL) += rtmpproto.o rtmppkt.o
+OBJS-$(CONFIG_RTMPHTTP_PROTOCOL) += rtmphttp.o
+OBJS-$(CONFIG_RTMPT_PROTOCOL) += rtmpproto.o rtmppkt.o
OBJS-$(CONFIG_RTP_PROTOCOL) += rtpproto.o
OBJS-$(CONFIG_SCTP_PROTOCOL) += sctp.o
OBJS-$(CONFIG_TCP_PROTOCOL) += tcp.o
diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index 1320a28..69f27ab 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -256,6 +256,8 @@ void av_register_all(void)
REGISTER_PROTOCOL (MD5, md5);
REGISTER_PROTOCOL (PIPE, pipe);
REGISTER_PROTOCOL (RTMP, rtmp);
+ REGISTER_PROTOCOL (RTMPT, rtmpt);
+ REGISTER_PROTOCOL (RTMPHTTP, rtmphttp);
Alphabetic order
REGISTER_PROTOCOL (RTP, rtp);
REGISTER_PROTOCOL (SCTP, sctp);
REGISTER_PROTOCOL (TCP, tcp);
diff --git a/libavformat/rtmphttp.c b/libavformat/rtmphttp.c
new file mode 100644
index 0000000..cc45e27
--- /dev/null
+++ b/libavformat/rtmphttp.c
@@ -0,0 +1,267 @@
+/*
+ * RTMP HTTP network protocol
+ * Copyright (c) 2012 Samuel Pitoiset
+ *
+ * This file is part of Libav.
+ *
+ * Libav 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.
+ *
+ * Libav 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 Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * RTMP HTTP protocol
+ */
+
+#include "libavutil/avstring.h"
+#include "libavutil/intfloat.h"
+#include "libavutil/opt.h"
+#include "internal.h"
+#include "http.h"
+
+#define RTMPT_DEFAULT_PORT 80
+
+/* protocol handler state */
+typedef enum {
+ STATE_START, ///< client has not done anything yet
+ STATE_WAITING, ///< client is waiting for a server reply
+ STATE_READY, ///< client is ready for sending requests
+} ClientState;
+
+/* protocol handler context */
+typedef struct RTMP_HTTPContext {
+ URLContext *stream; ///< HTTP stream
+ char host[256]; ///< hostname of the server
+ int port; ///< port to connect (default is 80)
+ char client_id[64]; ///< client ID used for all requests
except the first one
+ int seq; ///< sequence ID used for all requests
+ ClientState state; ///< current state
+ uint8_t *out_data; ///< output buffer
+ int out_size; ///< current output buffer size
+ int out_capacity; ///< current output buffer capacity
+} RTMP_HTTPContext;
+
+static int rtmp_http_send_cmd(URLContext *h, const char *cmd)
+{
+ RTMP_HTTPContext *rt = h->priv_data;
+ char uri[2048];
+ uint8_t c;
+ int ret;
+
+ ff_url_join(uri, sizeof(uri), "http", NULL, rt->host, rt->port,
+ "/%s/%s/%d", cmd, rt->client_id, rt->seq++);
+
+ av_opt_set_bin(rt->stream->priv_data, "post_data", rt->out_data,
+ rt->out_size, 0);
+
+ /* send a new request to the server */
+ if ((ret = ff_http_do_new_request(rt->stream, uri)) < 0)
+ return ret;
+
+ /* re-init output buffer */
+ rt->out_size = 0;
+
+ /* read the first byte which contains the polling interval */
+ if ((ret = ffurl_read(rt->stream, &c, 1)) < 0)
+ return ret;
+
+ /* client is waiting for a server reply */
+ rt->state = STATE_WAITING;
+
+ return ret;
+}
+
+static int rtmp_http_write(URLContext *h, const uint8_t *buf, int size)
+{
+ RTMP_HTTPContext *rt = h->priv_data;
+ void *ptr;
+
+ if (rt->out_size + size > rt->out_capacity) {
+ rt->out_capacity = (rt->out_size + size) * 2;
+ ptr = av_realloc(rt->out_data, rt->out_capacity);
+ if (!ptr)
+ return AVERROR(ENOMEM);
+ rt->out_data = ptr;
+ }
+
+ memcpy(rt->out_data + rt->out_size, buf, size);
+ rt->out_size += size;
+
+ return size;
+}
+
+static int rtmp_http_read(URLContext *h, uint8_t *buf, int size)
+{
+ RTMP_HTTPContext *rt = h->priv_data;
+ int ret, off = 0;
+
+ if ((h->flags & AVIO_FLAG_NONBLOCK) && rt->state != STATE_WAITING)
+ return AVERROR(EAGAIN);
+
+ /* try to read at least 1 byte of data */
+ do {
+ ret = ffurl_read(rt->stream, buf + off, size);
+ if (ret < 0 && ret != AVERROR_EOF)
+ return ret;
+
+ if (ret == AVERROR_EOF) {
+ if (rt->stream->flags & AVIO_FLAG_NONBLOCK) {
+ /* no incoming data to handle */
+ return AVERROR(EAGAIN);
+ }
This isn't totally right. I see that you set rt->stream to nonblocking
mode at the end - that's not right and not what I intended. I see that you
do this to distinguish between normal nonblocking reads (by the caller)
and reads by the close function (where we should not send a new request on
EOF).
You can't set rt->stream into nonblocking mode, it doesn't do anything
currently. What I intended was that you in rtmp_http_close would set
_this_ URLContext into nonblocking mode. For this to work, you would need
to return here (not below the sending of a new request) in nonblocking
mode. If returning here, you should set state to READY. Currently, the
state variable is mostly useless again since you never ever set the state
back to READY.
But instead of fixing it up this way, the way you've done it might
actually be quite a good direction, you'll need about these changes again:
- Don't set the http urlcontext to nonblocking mode in rtmp_http_close,
set this one to nonblocking mode.
- Add a context variable "finishing", you only set this at the end before
trying to read all the remaining data. If finishing is 1, you return here
(before sending a new send/idle request), if 0 you return below (as you do
now).
- Since you implicitly send a new request after EOF in nonblocking mode,
you don't need the shutdown function (again) and can get rid of both that
and the call in rtmpproto.c
- Get rid of the nonblocking check at the start of rtmp_http_read, which
checks the state. Since you really never set the state back into READY,
this is useless.
- Get rid of the state variable altogether. All you need is "int
initialized", which you check in rtmp_http_close - other than that, you
don't need anything else, since you normally just send a new request
immediately.
// Martin
_______________________________________________
libav-devel mailing list
libav-devel@libav.org
https://lists.libav.org/mailman/listinfo/libav-devel