1
0
Fork 0
forked from len0rd/rockbox

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
This commit is contained in:
Michael Sevakis 2010-05-16 14:41:00 +00:00
parent caa4f54e42
commit b197c3b0d6
5 changed files with 180 additions and 78 deletions

View file

@ -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,34 +605,95 @@ 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)
{
if (pwrap && sizewrap)
{
uint8_t *p = (uint8_t *)*pp;
size = disk_buf_probe(disk_buf.offset, size, 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 (size != (size_t)-1 && pwrap && sizewrap)
{
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;
}
}
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
{
@ -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);