[FFmpeg-devel] [PATCH v2] Option to prevent probing for HTTP seekability

Duncan Salerno duncan.salerno at gmail.com
Wed Sep 26 20:56:19 CEST 2012


Some HLS servers return 403 when the Range header is present. Add an option to HTTP to control sending the range header (default on). HLS sets this option to disabled.

Updated with feedback from Clément Bœsch. I'd prefer not to overload the meaning of is_streamed as I think its less clear whats going on.
---
 libavformat/hls.c  |   48 ++++++++++++++++++++++++++++++------------------
 libavformat/http.c |    6 ++++--
 2 files changed, 34 insertions(+), 20 deletions(-)

diff --git a/libavformat/hls.c b/libavformat/hls.c
index 00c3cf0..21b2b87 100644
--- a/libavformat/hls.c
+++ b/libavformat/hls.c
@@ -212,10 +212,15 @@ static int parse_playlist(HLSContext *c, const char *url,
     int close_in = 0;
 
     if (!in) {
-        close_in = 1;
-        if ((ret = avio_open2(&in, url, AVIO_FLAG_READ,
-                              c->interrupt_callback, NULL)) < 0)
+        AVDictionary *opts = NULL;
+        /* Some HLS servers dont like being sent the range header */
+        av_dict_set(&opts, "probe_seek", "0", 0);
+        ret = avio_open2(&in, url, AVIO_FLAG_READ,
+                         c->interrupt_callback, &opts);
+        av_dict_free(&opts);
+        if (ret < 0)
             return ret;
+        close_in = 1;
     }
 
     read_chomp_line(in, line, sizeof(line));
@@ -325,17 +330,19 @@ fail:
 
 static int open_input(struct variant *var)
 {
+    AVDictionary *opts = NULL;
+    int ret;
     struct segment *seg = var->segments[var->cur_seq_no - var->start_seq_no];
+    av_dict_set(&opts, "probe_seek", "0", 0);
     if (seg->key_type == KEY_NONE) {
-        return ffurl_open(&var->input, seg->url, AVIO_FLAG_READ,
-                          &var->parent->interrupt_callback, NULL);
+        ret = ffurl_open(&var->input, seg->url, AVIO_FLAG_READ,
+                             &var->parent->interrupt_callback, &opts);
     } else if (seg->key_type == KEY_AES_128) {
         char iv[33], key[33], url[MAX_URL_SIZE];
-        int ret;
         if (strcmp(seg->key, var->key_url)) {
             URLContext *uc;
             if (ffurl_open(&uc, seg->key, AVIO_FLAG_READ,
-                           &var->parent->interrupt_callback, NULL) == 0) {
+                           &var->parent->interrupt_callback, &opts) == 0) {
                 if (ffurl_read_complete(uc, var->key, sizeof(var->key))
                     != sizeof(var->key)) {
                     av_log(NULL, AV_LOG_ERROR, "Unable to read key file %s\n",
@@ -355,19 +362,24 @@ static int open_input(struct variant *var)
             snprintf(url, sizeof(url), "crypto+%s", seg->url);
         else
             snprintf(url, sizeof(url), "crypto:%s", seg->url);
-        if ((ret = ffurl_alloc(&var->input, url, AVIO_FLAG_READ,
-                               &var->parent->interrupt_callback)) < 0)
-            return ret;
-        av_opt_set(var->input->priv_data, "key", key, 0);
-        av_opt_set(var->input->priv_data, "iv", iv, 0);
-        if ((ret = ffurl_connect(var->input, NULL)) < 0) {
-            ffurl_close(var->input);
-            var->input = NULL;
-            return ret;
+        ret = ffurl_alloc(&var->input, url, AVIO_FLAG_READ,
+                          &var->parent->interrupt_callback);
+        if (ret >= 0) {
+            av_opt_set(var->input->priv_data, "key", key, 0);
+            av_opt_set(var->input->priv_data, "iv", iv, 0);
+            if ((ret = ffurl_connect(var->input, &opts)) < 0) {
+                ffurl_close(var->input);
+                var->input = NULL;
+            }
+            else
+                ret = 0;
         }
-        return 0;
     }
-    return AVERROR(ENOSYS);
+    else
+        ret = AVERROR(ENOSYS);
+
+    av_dict_free(&opts);
+    return ret;
 }
 
 static int read_data(void *opaque, uint8_t *buf, int buf_size)
diff --git a/libavformat/http.c b/libavformat/http.c
index ede4e8b..0eec2bb 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -50,6 +50,7 @@ typedef struct {
     HTTPAuthState proxy_auth_state;
     char *headers;
     int willclose;          /**< Set if the server correctly handles Connection: close and will close the connection after feeding us the content. */
+    int probe_seek;         /**< Set if we send the range header to probe if server support seeking. */
     int chunked_post;
     int end_chunked_post;   /**< A flag which indicates if the end of chunked encoding has been sent. */
     int end_header;         /**< A flag which indicates we have finished to read POST reply. */
@@ -64,6 +65,7 @@ typedef struct {
 #define E AV_OPT_FLAG_ENCODING_PARAM
 #define DEC AV_OPT_FLAG_DECODING_PARAM
 static const AVOption options[] = {
+{"probe_seek", "probe if server supports seeking by sending range header", OFFSET(probe_seek), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, D },
 {"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 },
 {"user-agent", "override User-Agent header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC},
@@ -411,10 +413,10 @@ 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);
-    // Note: we send this on purpose even when s->off is 0,
+    // Note: we send this on purpose even when s->off is 0 and probe_seek set,
     // 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)
+    if (!has_header(s->headers, "\r\nRange: ") && !post && (s->off > 0 || s->probe_seek))
         len += av_strlcatf(headers + len, sizeof(headers) - len,
                            "Range: bytes=%"PRId64"-\r\n", s->off);
 
-- 
1.7.9.5



More information about the ffmpeg-devel mailing list