From 1eec7d231577a2101ef82227797e3a5b6d221428 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 5 Jan 2018 17:38:09 +0100 Subject: [PATCH] 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. --- demux/demux.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/demux/demux.c b/demux/demux.c index cd1227a9ba..952d768120 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -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; }