0
0
mirror of https://github.com/mpv-player/mpv.git synced 2024-09-20 03:52:22 +02:00

demux: include EOF state in cached seekable range

This means if the user tries to seek past EOF, and we know EOF was seen
already, then use a cached seek, instead of triggering a low level seek.

This requires some annoying tracking, but seems pretty simple otherwise.

One advantage of doing this is that if the user tries to do this kind of
seek, there's no unnecessary waiting for a reaction by network (and in
most cases, redundant downloading of data just to discard it again).

Another is that this avoids creating overlapping seek ranges: previously, the
low level seek would naturally create a new range. Then it would read and add
data from the end of the stream due to the low level demuxer not being able to
seek to the target and selecting the last seek point before the end of the
stream. Consequently, this new range would overlap with the previous cached
range. But since the cache joining code is written such that you join the
current range with the _next_ range (instead of the previous as it would be
needed in this case), the overlapping ranges were left alone, until seeking back
to the previous range. That was ugly, sort of harmless, and could happen in
other cases, but this avoidable case was pretty easy to trigger.
This commit is contained in:
wm4 2018-01-05 17:38:09 +01:00 committed by Kevin Mitchell
parent 8e1390e734
commit 1eec7d2315

View File

@ -216,6 +216,9 @@ struct demux_cached_range {
// Computed from the stream queue's values. These fields (unlike as with
// demux_queue) are always either NOPTS, or fully valid.
double seek_start, seek_end;
// Set if the file ends with this range.
bool is_eof;
};
#define MAX_INDEX_ENTRIES 16
@ -246,6 +249,8 @@ struct demux_queue {
double seek_start, seek_end;
double last_pruned; // timestamp of last pruned keyframe
bool is_eof; // received true EOF here
// incomplete index to somewhat speed up seek operations
// the entries in index[] must be in packet queue append/removal order
int num_index; // valid index[] entries
@ -423,6 +428,7 @@ static void set_current_range(struct demux_internal *in,
static void update_seek_ranges(struct demux_cached_range *range)
{
range->seek_start = range->seek_end = MP_NOPTS_VALUE;
range->is_eof = true;
for (int n = 0; n < range->num_streams; n++) {
struct demux_queue *queue = range->streams[n];
@ -431,6 +437,8 @@ static void update_seek_ranges(struct demux_cached_range *range)
range->seek_start = MP_PTS_MAX(range->seek_start, queue->seek_start);
range->seek_end = MP_PTS_MIN(range->seek_end, queue->seek_end);
range->is_eof &= queue->is_eof;
if (queue->seek_start >= queue->seek_end) {
range->seek_start = range->seek_end = MP_NOPTS_VALUE;
break;
@ -517,6 +525,8 @@ static void clear_queue(struct demux_queue *queue)
queue->last_ts = queue->last_dts = MP_NOPTS_VALUE;
queue->keyframe_latest = NULL;
queue->keyframe_pts = queue->keyframe_end_pts = MP_NOPTS_VALUE;
queue->is_eof = false;
}
static void clear_cached_range(struct demux_internal *in,
@ -1044,6 +1054,7 @@ static void attempt_range_joining(struct demux_internal *in)
q1->keyframe_pts = q2->keyframe_pts;
q1->keyframe_end_pts = q2->keyframe_end_pts;
q1->keyframe_latest = q2->keyframe_latest;
q1->is_eof = q2->is_eof;
q2->head = q2->tail = NULL;
q2->next_prune_target = NULL;
@ -1096,6 +1107,7 @@ static void adjust_seek_range_on_packet(struct demux_stream *ds,
queue->seek_start = queue->keyframe_pts;
if (queue->keyframe_end_pts != MP_NOPTS_VALUE)
queue->seek_end = queue->keyframe_end_pts;
queue->is_eof = !dp;
update_seek_ranges(queue->range);
attempt_range_join = queue->range->seek_end > old_end;
if (queue->keyframe_latest->kf_seek_pts != MP_NOPTS_VALUE)
@ -1114,6 +1126,11 @@ static void adjust_seek_range_on_packet(struct demux_stream *ds,
queue->keyframe_pts = MP_PTS_MIN(queue->keyframe_pts, ts);
queue->keyframe_end_pts = MP_PTS_MAX(queue->keyframe_end_pts, ts);
if (queue->is_eof) {
queue->is_eof = false;
update_seek_ranges(queue->range);
}
}
if (attempt_range_join)
@ -2300,10 +2317,10 @@ static struct demux_cached_range *find_cache_seek_target(struct demux_internal *
for (int n = 0; n < in->num_ranges; n++) {
struct demux_cached_range *r = in->ranges[n];
if (r->seek_start != MP_NOPTS_VALUE) {
MP_VERBOSE(in, "cached range %d: %f <-> %f\n",
n, r->seek_start, r->seek_end);
MP_VERBOSE(in, "cached range %d: %f <-> %f (eof=%d)\n",
n, r->seek_start, r->seek_end, r->is_eof);
if (pts >= r->seek_start && pts <= r->seek_end) {
if (pts >= r->seek_start && (pts <= r->seek_end || r->is_eof)) {
MP_VERBOSE(in, "...using this range for in-cache seek.\n");
return r;
}