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:
parent
caa4f54e42
commit
b197c3b0d6
5 changed files with 180 additions and 78 deletions
|
@ -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);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue