From 2c572e2bb1cfa4e225a6a1599f5ecdbcf4bf2dc6 Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 13 Mar 2018 11:23:23 +0100 Subject: [PATCH] video: add an option to tune waiting for video timing Probably mostly useful for the libmpv render API. --- DOCS/man/options.rst | 20 ++++++++++++++++++++ libmpv/render.h | 6 ++++++ options/m_option.h | 3 +++ options/options.c | 2 ++ options/options.h | 2 ++ video/out/vo.c | 19 +++++++++++++++++-- 6 files changed, 50 insertions(+), 2 deletions(-) diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index 8713cf7244..16e4998453 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -5410,6 +5410,26 @@ Miscellaneous out. This delay in reaction time to sudden A/V offsets should be the only side effect of turning this option on, for all sound drivers. +``--video-timing-offset=`` + Control how long before video display target time the frame should be + rendered (default: 0.050). If a video frame should be displayed at a + certain time, the VO will start rendering the frame earlier, and then will + perform a blocking wait until the display time, and only then "swap" the + frame to display. The rendering cannot start before the previous frame is + displayed, so this value is implicitly limited by the video framerate. With + normal video frame rates, the default value will ensure that rendering is + always immediately started after the previous frame was displayed. On the + other hand, setting a too high value can reduce responsiveness with low + FPS value. + + For client API users using the render API (or the deprecated ``opengl-cb`` + API), this option is interesting, because you can stop the render API + from limiting your FPS (see ``mpv_render_context_render()`` documentation). + + This applies only to audio timing modes (e.g. ``--video-sync=audio``). In + other modes (``--video-sync=display-...``), video timing relies on vsync + blocking, and this option is not used. + ``--video-sync=`` How the player synchronizes audio and video. diff --git a/libmpv/render.h b/libmpv/render.h index 64a317d73c..75153befb8 100644 --- a/libmpv/render.h +++ b/libmpv/render.h @@ -270,6 +270,12 @@ void mpv_render_context_set_update_callback(mpv_render_context *ctx, * notifies you when a new frame was added. The details potentially depend on * the backends and the provided parameters. * + * Generally, libmpv will invoke your update callback some time before the video + * frame should be shown, and then lets this function block until the supposed + * display time. This will limit your rendering to video FPS. You can prevent + * this by setting the "video-timing-offset" global option to 0. (This applies + * only to "audio" video sync mode.) + * * @param ctx a valid render context * @param params an array of parameters, terminated by type==0. Which parameters * are required depends on the backend. It's left unspecified what diff --git a/options/m_option.h b/options/m_option.h index 078e9248b9..2402405cde 100644 --- a/options/m_option.h +++ b/options/m_option.h @@ -616,6 +616,9 @@ extern const char m_option_path_separator; #define OPT_FLOATRANGE(...) \ OPT_RANGE_(float, __VA_ARGS__, .type = &m_option_type_float) +#define OPT_DOUBLERANGE(...) \ + OPT_RANGE_(double, __VA_ARGS__, .type = &m_option_type_double) + #define OPT_INTPAIR(...) \ OPT_GENERAL_NOTYPE(__VA_ARGS__, .type = &m_option_type_intpair) diff --git a/options/options.c b/options/options.c index ebccc5976f..7c7a30ed27 100644 --- a/options/options.c +++ b/options/options.c @@ -139,6 +139,7 @@ static const m_option_t mp_vo_opt_list[] = { OPT_FLAG("keepaspect-window", keepaspect_window, 0), OPT_FLAG("hidpi-window-scale", hidpi_window_scale, 0), OPT_FLAG("native-fs", native_fs, 0), + OPT_DOUBLERANGE("video-timing-offset", timing_offset, 0, 0.0, 1.0), #if HAVE_X11 OPT_CHOICE("x11-netwm", x11_netwm, 0, ({"auto", 0}, {"no", -1}, {"yes", 1})), @@ -176,6 +177,7 @@ const struct m_sub_options vo_sub_opts = { .x11_bypass_compositor = 2, .mmcss_profile = "Playback", .ontop_level = -1, + .timing_offset = 0.050, }, }; diff --git a/options/options.h b/options/options.h index 1c58ca14b1..303b2e5761 100644 --- a/options/options.h +++ b/options/options.h @@ -50,6 +50,8 @@ typedef struct mp_vo_opts { char *mmcss_profile; + double timing_offset; + // vo_drm struct sws_opts *sws_opts; // vo_drm diff --git a/video/out/vo.c b/video/out/vo.c index ac4fa9a773..fc4630b731 100644 --- a/video/out/vo.c +++ b/video/out/vo.c @@ -147,6 +147,7 @@ struct vo_internal { int64_t num_successive_vsyncs; int64_t flip_queue_offset; // queue flip events at most this much in advance + int64_t timing_offset; // same (but from options; not VO configured) int64_t delayed_count; int64_t drop_count; @@ -212,11 +213,23 @@ static void dispatch_wakeup_cb(void *ptr) vo_wakeup(vo); } +// Initialize or update options from vo->opts +static void read_opts(struct vo *vo) +{ + struct vo_internal *in = vo->in; + + pthread_mutex_lock(&in->lock); + in->timing_offset = (uint64_t)(vo->opts->timing_offset * 1e6); + pthread_mutex_unlock(&in->lock); +} + static void update_opts(void *p) { struct vo *vo = p; if (m_config_cache_update(vo->opts_cache)) { + read_opts(vo); + // "Legacy" update of video position related options. if (vo->driver->control) vo->driver->control(vo, VOCTRL_SET_PANSCAN, NULL); @@ -728,8 +741,9 @@ bool vo_is_ready_for_frame(struct vo *vo, int64_t next_pts) if (r && next_pts >= 0) { // Don't show the frame too early - it would basically freeze the // display by disallowing OSD redrawing or VO interaction. - // Actually render the frame at earliest 50ms before target time. - next_pts -= (uint64_t)(0.050 * 1e6); + // Actually render the frame at earliest the given offset before target + // time. + next_pts -= in->timing_offset; next_pts -= in->flip_queue_offset; int64_t now = mp_time_us(); if (next_pts > now) @@ -1003,6 +1017,7 @@ static void *vo_thread(void *ptr) if (r < 0) return NULL; + read_opts(vo); update_display_fps(vo); vo_event(vo, VO_EVENT_WIN_STATE);