summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-01-31 22:40:35 +0100
committerwm4 <wm4@nowhere>2014-02-12 22:29:11 +0100
commit70a66b461d0e9699964cf12fea19fa696aff46ca (patch)
tree29d65f1f5838bfc08240404fd26b21c73e4414f8
parent844e8f2b5167785f241f65164d910a14768bd744 (diff)
downloadmpv-70a66b461d0e9699964cf12fea19fa696aff46ca.tar.bz2
mpv-70a66b461d0e9699964cf12fea19fa696aff46ca.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.
-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));