video: take refresh rate changes into account

This works only on X11, and only if the refresh rate changes due to the
window being moved to another screen (detected by us). It doesn't
include system screen reconfiguration yet.

This calls VOCTRL_GET_DISPLAY_FPS on every frame, which makes me uneasy.
It means extra thread communication with the win32 and Cocoa backends.
On the other hand, a frame doesn't happen _that_ often, and the
communication should still be pretty cheap and fast, so it's probably
ok.

Also needs some extra fuzz for vo_vdpau.c, because that does everything
differently.
This commit is contained in:
wm4 2014-08-17 02:50:59 +02:00
parent 4822056db7
commit 5b64f5ad35
3 changed files with 37 additions and 28 deletions

View File

@ -126,7 +126,6 @@ struct vo_internal {
int wakeup_pipe[2]; // used for VOs that use a unix FD for waiting
char *window_title;
bool hasframe;
bool request_redraw;
@ -135,7 +134,6 @@ struct vo_internal {
int64_t flip_queue_offset; // queue flip events at most this much in advance
int64_t last_flip;
int64_t vsync_interval;
int64_t drop_count;
bool dropped_frame; // the previous frame was dropped
struct mp_image *dropped_image; // used to possibly redraw the dropped frame
@ -146,6 +144,10 @@ struct vo_internal {
struct mp_image *frame_queued; // the image that should be rendered
int64_t frame_pts; // realtime of intended display
int64_t frame_duration; // realtime frame duration (for framedrop)
// --- The following fields can be accessed from the VO thread only
int64_t vsync_interval;
char *window_title;
};
static void forget_frames(struct vo *vo);
@ -295,6 +297,21 @@ void vo_destroy(struct vo *vo)
dealloc_vo(vo);
}
// to be called from VO thread only
static void update_display_fps(struct vo *vo)
{
double display_fps = 1000.0; // assume infinite if unset
if (vo->global->opts->frame_drop_fps > 0) {
display_fps = vo->global->opts->frame_drop_fps;
} else {
vo->driver->control(vo, VOCTRL_GET_DISPLAY_FPS, &display_fps);
}
int64_t n_interval = MPMAX((int64_t)(1e6 / display_fps), 1);
if (vo->in->vsync_interval != n_interval)
MP_VERBOSE(vo, "Assuming %f FPS for framedrop.\n", display_fps);
vo->in->vsync_interval = n_interval;
}
static void check_vo_caps(struct vo *vo)
{
int rot = vo->params->rotate;
@ -331,14 +348,7 @@ static void run_reconfig(void *p)
}
forget_frames(vo); // implicitly synchronized
double display_fps = 1000.0; // assume infinite if unset
if (vo->global->opts->frame_drop_fps > 0) {
display_fps = vo->global->opts->frame_drop_fps;
} else {
vo->driver->control(vo, VOCTRL_GET_DISPLAY_FPS, &display_fps);
}
vo->in->vsync_interval = MPMAX((int64_t)(1e6 / display_fps), 1);
MP_VERBOSE(vo, "Assuming %f FPS for framedrop.\n", display_fps);
update_display_fps(vo);
}
int vo_reconfig(struct vo *vo, struct mp_image_params *params, int flags)
@ -529,6 +539,8 @@ static bool render_frame(struct vo *vo)
{
struct vo_internal *in = vo->in;
update_display_fps(vo);
pthread_mutex_lock(&in->lock);
int64_t pts = in->frame_pts;
@ -770,6 +782,11 @@ void vo_set_flip_queue_offset(struct vo *vo, int64_t us)
pthread_mutex_unlock(&in->lock);
}
int64_t vo_get_vsync_interval(struct vo *vo)
{
return vo->in->vsync_interval;
}
/**
* \brief lookup an integer in a table, table must have 0 as the last key
* \param key key to search for

View File

@ -289,6 +289,7 @@ void vo_set_paused(struct vo *vo, bool paused);
int64_t vo_get_drop_count(struct vo *vo);
void vo_set_flip_queue_offset(struct vo *vo, int64_t us);
int64_t vo_get_vsync_interval(struct vo *vo);
void vo_wakeup(struct vo *vo);
const char *vo_get_window_title(struct vo *vo);

View File

@ -329,27 +329,11 @@ static int win_x11_init_vdpau_flip_queue(struct vo *vo)
CHECK_VDP_WARNING(vo, "Error setting colorkey");
}
vc->vsync_interval = 1;
if (vc->composite_detect && vo_x11_screen_is_composited(vo)) {
MP_INFO(vo, "Compositing window manager detected. Assuming timing info "
"is inaccurate.\n");
} else if (vc->user_fps > 0) {
vc->vsync_interval = 1e9 / vc->user_fps;
MP_INFO(vo, "Assuming user-specified display refresh rate of %.3f Hz.\n",
vc->user_fps);
} else if (vc->user_fps == 0) {
double fps = vo_x11_vm_get_fps(vo);
if (fps < 1)
MP_WARN(vo, "Failed to get display FPS\n");
else {
vc->vsync_interval = 1e9 / fps;
// This is verbose, but I'm not yet sure how common wrong values are
MP_INFO(vo, "Got display refresh rate %.3f Hz.\n", fps);
MP_INFO(vo, "If that value looks wrong give the "
"-vo vdpau:fps=X suboption manually.\n");
}
} else
MP_VERBOSE(vo, "framedrop/timing logic disabled by user.\n");
vc->user_fps = -1;
}
return 0;
}
@ -737,6 +721,13 @@ static void flip_page_timed(struct vo *vo, int64_t pts_us, int duration)
if (!check_preemption(vo))
return;
vc->vsync_interval = 1;
if (vc->user_fps > 0) {
vc->vsync_interval = 1e9 / vc->user_fps;
} else if (vc->user_fps == 0) {
vc->vsync_interval = vo_get_vsync_interval(vo) * 1000;
}
if (duration > INT_MAX / 1000)
duration = -1;
else