summaryrefslogtreecommitdiff
path: root/apps/plugins/mpegplayer/disk_buf.c
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2010-05-16 14:41:00 +0000
committerMichael Sevakis <jethead71@rockbox.org>2010-05-16 14:41:00 +0000
commitb197c3b0d6bfcf3daae4a7b1cad415b1acea28f6 (patch)
tree1c7bce8c4bc39617ff819111d39a41370ca8f49b /apps/plugins/mpegplayer/disk_buf.c
parentcaa4f54e4235f99acd1c69673c85a4557b6183a9 (diff)
downloadrockbox-b197c3b0d6bfcf3daae4a7b1cad415b1acea28f6.zip
rockbox-b197c3b0d6bfcf3daae4a7b1cad415b1acea28f6.tar.gz
rockbox-b197c3b0d6bfcf3daae4a7b1cad415b1acea28f6.tar.bz2
rockbox-b197c3b0d6bfcf3daae4a7b1cad415b1acea28f6.tar.xz
MPEGPlayer: Add a second layer of caching to help speed up byte-wise scanning and seeking a bit.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@26088 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/mpegplayer/disk_buf.c')
-rw-r--r--apps/plugins/mpegplayer/disk_buf.c150
1 files changed, 114 insertions, 36 deletions
diff --git a/apps/plugins/mpegplayer/disk_buf.c b/apps/plugins/mpegplayer/disk_buf.c
index 0720197..39563b7 100644
--- a/apps/plugins/mpegplayer/disk_buf.c
+++ b/apps/plugins/mpegplayer/disk_buf.c
@@ -49,6 +49,26 @@ static inline void disk_buf_on_clear_data_notify(struct stream_hdr *sh)
list_remove_item(&sh->nf);
}
+
+inline bool disk_buf_is_data_ready(struct stream_hdr *sh,
+ ssize_t margin)
+{
+ /* Data window available? */
+ off_t right = sh->win_right;
+
+ /* Margins past end-of-file can still return true */
+ if (right > disk_buf.filesize - margin)
+ right = disk_buf.filesize - margin;
+
+ return sh->win_left >= disk_buf.win_left &&
+ right + margin <= disk_buf.win_right;
+}
+
+void dbuf_l2_init(struct dbuf_l2_cache *l2_p)
+{
+ l2_p->addr = OFF_T_MAX; /* Mark as invalid */
+}
+
static int disk_buf_on_data_notify(struct stream_hdr *sh)
{
DEBUGF("DISK_BUF_DATA_NOTIFY: 0x%02X ", STR_FROM_HEADER(sh)->id);
@@ -519,17 +539,16 @@ static void disk_buf_thread(void)
}
/* Caches some data from the current file */
-static int disk_buf_probe(off_t start, size_t length,
- void **p, size_t *outlen)
+static ssize_t disk_buf_probe(off_t start, size_t length, void **p)
{
off_t end;
uint32_t tag, tag_end;
int page;
/* Can't read past end of file */
- if (length > (size_t)(disk_buf.filesize - disk_buf.offset))
+ if (length > (size_t)(disk_buf.filesize - start))
{
- length = disk_buf.filesize - disk_buf.offset;
+ length = disk_buf.filesize - start;
}
/* Can't cache more than the whole buffer size */
@@ -559,11 +578,6 @@ static int disk_buf_probe(off_t start, size_t length,
+ (start & DISK_BUF_PAGE_MASK);
}
- if (outlen != NULL)
- {
- *outlen = length;
- }
-
/* Obtain initial load point. If all data was cached, no message is sent
* otherwise begin on the first page that is not cached. Since we have to
* send the message anyway, the buffering thread will determine what else
@@ -573,12 +587,17 @@ static int disk_buf_probe(off_t start, size_t length,
if (disk_buf.cache[page] != tag)
{
static struct dbuf_range rng IBSS_ATTR;
+ intptr_t result;
+
DEBUGF("disk_buf: cache miss\n");
rng.tag_start = tag;
rng.tag_end = tag_end;
rng.pg_start = page;
- return rb->queue_send(disk_buf.q, DISK_BUF_CACHE_RANGE,
- (intptr_t)&rng);
+
+ result = rb->queue_send(disk_buf.q, DISK_BUF_CACHE_RANGE,
+ (intptr_t)&rng);
+
+ return result == DISK_BUF_NOTIFY_OK ? (ssize_t)length : -1;
}
if (++page >= disk_buf.pgcount)
@@ -586,35 +605,96 @@ static int disk_buf_probe(off_t start, size_t length,
}
while (++tag <= tag_end);
- return DISK_BUF_NOTIFY_OK;
+ return length;
}
/* Attempt to get a pointer to size bytes on the buffer. Returns real amount of
* data available as well as the size of non-wrapped data after *p. */
-ssize_t _disk_buf_getbuffer(size_t size, void **pp, void **pwrap, size_t *sizewrap)
+ssize_t disk_buf_getbuffer(size_t size, void **pp, void **pwrap,
+ size_t *sizewrap)
{
disk_buf_lock();
- if (disk_buf_probe(disk_buf.offset, size, pp, &size) == DISK_BUF_NOTIFY_OK)
+ size = disk_buf_probe(disk_buf.offset, size, pp);
+
+ if (size != (size_t)-1 && pwrap && sizewrap)
{
- if (pwrap && sizewrap)
- {
- uint8_t *p = (uint8_t *)*pp;
+ uint8_t *p = (uint8_t *)*pp;
- if (p + size > disk_buf.end + DISK_GUARDBUF_SIZE)
- {
- /* Return pointer to wraparound and the size of same */
- size_t nowrap = (disk_buf.end + DISK_GUARDBUF_SIZE) - p;
- *pwrap = disk_buf.start + DISK_GUARDBUF_SIZE;
- *sizewrap = size - nowrap;
- }
- else
- {
- *pwrap = NULL;
- *sizewrap = 0;
- }
+ if (p + size > disk_buf.end + DISK_GUARDBUF_SIZE)
+ {
+ /* Return pointer to wraparound and the size of same */
+ size_t nowrap = (disk_buf.end + DISK_GUARDBUF_SIZE) - p;
+ *pwrap = disk_buf.start + DISK_GUARDBUF_SIZE;
+ *sizewrap = size - nowrap;
+ }
+ else
+ {
+ *pwrap = NULL;
+ *sizewrap = 0;
}
}
+
+ disk_buf_unlock();
+
+ return size;
+}
+
+ssize_t disk_buf_getbuffer_l2(struct dbuf_l2_cache *l2,
+ size_t size, void **pp)
+{
+ off_t offs;
+ off_t l2_addr;
+ size_t l2_size;
+ void *l2_p;
+
+ if (l2 == NULL)
+ {
+ /* Shouldn't have to check this normally */
+ DEBUGF("disk_buf_getbuffer_l2: l2 = NULL!\n");
+ }
+
+ if (size > DISK_BUF_L2_CACHE_SIZE)
+ {
+ /* Asking for too much; just go through L1 */
+ return disk_buf_getbuffer(size, pp, NULL, NULL);
+ }
+
+ offs = disk_buf.offset; /* Other calls keep this within bounds */
+ l2_addr = l2->addr;
+
+ if (offs >= l2_addr && offs < l2_addr + DISK_BUF_L2_CACHE_SIZE)
+ {
+ /* Data is in the local buffer */
+ offs &= DISK_BUF_L2_CACHE_MASK;
+
+ *pp = l2->data + offs;
+ if (offs + size > l2->size)
+ size = l2->size - offs; /* Keep size within file limits */
+
+ return size;
+ }
+
+ /* Have to probe main buffer */
+ l2_addr = offs & ~DISK_BUF_L2_CACHE_MASK;
+ l2_size = DISK_BUF_L2_CACHE_SIZE*2; /* 2nd half is a guard buffer */
+
+ disk_buf_lock();
+
+ l2_size = disk_buf_probe(l2_addr, l2_size, &l2_p);
+
+ if (l2_size != (size_t)-1)
+ {
+ rb->memcpy(l2->data, l2_p, l2_size);
+
+ l2->addr = l2_addr;
+ l2->size = l2_size;
+ offs -= l2_addr;
+
+ *pp = l2->data + offs;
+ if (offs + size > l2->size)
+ size = l2->size - offs; /* Keep size within file limits */
+ }
else
{
size = -1;
@@ -625,6 +705,7 @@ ssize_t _disk_buf_getbuffer(size_t size, void **pp, void **pwrap, size_t *sizewr
return size;
}
+
/* Read size bytes of data into a buffer - advances the buffer pointer
* and returns the real size read. */
ssize_t disk_buf_read(void *buffer, size_t size)
@@ -633,8 +714,9 @@ ssize_t disk_buf_read(void *buffer, size_t size)
disk_buf_lock();
- if (disk_buf_probe(disk_buf.offset, size, PUN_PTR(void **, &p),
- &size) == DISK_BUF_NOTIFY_OK)
+ size = disk_buf_probe(disk_buf.offset, size, (void **)&p);
+
+ if (size != (size_t)-1)
{
if (p + size > disk_buf.end + DISK_GUARDBUF_SIZE)
{
@@ -652,10 +734,6 @@ ssize_t disk_buf_read(void *buffer, size_t size)
disk_buf.offset += size;
}
- else
- {
- size = -1;
- }
disk_buf_unlock();
@@ -713,7 +791,7 @@ ssize_t disk_buf_prepare_streaming(off_t pos, size_t len)
DEBUGF("prepare streaming:\n pos:%ld len:%zu\n", pos, len);
pos = disk_buf_lseek(pos, SEEK_SET);
- disk_buf_probe(pos, len, NULL, &len);
+ len = disk_buf_probe(pos, len, NULL);
DEBUGF(" probe done: pos:%ld len:%zu\n", pos, len);