summaryrefslogtreecommitdiffstats
path: root/stream
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-01-31 22:40:35 +0100
committerwm4 <wm4@nowhere>2014-01-31 22:40:35 +0100
commiteb1778074078077d2bc0035fb402dda6b9df81a8 (patch)
tree15c60659cfe19c4a2ccd6a18c1a9a9f2727d2e7f /stream
parentd8dd9a6725a0f9b961c641ed83b325bbdbb82482 (diff)
downloadmpv-eb1778074078077d2bc0035fb402dda6b9df81a8.tar.bz2
mpv-eb1778074078077d2bc0035fb402dda6b9df81a8.tar.xz
cache: refuse to seek outside of cache boundaries
Note that this still happens in the stream level, so we can't have nice highlevel behavior restricting seeking. Instead, if a seek leads to the demuxer requesting data outside of the cached range, the seek will simply fail. This might confuse the demuxer, and the resulting behavior is not necessarily useful. Note that this also doesn't try to skip data on a forward seek. This would just freeze the stream with slow unseekable streams. One nice thing is that stream.h has a separate function for merely skipping data (separate from seeking forward), which is pretty useful in this case: we want skipping of data to work, even if we reject seeking forward by skipping data as too expensive. This probably is or will be useful for demux_mkv.c.
Diffstat (limited to 'stream')
-rw-r--r--stream/cache.c22
1 files changed, 18 insertions, 4 deletions
diff --git a/stream/cache.c b/stream/cache.c
index d96f46daaf..040e30a558 100644
--- a/stream/cache.c
+++ b/stream/cache.c
@@ -75,6 +75,7 @@ struct priv {
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
struct mp_log *log;
@@ -475,6 +476,7 @@ static int cache_seek(stream_t *cache, int64_t pos)
{
struct priv *s = cache->priv;
assert(s->cache_thread_running);
+ int r = 1;
pthread_mutex_lock(&s->mutex);
@@ -482,12 +484,21 @@ static int cache_seek(stream_t *cache, int64_t pos)
" (cur=%" PRId64 ") <= %" PRId64 " \n",
s->min_filepos, pos, s->read_filepos, s->max_filepos);
- cache->pos = s->read_filepos = pos;
- s->eof = false; // so that cache_read() will actually wait for new data
- pthread_cond_signal(&s->wakeup);
+ if (!s->seekable && pos > s->max_filepos) {
+ MP_ERR(s, "Attempting to seek past cached data in unseekable stream.\n");
+ r = 0;
+ } else if (!s->seekable && pos < s->min_filepos) {
+ MP_ERR(s, "Attempting to seek before cached data in unseekable stream.\n");
+ r = 0;
+ } else {
+ cache->pos = s->read_filepos = pos;
+ s->eof = false; // so that cache_read() will actually wait for new data
+ pthread_cond_signal(&s->wakeup);
+ }
+
pthread_mutex_unlock(&s->mutex);
- return 1;
+ return r;
}
static int cache_control(stream_t *cache, int cmd, void *arg)
@@ -600,6 +611,9 @@ int stream_cache_init(stream_t *cache, stream_t *stream, int64_t size,
if (min > s->buffer_size - s->fill_limit)
min = s->buffer_size - s->fill_limit;
+ s->seekable = (stream->flags & MP_STREAM_SEEK) == MP_STREAM_SEEK &&
+ stream->end_pos > 0;
+
if (pthread_create(&s->cache_thread, NULL, cache_thread, s) != 0) {
MP_ERR(s, "Starting cache process/thread failed: %s.\n",
strerror(errno));