dnxhdenc: Optimize get_pixels_8x4_sym for 10-bit
[ffmpeg.git] / libavformat / rtmphttp.c
index fdcff50..0334ba5 100644 (file)
@@ -2,20 +2,20 @@
  * RTMP HTTP network protocol
  * Copyright (c) 2012 Samuel Pitoiset
  *
- * This file is part of Libav.
+ * This file is part of FFmpeg.
  *
- * Libav is free software; you can redistribute it and/or
+ * 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.
  *
- * Libav is distributed in the hope that it will be useful,
+ * 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 Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
 #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)
@@ -44,6 +48,8 @@ typedef struct RTMP_HTTPContext {
     int          out_capacity;      ///< current output buffer capacity
     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)
@@ -70,20 +76,24 @@ static int rtmp_http_send_cmd(URLContext *h, const char *cmd)
     if ((ret = ffurl_read(rt->stream, &c, 1)) < 0)
         return ret;
 
+    /* re-init the number of bytes read */
+    rt->nb_bytes_read = 0;
+
     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) {
+        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);
@@ -103,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. */
@@ -117,6 +127,12 @@ static int rtmp_http_read(URLContext *h, uint8_t *buf, int size)
                 if ((ret = rtmp_http_send_cmd(h, "send")) < 0)
                     return ret;
             } else {
+                if (rt->nb_bytes_read == 0) {
+                    /* Wait 50ms before retrying to read a server reply in
+                     * order to reduce the number of idle requets. */
+                    av_usleep(50000);
+                }
+
                 if ((ret = rtmp_http_write(h, "", 1)) < 0)
                     return ret;
 
@@ -131,6 +147,7 @@ static int rtmp_http_read(URLContext *h, uint8_t *buf, int size)
         } else {
             off  += ret;
             size -= ret;
+            rt->nb_bytes_read += ret;
         }
     } while (off <= 0);
 
@@ -173,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
@@ -183,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)
@@ -205,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;
@@ -215,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';
 
@@ -228,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,
 };