summaryrefslogtreecommitdiffstats
path: root/demux
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2017-10-25 16:26:03 +0200
committerwm4 <wm4@nowhere>2017-10-25 16:39:33 +0200
commitec8cad40f243870bd7e9b030771a7052089058fa (patch)
treea713f51c2ef5cdec48da1f210ed3c18d01e54c5f /demux
parentd235380cd3ae9490a25937ee44b08615ed97e1cc (diff)
downloadmpv-ec8cad40f243870bd7e9b030771a7052089058fa.tar.bz2
mpv-ec8cad40f243870bd7e9b030771a7052089058fa.tar.xz
demux: better computation of seek start target
Avoids that cache seeking is not possible with files that have audio frames with no timestamps (such as avi, sometimes mkv sub-packets from lacing). These would set back_pts (first seekable PTS) to NOPTS, and thus disable cache seeking completely. Instead, prune such packets until we find one with timestamps. One corner case is that the new next good packet might be in the forward cache. In this case we defer dropping until the next time this code is run, and the reader position has possibly moved past the drop point.
Diffstat (limited to 'demux')
-rw-r--r--demux/demux.c32
1 files changed, 24 insertions, 8 deletions
diff --git a/demux/demux.c b/demux/demux.c
index 5c7b99358b..c919a885a6 100644
--- a/demux/demux.c
+++ b/demux/demux.c
@@ -802,18 +802,36 @@ static void prune_old_packets(struct demux_internal *in)
assert(earliest_stream >= 0); // incorrect accounting of "buffered"?
struct demux_stream *ds = in->streams[earliest_stream]->ds;
+ ds->back_pts = MP_NOPTS_VALUE;
+
// Prune all packets until the next keyframe or reader_head. Keeping
// those packets would not help with seeking at all, so we strictly
// drop them.
+ // In addition, we need to find the new possibly min. seek target,
+ // which in the worst case could be inside the forward buffer. The fact
+ // that many keyframe ranges without keyframes exist (audio packets)
+ // makes this much harder.
// Note: might be pretty inefficient for streams with many small audio
- // or subtitle packets. (All are keyframe and selection logic runs for
+ // or subtitle packets. (All are keyframes, and selection logic runs for
// every packet.)
- bool dropped_one = false;
- while (ds->queue_head && ds->queue_head != ds->reader_head) {
+ struct demux_packet *next_seek_target = NULL;
+ for (struct demux_packet *dp = ds->queue_head; dp; dp = dp->next) {
+ // (Has to be _after_ queue_head to drop at least 1 packet.)
+ if (dp->keyframe && dp != ds->queue_head) {
+ next_seek_target = dp;
+ // Note that we set back_pts to this even if we leave some
+ // packets before it - it will still be only viable seek target.
+ ds->back_pts = recompute_keyframe_target_pts(dp);
+ if (ds->back_pts != MP_NOPTS_VALUE)
+ break;
+ }
+ }
+
+ while (ds->queue_head && (ds->queue_head != ds->reader_head &&
+ ds->queue_head != next_seek_target))
+ {
struct demux_packet *dp = ds->queue_head;
- if (dp->keyframe && dropped_one)
- break;
- dropped_one = true;
+
size_t bytes = demux_packet_estimate_total_size(dp);
buffered -= bytes;
MP_TRACE(in, "dropping backbuffer packet size %zd from stream %d\n",
@@ -825,8 +843,6 @@ static void prune_old_packets(struct demux_internal *in)
talloc_free(dp);
ds->bw_bytes -= bytes;
}
-
- ds->back_pts = recompute_keyframe_target_pts(ds->queue_head);
}
}