diff options
Diffstat (limited to 'stream/cache.c')
-rw-r--r-- | stream/cache.c | 97 |
1 files changed, 61 insertions, 36 deletions
diff --git a/stream/cache.c b/stream/cache.c index 8c18d18b1a..f8304df8b9 100644 --- a/stream/cache.c +++ b/stream/cache.c @@ -42,6 +42,7 @@ #include <assert.h> #include <pthread.h> #include <time.h> +#include <math.h> #include <sys/time.h> #include <libavutil/common.h> @@ -95,6 +96,9 @@ struct priv { bool idle; // cache thread has stopped reading int64_t reads; // number of actual read attempts performed + int64_t speed_start; // start time (us) for calculating download speed + int64_t speed_amount; // bytes read since speed_start + double speed; bool enable_readahead; // actively read beyond read() position int64_t read_filepos; // client read position (mirrors cache->pos) @@ -132,7 +136,7 @@ static void cache_wakeup_and_wait(struct priv *s, double *retry_time) { double start = mp_time_sec(); if (*retry_time >= CACHE_WAIT_TIME) { - MP_WARN(s, "Cache is not responding - slow/stuck network connection?\n"); + MP_VERBOSE(s, "Cache is not responding - slow/stuck network connection?\n"); *retry_time = -1; // do not warn again for this call } @@ -152,6 +156,16 @@ static void cache_drop_contents(struct priv *s) s->start_pts = MP_NOPTS_VALUE; } +static void update_speed(struct priv *s) +{ + int64_t now = mp_time_us(); + s->speed = 0; + if (s->speed_start && s->speed_start < now) + s->speed = s->speed_amount * 1e6 / (now - s->speed_start); + s->speed_amount = 0; + s->speed_start = now; +} + // Copy at most dst_size from the cache at the given absolute file position pos. // Return number of bytes that could actually be read. // Does not advance the file position, or change anything else. @@ -190,6 +204,7 @@ static size_t read_buffer(struct priv *s, unsigned char *dst, static void cache_fill(struct priv *s) { int64_t read = s->read_filepos; + bool read_attempted = false; int len = 0; // drop cache contents only if seeking backward or too much fwd. @@ -211,14 +226,17 @@ static void cache_fill(struct priv *s) goto done; } - if (!s->enable_readahead && s->read_min <= s->max_filepos) { - s->idle = true; - return; - } + if (!s->enable_readahead && s->read_min <= s->max_filepos) + goto done; if (mp_cancel_test(s->cache->cancel)) goto done; + if (!s->speed_start) { + s->speed_start = mp_time_us(); + s->speed_amount = 0; + } + // number of buffer bytes which should be preserved in backwards direction int64_t back = MPCLAMP(read - s->min_filepos, 0, s->back_size); @@ -240,11 +258,8 @@ static void cache_fill(struct priv *s) if (pos >= s->buffer_size) pos -= s->buffer_size; // wrap-around - if (space < FILL_LIMIT) { - s->idle = true; - s->reads++; // don't stuck main thread - return; - } + if (space < FILL_LIMIT) + goto done; // limit to end of buffer (without wrapping) if (pos + space >= s->buffer_size) @@ -274,16 +289,32 @@ static void cache_fill(struct priv *s) s->max_filepos += len; if (pos + len == s->buffer_size) s->offset += s->buffer_size; // wrap... + s->speed_amount += len; -done: - s->eof = len <= 0; - s->idle = s->eof; - s->reads++; - if (s->eof) { + read_attempted = true; + +done: ; + + bool prev_eof = s->eof; + if (read_attempted) + s->eof = len <= 0; + if (!prev_eof && s->eof) { s->eof_pos = stream_tell(s->stream); - MP_TRACE(s, "EOF reached.\n"); + s->speed_start = 0; + MP_VERBOSE(s, "EOF reached.\n"); + } + s->idle = s->eof || !read_attempted; + s->reads++; + + if (s->idle) { + update_speed(s); + s->speed_start = 0; } + int64_t now = mp_time_us(); + if (s->speed_start && s->speed_start + 1000000 <= now) + update_speed(s); + pthread_cond_signal(&s->wakeup); } @@ -335,6 +366,7 @@ static int resize_cache(struct priv *s, int64_t size) s->buffer_size = buffer_size; s->buffer = buffer; s->idle = false; + s->speed_start = 0; s->eof = false; //make sure that we won't wait from cache_fill @@ -371,14 +403,13 @@ static int cache_get_cached_control(stream_t *cache, int cmd, void *arg) { struct priv *s = cache->priv; switch (cmd) { - case STREAM_CTRL_GET_CACHE_SIZE: - *(int64_t *)arg = s->buffer_size - s->back_size; - return STREAM_OK; - case STREAM_CTRL_GET_CACHE_FILL: - *(int64_t *)arg = s->max_filepos - s->read_filepos; - return STREAM_OK; - case STREAM_CTRL_GET_CACHE_IDLE: - *(int *)arg = s->idle; + case STREAM_CTRL_GET_CACHE_INFO: + *(struct stream_cache_info *)arg = (struct stream_cache_info) { + .size = s->buffer_size - s->back_size, + .fill = s->max_filepos - s->read_filepos, + .idle = s->idle, + .speed = llrint(s->speed), + }; return STREAM_OK; case STREAM_CTRL_SET_READAHEAD: s->enable_readahead = *(int *)arg; @@ -409,10 +440,6 @@ static int cache_get_cached_control(stream_t *cache, int cmd, void *arg) } return STREAM_UNSUPPORTED; } - case STREAM_CTRL_RESUME_CACHE: - s->idle = s->eof = false; - pthread_cond_signal(&s->wakeup); - return STREAM_OK; case STREAM_CTRL_AVSEEK: if (!s->has_avseek) return STREAM_UNSUPPORTED; @@ -683,17 +710,15 @@ int stream_cache_init(stream_t *cache, stream_t *stream, for (;;) { if (mp_cancel_test(cache->cancel)) return -1; - int64_t fill; - int idle; - if (stream_control(s->cache, STREAM_CTRL_GET_CACHE_FILL, &fill) < 0) - break; - if (stream_control(s->cache, STREAM_CTRL_GET_CACHE_IDLE, &idle) < 0) + struct stream_cache_info info; + if (stream_control(s->cache, STREAM_CTRL_GET_CACHE_INFO, &info) < 0) break; MP_INFO(s, "\rCache fill: %5.2f%% " - "(%" PRId64 " bytes) ", 100.0 * fill / s->buffer_size, fill); - if (fill >= min) + "(%" PRId64 " bytes) ", 100.0 * info.fill / s->buffer_size, + info.fill); + if (info.fill >= min) break; - if (idle) + if (info.idle) break; // file is smaller than prefill size // Wake up if the cache is done reading some data (or on timeout/abort) pthread_mutex_lock(&s->mutex); |