1
0
mirror of https://github.com/mpv-player/mpv synced 2024-12-27 01:22:30 +00:00

demux: reduce overhead when searching over keyframe ranges

The demuxer cache seeking mechanism looks at keyframe ranges to
determine the earlierst PTS of a packet. Instead of looping over all
packets twice (once to find the next keyframe, a second time to find the
seek PTS), do it in one go.

For that basically turn recompute_keyframe_target_pts() into an
iteration functionn. Functionality should be unchanged with this commit.
This commit is contained in:
wm4 2017-11-04 18:18:42 +01:00
parent 75cdd13e29
commit 6e998be7be

View File

@ -566,6 +566,14 @@ static double get_refresh_seek_pts(struct demux_internal *in)
return start_ts - 1.0;
}
// Return the next keyframe packet in the list (dp itself if it's one).
static struct demux_packet *find_keyframe(struct demux_packet *dp)
{
while (dp && !dp->keyframe)
dp = dp->next;
return dp;
}
// Get the PTS in the keyframe range starting at or following dp. We assume
// that the minimum PTS values within a keyframe range are strictly monotonic
// increasing relative to the range after it. Since we don't assume that the
@ -576,24 +584,25 @@ static double get_refresh_seek_pts(struct demux_internal *in)
// The caller assumption is that the first frame decoded from this packet
// position will result in a frame with the PTS returned from this function.
// (For corner cases with non-key frames, assuming those packets are skipped.)
static double recompute_keyframe_target_pts(struct demux_packet *dp)
// *next_kf, if not NULL, it set to the next keyframe packet (the one which
// ends the current range), or NULL if there's none.
// *next_kf is never set to dp, unless dp==NULL.
static double recompute_keyframe_target_pts(struct demux_packet *dp,
struct demux_packet **next_kf)
{
bool in_keyframe_range = false;
double res = MP_NOPTS_VALUE;
dp = find_keyframe(dp);
while (dp) {
if (dp->keyframe) {
if (in_keyframe_range)
break;
in_keyframe_range = true;
}
if (in_keyframe_range) {
double ts = PTS_OR_DEF(dp->pts, dp->dts);
if (dp->segmented && (ts < dp->start || ts > dp->end))
ts = MP_NOPTS_VALUE;
res = MP_PTS_MIN(res, ts);
}
double ts = PTS_OR_DEF(dp->pts, dp->dts);
if (dp->segmented && (ts < dp->start || ts > dp->end))
ts = MP_NOPTS_VALUE;
res = MP_PTS_MIN(res, ts);
dp = dp->next;
if (dp && dp->keyframe)
break;
}
if (next_kf)
*next_kf = dp;
return res;
}
@ -661,7 +670,7 @@ void demux_add_packet(struct sh_stream *stream, demux_packet_t *dp)
// (In theory it'd be more efficient to make this incremental.)
if (ds->back_pts == MP_NOPTS_VALUE && dp->keyframe && ds->in->seekable_cache)
ds->back_pts = recompute_keyframe_target_pts(ds->queue_head);
ds->back_pts = recompute_keyframe_target_pts(ds->queue_head, NULL);
if (!ds->ignore_eof) {
// obviously not true anymore
@ -838,16 +847,13 @@ static void prune_old_packets(struct demux_internal *in)
// every packet.)
struct demux_packet *next_seek_target = NULL;
if (in->seekable_cache) {
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;
}
// (Has to be _after_ queue_head to drop at least 1 packet.)
struct demux_packet *dp = find_keyframe(ds->queue_head->next);
while (dp && ds->back_pts == MP_NOPTS_VALUE) {
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, &dp);
}
}
@ -1678,11 +1684,10 @@ static struct demux_packet *find_seek_target(struct demux_stream *ds,
{
struct demux_packet *target = NULL;
double target_diff = MP_NOPTS_VALUE;
for (struct demux_packet *dp = ds->queue_head; dp; dp = dp->next) {
if (!dp->keyframe)
continue;
double range_pts = recompute_keyframe_target_pts(dp);
struct demux_packet *dp = find_keyframe(ds->queue_head);
while (dp) {
struct demux_packet *cur = dp;
double range_pts = recompute_keyframe_target_pts(dp, &dp);
if (range_pts == MP_NOPTS_VALUE)
continue;
@ -1700,7 +1705,7 @@ static struct demux_packet *find_seek_target(struct demux_stream *ds,
continue;
}
target_diff = diff;
target = dp;
target = cur;
}
return target;
@ -1747,7 +1752,8 @@ static bool try_seek_cache(struct demux_internal *in, double pts, int flags)
if (ds->selected && ds->type == STREAM_VIDEO) {
struct demux_packet *target = find_seek_target(ds, pts, flags);
if (target) {
double target_pts = recompute_keyframe_target_pts(target);
double target_pts =
recompute_keyframe_target_pts(target, NULL);
if (target_pts != MP_NOPTS_VALUE) {
MP_VERBOSE(in, "adjust seek target %f -> %f\n",
pts, target_pts);