mirror of https://github.com/mpv-player/mpv
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.
This commit is contained in:
parent
d235380cd3
commit
ec8cad40f2
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue