From: Aman Karmani <a...@tmm1.net> The HTTP spec allows '*' for document size in Content-Range response headers, to specify that the file size is unknown:
Content-Range: <unit> <range-start>-<range-end>/<size> Content-Range: <unit> <range-start>-<range-end>/* Content-Range: <unit> */<size> In the case where the filesize is unknown, this patch keeps track of a new fileend variable which is the approximate size based on the range and data returned by the server. Practically speaking, this patch can be used effectively "tail" a stream that is still being appended to. For example, a PVR system may record an mpegts stream to disk, and serve up the same file to players while the stream is actively being recorded. By adding a `Content-Range: bytes X-Y/*` header to the response, the server can inform the ffmpeg-based player that the stream is "active" and that the file size will continue to grow. For every incoming request, the server would: - open file handle to recording in progress - seek file handle to offset requested by the incoming `Range` header - query the current file size of the file - return a `Content-Range` header with the format `bytes <start offset>-<current file size>/*` - copy bytes from the file to the http socket - on eof, wait and try reading from the file again to "tail" it as long as the recording is "active" On the ffmpeg size, we simply use MAX(s->off, s->fileend) to decide how large the file is whenever requested via AVSEEK_SIZE. This effectively allows ffmpeg based players to watch and seek around a growing mpegts stream even while it is being appended to. Signed-off-by: Aman Karmani <a...@tmm1.net> --- libavformat/http.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/libavformat/http.c b/libavformat/http.c index 476b9a8456..9dc0ff935d 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -68,7 +68,7 @@ typedef struct HTTPContext { /* Used if "Transfer-Encoding: chunked" otherwise -1. */ uint64_t chunksize; int chunkend; - uint64_t off, end_off, filesize; + uint64_t off, end_off, filesize, fileend; char *location; HTTPAuthState auth_state; HTTPAuthState proxy_auth_state; @@ -621,6 +621,7 @@ static int http_open(URLContext *h, const char *uri, int flags, h->is_streamed = 1; s->filesize = UINT64_MAX; + s->fileend = UINT64_MAX; s->location = av_strdup(uri); if (!s->location) return AVERROR(ENOMEM); @@ -750,13 +751,22 @@ static int parse_location(HTTPContext *s, const char *p) static void parse_content_range(URLContext *h, const char *p) { HTTPContext *s = h->priv_data; - const char *slash; + const char *slash, *dash; + uint64_t range_end = UINT64_MAX; if (!strncmp(p, "bytes ", 6)) { p += 6; s->off = strtoull(p, NULL, 10); - if ((slash = strchr(p, '/')) && strlen(slash) > 0) - s->filesize = strtoull(slash + 1, NULL, 10); + if ((dash = strchr(p, '-'))) + range_end = strtoll(dash + 1, NULL, 10); + if ((slash = strchr(p, '/')) && strlen(slash) > 0) { + if (slash[0] == '*') { + s->fileend = range_end; + } else { + s->filesize = strtoull(slash + 1, NULL, 10); + s->fileend = UINT64_MAX; + } + } } if (s->seekable == -1 && (!s->is_akamai || s->filesize != 2147483647)) h->is_streamed = 0; /* we _can_ in fact seek */ @@ -1404,6 +1414,7 @@ static int http_connect(URLContext *h, const char *path, const char *local_path, s->off = 0; s->icy_data_read = 0; s->filesize = UINT64_MAX; + s->fileend = UINT64_MAX; s->willclose = 0; s->end_chunked_post = 0; s->end_header = 0; @@ -1779,19 +1790,21 @@ static int64_t http_seek_internal(URLContext *h, int64_t off, int whence, int fo int old_buf_size, ret; AVDictionary *options = NULL; - if (whence == AVSEEK_SIZE) + if (whence == AVSEEK_SIZE && s->fileend != UINT64_MAX) + return s->off > s->fileend ? s->off : s->fileend; + else if (whence == AVSEEK_SIZE) return s->filesize; else if (!force_reconnect && ((whence == SEEK_CUR && off == 0) || (whence == SEEK_SET && off == s->off))) return s->off; - else if ((s->filesize == UINT64_MAX && whence == SEEK_END)) + else if ((s->filesize == UINT64_MAX && s->fileend == UINT64_MAX && whence == SEEK_END)) return AVERROR(ENOSYS); if (whence == SEEK_CUR) off += s->off; else if (whence == SEEK_END) - off += s->filesize; + off += s->fileend > 0 ? s->fileend : s->filesize; else if (whence != SEEK_SET) return AVERROR(EINVAL); if (off < 0) -- 2.33.0 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".