Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions DOCS/man/input.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2311,11 +2311,12 @@ Property list

``mistimed-frame-count``
Number of video frames that were not timed correctly in display-sync mode
for the sake of keeping A/V sync. This does not include external
for the sake of keeping A/V sync (i.e using the ``display-desync`` mode should
not change this value from 0), or in ``vrr-adjust`` mode for the sake of keeping
within the defined refresh rate range. This does not include external
circumstances, such as video rendering being too slow or the graphics
driver somehow skipping a vsync. It does not include rounding errors either
(which can happen especially with bad source timestamps). For example,
using the ``display-desync`` mode should never change this value from 0.
(which can happen especially with bad source timestamps).

``vsync-ratio``
For how many vsyncs a frame is displayed on average. This is available if
Expand Down
54 changes: 54 additions & 0 deletions DOCS/man/options.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1320,6 +1320,10 @@
Set this option only if you have reason to believe the automatically
determined value is wrong.

``--minimum-display-fps=<fps>``
Set the minimum display FPS used with the ``--vrr-adjust=true`` mode. By
default, it uses the maximum display fps.

``--hwdec=<api1,api2,...|no|auto|auto-copy>``
Specify the hardware video decoding API that should be used if possible.
Whether hardware decoding is actually done depends on the video codec. If
Expand Down Expand Up @@ -8224,6 +8228,56 @@
frame dropping due to the audio "overshooting" and skipping multiple video
frames before the sync logic can react.

``--vrr-adjust=<yes|no>``
This option tries to increase the chance of the display being ready for
frames the moment they are sent (default: no), for cases where the
display is unreliable, primarily useful for VRR displays. This uses
``--minimum-display-fps`` and display-fps (maximum fps).

Check failure on line 8236 in DOCS/man/options.rst

View workflow job for this annotation

GitHub Actions / editorconfig

Trailing whitespace
This is done by observing each individual frame and dynamically:

1. Not doing anything if they are perfectly between the minimum refresh time
and the middle refresh time.
2. Repeating frames at a middle refresh time if possible, else repeating
tending towards the middle refresh time (the middle refresh time gives
us the best error leeway in case there are random application or OS delays
that would put us in a position that exceeds either the minimum or
the maximum refresh time).
3. If we can't reliably repeat it, then we send it even if it's between the

Check failure on line 8246 in DOCS/man/options.rst

View workflow job for this annotation

GitHub Actions / editorconfig

Trailing whitespace
middle refresh time and the maximum refresh time. Note that because of the
above mentioned potential delays, this may cause us to exceed our target
even if we initially appear in valid range.
4. If the next frame exceeds our minimum refresh time, whether because our
repetition failed or that's how the frames exist, we will move it to the
closest valid position that's within the refresh range. If two frames are
put on the same position, we send the newest one only.

Note: This is not compatible with ``--video-sync=display-...`` modes, yet,
which would be the only ones capable of getting rid of the last displaying
weirdnesses.

``--vrr-adjust-max-refresh-variance=<0.0-1.0>``
How much percentage wise the refresh time can vary from one frame to the next,
where 1.0 means the refresh time can immediatelly move between the minimum and
maximum refresh time, while 0 means the refresh time is static. (default: 1.0)

The default does not take into account refresh rate flicker (which may happen
in specific cases, eg. when time between frames is constantly higher than
minimum refresh time + middle refresh time), and optimizes just for reaching
target position. If that's a problem, then this option can limit sudden changes in refresh
time. The lower the value set, the more refresh time stability, the higher chance
of missing our target.

Check failure on line 8269 in DOCS/man/options.rst

View workflow job for this annotation

GitHub Actions / editorconfig

Trailing whitespace

``--vrr-adjust-target-refresh-rate=<fps>``
Set the refresh rate we should tend towards, instead of the default "middle refresh
time". Setting it at a lower refresh rate will reduce the amount of repetitions,
which can help if computational burden is a problem. However, increasing it or
reducing it will come at a cost of potential chance increase of missing our target.

When needed, we will still use the entire range of ``--minimum-display-fps`` and
``--display-fps-override``, so this option only increases the chance towards
the refresh rate we tend towards.

Miscellaneous
-------------

