Merge commit '8075c3d8bb1f6aade0cc7c5c40db9bc1bcd84cab'
[ffmpeg.git] / libavformat / http.c
index fd5861c..95a64e4 100644 (file)
@@ -54,8 +54,6 @@ typedef struct {
     char *content_type;
     char *user_agent;
     int64_t off, filesize, req_end_offset;
-    int icy_data_read;      ///< how much data was read since last ICY metadata packet
-    int icy_metaint;        ///< after how many bytes of read data a new metadata packet will be found
     char *location;
     HTTPAuthState auth_state;
     HTTPAuthState proxy_auth_state;
@@ -78,6 +76,10 @@ typedef struct {
     char *mime_type;
     char *cookies;          ///< holds newline (\n) delimited Set-Cookie header field values (without the "Set-Cookie: " field name)
     int icy;
+    /* how much data was read since the last ICY metadata packet */
+    int icy_data_read;
+    /* after how many bytes of read data a new metadata packet will be found */
+    int icy_metaint;
     char *icy_metadata_headers;
     char *icy_metadata_packet;
 #if CONFIG_ZLIB
@@ -104,8 +106,8 @@ static const AVOption options[] = {
 {"mime_type", "set MIME type", OFFSET(mime_type), AV_OPT_TYPE_STRING, {0}, 0, 0, 0 },
 {"cookies", "set cookies to be sent in applicable future requests, use newline delimited Set-Cookie HTTP field value syntax", OFFSET(cookies), AV_OPT_TYPE_STRING, {0}, 0, 0, D },
 {"icy", "request ICY metadata", OFFSET(icy), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D },
-{"icy_metadata_headers", "return ICY metadata headers", OFFSET(icy_metadata_headers), AV_OPT_TYPE_STRING, {0}, 0, 0, 0 },
-{"icy_metadata_packet", "return current ICY metadata packet", OFFSET(icy_metadata_packet), AV_OPT_TYPE_STRING, {0}, 0, 0, 0 },
+{"icy_metadata_headers", "return ICY metadata headers", OFFSET(icy_metadata_headers), AV_OPT_TYPE_STRING, {0}, 0, 0, AV_OPT_FLAG_EXPORT },
+{"icy_metadata_packet", "return current ICY metadata packet", OFFSET(icy_metadata_packet), AV_OPT_TYPE_STRING, {0}, 0, 0, AV_OPT_FLAG_EXPORT },
 {"auth_type", "HTTP authentication type", OFFSET(auth_state.auth_type), AV_OPT_TYPE_INT, {.i64 = HTTP_AUTH_NONE}, HTTP_AUTH_NONE, HTTP_AUTH_BASIC, D|E, "auth_type" },
 {"none", "No auth method set, autodetect", 0, AV_OPT_TYPE_CONST, {.i64 = HTTP_AUTH_NONE}, 0, 0, D|E, "auth_type" },
 {"basic", "HTTP basic authentication", 0, AV_OPT_TYPE_CONST, {.i64 = HTTP_AUTH_BASIC}, 0, 0, D|E, "auth_type" },
@@ -403,6 +405,23 @@ static int parse_content_encoding(URLContext *h, char *p)
     return 0;
 }
 
+// Concat all Icy- header lines
+static int parse_icy(HTTPContext *s, const char *tag, const char *p)
+{
+    int len = 4 + strlen(p) + strlen(tag);
+    int ret;
+
+    if (s->icy_metadata_headers)
+        len += strlen(s->icy_metadata_headers);
+
+    if ((ret = av_reallocp(&s->icy_metadata_headers, len)) < 0)
+        return ret;
+
+    av_strlcatf(s->icy_metadata_headers, len, "%s: %s\n", tag, p);
+
+    return 0;
+}
+
 static int process_line(URLContext *h, char *line, int line_count,
                         int *new_location)
 {
@@ -489,13 +508,8 @@ static int process_line(URLContext *h, char *line, int line_count,
         } else if (!av_strcasecmp (tag, "Icy-MetaInt")) {
             s->icy_metaint = strtoll(p, NULL, 10);
         } else if (!av_strncasecmp(tag, "Icy-", 4)) {
-            // Concat all Icy- header lines
-            char *buf = av_asprintf("%s%s: %s\n",
-                s->icy_metadata_headers ? s->icy_metadata_headers : "", tag, p);
-            if (!buf)
-                return AVERROR(ENOMEM);
-            av_freep(&s->icy_metadata_headers);
-            s->icy_metadata_headers = buf;
+            if ((ret = parse_icy(s, tag, p)) < 0)
+                return ret;
         } else if (!av_strcasecmp(tag, "Content-Encoding")) {
             if ((ret = parse_content_encoding(h, p)) < 0)
                 return ret;
@@ -905,37 +919,52 @@ static int http_read_stream_all(URLContext *h, uint8_t *buf, int size)
     return pos;
 }
 
+static int store_icy(URLContext *h, int size)
+{
+    HTTPContext *s = h->priv_data;
+    /* until next metadata packet */
+    int remaining = s->icy_metaint - s->icy_data_read;
+
+    if (remaining < 0)
+        return AVERROR_INVALIDDATA;
+
+    if (!remaining) {
+        // The metadata packet is variable sized. It has a 1 byte header
+        // which sets the length of the packet (divided by 16). If it's 0,
+        // the metadata doesn't change. After the packet, icy_metaint bytes
+        // of normal data follow.
+        uint8_t ch;
+        int len = http_read_stream_all(h, &ch, 1);
+        if (len < 0)
+            return len;
+        if (ch > 0) {
+            char data[255 * 16 + 1];
+            int ret;
+            len = ch * 16;
+            ret = http_read_stream_all(h, data, len);
+            if (ret < 0)
+                return ret;
+            data[len + 1] = 0;
+            if ((ret = av_opt_set(s, "icy_metadata_packet", data, 0)) < 0)
+                return ret;
+        }
+        s->icy_data_read = 0;
+        remaining = s->icy_metaint;
+    }
+
+    return FFMIN(size, remaining);
+}
+
 static int http_read(URLContext *h, uint8_t *buf, int size)
 {
     HTTPContext *s = h->priv_data;
 
     if (s->icy_metaint > 0) {
-        int remaining = s->icy_metaint - s->icy_data_read; /* until next metadata packet */
-        if (!remaining) {
-            // The metadata packet is variable sized. It has a 1 byte header
-            // which sets the length of the packet (divided by 16). If it's 0,
-            // the metadata doesn't change. After the packet, icy_metaint bytes
-            // of normal data follow.
-            uint8_t ch;
-            int len = http_read_stream_all(h, &ch, 1);
-            if (len < 1)
-                return len;
-            if (ch > 0) {
-                char data[255 * 16 + 1];
-                int ret;
-                len = ch * 16;
-                ret = http_read_stream_all(h, data, len);
-                if (ret < len)
-                    return ret;
-                data[len + 1] = 0;
-                if ((ret = av_opt_set(s, "icy_metadata_packet", data, 0)) < 0)
-                    return ret;
-            }
-            s->icy_data_read = 0;
-            remaining = s->icy_metaint;
-        }
-        size = FFMIN(size, remaining);
+        size = store_icy(h, size);
+        if (size < 0)
+            return size;
     }
+
     size = http_read_stream(h, buf, size);
     if (size > 0)
         s->icy_data_read += size;