]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/rtmphttp.c
Check mp3 header before calling avpriv_mpegaudio_decode_header().
[ffmpeg] / libavformat / rtmphttp.c
index 544b49350007e2aa5ebeade22eda0bdff9686c50..34c68fb437e33a1f39ae6724424116820c6d655c 100644 (file)
  * RTMP HTTP protocol
  */
 
-#include <unistd.h>
-
 #include "libavutil/avstring.h"
 #include "libavutil/intfloat.h"
 #include "libavutil/opt.h"
+#include "libavutil/time.h"
 #include "internal.h"
 #include "http.h"
+#include "rtmp.h"
 
 #define RTMPT_DEFAULT_PORT 80
+#define RTMPTS_DEFAULT_PORT RTMPS_DEFAULT_PORT
 
 /* protocol handler context */
 typedef struct RTMP_HTTPContext {
+    const AVClass *class;
     URLContext   *stream;           ///< HTTP stream
     char         host[256];         ///< hostname of the server
     int          port;              ///< port to connect (default is 80)
@@ -47,6 +49,7 @@ typedef struct RTMP_HTTPContext {
     int          initialized;       ///< flag indicating when the http context is initialized
     int          finishing;         ///< flag indicating when the client closes the connection
     int          nb_bytes_read;     ///< number of bytes read since the last request
+    int          tls;               ///< use Transport Security Layer (RTMPTS)
 } RTMP_HTTPContext;
 
 static int rtmp_http_send_cmd(URLContext *h, const char *cmd)
@@ -82,14 +85,15 @@ static int rtmp_http_send_cmd(URLContext *h, const char *cmd)
 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) {
+        int err;
         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;
+        if ((err = av_reallocp(&rt->out_data, rt->out_capacity)) < 0) {
+            rt->out_size = 0;
+            rt->out_capacity = 0;
+            return err;
+        }
     }
 
     memcpy(rt->out_data + rt->out_size, buf, size);
@@ -109,7 +113,7 @@ static int rtmp_http_read(URLContext *h, uint8_t *buf, int size)
         if (ret < 0 && ret != AVERROR_EOF)
             return ret;
 
-        if (ret == AVERROR_EOF) {
+        if (!ret || ret == AVERROR_EOF) {
             if (rt->finishing) {
                 /* Do not send new requests when the client wants to
                  * close the connection. */
@@ -126,7 +130,7 @@ static int rtmp_http_read(URLContext *h, uint8_t *buf, int size)
                 if (rt->nb_bytes_read == 0) {
                     /* Wait 50ms before retrying to read a server reply in
                      * order to reduce the number of idle requets. */
-                    usleep(50000);
+                    av_usleep(50000);
                 }
 
                 if ((ret = rtmp_http_write(h, "", 1)) < 0)
@@ -186,9 +190,6 @@ static int rtmp_http_open(URLContext *h, const char *uri, int flags)
     av_url_split(NULL, 0, NULL, 0, rt->host, sizeof(rt->host), &rt->port,
                  NULL, 0, uri);
 
-    if (rt->port < 0)
-        rt->port = RTMPT_DEFAULT_PORT;
-
     /* This is the first request that is sent to the server in order to
      * register a client on the server and start a new session. The server
      * replies with a unique id (usually a number) that is used by the client
@@ -196,7 +197,15 @@ static int rtmp_http_open(URLContext *h, const char *uri, int flags)
      * Note: the reply doesn't contain a value for the polling interval.
      * A successful connect resets the consecutive index that is used
      * in the URLs. */
-    ff_url_join(url, sizeof(url), "http", NULL, rt->host, rt->port, "/open/1");
+    if (rt->tls) {
+        if (rt->port < 0)
+            rt->port = RTMPTS_DEFAULT_PORT;
+        ff_url_join(url, sizeof(url), "https", NULL, rt->host, rt->port, "/open/1");
+    } else {
+        if (rt->port < 0)
+            rt->port = RTMPT_DEFAULT_PORT;
+        ff_url_join(url, sizeof(url), "http", NULL, rt->host, rt->port, "/open/1");
+    }
 
     /* alloc the http context */
     if ((ret = ffurl_alloc(&rt->stream, url, AVIO_FLAG_READ_WRITE, NULL)) < 0)
@@ -218,7 +227,7 @@ static int rtmp_http_open(URLContext *h, const char *uri, int flags)
     /* read the server reply which contains a unique ID */
     for (;;) {
         ret = ffurl_read(rt->stream, rt->client_id + off, sizeof(rt->client_id) - off);
-        if (ret == AVERROR_EOF)
+        if (!ret || ret == AVERROR_EOF)
             break;
         if (ret < 0)
             goto fail;
@@ -228,7 +237,7 @@ static int rtmp_http_open(URLContext *h, const char *uri, int flags)
             goto fail;
         }
     }
-    while (off > 0 && isspace(rt->client_id[off - 1]))
+    while (off > 0 && av_isspace(rt->client_id[off - 1]))
         off--;
     rt->client_id[off] = '\0';
 
@@ -241,12 +250,28 @@ fail:
     return ret;
 }
 
-URLProtocol ff_rtmphttp_protocol = {
-    .name           = "rtmphttp",
+#define OFFSET(x) offsetof(RTMP_HTTPContext, x)
+#define DEC AV_OPT_FLAG_DECODING_PARAM
+
+static const AVOption ffrtmphttp_options[] = {
+    {"ffrtmphttp_tls", "Use a HTTPS tunneling connection (RTMPTS).", OFFSET(tls), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC},
+    { NULL },
+};
+
+static const AVClass ffrtmphttp_class = {
+    .class_name = "ffrtmphttp",
+    .item_name  = av_default_item_name,
+    .option     = ffrtmphttp_options,
+    .version    = LIBAVUTIL_VERSION_INT,
+};
+
+URLProtocol ff_ffrtmphttp_protocol = {
+    .name           = "ffrtmphttp",
     .url_open       = rtmp_http_open,
     .url_read       = rtmp_http_read,
     .url_write      = rtmp_http_write,
     .url_close      = rtmp_http_close,
     .priv_data_size = sizeof(RTMP_HTTPContext),
     .flags          = URL_PROTOCOL_FLAG_NETWORK,
+    .priv_data_class= &ffrtmphttp_class,
 };