summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/man/input.rst8
-rw-r--r--player/command.c31
-rw-r--r--video/out/vo.c77
-rw-r--r--video/out/vo.h2
4 files changed, 117 insertions, 1 deletions
diff --git a/DOCS/man/input.rst b/DOCS/man/input.rst
index 367d9f185b..1a59f283fe 100644
--- a/DOCS/man/input.rst
+++ b/DOCS/man/input.rst
@@ -1487,6 +1487,14 @@ Property list
available on all platforms. Note that any of the listed facts may change
any time without a warning.
+``estimated-display-fps``
+ Only available if display-sync mode (as selected by ``--video-sync``) is
+ active. Returns the actual rate at which display refreshes seem to occur,
+ measured by system time.
+
+``vsync-jitter``
+ Estimated deviation factor of the vsync duration.
+
``video-aspect`` (RW)
Video aspect, see ``--video-aspect``.
diff --git a/player/command.c b/player/command.c
index c6fb5d6fdd..cc30d2b21a 100644
--- a/player/command.c
+++ b/player/command.c
@@ -2629,6 +2629,32 @@ static int mp_property_display_fps(void *ctx, struct m_property *prop,
return m_property_double_ro(action, arg, fps);
}
+static int mp_property_estimated_display_fps(void *ctx, struct m_property *prop,
+ int action, void *arg)
+{
+ MPContext *mpctx = ctx;
+ struct vo *vo = mpctx->video_out;
+ if (!vo)
+ return M_PROPERTY_UNAVAILABLE;
+ double interval = vo_get_estimated_vsync_interval(vo);
+ if (interval <= 0)
+ return M_PROPERTY_UNAVAILABLE;
+ return m_property_double_ro(action, arg, 1.0 / interval);
+}
+
+static int mp_property_vsync_jitter(void *ctx, struct m_property *prop,
+ int action, void *arg)
+{
+ MPContext *mpctx = ctx;
+ struct vo *vo = mpctx->video_out;
+ if (!vo)
+ return M_PROPERTY_UNAVAILABLE;
+ double stddev = vo_get_estimated_vsync_jitter(vo);
+ if (stddev < 0)
+ return M_PROPERTY_UNAVAILABLE;
+ return m_property_double_ro(action, arg, stddev);
+}
+
static int mp_property_display_names(void *ctx, struct m_property *prop,
int action, void *arg)
{
@@ -3612,6 +3638,8 @@ static const struct m_property mp_properties[] = {
{"window-minimized", mp_property_win_minimized},
{"display-names", mp_property_display_names},
{"display-fps", mp_property_display_fps},
+ {"estimated-display-fps", mp_property_estimated_display_fps},
+ {"vsync-jitter", mp_property_vsync_jitter},
{"working-directory", mp_property_cwd},
@@ -3656,7 +3684,8 @@ static const char *const *const mp_event_property_change[] = {
"percent-pos", "time-remaining", "playtime-remaining", "playback-time",
"estimated-vf-fps", "drop-frame-count", "vo-drop-frame-count",
"total-avsync-change", "audio-speed-correction", "video-speed-correction",
- "vo-delayed-frame-count", "mistimed-frame-count", "vsync-ratio"),
+ "vo-delayed-frame-count", "mistimed-frame-count", "vsync-ratio",
+ "estimated-display-fps", "vsync-jitter"),
E(MPV_EVENT_VIDEO_RECONFIG, "video-out-params", "video-params",
"video-format", "video-codec", "video-bitrate", "dwidth", "dheight",
"width", "height", "fps", "aspect", "vo-configured", "current-vo",
diff --git a/video/out/vo.c b/video/out/vo.c
index 6606cf82f7..883d0e9818 100644
--- a/video/out/vo.c
+++ b/video/out/vo.c
@@ -142,6 +142,13 @@ struct vo_internal {
int64_t vsync_interval;
+ int64_t *vsync_samples;
+ int num_vsync_samples;
+ int64_t prev_vsync;
+ double estimated_vsync_interval;
+ double estimated_vsync_jitter;
+ bool expecting_vsync;
+
int64_t flip_queue_offset; // queue flip events at most this much in advance
int64_t delayed_count;
@@ -312,6 +319,48 @@ void vo_destroy(struct vo *vo)
dealloc_vo(vo);
}
+// Drop timing information on discontinuities like seeking.
+// Always called locked.
+static void reset_vsync_timings(struct vo *vo)
+{
+ struct vo_internal *in = vo->in;
+ in->num_vsync_samples = 0;
+ in->prev_vsync = 0;
+ in->estimated_vsync_interval = 0;
+ in->estimated_vsync_jitter = -1;
+ in->expecting_vsync = false;
+}
+
+// Always called locked.
+static void update_vsync_timing_after_swap(struct vo *vo)
+{
+ struct vo_internal *in = vo->in;
+
+ if (!in->expecting_vsync || !in->prev_vsync) {
+ reset_vsync_timings(vo);
+ return;
+ }
+
+ int64_t now = mp_time_us();
+ if (in->num_vsync_samples >= 200)
+ in->num_vsync_samples -= 1;
+ MP_TARRAY_INSERT_AT(in, in->vsync_samples, in->num_vsync_samples, 0,
+ now - in->prev_vsync);
+ in->prev_vsync = now;
+
+ double avg = 0, jitter = 0;
+ for (int n = 0; n < in->num_vsync_samples; n++) {
+ avg += in->vsync_samples[n] / 1e6;
+ double diff = in->vsync_samples[n] / (double)in->vsync_interval - 1.0;
+ jitter += diff * diff;
+ }
+ avg /= in->num_vsync_samples;
+ in->estimated_vsync_interval = avg;
+ in->estimated_vsync_jitter = sqrt(jitter / in->num_vsync_samples);
+
+ MP_STATS(vo, "value %f jitter", in->estimated_vsync_jitter);
+}
+
// to be called from VO thread only
static void update_display_fps(struct vo *vo)
{
@@ -383,6 +432,7 @@ static void run_reconfig(void *p)
talloc_free(in->current_frame);
in->current_frame = NULL;
forget_frames(vo);
+ reset_vsync_timings(vo);
pthread_mutex_unlock(&in->lock);
update_display_fps(vo);
@@ -705,6 +755,10 @@ static bool render_frame(struct vo *vo)
if (in->current_frame->num_vsyncs > 0)
in->current_frame->num_vsyncs -= 1;
+ in->expecting_vsync = in->current_frame->display_synced && !in->paused;
+ if (in->expecting_vsync && !in->prev_vsync)
+ in->prev_vsync = mp_time_us();
+
if (in->dropped_frame) {
in->drop_count += 1;
} else {
@@ -740,6 +794,8 @@ static bool render_frame(struct vo *vo)
double diff = (in->vsync_interval - in->vsync_interval_approx) / 1e6;
if (fabs(diff) < 0.150)
MP_STATS(vo, "value %f vsync-diff", diff);
+
+ update_vsync_timing_after_swap(vo);
}
if (!in->dropped_frame) {
@@ -864,6 +920,7 @@ void vo_set_paused(struct vo *vo, bool paused)
if (in->paused && in->dropped_frame)
in->request_redraw = true;
in->last_flip = 0;
+ reset_vsync_timings(vo);
}
pthread_mutex_unlock(&in->lock);
vo_control(vo, paused ? VOCTRL_PAUSE : VOCTRL_RESUME, NULL);
@@ -911,6 +968,7 @@ void vo_seek_reset(struct vo *vo)
pthread_mutex_lock(&in->lock);
forget_frames(vo);
in->last_flip = 0;
+ reset_vsync_timings(vo);
in->send_reset = true;
wakeup_locked(vo);
pthread_mutex_unlock(&in->lock);
@@ -1022,6 +1080,25 @@ int64_t vo_get_vsync_interval(struct vo *vo)
return res;
}
+// Returns duration of a display refresh in seconds.
+double vo_get_estimated_vsync_interval(struct vo *vo)
+{
+ struct vo_internal *in = vo->in;
+ pthread_mutex_lock(&in->lock);
+ double res = in->estimated_vsync_interval;
+ pthread_mutex_unlock(&in->lock);
+ return res;
+}
+
+double vo_get_estimated_vsync_jitter(struct vo *vo)
+{
+ struct vo_internal *in = vo->in;
+ pthread_mutex_lock(&in->lock);
+ double res = in->estimated_vsync_jitter;
+ pthread_mutex_unlock(&in->lock);
+ return res;
+}
+
// Get the time in seconds at after which the currently rendering frame will
// end. Returns positive values if the frame is yet to be finished, negative
// values if it already finished.
diff --git a/video/out/vo.h b/video/out/vo.h
index bd68858b43..0f934ebdc4 100644
--- a/video/out/vo.h
+++ b/video/out/vo.h
@@ -348,6 +348,8 @@ void vo_set_queue_params(struct vo *vo, int64_t offset_us, bool vsync_timed,
int num_req_frames);
int vo_get_num_req_frames(struct vo *vo);
int64_t vo_get_vsync_interval(struct vo *vo);
+double vo_get_estimated_vsync_interval(struct vo *vo);
+double vo_get_estimated_vsync_jitter(struct vo *vo);
double vo_get_display_fps(struct vo *vo);
double vo_get_delay(struct vo *vo);