This adds a `read_buf_size` option which can help avoid excessive seeking when a file has e.g. badly interleaved audio and video.
--- libavformat/cache.c | 69 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 57 insertions(+), 12 deletions(-) diff --git a/libavformat/cache.c b/libavformat/cache.c index 66bbbf54c9..d2fd467032 100644 --- a/libavformat/cache.c +++ b/libavformat/cache.c @@ -63,6 +63,8 @@ typedef struct Context { URLContext *inner; int64_t cache_hit, cache_miss; int read_ahead_limit; + int read_buf_size; + unsigned char* read_buf; } Context; static int cmp(const void *key, const void *node) @@ -86,6 +88,8 @@ static int cache_open(URLContext *h, const char *arg, int flags, AVDictionary ** unlink(buffername); av_freep(&buffername); + c->read_buf = av_mallocz(c->read_buf_size); + return ffurl_open_whitelist(&c->inner, arg, flags, &h->interrupt_callback, options, h->protocol_whitelist, h->protocol_blacklist, h); } @@ -158,6 +162,12 @@ static int cache_read(URLContext *h, unsigned char *buf, int size) Context *c= h->priv_data; CacheEntry *entry, *next[2] = {NULL, NULL}; int64_t r; + int read_size, read_pos; + unsigned char* read_buf; + + if (!buf) { + buf = c->read_buf; + } entry = av_tree_find(c->root, &c->logical_pos, cmp, (void**)next); @@ -200,18 +210,52 @@ static int cache_read(URLContext *h, unsigned char *buf, int size) c->inner_pos = r; } - r = ffurl_read(c->inner, buf, size); - if (r == AVERROR_EOF && size>0) { - c->is_true_eof = 1; - av_assert0(c->end >= c->logical_pos); + read_size = c->read_buf_size; + read_buf = c->read_buf; + + if (size >= read_size) { + read_size = size; + read_buf = buf; } - if (r<=0) + + read_pos = 0; + do { + r = ffurl_read(c->inner, read_buf + read_pos, read_size - read_pos); + + if (r == AVERROR_EOF) { + c->is_true_eof = 1; + av_assert0(c->end >= c->logical_pos); + break; + } + + if (r == 0 || r == AVERROR(EAGAIN)) { + break; + } + + if (r < 0) { + return r; + } + + c->inner_pos += r; + read_pos += r; + } while (read_pos < read_size); + + if (read_pos == 0) { return r; - c->inner_pos += r; + } - c->cache_miss ++; + r = read_pos; + + c->cache_miss++; + + add_entry(h, read_buf, r); + + r = FFMIN(r, size); + + if (read_buf != buf) { + memcpy(buf, read_buf, r); + } - add_entry(h, buf, r); c->logical_pos += r; c->end = FFMAX(c->end, c->logical_pos); @@ -257,12 +301,11 @@ resolve_eof: whence == SEEK_END && pos <= 0) && ret < 0) { if ( (whence == SEEK_SET && c->read_ahead_limit >= pos - c->logical_pos) || c->read_ahead_limit < 0) { - uint8_t tmp[32768]; while (c->logical_pos < pos || whence == SEEK_END) { - int size = sizeof(tmp); + int size = c->read_buf_size; if (whence == SEEK_SET) - size = FFMIN(sizeof(tmp), pos - c->logical_pos); - ret = cache_read(h, tmp, size); + size = FFMIN(c->read_buf_size, pos - c->logical_pos); + ret = cache_read(h, NULL, size); if (ret == AVERROR_EOF && whence == SEEK_END) { av_assert0(c->is_true_eof); goto resolve_eof; @@ -300,6 +343,7 @@ static int cache_close(URLContext *h) ffurl_close(c->inner); av_tree_enumerate(c->root, NULL, NULL, enu_free); av_tree_destroy(c->root); + av_free(c->read_buf); return 0; } @@ -309,6 +353,7 @@ static int cache_close(URLContext *h) static const AVOption options[] = { { "read_ahead_limit", "Amount in bytes that may be read ahead when seeking isn't supported, -1 for unlimited", OFFSET(read_ahead_limit), AV_OPT_TYPE_INT, { .i64 = 65536 }, -1, INT_MAX, D }, + { "read_buf_size", "Lowest amount of bytes that may be read at a time.", OFFSET(read_buf_size), AV_OPT_TYPE_INT, { .i64 = 65536 }, -1, INT_MAX, D }, {NULL}, }; -- 2.18.0 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel