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

Duncan Salerno duncan.salerno at gmail.com
Tue Sep 25 22:38:09 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.
---
 libavformat/hls.c  |   27 +++++++++++++++++++++------
 libavformat/http.c |    6 ++++--
 2 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/libavformat/hls.c b/libavformat/hls.c
index 00c3cf0..3bd29bc 100644
--- a/libavformat/hls.c
+++ b/libavformat/hls.c
@@ -212,10 +212,16 @@ static int parse_playlist(HLSContext *c, const char *url,
     int close_in = 0;
 
     if (!in) {
+        AVDictionary *opts = NULL;
+        /* Some HLS servers dont like being sent the range header */
+        av_dict_set(&opts, "probe_seek", "0", 0);
         close_in = 1;
         if ((ret = avio_open2(&in, url, AVIO_FLAG_READ,
-                              c->interrupt_callback, NULL)) < 0)
+                              c->interrupt_callback, &opts)) < 0) {
+            av_dict_free(&opts);
             return ret;
+        }
+        av_dict_free(&opts);
     }
 
     read_chomp_line(in, line, sizeof(line));
@@ -325,17 +331,21 @@ fail:
 
 static int open_input(struct variant *var)
 {
+    AVDictionary *opts = NULL;
     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);
+        int ret = ffurl_open(&var->input, seg->url, AVIO_FLAG_READ,
+                             &var->parent->interrupt_callback, &opts);
+        av_dict_free(&opts);
+        return ret;
     } 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",
@@ -356,17 +366,22 @@ static int open_input(struct variant *var)
         else
             snprintf(url, sizeof(url), "crypto:%s", seg->url);
         if ((ret = ffurl_alloc(&var->input, url, AVIO_FLAG_READ,
-                               &var->parent->interrupt_callback)) < 0)
+                               &var->parent->interrupt_callback)) < 0) {
+            av_dict_free(&opts);
             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) {
+        if ((ret = ffurl_connect(var->input, &opts)) < 0) {
             ffurl_close(var->input);
             var->input = NULL;
+            av_dict_free(&opts);
             return ret;
         }
+        av_dict_free(&opts);
         return 0;
     }
+    av_dict_free(&opts);
     return AVERROR(ENOSYS);
 }
 
diff --git a/libavformat/http.c b/libavformat/http.c
index ede4e8b..6d47882 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;
     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