diff options
author | wm4 <wm4@nowhere> | 2014-01-31 22:40:35 +0100 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2014-01-31 22:40:35 +0100 |
commit | eb1778074078077d2bc0035fb402dda6b9df81a8 (patch) | |
tree | 15c60659cfe19c4a2ccd6a18c1a9a9f2727d2e7f /stream | |
parent | d8dd9a6725a0f9b961c641ed83b325bbdbb82482 (diff) | |
download | mpv-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.c | 22 |
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)); |