]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/http.c
riff: add "GXVE" FourCC for WMV2
[ffmpeg] / libavformat / http.c
index 84cc7f1fd34f4a40c6a3b5339350851c324369ee..948930a053d765cf462a39d265ff7df06d93f8ae 100644 (file)
@@ -51,13 +51,14 @@ typedef struct {
     int http_code;
     /* Used if "Transfer-Encoding: chunked" otherwise -1. */
     int64_t chunksize;
-    int64_t off, filesize;
+    int64_t off, end_off, filesize;
     char *location;
     HTTPAuthState auth_state;
     HTTPAuthState proxy_auth_state;
     char *headers;
     char *mime_type;
     char *user_agent;
+    char *content_type;
     /* Set if the server correctly handles Connection: close and will close
      * the connection after feeding us the content. */
     int willclose;
@@ -92,11 +93,12 @@ typedef struct {
 #define DEFAULT_USER_AGENT "Lavf/" AV_STRINGIFY(LIBAVFORMAT_VERSION)
 static const AVOption options[] = {
 {"chunked_post", "use chunked transfer-encoding for posts", OFFSET(chunked_post), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, E },
-{"headers", "custom HTTP headers, can override built in default headers", OFFSET(headers), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D|E },
+{"headers", "set custom HTTP headers, can override built in default headers", OFFSET(headers), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D|E },
+{"content_type", "set a specific content type for the POST messages", OFFSET(content_type), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D|E },
 {"user_agent", "override User-Agent header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = DEFAULT_USER_AGENT}, 0, 0, D },
 {"user-agent", "override User-Agent header, for compatibility with ffmpeg", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = DEFAULT_USER_AGENT}, 0, 0, D },
 {"multiple_requests", "use persistent connections", OFFSET(multiple_requests), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D|E },
-{"post_data", "custom HTTP post data", OFFSET(post_data), AV_OPT_TYPE_BINARY, .flags = D|E },
+{"post_data", "set custom HTTP post data", OFFSET(post_data), AV_OPT_TYPE_BINARY, .flags = D|E },
 {"mime_type", "export the MIME type", OFFSET(mime_type), AV_OPT_TYPE_STRING, {0}, 0, 0, AV_OPT_FLAG_EXPORT | AV_OPT_FLAG_READONLY  },
 {"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, AV_OPT_FLAG_EXPORT },
@@ -106,6 +108,8 @@ static const AVOption options[] = {
 {"basic", "HTTP basic authentication", 0, AV_OPT_TYPE_CONST, {.i64 = HTTP_AUTH_BASIC}, 0, 0, D|E, "auth_type" },
 {"send_expect_100", "Force sending an Expect: 100-continue header for POST", OFFSET(send_expect_100), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, E },
 {"location", "The actual location of the data received", OFFSET(location), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D|E },
+{"offset", "initial byte offset", OFFSET(off), AV_OPT_TYPE_INT64, {.i64 = 0}, 0, INT64_MAX, D },
+{"end_offset", "try to limit the request to bytes preceding this offset", OFFSET(end_off), AV_OPT_TYPE_INT64, {.i64 = 0}, 0, INT64_MAX, D },
 {NULL}
 };
 #define HTTP_CLASS(flavor)\
@@ -349,7 +353,7 @@ static int parse_location(HTTPContext *s, const char *p)
 }
 
 /* "bytes $from-$to/$document_size" */
-static void parse_content_range(URLContext *h, char *p)
+static void parse_content_range(URLContext *h, const char *p)
 {
     HTTPContext *s = h->priv_data;
     const char *slash;
@@ -363,7 +367,7 @@ static void parse_content_range(URLContext *h, char *p)
     h->is_streamed = 0; /* we _can_ in fact seek */
 }
 
-static int parse_content_encoding(URLContext *h, char *p)
+static int parse_content_encoding(URLContext *h, const char *p)
 {
     HTTPContext *s = h->priv_data;
 
@@ -401,6 +405,7 @@ static int parse_content_encoding(URLContext *h, char *p)
 static int parse_icy(HTTPContext *s, const char *tag, const char *p)
 {
     int len = 4 + strlen(p) + strlen(tag);
+    int is_first = !s->icy_metadata_headers;
     int ret;
 
     if (s->icy_metadata_headers)
@@ -409,6 +414,9 @@ static int parse_icy(HTTPContext *s, const char *tag, const char *p)
     if ((ret = av_reallocp(&s->icy_metadata_headers, len)) < 0)
         return ret;
 
+    if (is_first)
+        *s->icy_metadata_headers = '\0';
+
     av_strlcatf(s->icy_metadata_headers, len, "%s: %s\n", tag, p);
 
     return 0;
@@ -571,9 +579,18 @@ static int http_connect(URLContext *h, const char *path, const char *local_path,
     if (!has_header(s->headers, "\r\nAccept: "))
         len += av_strlcpy(headers + len, "Accept: */*\r\n",
                           sizeof(headers) - len);
-    if (!has_header(s->headers, "\r\nRange: ") && !post)
+    // Note: we send this on purpose even when s->off is 0 when we're probing,
+    // since it allows us to detect more reliably if a (non-conforming)
+    // server supports seeking by analysing the reply headers.
+    if (!has_header(s->headers, "\r\nRange: ") && !post) {
         len += av_strlcatf(headers + len, sizeof(headers) - len,
-                           "Range: bytes=%"PRId64"-\r\n", s->off);
+                           "Range: bytes=%"PRId64"-", s->off);
+        if (s->end_off)
+            len += av_strlcatf(headers + len, sizeof(headers) - len,
+                               "%"PRId64, s->end_off - 1);
+        len += av_strlcpy(headers + len, "\r\n",
+                          sizeof(headers) - len);
+    }
     if (send_expect_100 && !has_header(s->headers, "\r\nExpect: "))
         len += av_strlcatf(headers + len, sizeof(headers) - len,
                            "Expect: 100-continue\r\n");
@@ -594,6 +611,10 @@ static int http_connect(URLContext *h, const char *path, const char *local_path,
     if (!has_header(s->headers, "\r\nContent-Length: ") && s->post_data)
         len += av_strlcatf(headers + len, sizeof(headers) - len,
                            "Content-Length: %d\r\n", s->post_datalen);
+
+    if (!has_header(s->headers, "\r\nContent-Type: ") && s->content_type)
+        len += av_strlcatf(headers + len, sizeof(headers) - len,
+                           "Content-Type: %s\r\n", s->content_type);
     if (!has_header(s->headers, "\r\nIcy-MetaData: ") && s->icy) {
         len += av_strlcatf(headers + len, sizeof(headers) - len,
                            "Icy-MetaData: %d\r\n", 1);
@@ -890,6 +911,9 @@ static int64_t http_seek(URLContext *h, int64_t off, int whence)
 
     if (whence == AVSEEK_SIZE)
         return s->filesize;
+    else if ((whence == SEEK_CUR && off == 0) ||
+             (whence == SEEK_SET && off == s->off))
+        return s->off;
     else if ((s->filesize == -1 && whence == SEEK_END) || h->is_streamed)
         return AVERROR(ENOSYS);