summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2017-11-04 18:18:42 +0100
committerwm4 <wm4@nowhere>2017-11-04 18:18:42 +0100
commit6e998be7bed7d25e98bfe1c7d6ca079f081da7d1 (patch)
treefbcdb6ba840ee789d0157890e68891ae77241fb6
parent75cdd13e29b7bbd8ff16f81f7b3b1043f752e71e (diff)
downloadmpv-6e998be7bed7d25e98bfe1c7d6ca079f081da7d1.tar.bz2
mpv-6e998be7bed7d25e98bfe1c7d6ca079f081da7d1.tar.xz
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.
-rw-r--r--demux/demux.c68
1 files changed, 37 insertions, 31 deletions
diff --git a/demux/demux.c b/demux/demux.c
index 95aeb2435b..c745bb9d3b 100644
--- a/demux/demux.c
+++ b/demux/demux.c
@@ -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);