Expand Down
8 changes: 8 additions & 0 deletions options/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ static const m_option_t mp_vo_opt_list[] = {
{"show-in-taskbar", OPT_BOOL(show_in_taskbar)},
{"display-fps-override", OPT_DOUBLE(display_fps_override),
M_RANGE(0, DBL_MAX)},
{"minimum-display-fps", OPT_DOUBLE(minimum_display_fps),
M_RANGE(0, DBL_MAX)},
{"video-timing-offset", OPT_DOUBLE(timing_offset), M_RANGE(0.0, 1.0)},
{"video-sync", OPT_CHOICE(video_sync,
{"audio", VS_DEFAULT},
Expand All @@ -200,6 +202,9 @@ static const m_option_t mp_vo_opt_list[] = {
{"display-vdrop", VS_DISP_VDROP},
{"display-desync", VS_DISP_NONE},
{"desync", VS_NONE})},
{"vrr-adjust", OPT_BOOL(vrr_adjust)},
{"vrr-adjust-max-refresh-variance", OPT_DOUBLE(vrr_max_refresh_variance), M_RANGE(0.0, 1.0)},
{"vrr-adjust-target-refresh-rate", OPT_DOUBLE(vrr_target_refresh_rate)},
#if HAVE_X11
{"x11-netwm", OPT_CHOICE(x11_netwm, {"auto", 0}, {"no", -1}, {"yes", 1})},
{"x11-bypass-compositor", OPT_CHOICE(x11_bypass_compositor,
Expand Down Expand Up @@ -292,7 +297,10 @@ const struct m_sub_options vo_sub_opts = {
.wl_present = true,
.mmcss_profile = "Playback",
.ontop_level = -1,
.minimum_display_fps = -1,
.timing_offset = 0.050,
.vrr_max_refresh_variance = 1,
.vrr_target_refresh_rate = -1,
.swapchain_depth = 2,
.focus_on = 1,
},
Expand Down
4 changes: 4 additions & 0 deletions options/options.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,12 @@ typedef struct mp_vo_opts {
int window_corners;

double display_fps_override;
double minimum_display_fps;
double timing_offset;
int video_sync;
bool vrr_adjust;
double vrr_max_refresh_variance;
double vrr_target_refresh_rate;

struct m_geometry android_surface_size;

Expand Down
2 changes: 1 addition & 1 deletion player/command.c
Original file line number Diff line number Diff line change
Expand Up @@ -765,7 +765,7 @@ static int mp_property_mistimed_frame_count(void *ctx, struct m_property *prop,
int action, void *arg)
{
MPContext *mpctx = ctx;
if (!mpctx->vo_chain || !mpctx->display_sync_active)
if (!mpctx->vo_chain || !(mpctx->display_sync_active || mpctx->video_out->opts->vrr_adjust))
return M_PROPERTY_UNAVAILABLE;

return m_property_int_ro(action, arg, mpctx->mistimed_frames_total);
Expand Down
5 changes: 5 additions & 0 deletions player/video.c
Original file line number Diff line number Diff line change
Expand Up @@ -808,6 +808,11 @@ static void handle_display_sync_frame(struct MPContext *mpctx,

mpctx->display_sync_active = false;

if (vo->opts->vrr_adjust && vo_get_pts_offset(vo) != 0) {
mpctx->mistimed_frames_total += 1;
MP_STATS(mpctx, "mistimed");
}

if (!VS_IS_DISP(mode) || !vo_is_visible(vo))
return;

Expand Down
2 changes: 1 addition & 1 deletion video/out/gpu/video.c
Original file line number Diff line number Diff line change
Expand Up @@ -3596,7 +3596,7 @@ void gl_video_render_frame(struct gl_video *p, struct vo_frame *frame,

// For the non-interpolation case, we draw to a single "cache"
// texture to speed up subsequent re-draws (if any exist)
bool repeats = frame->num_vsyncs > 1 && frame->display_synced;
bool repeats = frame->request_repeat;
bool r = false;
if ((repeats || frame->still) && !p->dumb_mode &&
(p->ra->caps & RA_CAP_BLIT) && fbo->tex->params.blit_dst)
Expand Down
Loading
Loading