summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/man/en/input.rst12
-rw-r--r--player/command.c29
-rw-r--r--stream/cache.c98
-rw-r--r--stream/stream.h1
4 files changed, 119 insertions, 21 deletions
diff --git a/DOCS/man/en/input.rst b/DOCS/man/en/input.rst
index a1e4ee45e3..e64bc7ebef 100644
--- a/DOCS/man/en/input.rst
+++ b/DOCS/man/en/input.rst
@@ -715,6 +715,18 @@ an option at runtime.
``cache``
Network cache fill state (0-100).
+``cache-size`` (RW)
+ Total network cache size in KB. This is similar to ``--cache``. This allows
+ to set the cache size at runtime. Currently, it's not possible to enable
+ or disable the cache at runtime using this property, just to resize an
+ existing cache.
+
+ Note that this tries to keep the cache contents as far as possible. To make
+ this easier, the cache resizing code will allocate the new cache while the
+ old cache is still allocated.
+
+ Don't use this when playing DVD or Bluray.
+
``pts-association-mode`` (RW)
See ``--pts-association-mode``.
diff --git a/player/command.c b/player/command.c
index 9921a055f5..a0adfb2ea3 100644
--- a/player/command.c
+++ b/player/command.c
@@ -939,6 +939,34 @@ static int mp_property_cache(m_option_t *prop, int action, void *arg,
return m_property_int_ro(prop, action, arg, cache);
}
+static int mp_property_cache_size(m_option_t *prop, int action, void *arg,
+ void *ctx)
+{
+ MPContext *mpctx = ctx;
+ if (!mpctx->stream)
+ return M_PROPERTY_UNAVAILABLE;
+ switch (action) {
+ case M_PROPERTY_GET: {
+ int64_t size = -1;
+ stream_control(mpctx->stream, STREAM_CTRL_GET_CACHE_SIZE, &size);
+ if (size <= 0)
+ break;
+ *(int *)arg = size / 1024;
+ return M_PROPERTY_OK;
+ }
+ case M_PROPERTY_SET: {
+ int64_t size = *(int *)arg * 1024LL;
+ int r = stream_control(mpctx->stream, STREAM_CTRL_SET_CACHE_SIZE, &size);
+ if (r == STREAM_UNSUPPORTED)
+ break;
+ if (r == STREAM_OK)
+ return M_PROPERTY_OK;
+ return M_PROPERTY_ERROR;
+ }
+ }
+ return M_PROPERTY_NOT_IMPLEMENTED;
+}
+
static int mp_property_clock(m_option_t *prop, int action, void *arg,
MPContext *mpctx)
{
@@ -2150,6 +2178,7 @@ static const m_option_t mp_properties[] = {
M_PROPERTY("chapter-metadata", mp_property_chapter_metadata),
M_OPTION_PROPERTY_CUSTOM("pause", mp_property_pause),
{ "cache", mp_property_cache, CONF_TYPE_INT },
+ { "cache-size", mp_property_cache_size, CONF_TYPE_INT, M_OPT_MIN, 0 },
M_OPTION_PROPERTY("pts-association-mode"),
M_OPTION_PROPERTY("hr-seek"),
{ "clock", mp_property_clock, CONF_TYPE_STRING,
diff --git a/stream/cache.c b/stream/cache.c
index 6333eeb0e9..69d60b4fff 100644
--- a/stream/cache.c
+++ b/stream/cache.c
@@ -69,10 +69,10 @@ struct priv {
pthread_cond_t wakeup;
// Constants (as long as cache thread is running)
+ // Some of these might actually be changed by a synced cache resize.
unsigned char *buffer; // base pointer of the allocated buffer memory
int64_t buffer_size; // size of the allocated buffer memory
int64_t back_size; // keep back_size amount of old bytes for backward seek
- int64_t fill_limit; // we should fill buffer only if space>=fill_limit
int64_t seek_limit; // keep filling cache if distance is less that seek limit
struct byte_meta *bm; // additional per-byte metadata
bool seekable; // underlying stream is seekable
@@ -132,6 +132,9 @@ enum {
CACHE_CTRL_PING = -2,
};
+// we should fill buffer only if space>=FILL_LIMIT
+#define FILL_LIMIT (FFMAX(16 * 1024, BYTE_META_CHUNK_SIZE * 2))
+
static int64_t mp_clipi64(int64_t val, int64_t min, int64_t max)
{
val = FFMIN(val, max);
@@ -271,7 +274,7 @@ static bool cache_fill(struct priv *s)
if (pos >= s->buffer_size)
pos -= s->buffer_size; // wrap-around
- if (space < s->fill_limit) {
+ if (space < FILL_LIMIT) {
s->idle = true;
s->reads++; // don't stuck main thread
return false;
@@ -318,6 +321,66 @@ static bool cache_fill(struct priv *s)
return true;
}
+// This is called both during init and at runtime.
+static int resize_cache(struct priv *s, int64_t size)
+{
+ int64_t min_size = FILL_LIMIT * 4;
+ int64_t max_size = ((size_t)-1) / 4;
+ int64_t buffer_size = MPMIN(MPMAX(size, min_size), max_size);
+
+ unsigned char *buffer = malloc(buffer_size);
+ struct byte_meta *bm = calloc(buffer_size / BYTE_META_CHUNK_SIZE + 2,
+ sizeof(struct byte_meta));
+ if (!buffer || !bm) {
+ free(buffer);
+ free(bm);
+ return STREAM_ERROR;
+ }
+
+ if (s->buffer) {
+ // Copy & free the old ringbuffer data.
+ // If the buffer is too small, prefer to copy these regions:
+ // 1. Data starting from read_filepos, until cache end
+ size_t read_1 = read_buffer(s, buffer, buffer_size, s->read_filepos);
+ // 2. then data from before read_filepos until cache start
+ // (this one needs to be copied to the end of the ringbuffer)
+ size_t read_2 = 0;
+ if (s->min_filepos < s->read_filepos) {
+ size_t copy_len = buffer_size - read_1;
+ copy_len = MPMIN(copy_len, s->read_filepos - s->min_filepos);
+ assert(copy_len + read_1 <= buffer_size);
+ read_2 = read_buffer(s, buffer + buffer_size - copy_len, copy_len,
+ s->read_filepos - copy_len);
+ // This shouldn't happen, unless copy_len was computed incorrectly.
+ assert(read_2 == copy_len);
+ }
+ // Set it up such that read_1 is at buffer pos 0, and read_2 wraps
+ // around below it, so that it is located at the end of the buffer.
+ s->min_filepos = s->read_filepos - read_2;
+ s->max_filepos = s->read_filepos + read_1;
+ s->offset = s->max_filepos - read_1;
+ } else {
+ cache_drop_contents(s);
+ }
+
+ free(s->buffer);
+ free(s->bm);
+
+ s->buffer_size = buffer_size;
+ s->back_size = buffer_size / 2;
+ s->buffer = buffer;
+ s->bm = bm;
+ s->idle = false;
+ s->eof = false;
+
+ //make sure that we won't wait from cache_fill
+ //more data than it is allowed to fill
+ if (s->seek_limit > s->buffer_size - FILL_LIMIT)
+ s->seek_limit = s->buffer_size - FILL_LIMIT;
+
+ return STREAM_OK;
+}
+
static void update_cached_controls(struct priv *s)
{
unsigned int ui;
@@ -439,10 +502,16 @@ static bool control_needs_flush(int stream_ctrl)
static void cache_execute_control(struct priv *s)
{
uint64_t old_pos = stream_tell(s->stream);
-
- s->control_res = stream_control(s->stream, s->control, s->control_arg);
s->control_flush = false;
+ switch (s->control) {
+ case STREAM_CTRL_SET_CACHE_SIZE:
+ s->control_res = resize_cache(s, *(int64_t *)s->control_arg);
+ break;
+ default:
+ s->control_res = stream_control(s->stream, s->control, s->control_arg);
+ }
+
bool pos_changed = old_pos != stream_tell(s->stream);
bool ok = s->control_res == STREAM_OK;
if (pos_changed && !ok) {
@@ -609,18 +678,10 @@ int stream_cache_init(stream_t *cache, stream_t *stream, int64_t size,
struct priv *s = talloc_zero(NULL, struct priv);
s->log = cache->log;
- //64kb min_size
- s->fill_limit = FFMAX(16 * 1024, BYTE_META_CHUNK_SIZE * 2);
- s->buffer_size = FFMAX(size, s->fill_limit * 4);
- s->back_size = s->buffer_size / 2;
+ s->seek_limit = seek_limit;
- s->buffer = malloc(s->buffer_size);
- s->bm = malloc((s->buffer_size / BYTE_META_CHUNK_SIZE + 2) *
- sizeof(struct byte_meta));
- if (!s->buffer || !s->bm) {
+ if (resize_cache(s, size) != STREAM_OK) {
MP_ERR(s, "Failed to allocate cache buffer.\n");
- free(s->buffer);
- free(s->bm);
talloc_free(s);
return -1;
}
@@ -637,13 +698,8 @@ int stream_cache_init(stream_t *cache, stream_t *stream, int64_t size,
cache->control = cache_control;
cache->close = cache_uninit;
- s->seek_limit = seek_limit;
- //make sure that we won't wait from cache_fill
- //more data than it is allowed to fill
- if (s->seek_limit > s->buffer_size - s->fill_limit)
- s->seek_limit = s->buffer_size - s->fill_limit;
- if (min > s->buffer_size - s->fill_limit)
- min = s->buffer_size - s->fill_limit;
+ if (min > s->buffer_size - FILL_LIMIT)
+ min = s->buffer_size - FILL_LIMIT;
s->seekable = (stream->flags & MP_STREAM_SEEK) == MP_STREAM_SEEK &&
stream->end_pos > 0;
diff --git a/stream/stream.h b/stream/stream.h
index c23d173165..589728d4ac 100644
--- a/stream/stream.h
+++ b/stream/stream.h
@@ -83,6 +83,7 @@ enum stream_ctrl {
STREAM_CTRL_GET_CURRENT_TITLE,
STREAM_CTRL_SET_CURRENT_TITLE,
STREAM_CTRL_GET_CACHE_SIZE,
+ STREAM_CTRL_SET_CACHE_SIZE,
STREAM_CTRL_GET_CACHE_FILL,
STREAM_CTRL_GET_CACHE_IDLE,
STREAM_CTRL_RESUME_CACHE,