[FFmpeg-devel] avformat/http: allow content range to set filesize

Submitted by PHILIP DE NIER on Dec. 9, 2016, 11:54 a.m.

Details

Message ID 661340250.1596155.1481284482287@mail.yahoo.com
State New
Headers show

Commit Message

PHILIP DE NIER Dec. 9, 2016, 11:54 a.m.
Hi,
Attached patch fixes issue #6007 for me.
I think it could improved / extended because the "if (s->seekable == -1 && (!s->is_akamai || s->content_range_len != 2147483647))" is probably better placed http_read_header along with the similar is_mediagateway workaround. I wasn't sure whether the is_akamai should only be triggered if the filesize was read from the Content-Range header.
Philip

Comments

Philip de Nier Jan. 31, 2017, 10:26 a.m.
On 09/12/2016 11:54, PHILIP DE NIER wrote:
> Hi,
> Attached patch fixes issue #6007 for me.
> I think it could improved / extended because the "if (s->seekable ==
> -1 && (!s->is_akamai || s->content_range_len != 2147483647))" is
> probably better placed http_read_header along with the similar
> is_mediagateway workaround. I wasn't sure whether the is_akamai should
> only be triggered if the filesize was read from the Content-Range header.
> Philip
>
>
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>

Ping?

A summary of issue #6007:
A quicktime file is being served using chunked transfer and byte range
requests enabled. FFmpeg opens the file in libavformat, mov.c
mov_read_default and it fails to complete because the (seekable) file
returns an error (ENOSYS) for avio_size. avio_size is returning an error
because the code in libavformat/http.c is ignoring the resource length
provided by the Content-Range response header.

Thanks.
Philip
Aman Gupta Dec. 21, 2017, 2:02 a.m.
On Tue, Jan 31, 2017 at 2:26 AM, Philip de Nier <philipn@rd.bbc.co.uk>
wrote:

> On 09/12/2016 11:54, PHILIP DE NIER wrote:
> > Hi,
> > Attached patch fixes issue #6007 for me.
> > I think it could improved / extended because the "if (s->seekable ==
> > -1 && (!s->is_akamai || s->content_range_len != 2147483647))" is
> > probably better placed http_read_header along with the similar
> > is_mediagateway workaround. I wasn't sure whether the is_akamai should
> > only be triggered if the filesize was read from the Content-Range header.
> > Philip
> >
> >
> >
> > _______________________________________________
> > ffmpeg-devel mailing list
> > ffmpeg-devel@ffmpeg.org
> > http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> >
>
> Ping?
>
> A summary of issue #6007:
> A quicktime file is being served using chunked transfer and byte range
> requests enabled. FFmpeg opens the file in libavformat, mov.c
> mov_read_default and it fails to complete because the (seekable) file
> returns an error (ENOSYS) for avio_size. avio_size is returning an error
> because the code in libavformat/http.c is ignoring the resource length
> provided by the Content-Range response header.
>

This looks reasonable to me. Any thoughts Anssi?

Aman


>
> Thanks.
> Philip
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>

Patch hide | download patch | download mbox

From 0ac79d03981e823a1922e7e1f58af7f3b02dca7d Mon Sep 17 00:00:00 2001
From: Philip de Nier <philipn@rd.bbc.co.uk>
Date: Wed, 7 Dec 2016 15:09:09 +0000
Subject: [PATCH] http: allow content range to set filesize

Set filesize to Content-Length if present and Transfer-Encoding is
not chunked. Otherwise set to Content-Range instance length if present.

Solves issue where filesize is set to unknown when using byte range
requests in combination with chunked transfers.

Fixes issue #6007
---
 libavformat/http.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/libavformat/http.c b/libavformat/http.c
index 944a6cf..8dfaa5d 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -63,6 +63,7 @@  typedef struct HTTPContext {
     int http_code;
     /* Used if "Transfer-Encoding: chunked" otherwise -1. */
     uint64_t chunksize;
+    uint64_t content_len, content_range_len;
     uint64_t off, end_off, filesize;
     char *location;
     HTTPAuthState auth_state;
@@ -618,9 +619,9 @@  static void parse_content_range(URLContext *h, const char *p)
         p     += 6;
         s->off = strtoull(p, NULL, 10);
         if ((slash = strchr(p, '/')) && strlen(slash) > 0)
-            s->filesize = strtoull(slash + 1, NULL, 10);
+            s->content_range_len = strtoull(slash + 1, NULL, 10);
     }
-    if (s->seekable == -1 && (!s->is_akamai || s->filesize != 2147483647))
+    if (s->seekable == -1 && (!s->is_akamai || s->content_range_len != 2147483647))
         h->is_streamed = 0; /* we _can_ in fact seek */
 }
 
@@ -810,7 +811,7 @@  static int process_line(URLContext *h, char *line, int line_count,
             *new_location = 1;
         } else if (!av_strcasecmp(tag, "Content-Length") &&
                    s->filesize == UINT64_MAX) {
-            s->filesize = strtoull(p, NULL, 10);
+            s->content_len = strtoull(p, NULL, 10);
         } else if (!av_strcasecmp(tag, "Content-Range")) {
             parse_content_range(h, p);
         } else if (!av_strcasecmp(tag, "Accept-Ranges") &&
@@ -819,7 +820,6 @@  static int process_line(URLContext *h, char *line, int line_count,
             h->is_streamed = 0;
         } else if (!av_strcasecmp(tag, "Transfer-Encoding") &&
                    !av_strncasecmp(p, "chunked", 7)) {
-            s->filesize  = UINT64_MAX;
             s->chunksize = 0;
         } else if (!av_strcasecmp(tag, "WWW-Authenticate")) {
             ff_http_auth_handle_header(&s->auth_state, tag, p);
@@ -974,6 +974,8 @@  static int http_read_header(URLContext *h, int *new_location)
     int err = 0;
 
     s->chunksize = UINT64_MAX;
+    s->content_range_len = UINT64_MAX;
+    s->content_len = UINT64_MAX;
 
     for (;;) {
         if ((err = http_get_line(s, line, sizeof(line))) < 0)
@@ -989,6 +991,13 @@  static int http_read_header(URLContext *h, int *new_location)
         s->line_count++;
     }
 
+    if (s->filesize == UINT64_MAX) {
+        if (s->chunksize == UINT64_MAX && s->content_len != UINT64_MAX)
+            s->filesize = s->content_len;
+        else if (s->content_range_len != UINT64_MAX)
+            s->filesize = s->content_range_len;
+    }
+
     if (s->seekable == -1 && s->is_mediagateway && s->filesize == 2000000000)
         h->is_streamed = 1; /* we can in fact _not_ seek */
 
-- 
1.9.1