summaryrefslogtreecommitdiff
path: root/apps
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
parentcaa4f54e4235f99acd1c69673c85a4557b6183a9 (diff)
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')
-rw-r--r--apps/plugins/mpegplayer/disk_buf.c150
-rw-r--r--apps/plugins/mpegplayer/disk_buf.h42
-rw-r--r--apps/plugins/mpegplayer/mpeg_misc.c6
-rw-r--r--apps/plugins/mpegplayer/mpeg_misc.h6
-rw-r--r--apps/plugins/mpegplayer/mpeg_parser.c50
5 files changed, 178 insertions, 76 deletions
diff --git a/apps/plugins/mpegplayer/disk_buf.c b/apps/plugins/mpegplayer/disk_buf.c
index 0720197f3a..39563b7041 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);
diff --git a/apps/plugins/mpegplayer/disk_buf.h b/apps/plugins/mpegplayer/disk_buf.h
index e16939a92e..a5a10cfe69 100644
--- a/apps/plugins/mpegplayer/disk_buf.h
+++ b/apps/plugins/mpegplayer/disk_buf.h
@@ -23,6 +23,10 @@
#ifndef DISK_BUF_H
#define DISK_BUF_H
+#ifndef OFF_T_MAX
+#define OFF_T_MAX (~(off_t)1 << (sizeof (off_t)*8 - 1))
+#endif
+
#define DISK_BUF_PAGE_SHIFT 15 /* 32KB cache lines */
#define DISK_BUF_PAGE_SIZE (1 << DISK_BUF_PAGE_SHIFT)
#define DISK_BUF_PAGE_MASK (DISK_BUF_PAGE_SIZE-1)
@@ -58,6 +62,19 @@ struct dbuf_range
int pg_start;
};
+#define DISK_BUF_L2_CACHE_SHIFT 6
+#define DISK_BUF_L2_CACHE_SIZE (1 << DISK_BUF_L2_CACHE_SHIFT)
+#define DISK_BUF_L2_CACHE_MASK (DISK_BUF_L2_CACHE_SIZE-1)
+
+struct dbuf_l2_cache
+{
+ off_t addr; /* L2 file offset */
+ size_t size; /* Real size */
+ uint8_t data[DISK_BUF_L2_CACHE_SIZE*2]; /* Local data and guard */
+};
+
+void dbuf_l2_init(struct dbuf_l2_cache *l2_p);
+
/* This object is an extension of the stream manager and handles some
* playback events as well as buffering */
struct disk_buf
@@ -88,20 +105,8 @@ struct disk_buf
extern struct disk_buf disk_buf SHAREDBSS_ATTR;
-static 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;
-}
-
+struct stream_hdr;
+bool disk_buf_is_data_ready(struct stream_hdr *sh, ssize_t margin);
bool disk_buf_init(void);
void disk_buf_exit(void);
@@ -111,11 +116,10 @@ static inline int disk_buf_status(void)
int disk_buf_open(const char *filename);
void disk_buf_close(void);
-ssize_t _disk_buf_getbuffer(size_t size, void **pp, void **pwrap,
- size_t *sizewrap);
-#define disk_buf_getbuffer(size, pp, pwrap, sizewrap) \
- _disk_buf_getbuffer((size), PUN_PTR(void **, (pp)), \
- PUN_PTR(void **, (pwrap)), (sizewrap))
+ssize_t disk_buf_getbuffer(size_t size, void **pp, void **pwrap,
+ size_t *sizewrap);
+ssize_t disk_buf_getbuffer_l2(struct dbuf_l2_cache *l2,
+ size_t size, void **pp);
ssize_t disk_buf_read(void *buffer, size_t size);
ssize_t disk_buf_lseek(off_t offset, int whence);
diff --git a/apps/plugins/mpegplayer/mpeg_misc.c b/apps/plugins/mpegplayer/mpeg_misc.c
index fd564a49c3..8e6ccf650f 100644
--- a/apps/plugins/mpegplayer/mpeg_misc.c
+++ b/apps/plugins/mpegplayer/mpeg_misc.c
@@ -25,6 +25,12 @@
/** Streams **/
+/* Initializes the cursor */
+void stream_scan_init(struct stream_scan *sk)
+{
+ dbuf_l2_init(&sk->l2);
+}
+
/* Ensures direction is -1 or 1 and margin is properly initialized */
void stream_scan_normalize(struct stream_scan *sk)
{
diff --git a/apps/plugins/mpegplayer/mpeg_misc.h b/apps/plugins/mpegplayer/mpeg_misc.h
index 7bac7eb255..5f60193d52 100644
--- a/apps/plugins/mpegplayer/mpeg_misc.h
+++ b/apps/plugins/mpegplayer/mpeg_misc.h
@@ -28,6 +28,8 @@
#define ALIGNED_ATTR(x) __attribute__((aligned(x)))
#endif
+#include "disk_buf.h"
+
/* Generic states for when things are too simple to care about naming them */
enum state_enum
{
@@ -158,11 +160,15 @@ struct stream_scan
off_t dir; /* Direction - >= 0; forward, < 0 backward */
ssize_t margin; /* Used by function to track margin between position and data end */
intptr_t data; /* */
+ struct dbuf_l2_cache l2;
};
#define SSCAN_REVERSE (-1)
#define SSCAN_FORWARD 1
+/* Initializes the cursor */
+void stream_scan_init(struct stream_scan *sk);
+
/* Ensures direction is -1 or 1 and margin is properly initialized */
void stream_scan_normalize(struct stream_scan *sk);
diff --git a/apps/plugins/mpegplayer/mpeg_parser.c b/apps/plugins/mpegplayer/mpeg_parser.c
index 714f38ac09..f21292abd5 100644
--- a/apps/plugins/mpegplayer/mpeg_parser.c
+++ b/apps/plugins/mpegplayer/mpeg_parser.c
@@ -99,7 +99,7 @@ uint8_t * mpeg_parser_scan_start_code(struct stream_scan *sk, uint32_t code)
{
uint8_t *p;
off_t pos = disk_buf_lseek(sk->pos, SEEK_SET);
- ssize_t len = disk_buf_getbuffer(4, &p, NULL, NULL);
+ ssize_t len = disk_buf_getbuffer_l2(&sk->l2, 4, (void **)&p);
if (pos < 0 || len < 4)
break;
@@ -131,7 +131,7 @@ unsigned mpeg_parser_scan_pes(struct stream_scan *sk)
{
uint8_t *p;
off_t pos = disk_buf_lseek(sk->pos, SEEK_SET);
- ssize_t len = disk_buf_getbuffer(4, &p, NULL, NULL);
+ ssize_t len = disk_buf_getbuffer_l2(&sk->l2, 4, (void **)&p);
if (pos < 0 || len < 4)
break;
@@ -192,7 +192,7 @@ uint32_t mpeg_parser_scan_pts(struct stream_scan *sk, unsigned id)
{
uint8_t *p;
off_t pos = disk_buf_lseek(sk->pos, SEEK_SET);
- ssize_t len = disk_buf_getbuffer(35, &p, NULL, NULL);
+ ssize_t len = disk_buf_getbuffer_l2(&sk->l2, 30, (void **)&p);
if (pos < 0 || len < 4)
break;
@@ -201,7 +201,7 @@ uint32_t mpeg_parser_scan_pts(struct stream_scan *sk, unsigned id)
{
uint8_t *h = p;
- if (sk->margin < 6)
+ if (sk->margin < 7)
{
/* Insufficient data */
}
@@ -215,29 +215,33 @@ uint32_t mpeg_parser_scan_pts(struct stream_scan *sk, unsigned id)
}
else /* mpeg1 */
{
- ssize_t l = 7;
+ ssize_t l = 6;
ssize_t margin = sk->margin;
/* Skip stuffing_byte */
- while (h[l - 1] == 0xff && ++l <= 23)
+ while (margin > 7 && h[l] == 0xff && ++l <= 22)
--margin;
- if ((h[l - 1] & 0xc0) == 0x40)
+ if (margin >= 7)
{
- /* Skip STD_buffer_scale and STD_buffer_size */
- margin -= 2;
- l += 2;
- }
-
- if (margin >= 4)
- {
- /* header points to the mpeg1 pes header */
- h += l;
+ if ((h[l] & 0xc0) == 0x40)
+ {
+ /* Skip STD_buffer_scale and STD_buffer_size */
+ margin -= 2;
+ l += 2;
+ }
- if ((h[-1] & 0xe0) == 0x20)
+ if (margin >= 5)
{
- sk->data = (h + 4) - p;
- return read_pts(h, -1);
+ /* Header points to the mpeg1 pes header */
+ h += l;
+
+ if ((h[0] & 0xe0) == 0x20)
+ {
+ /* PTS or PTS_DTS indicated */
+ sk->data = (h + 5) - p;
+ return read_pts(h, 0);
+ }
}
}
}
@@ -357,6 +361,8 @@ static off_t mpeg_parser_seek_PTS(uint32_t time, unsigned id)
enum state_enum state = STATE0;
struct stream_scan sk;
+ stream_scan_init(&sk);
+
/* Initial estimate taken from average bitrate - later interpolations are
* taken similarly based on the remaining file interval */
pos_new = muldiv_uint32(time - time_left, pos_right - pos_left,
@@ -564,6 +570,8 @@ static bool prepare_image(uint32_t time)
int tries;
int result;
+ stream_scan_init(&sk);
+
if (!str_send_msg(&video_str, STREAM_NEEDS_SYNC, time))
{
DEBUGF("Image was ready\n");
@@ -734,7 +742,7 @@ static int parse_demux(struct stream *str, enum stream_parse_mode type)
str->hdr.pos = disk_buf_lseek(str->hdr.pos, SEEK_SET);
if (str->hdr.pos < 0 || str->hdr.pos >= str->hdr.limit ||
- disk_buf_getbuffer(MIN_BUFAHEAD, &p, NULL, NULL) <= 0)
+ disk_buf_getbuffer(MIN_BUFAHEAD, (void **)&p, NULL, NULL) <= 0)
{
str_end_of_stream(str);
return STREAM_DATA_END;
@@ -1009,7 +1017,7 @@ static int parse_elementary(struct stream *str, enum stream_parse_mode type)
case STREAM_PM_RANDOM_ACCESS:
str->hdr.pos = disk_buf_lseek(str->hdr.pos, SEEK_SET);
- len = disk_buf_getbuffer(DISK_BUF_PAGE_SIZE, &p, NULL, NULL);
+ len = disk_buf_getbuffer(DISK_BUF_PAGE_SIZE, (void **)&p, NULL, NULL);
if (len <= 0 || str->hdr.pos < 0 || str->hdr.pos >= str->hdr.limit)
{