mirror of https://github.com/mpv-player/mpv
vo: disregard system-reported display FPS if it's too imprecise
If the system-reported display FPS (returned by the VO backends, or forced with --display-fps) is too imprecise (deviating frame duration by more than 1%). This works if the display FPS is off by almost 1 (typical for old/bad/broken OS APIs). Actually it even works if the FPs is completely wrong. Is it a good idea? Probably not. It might be better to only output a warning message. But unless there are reports about it going terribly wrong, I'll go with this for now.
This commit is contained in:
parent
85498a0797
commit
41f2c653e2
|
@ -138,8 +138,9 @@ struct vo_internal {
|
||||||
int queued_events; // event mask for the user
|
int queued_events; // event mask for the user
|
||||||
int internal_events; // event mask for us
|
int internal_events; // event mask for us
|
||||||
|
|
||||||
int64_t vsync_interval;
|
int64_t nominal_vsync_interval;
|
||||||
|
|
||||||
|
int64_t vsync_interval;
|
||||||
int64_t *vsync_samples;
|
int64_t *vsync_samples;
|
||||||
int num_vsync_samples;
|
int num_vsync_samples;
|
||||||
int64_t prev_vsync;
|
int64_t prev_vsync;
|
||||||
|
@ -331,6 +332,17 @@ static void reset_vsync_timings(struct vo *vo)
|
||||||
in->expecting_vsync = false;
|
in->expecting_vsync = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static double vsync_stddef(struct vo *vo, int64_t ref_vsync)
|
||||||
|
{
|
||||||
|
struct vo_internal *in = vo->in;
|
||||||
|
double jitter = 0;
|
||||||
|
for (int n = 0; n < in->num_vsync_samples; n++) {
|
||||||
|
double diff = in->vsync_samples[n] - ref_vsync;
|
||||||
|
jitter += diff * diff;
|
||||||
|
}
|
||||||
|
return sqrt(jitter / in->num_vsync_samples);
|
||||||
|
}
|
||||||
|
|
||||||
// Always called locked.
|
// Always called locked.
|
||||||
static void update_vsync_timing_after_swap(struct vo *vo)
|
static void update_vsync_timing_after_swap(struct vo *vo)
|
||||||
{
|
{
|
||||||
|
@ -355,15 +367,32 @@ static void update_vsync_timing_after_swap(struct vo *vo)
|
||||||
}
|
}
|
||||||
in->prev_vsync = now;
|
in->prev_vsync = now;
|
||||||
|
|
||||||
double avg = 0, jitter = 0;
|
double avg = 0;
|
||||||
for (int n = 0; n < in->num_vsync_samples; n++) {
|
for (int n = 0; n < in->num_vsync_samples; n++)
|
||||||
avg += in->vsync_samples[n] / 1e6;
|
avg += in->vsync_samples[n];
|
||||||
double diff = in->vsync_samples[n] / (double)in->vsync_interval - 1.0;
|
in->estimated_vsync_interval = avg / in->num_vsync_samples;
|
||||||
jitter += diff * diff;
|
in->estimated_vsync_jitter =
|
||||||
|
vsync_stddef(vo, in->vsync_interval) / in->vsync_interval;
|
||||||
|
|
||||||
|
// Switch to assumed display FPS if it seems "better". (Note that small
|
||||||
|
// differences are handled as drift instead.)
|
||||||
|
if (in->num_vsync_samples == max_samples &&
|
||||||
|
fabs((in->nominal_vsync_interval - in->estimated_vsync_interval))
|
||||||
|
>= 0.01 * in->nominal_vsync_interval &&
|
||||||
|
in->estimated_vsync_interval <= 1e6 / 20.0 &&
|
||||||
|
in->estimated_vsync_interval >= 1e6 / 99.0)
|
||||||
|
{
|
||||||
|
double mjitter = vsync_stddef(vo, in->estimated_vsync_interval);
|
||||||
|
double njitter = vsync_stddef(vo, in->nominal_vsync_interval);
|
||||||
|
if (mjitter * 1.01 < njitter) {
|
||||||
|
if (in->vsync_interval == in->nominal_vsync_interval) {
|
||||||
|
MP_WARN(vo, "Reported display FPS seems incorrect.\n"
|
||||||
|
"Assuming a value closer to %.3f Hz.\n",
|
||||||
|
1e6 / in->estimated_vsync_interval);
|
||||||
|
}
|
||||||
|
in->vsync_interval = in->estimated_vsync_interval;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
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);
|
MP_STATS(vo, "value %f jitter", in->estimated_vsync_jitter);
|
||||||
MP_STATS(vo, "value %f vsync-diff", in->vsync_samples[0] / 1e6);
|
MP_STATS(vo, "value %f vsync-diff", in->vsync_samples[0] / 1e6);
|
||||||
|
@ -422,6 +451,9 @@ static void update_display_fps(struct vo *vo)
|
||||||
in->queued_events |= VO_EVENT_WIN_STATE;
|
in->queued_events |= VO_EVENT_WIN_STATE;
|
||||||
mp_input_wakeup(vo->input_ctx);
|
mp_input_wakeup(vo->input_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
in->nominal_vsync_interval = in->display_fps > 0 ? 1e6 / in->display_fps : 0;
|
||||||
|
in->vsync_interval = MPMAX(in->nominal_vsync_interval, 1);
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&in->lock);
|
pthread_mutex_unlock(&in->lock);
|
||||||
}
|
}
|
||||||
|
@ -682,9 +714,6 @@ static bool render_frame(struct vo *vo)
|
||||||
|
|
||||||
pthread_mutex_lock(&in->lock);
|
pthread_mutex_lock(&in->lock);
|
||||||
|
|
||||||
vo->in->vsync_interval = in->display_fps > 0 ? 1e6 / in->display_fps : 0;
|
|
||||||
vo->in->vsync_interval = MPMAX(vo->in->vsync_interval, 1);
|
|
||||||
|
|
||||||
if (in->frame_queued) {
|
if (in->frame_queued) {
|
||||||
talloc_free(in->current_frame);
|
talloc_free(in->current_frame);
|
||||||
in->current_frame = in->frame_queued;
|
in->current_frame = in->frame_queued;
|
||||||
|
@ -1051,7 +1080,7 @@ double vo_get_estimated_vsync_interval(struct vo *vo)
|
||||||
{
|
{
|
||||||
struct vo_internal *in = vo->in;
|
struct vo_internal *in = vo->in;
|
||||||
pthread_mutex_lock(&in->lock);
|
pthread_mutex_lock(&in->lock);
|
||||||
double res = in->estimated_vsync_interval;
|
double res = in->estimated_vsync_interval / 1e6;
|
||||||
pthread_mutex_unlock(&in->lock);
|
pthread_mutex_unlock(&in->lock);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue