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

Reply via email to