cache, dvd, bluray: simplify stream time handling

We used a complicated and approximate method to cache the stream
timestamp, which is basically per-byte. (To reduce overhead, it was only
cached per 8KB-block, so it was approximate.)

Simplify this, and read/keep the timestamp only on discontinuities. This
is when demux_disc.c actually needs the timestamp.

Note that caching is currently disabled for dvdnav, but we still read
the timestamp only after some data is read. libdvdread behaves well, but
I don't know about libbluray, and the previous code also read the
timestamp only after reading data, so try to keep it safe.

Also drop the start_time offset. It wouldn't be correct anymore if used
with the cache, and the idea behind it wasn't very sane either (making
the player to offset the initial playback time to 0).
This commit is contained in:
wm4 2014-07-07 19:09:37 +02:00
parent 4d829d750c
commit 4981367021
2 changed files with 16 additions and 46 deletions

View File

@ -285,8 +285,6 @@ static int d_open(demuxer_t *demuxer, enum demux_check check)
if (demuxer->stream->uncached_type == STREAMTYPE_CDDA)
demux = "+rawaudio";
reset_pts(demuxer);
p->slave = demux_open(demuxer->stream, demux, NULL, demuxer->global);
if (!p->slave)
return -1;
@ -294,8 +292,6 @@ static int d_open(demuxer_t *demuxer, enum demux_check check)
// So that we don't miss initial packets of delayed subtitle streams.
p->slave->stream_select_default = true;
demuxer->start_time = p->pts[STREAM_VIDEO].base_time;
// Can be seekable even if the stream isn't.
demuxer->seekable = true;

View File

@ -76,7 +76,6 @@ struct priv {
int64_t buffer_size; // size of the allocated buffer memory
int64_t back_size; // keep back_size amount of old bytes for backward seek
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;
@ -116,17 +115,10 @@ struct priv {
int stream_cache_fill;
struct mp_tags *stream_metadata;
char *disc_name;
};
// Store additional per-byte metadata. Since per-byte would be way too
// inefficient, store it only for every BYTE_META_CHUNK_SIZE byte.
struct byte_meta {
float stream_pts;
double start_pts;
};
enum {
BYTE_META_CHUNK_SIZE = 8 * 1024,
CACHE_INTERRUPTED = -1,
CACHE_CTRL_NONE = 0,
@ -134,7 +126,7 @@ enum {
CACHE_CTRL_PING = -2,
// we should fill buffer only if space>=FILL_LIMIT
FILL_LIMIT = FFMAX(16 * 1024, BYTE_META_CHUNK_SIZE * 2),
FILL_LIMIT = 16 * 1024,
};
static int64_t mp_clipi64(int64_t val, int64_t min, int64_t max)
@ -179,6 +171,7 @@ static void cache_drop_contents(struct priv *s)
{
s->offset = s->min_filepos = s->max_filepos = s->read_filepos;
s->eof = false;
s->start_pts = MP_NOPTS_VALUE;
}
// Copy at most dst_size from the cache at the given absolute file position pos.
@ -278,13 +271,12 @@ static bool cache_fill(struct priv *s)
len = stream_read_partial(s->stream, &s->buffer[pos], space);
pthread_mutex_lock(&s->mutex);
double pts;
if (stream_control(s->stream, STREAM_CTRL_GET_CURRENT_TIME, &pts) <= 0)
pts = MP_NOPTS_VALUE;
for (int64_t b_pos = pos; b_pos < pos + len + BYTE_META_CHUNK_SIZE;
b_pos += BYTE_META_CHUNK_SIZE)
{
s->bm[b_pos / BYTE_META_CHUNK_SIZE] = (struct byte_meta){.stream_pts = pts};
// Do this after reading a block, because at least libdvdnav updates the
// stream position only after actually reading something after a seek.
if (s->start_pts == MP_NOPTS_VALUE) {
double pts;
if (stream_control(s->stream, STREAM_CTRL_GET_CURRENT_TIME, &pts) > 0)
s->start_pts = pts;
}
s->max_filepos += len;
@ -311,11 +303,8 @@ static int resize_cache(struct priv *s, int64_t size)
int64_t buffer_size = MPMIN(MPMAX(size, min_size), max_size);
unsigned char *buffer = malloc(buffer_size);
struct byte_meta *bm = calloc(buffer_size / BYTE_META_CHUNK_SIZE + 2,
sizeof(struct byte_meta));
if (!buffer || !bm) {
if (!buffer) {
free(buffer);
free(bm);
return STREAM_ERROR;
}
@ -346,12 +335,10 @@ static int resize_cache(struct priv *s, int64_t size)
}
free(s->buffer);
free(s->bm);
s->buffer_size = buffer_size;
s->back_size = buffer_size / 2;
s->buffer = buffer;
s->bm = bm;
s->idle = false;
s->eof = false;
@ -360,9 +347,6 @@ static int resize_cache(struct priv *s, int64_t size)
if (s->seek_limit > s->buffer_size - FILL_LIMIT)
s->seek_limit = s->buffer_size - FILL_LIMIT;
for (size_t n = 0; n < s->buffer_size / BYTE_META_CHUNK_SIZE + 2; n++)
s->bm[n] = (struct byte_meta){.stream_pts = MP_NOPTS_VALUE};
return STREAM_OK;
}
@ -419,21 +403,10 @@ static int cache_get_cached_control(stream_t *cache, int cmd, void *arg)
*(unsigned int *)arg = s->stream_num_chapters;
return STREAM_OK;
case STREAM_CTRL_GET_CURRENT_TIME: {
if (s->read_filepos >= s->min_filepos &&
s->read_filepos <= s->max_filepos &&
s->min_filepos < s->max_filepos)
{
int64_t fpos = FFMIN(s->read_filepos, s->max_filepos - 1);
int64_t pos = fpos - s->offset;
if (pos < 0)
pos += s->buffer_size;
else if (pos >= s->buffer_size)
pos -= s->buffer_size;
double pts = s->bm[pos / BYTE_META_CHUNK_SIZE].stream_pts;
*(double *)arg = pts;
return pts == MP_NOPTS_VALUE ? STREAM_UNSUPPORTED : STREAM_OK;
}
return STREAM_UNSUPPORTED;
if (s->start_pts == MP_NOPTS_VALUE)
return STREAM_UNSUPPORTED;
*(double *)arg = s->start_pts;
return STREAM_OK;
}
case STREAM_CTRL_GET_METADATA: {
if (s->stream_metadata) {
@ -642,7 +615,6 @@ static void cache_uninit(stream_t *cache)
pthread_mutex_destroy(&s->mutex);
pthread_cond_destroy(&s->wakeup);
free(s->buffer);
free(s->bm);
talloc_free(s);
}
@ -657,6 +629,8 @@ int stream_cache_init(stream_t *cache, stream_t *stream,
struct priv *s = talloc_zero(NULL, struct priv);
s->log = cache->log;
cache_drop_contents(s);
s->seek_limit = opts->seek_min * 1024ULL;
if (resize_cache(s, opts->size * 1024ULL) != STREAM_OK) {