From 5f1ff78516bb5aaf6c38a5df55959e1165c059ee Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 20 Mar 2016 19:48:55 +0100 Subject: command: add cache-speed property Should reflect I/O speed. This could go into the terminal status line. But I'm not sure how to put it there, since it already uses too much space, so it's not there yet. --- DOCS/interface-changes.rst | 1 + DOCS/man/input.rst | 5 ++++ player/command.c | 18 +++++++++++++- stream/cache.c | 61 +++++++++++++++++++++++++++++++++++----------- stream/stream.h | 1 + 5 files changed, 71 insertions(+), 15 deletions(-) diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index 4ef60aa312..7dac36eac9 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -24,6 +24,7 @@ Interface changes "track-list/N/demux-channel-count" instead) - remove write access to "stream-pos", and change semantics for read access - Lua scripts now don't suspend mpv by default while script code is run + - add "cache-speed" property --- mpv 0.16.0 --- - change --audio-channels default to stereo (use --audio-channels=auto to get the old default) diff --git a/DOCS/man/input.rst b/DOCS/man/input.rst index 79a6790e49..63506e7a4e 100644 --- a/DOCS/man/input.rst +++ b/DOCS/man/input.rst @@ -1195,6 +1195,11 @@ Property list ``cache-used`` (R) Total used cache size in KB. +``cache-speed`` (R) + Current I/O read speed between the cache and the lower layer (like network). + This is a float (using ``MPV_FORMAT_DOUBLE`` in the client API) and gives + the value bytes per seconds over a 1 second window. + ``cache-idle`` (R) Returns ``yes`` if the cache is idle, which means the cache is filled as much as possible, and is currently not reading more data. diff --git a/player/command.c b/player/command.c index 068ab7cf5e..9d8528571a 100644 --- a/player/command.c +++ b/player/command.c @@ -1430,6 +1430,21 @@ static int mp_property_cache_free(void *ctx, struct m_property *prop, return property_int_kb_size((size - size_used) / 1024, action, arg); } +static int mp_property_cache_speed(void *ctx, struct m_property *prop, + int action, void *arg) +{ + MPContext *mpctx = ctx; + if (!mpctx->demuxer) + return M_PROPERTY_UNAVAILABLE; + + double speed = -1; + demux_stream_control(mpctx->demuxer, STREAM_CTRL_GET_CACHE_SPEED, &speed); + if (speed < 0) + return M_PROPERTY_UNAVAILABLE; + + return m_property_double_ro(action, arg, speed); +} + static int mp_property_cache_idle(void *ctx, struct m_property *prop, int action, void *arg) { @@ -3606,6 +3621,7 @@ static const struct m_property mp_properties[] = { {"cache-used", mp_property_cache_used}, {"cache-size", mp_property_cache_size}, {"cache-idle", mp_property_cache_idle}, + {"cache-speed", mp_property_cache_speed}, {"demuxer-cache-duration", mp_property_demuxer_cache_duration}, {"demuxer-cache-time", mp_property_demuxer_cache_time}, {"demuxer-cache-idle", mp_property_demuxer_cache_idle}, @@ -3820,7 +3836,7 @@ static const char *const *const mp_event_property_change[] = { E(MPV_EVENT_CHAPTER_CHANGE, "chapter", "chapter-metadata"), E(MP_EVENT_CACHE_UPDATE, "cache", "cache-free", "cache-used", "cache-idle", "demuxer-cache-duration", "demuxer-cache-idle", "paused-for-cache", - "demuxer-cache-time", "cache-buffering-state"), + "demuxer-cache-time", "cache-buffering-state", "cache-speed"), E(MP_EVENT_WIN_RESIZE, "window-scale", "osd-width", "osd-height", "osd-par"), E(MP_EVENT_WIN_STATE, "window-minimized", "display-names", "display-fps", "fullscreen"), }; diff --git a/stream/cache.c b/stream/cache.c index 8421a6fc33..7fd53c7a6a 100644 --- a/stream/cache.c +++ b/stream/cache.c @@ -95,6 +95,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) @@ -152,6 +155,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 +203,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 +225,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 +257,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,15 +288,30 @@ 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: + read_attempted = true; + +done: ; + + bool prev_eof = s->eof; s->eof = len <= 0; - s->idle = s->eof; - s->reads++; - if (s->eof) { + 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 +364,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 @@ -380,6 +410,9 @@ static int cache_get_cached_control(stream_t *cache, int cmd, void *arg) case STREAM_CTRL_GET_CACHE_IDLE: *(int *)arg = s->idle; return STREAM_OK; + case STREAM_CTRL_GET_CACHE_SPEED: + *(double *)arg = s->speed; + return STREAM_OK; case STREAM_CTRL_SET_READAHEAD: s->enable_readahead = *(int *)arg; pthread_cond_signal(&s->wakeup); diff --git a/stream/stream.h b/stream/stream.h index c75bb495e4..e6964c2020 100644 --- a/stream/stream.h +++ b/stream/stream.h @@ -71,6 +71,7 @@ enum stream_ctrl { STREAM_CTRL_SET_CACHE_SIZE, STREAM_CTRL_GET_CACHE_FILL, STREAM_CTRL_GET_CACHE_IDLE, + STREAM_CTRL_GET_CACHE_SPEED, STREAM_CTRL_SET_READAHEAD, // stream_memory.c -- cgit v1.2.3