Opened 4 years ago
Last modified 4 years ago
#9071 new defect
HLS (EXT-X-BYTERANGE) and persistent connection how Range header is replaced ?
Reported by: | e2iplayer | Owned by: | |
---|---|---|---|
Priority: | normal | Component: | avformat |
Version: | git-master | Keywords: | hls |
Cc: | liuqi05@kuaishou.com | Blocked By: | |
Blocking: | Reproduced by developer: | no | |
Analyzed by developer: | yes |
Description
Summary of the bug:
During analysis of previous reported by me bug #9070
I found that HLS segments in (EXT-X-BYTERANGE) format are handled wrongly when persistent connection is enabled.
To be able to correctly set Range header in http.c there is need to pass options with:
av_dict_set_int(&opts, "offset", seg->url_offset, 0); av_dict_set_int(&opts, "end_offset", seg->url_offset + seg->size, 0);
But as you can see in hls.c if connection is re-used the "offset" and "end_offset" are not replaced by new values.
What causes that wrong Range header will be send.
In ff_http_do_new_request only s->off will be set to 0, so if connection will be reused second segment will be requested with Range header == "bytes=0-valueFromPrevRequest"
Is there something I don't understand?
Change History (3)
comment:1 by , 4 years ago
Cc: | added |
---|
comment:2 by , 4 years ago
Unfortunately not. I tried to made some investigation but I don't understand how options are propagated between contexts.
Please take a look:
diff -x '*.[^ch]' -uNr ffmpeg2/libavformat/hls.c ffmpeg/libavformat/hls.c --- ffmpeg-4.2.2_http/ffmpeg-4.2.2/libavformat/hls.c 2021-01-19 10:18:44.494479917 +0100 +++ ffmpeg-4.2.2/libavformat/hls.c 2021-01-20 13:01:54.113543376 +0100 @@ -598,8 +598,10 @@ return 0; } +int ff_http_do_new_request2(URLContext *h, const char *uri, AVDictionary *opts); + static int open_url_keepalive(AVFormatContext *s, AVIOContext **pb, - const char *url) + const char *url, AVDictionary *opts) { #if !CONFIG_HTTP_PROTOCOL return AVERROR_PROTOCOL_NOT_FOUND; @@ -608,7 +610,7 @@ URLContext *uc = ffio_geturlcontext(*pb); av_assert0(uc); (*pb)->eof_reached = 0; - ret = ff_http_do_new_request(uc, url); + ret = ff_http_do_new_request2(uc, url, opts); if (ret < 0) { ff_format_io_close(s, pb); } @@ -661,7 +663,7 @@ return AVERROR_INVALIDDATA; if (is_http && c->http_persistent && *pb) { - ret = open_url_keepalive(c->ctx, pb, url); + ret = open_url_keepalive(c->ctx, pb, url, tmp); if (ret == AVERROR_EXIT) { return ret; } else if (ret < 0) { @@ -718,7 +720,10 @@ if (is_http && !in && c->http_persistent && c->playlist_pb) { in = c->playlist_pb; - ret = open_url_keepalive(c->ctx, &c->playlist_pb, url); + AVDictionary *opts = NULL; + av_dict_copy(&opts, c->avio_opts, 0); + ret = open_url_keepalive(c->ctx, &c->playlist_pb, url, opts); + av_dict_free(&opts); if (ret == AVERROR_EXIT) { return ret; } else if (ret < 0) { diff -x '*.[^ch]' -uNr ffmpeg2/libavformat/http.c ffmpeg/libavformat/http.c --- ffmpeg-4.2.2_http/ffmpeg-4.2.2/libavformat/http.c 2021-01-19 10:20:05.614484136 +0100 +++ ffmpeg-4.2.2/libavformat/http.c 2021-01-20 14:07:25.875704582 +0100 @@ -242,6 +242,7 @@ err = http_connect(h, path, local_path, hoststr, auth, proxyauth, &location_changed); + if (err < 0) return err; @@ -304,8 +305,9 @@ return location_changed; return ff_http_averror(s->http_code, AVERROR(EIO)); } +int ff_http_do_new_request2(URLContext *h, const char *uri, AVDictionary *opts); -int ff_http_do_new_request(URLContext *h, const char *uri) +int ff_http_do_new_request2(URLContext *h, const char *uri, AVDictionary *opts) { HTTPContext *s = h->priv_data; AVDictionary *options = NULL; @@ -350,12 +352,32 @@ if (!s->location) return AVERROR(ENOMEM); av_log(s, AV_LOG_INFO, "Opening \'%s\' for %s\n", uri, h->flags & AVIO_FLAG_WRITE ? "writing" : "reading"); + if (opts) { + AVDictionaryEntry *t = NULL; + while ((t = av_dict_get(opts, "", t, AV_DICT_IGNORE_SUFFIX))) { + if (!strcmp(t->key, "offset")) { + s->off = strtoull(t->value, NULL, 10); + } + if (!strcmp(t->key, "end_offset")) { + s->end_off = strtoull(t->value, NULL, 10); + } + } + av_dict_copy(&options, opts, 0); + } ret = http_open_cnx(h, &options); av_dict_free(&options); return ret; } +int ff_http_do_new_request(URLContext *h, const char *uri) +{ + return ff_http_do_new_request2(h, uri, NULL); +} +
I do not undestand why this:
+ AVDictionaryEntry *t = NULL; + while ((t = av_dict_get(opts, "", t, AV_DICT_IGNORE_SUFFIX))) { + if (!strcmp(t->key, "offset")) { + s->off = strtoull(t->value, NULL, 10); + } + if (!strcmp(t->key, "end_offset")) { + s->end_off = strtoull(t->value, NULL, 10); + } + }
is needed? Why this is not automaticly applied to URLContext in the function
ret = http_open_cnx(h, &options);
do you have any idea?
comment:3 by , 4 years ago
Keywords: | hls added |
---|---|
Priority: | important → normal |
Looks you have known how to fix it, can you send a patch to maillist please?