diff --git a/DOCS/client-api-changes.rst b/DOCS/client-api-changes.rst index 78ef3e789d58d..f0926471f3ff0 100644 --- a/DOCS/client-api-changes.rst +++ b/DOCS/client-api-changes.rst @@ -32,6 +32,8 @@ API changes :: + --- mpv 0.37.0 --- + 2.2 - add mpv_time_ns() --- mpv 0.36.0 --- 2.1 - add mpv_del_property() --- mpv 0.35.0 --- diff --git a/audio/out/ao_wasapi_utils.c b/audio/out/ao_wasapi_utils.c index 07c7ddb43f6f0..6c5bfb3ab1f15 100644 --- a/audio/out/ao_wasapi_utils.c +++ b/audio/out/ao_wasapi_utils.c @@ -945,7 +945,7 @@ bool wasapi_thread_init(struct ao *ao) { struct wasapi_state *state = ao->priv; MP_DBG(ao, "Init wasapi thread\n"); - int64_t retry_wait = 1; + int64_t retry_wait = 1000; bool align_hack = false; HRESULT hr; @@ -1028,13 +1028,13 @@ bool wasapi_thread_init(struct ao *ao) goto retry; case AUDCLNT_E_DEVICE_IN_USE: case AUDCLNT_E_DEVICE_INVALIDATED: - if (retry_wait > 8) { + if (retry_wait > 8000) { MP_FATAL(ao, "Bad device retry failed\n"); return false; } wasapi_thread_uninit(ao); MP_WARN(ao, "Retrying in %"PRId64" us\n", retry_wait); - mp_sleep_us(retry_wait); + mp_sleep_ns(retry_wait); retry_wait *= 2; goto retry; } diff --git a/libmpv/client.h b/libmpv/client.h index 4199744ba7f4d..0a548a58eb633 100644 --- a/libmpv/client.h +++ b/libmpv/client.h @@ -248,7 +248,7 @@ extern "C" { * relational operators (<, >, <=, >=). */ #define MPV_MAKE_VERSION(major, minor) (((major) << 16) | (minor) | 0UL) -#define MPV_CLIENT_API_VERSION MPV_MAKE_VERSION(2, 1) +#define MPV_CLIENT_API_VERSION MPV_MAKE_VERSION(2, 2) /** * The API user is allowed to "#define MPV_ENABLE_DEPRECATED 0" before @@ -602,7 +602,7 @@ MPV_EXPORT mpv_handle *mpv_create_weak_client(mpv_handle *ctx, const char *name) MPV_EXPORT int mpv_load_config_file(mpv_handle *ctx, const char *filename); /** - * Return the internal time in microseconds. This has an arbitrary start offset, + * Return the internal time in nanoseconds. This has an arbitrary start offset, * but will never wrap or go backwards. * * Note that this is always the real time, and doesn't necessarily have to do @@ -615,6 +615,11 @@ MPV_EXPORT int mpv_load_config_file(mpv_handle *ctx, const char *filename); * * Safe to be called from mpv render API threads. */ +MPV_EXPORT int64_t mpv_get_time_ns(mpv_handle *ctx); + +/** + * Same as mpv_get_time_ns but in microseconds. + */ MPV_EXPORT int64_t mpv_get_time_us(mpv_handle *ctx); /** @@ -1951,6 +1956,8 @@ MPV_DEFINE_SYM_PTR(mpv_create_weak_client) #define mpv_create_weak_client pfn_mpv_create_weak_client MPV_DEFINE_SYM_PTR(mpv_load_config_file) #define mpv_load_config_file pfn_mpv_load_config_file +MPV_DEFINE_SYM_PTR(mpv_get_time_ns) +#define mpv_get_time_ns pfn_mpv_get_time_ns MPV_DEFINE_SYM_PTR(mpv_get_time_us) #define mpv_get_time_us pfn_mpv_get_time_us MPV_DEFINE_SYM_PTR(mpv_free_node_contents) diff --git a/meson.build b/meson.build index 6806105caaa78..4485c74a56be1 100644 --- a/meson.build +++ b/meson.build @@ -403,7 +403,7 @@ if posix subprocess_source = files('osdep/subprocess-posix.c') sources += path_source + subprocess_source + \ files('input/ipc-unix.c', - 'osdep/polldev.c', + 'osdep/poll_wrapper.c', 'osdep/terminal-unix.c', 'sub/filter_regex.c') endif @@ -424,6 +424,9 @@ if posix and not darwin 'osdep/timer-linux.c') endif +features += {'ppoll': cc.has_function('ppoll', args: '-D_GNU_SOURCE', + prefix: '#include ')} + cd_devices = { 'windows': 'D:', 'cygwin': 'D:', diff --git a/osdep/polldev.c b/osdep/poll_wrapper.c similarity index 81% rename from osdep/polldev.c rename to osdep/poll_wrapper.c index dc86d5d022f58..48a66d2cd136a 100644 --- a/osdep/polldev.c +++ b/osdep/poll_wrapper.c @@ -1,6 +1,4 @@ /* - * poll shim that supports device files on macOS. - * * This file is part of mpv. * * mpv is free software; you can redistribute it and/or @@ -22,9 +20,23 @@ #include #include -#include "osdep/polldev.h" +#include "config.h" +#include "poll_wrapper.h" +#include "timer.h" + + +int mp_poll(struct pollfd *fds, int nfds, int64_t timeout_ns) +{ +#if HAVE_PPOLL + struct timespec ts = mp_time_ns_to_realtime(timeout_ns); + return ppoll(fds, nfds, &ts, NULL); +#endif + return poll(fds, nfds, timeout_ns / 1e6); +} -int polldev(struct pollfd fds[], nfds_t nfds, int timeout) { +// poll shim that supports device files on macOS. +int polldev(struct pollfd fds[], nfds_t nfds, int timeout) +{ #ifdef __APPLE__ int maxfd = 0; fd_set readfds, writefds; diff --git a/osdep/polldev.h b/osdep/poll_wrapper.h similarity index 51% rename from osdep/polldev.h rename to osdep/poll_wrapper.h index 8593c1e77c973..b359ed39a0197 100644 --- a/osdep/polldev.h +++ b/osdep/poll_wrapper.h @@ -1,7 +1,12 @@ #pragma once #include +#include // Behaves like poll(3) but works for device files on macOS. // Only supports POLLIN and POLLOUT. int polldev(struct pollfd fds[], nfds_t nfds, int timeout); + +// Generic polling wrapper. It will try and use higher resolution +// polling (ppoll) if available. +int mp_poll(struct pollfd *fds, int nfds, int64_t timeout_ns); diff --git a/osdep/terminal-unix.c b/osdep/terminal-unix.c index e03599d829b49..fabaf402e518c 100644 --- a/osdep/terminal-unix.c +++ b/osdep/terminal-unix.c @@ -31,7 +31,7 @@ #include "osdep/io.h" #include "osdep/threads.h" -#include "osdep/polldev.h" +#include "osdep/poll_wrapper.h" #include "common/common.h" #include "misc/bstr.h" diff --git a/osdep/timer-darwin.c b/osdep/timer-darwin.c index a114d0d727067..bb8a9b43248b8 100644 --- a/osdep/timer-darwin.c +++ b/osdep/timer-darwin.c @@ -28,10 +28,9 @@ static double timebase_ratio_ns; -void mp_sleep_us(int64_t us) +void mp_sleep_ns(int64_t ns) { - uint64_t deadline = us * 1e3 / timebase_ratio_ns + mach_absolute_time(); - + uint64_t deadline = ns / timebase_ratio_ns + mach_absolute_time(); mach_wait_until(deadline); } diff --git a/osdep/timer-linux.c b/osdep/timer-linux.c index 0289233695206..ff4b137cb227e 100644 --- a/osdep/timer-linux.c +++ b/osdep/timer-linux.c @@ -22,13 +22,13 @@ #include #include "timer.h" -void mp_sleep_us(int64_t us) +void mp_sleep_ns(int64_t ns) { - if (us < 0) + if (ns < 0) return; struct timespec ts; - ts.tv_sec = us / 1000000; - ts.tv_nsec = (us % 1000000) * 1000; + ts.tv_sec = ns / UINT64_C(1000000000); + ts.tv_nsec = ns % UINT64_C(1000000000); nanosleep(&ts, NULL); } diff --git a/osdep/timer-win2.c b/osdep/timer-win2.c index dd7a42f0d1600..7867b5a5251dd 100644 --- a/osdep/timer-win2.c +++ b/osdep/timer-win2.c @@ -52,17 +52,41 @@ void mp_end_hires_timers(int res_ms) #endif } -void mp_sleep_us(int64_t us) +void mp_sleep_ns(int64_t ns) { - if (us < 0) + if (ns < 0) return; - // Sleep(0) won't sleep for one clocktick as the unix usleep - // instead it will only make the thread ready - // it may take some time until it actually starts to run again - if (us < 1000) - us = 1000; - int hrt = mp_start_hires_timers(us / 1000); - Sleep(us / 1000); + + int hrt = mp_start_hires_timers(ns < 1e6 ? 1 : ns / 1e6); + +#ifndef CREATE_WAITABLE_TIMER_HIGH_RESOLUTION +#define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION 0x2 +#endif + + HANDLE timer = CreateWaitableTimerEx(NULL, NULL, + CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, + TIMER_ALL_ACCESS); + + // CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is supported in Windows 10 1803+, + // retry without it. + if (!timer) + timer = CreateWaitableTimerEx(NULL, NULL, 0, TIMER_ALL_ACCESS); + + if (!timer) + goto end; + + // Time is expected in 100 nanosecond intervals. + // Negative values indicate relative time. + LARGE_INTEGER time = (LARGE_INTEGER){ .QuadPart = -(ns / 100) }; + if (!SetWaitableTimer(timer, &time, 0, NULL, NULL, 0)) + goto end; + + if (WaitForSingleObject(timer, INFINITE) != WAIT_OBJECT_0) + goto end; + +end: + if (timer) + CloseHandle(timer); mp_end_hires_timers(hrt); } diff --git a/osdep/timer.h b/osdep/timer.h index d76ad16129bec..b273cb405e504 100644 --- a/osdep/timer.h +++ b/osdep/timer.h @@ -29,7 +29,7 @@ int64_t mp_time_us(void); // Return time in nanoseconds. Never wraps. Never returns 0 or negative values. int64_t mp_time_ns(void); -// Return time in seconds. Can have down to 1 microsecond resolution, but will +// Return time in seconds. Can have down to 1 nanosecond resolution, but will // be much worse when casted to float. double mp_time_sec(void); @@ -37,8 +37,8 @@ double mp_time_sec(void); void mp_raw_time_init(void); uint64_t mp_raw_time_ns(void); -// Sleep in microseconds. -void mp_sleep_us(int64_t us); +// Sleep in nanoseconds. +void mp_sleep_ns(int64_t ns); #ifdef _WIN32 // returns: timer resolution in ms if needed and started successfully, else 0 diff --git a/player/client.c b/player/client.c index 71e4fb99c7959..f16af4528e0c4 100644 --- a/player/client.c +++ b/player/client.c @@ -2129,6 +2129,11 @@ void mpv_free(void *data) talloc_free(data); } +int64_t mpv_get_time_ns(mpv_handle *ctx) +{ + return mp_time_ns(); +} + int64_t mpv_get_time_us(mpv_handle *ctx) { return mp_time_us(); diff --git a/player/command.c b/player/command.c index cf4971a4b35d2..1a4cca9befb10 100644 --- a/player/command.c +++ b/player/command.c @@ -2491,7 +2491,7 @@ static int mp_property_estimated_display_fps(void *ctx, struct m_property *prop, struct vo *vo = mpctx->video_out; if (!vo) return M_PROPERTY_UNAVAILABLE; - double interval = vo_get_estimated_vsync_interval(vo); + double interval = vo_get_estimated_vsync_interval(vo) / 1e9; if (interval <= 0) return M_PROPERTY_UNAVAILABLE; return m_property_double_ro(action, arg, 1.0 / interval); diff --git a/player/core.h b/player/core.h index 556620cf8ac4c..18a833595303f 100644 --- a/player/core.h +++ b/player/core.h @@ -391,7 +391,7 @@ typedef struct MPContext { double start_timestamp; // Timestamp from the last time some timing functions read the - // current time, in microseconds. + // current time, in nanoseconds. // Used to turn a new time value to a delta from last time. int64_t last_time; diff --git a/player/playloop.c b/player/playloop.c index b0df04f2d9ca8..eb42a3131c097 100644 --- a/player/playloop.c +++ b/player/playloop.c @@ -123,10 +123,10 @@ static void mp_process_input(struct MPContext *mpctx) double get_relative_time(struct MPContext *mpctx) { - int64_t new_time = mp_time_us(); + int64_t new_time = mp_time_ns(); int64_t delta = new_time - mpctx->last_time; mpctx->last_time = new_time; - return delta * 0.000001; + return delta * 1e-9; } void update_core_idle_state(struct MPContext *mpctx) diff --git a/player/video.c b/player/video.c index 7da9cf46fe2b1..e5b0b6b3a24b1 100644 --- a/player/video.c +++ b/player/video.c @@ -1198,7 +1198,7 @@ void write_video(struct MPContext *mpctx) } double time_frame = MPMAX(mpctx->time_frame, -1); - int64_t pts = mp_time_us() + (int64_t)(time_frame * 1e6); + int64_t pts = mp_time_ns() + (int64_t)(time_frame * 1e9); // wait until VO wakes us up to get more frames // (NB: in theory, the 1st frame after display sync mode change uses the @@ -1240,7 +1240,7 @@ void write_video(struct MPContext *mpctx) diff /= mpctx->video_speed; if (mpctx->time_frame < 0) diff += mpctx->time_frame; - frame->duration = MPCLAMP(diff, 0, 10) * 1e6; + frame->duration = MPCLAMP(diff, 0, 10) * 1e9; } mpctx->video_pts = mpctx->next_frames[0]->pts; diff --git a/video/out/drm_common.c b/video/out/drm_common.c index 4f235956ad532..f8d68dfa81ad2 100644 --- a/video/out/drm_common.c +++ b/video/out/drm_common.c @@ -42,6 +42,7 @@ #include "common/msg.h" #include "options/m_config.h" #include "osdep/io.h" +#include "osdep/poll_wrapper.h" #include "osdep/timer.h" #include "misc/ctype.h" #include "video/out/vo.h" @@ -283,12 +284,12 @@ static void vt_switcher_destroy(struct vt_switcher *s) close(vt_switcher_pipe[1]); } -static void vt_switcher_poll(struct vt_switcher *s, int timeout_ms) +static void vt_switcher_poll(struct vt_switcher *s, int timeout_ns) { struct pollfd fds[1] = { { .events = POLLIN, .fd = vt_switcher_pipe[0] }, }; - poll(fds, 1, timeout_ms); + mp_poll(fds, 1, timeout_ns); if (!fds[0].revents) return; @@ -1304,15 +1305,15 @@ void vo_drm_set_monitor_par(struct vo *vo) MP_VERBOSE(drm, "Monitor pixel aspect: %g\n", vo->monitor_par); } -void vo_drm_wait_events(struct vo *vo, int64_t until_time_us) +void vo_drm_wait_events(struct vo *vo, int64_t until_time_ns) { struct vo_drm_state *drm = vo->drm; if (drm->vt_switcher_active) { - int64_t wait_us = until_time_us - mp_time_us(); - int timeout_ms = MPCLAMP((wait_us + 500) / 1000, 0, 10000); - vt_switcher_poll(&drm->vt_switcher, timeout_ms); + int64_t wait_ns = until_time_ns - mp_time_ns(); + int64_t timeout_ns = MPCLAMP(wait_ns, 1e6, 1e10); + vt_switcher_poll(&drm->vt_switcher, timeout_ns); } else { - vo_wait_default(vo, until_time_us); + vo_wait_default(vo, until_time_ns); } } diff --git a/video/out/drm_common.h b/video/out/drm_common.h index ac915848993aa..cadef2019f070 100644 --- a/video/out/drm_common.h +++ b/video/out/drm_common.h @@ -114,7 +114,7 @@ double vo_drm_get_display_fps(struct vo_drm_state *drm); void vo_drm_get_vsync(struct vo *vo, struct vo_vsync_info *info); void vo_drm_set_monitor_par(struct vo *vo); void vo_drm_uninit(struct vo *vo); -void vo_drm_wait_events(struct vo *vo, int64_t until_time_us); +void vo_drm_wait_events(struct vo *vo, int64_t until_time_ns); void vo_drm_wait_on_flip(struct vo_drm_state *drm); void vo_drm_wakeup(struct vo *vo); diff --git a/video/out/gpu/context.h b/video/out/gpu/context.h index 27d8462f97cc0..6788e6fd89bbd 100644 --- a/video/out/gpu/context.h +++ b/video/out/gpu/context.h @@ -48,7 +48,7 @@ struct ra_ctx_fns { // These behave exactly like vo_driver.wakeup/wait_events. They are // optional. void (*wakeup)(struct ra_ctx *ctx); - void (*wait_events)(struct ra_ctx *ctx, int64_t until_time_us); + void (*wait_events)(struct ra_ctx *ctx, int64_t until_time_ns); void (*update_render_opts)(struct ra_ctx *ctx); // Initialize/destroy the 'struct ra' and possibly the underlying VO backend. diff --git a/video/out/opengl/context_drm_egl.c b/video/out/opengl/context_drm_egl.c index 5141f2ce2a512..16046b1577bc4 100644 --- a/video/out/opengl/context_drm_egl.c +++ b/video/out/opengl/context_drm_egl.c @@ -734,9 +734,9 @@ static int drm_egl_control(struct ra_ctx *ctx, int *events, int request, return ret; } -static void drm_egl_wait_events(struct ra_ctx *ctx, int64_t until_time_us) +static void drm_egl_wait_events(struct ra_ctx *ctx, int64_t until_time_ns) { - vo_drm_wait_events(ctx->vo, until_time_us); + vo_drm_wait_events(ctx->vo, until_time_ns); } static void drm_egl_wakeup(struct ra_ctx *ctx) diff --git a/video/out/opengl/context_glx.c b/video/out/opengl/context_glx.c index 5d22563632d6f..40622245e6cd4 100644 --- a/video/out/opengl/context_glx.c +++ b/video/out/opengl/context_glx.c @@ -334,9 +334,9 @@ static void glx_wakeup(struct ra_ctx *ctx) vo_x11_wakeup(ctx->vo); } -static void glx_wait_events(struct ra_ctx *ctx, int64_t until_time_us) +static void glx_wait_events(struct ra_ctx *ctx, int64_t until_time_ns) { - vo_x11_wait_events(ctx->vo, until_time_us); + vo_x11_wait_events(ctx->vo, until_time_ns); } const struct ra_ctx_fns ra_ctx_glx = { diff --git a/video/out/opengl/context_wayland.c b/video/out/opengl/context_wayland.c index aa8bb2d92181f..26c52688d340f 100644 --- a/video/out/opengl/context_wayland.c +++ b/video/out/opengl/context_wayland.c @@ -198,9 +198,9 @@ static void wayland_egl_wakeup(struct ra_ctx *ctx) vo_wayland_wakeup(ctx->vo); } -static void wayland_egl_wait_events(struct ra_ctx *ctx, int64_t until_time_us) +static void wayland_egl_wait_events(struct ra_ctx *ctx, int64_t until_time_ns) { - vo_wayland_wait_events(ctx->vo, until_time_us); + vo_wayland_wait_events(ctx->vo, until_time_ns); } static void wayland_egl_update_render_opts(struct ra_ctx *ctx) diff --git a/video/out/opengl/context_x11egl.c b/video/out/opengl/context_x11egl.c index a0f710f3ecb4a..3201f298f68c0 100644 --- a/video/out/opengl/context_x11egl.c +++ b/video/out/opengl/context_x11egl.c @@ -208,9 +208,9 @@ static void mpegl_wakeup(struct ra_ctx *ctx) vo_x11_wakeup(ctx->vo); } -static void mpegl_wait_events(struct ra_ctx *ctx, int64_t until_time_us) +static void mpegl_wait_events(struct ra_ctx *ctx, int64_t until_time_ns) { - vo_x11_wait_events(ctx->vo, until_time_us); + vo_x11_wait_events(ctx->vo, until_time_ns); } const struct ra_ctx_fns ra_ctx_x11_egl = { diff --git a/video/out/opengl/hwdec_dxva2egl.c b/video/out/opengl/hwdec_dxva2egl.c index d870d982cd14c..0ca10ef7af804 100644 --- a/video/out/opengl/hwdec_dxva2egl.c +++ b/video/out/opengl/hwdec_dxva2egl.c @@ -343,7 +343,7 @@ static int mapper_map(struct ra_hwdec_mapper *mapper) // of the above StretchRect. Timeout of 8ms is required to reliably // render 4k on Intel Haswell, Ivybridge and Cherry Trail Atom. const int max_retries = 8; - const int64_t wait_us = 1000; + const int64_t wait_ns = 1e6; int retries = 0; while (true) { hr = IDirect3DQuery9_GetData(p->query9, NULL, 0, D3DGETDATA_FLUSH); @@ -353,10 +353,10 @@ static int mapper_map(struct ra_hwdec_mapper *mapper) } else if (hr == S_FALSE) { if (++retries > max_retries) { MP_VERBOSE(mapper, "Failed to flush frame after %lld ms\n", - (long long)(wait_us * max_retries) / 1000); + (long long)(wait_ns * max_retries) / 1e6); break; } - mp_sleep_us(wait_us); + mp_sleep_ns(wait_ns); } else { break; } diff --git a/video/out/vo.c b/video/out/vo.c index 669595f1cedb0..4fab586dfdfe7 100644 --- a/video/out/vo.c +++ b/video/out/vo.c @@ -232,7 +232,7 @@ 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); + in->timing_offset = (uint64_t)(vo->opts->timing_offset * 1e9); pthread_mutex_unlock(&in->lock); } @@ -717,7 +717,7 @@ void vo_wait_default(struct vo *vo, int64_t until_time) pthread_mutex_lock(&in->lock); if (!in->need_wakeup) { - struct timespec ts = mp_time_us_to_realtime(until_time); + struct timespec ts = mp_time_ns_to_realtime(until_time); pthread_cond_timedwait(&in->wakeup, &in->lock, &ts); } pthread_mutex_unlock(&in->lock); @@ -782,7 +782,7 @@ bool vo_is_ready_for_frame(struct vo *vo, int64_t next_pts) // time. next_pts -= in->timing_offset; next_pts -= in->flip_queue_offset; - int64_t now = mp_time_us(); + int64_t now = mp_time_ns(); if (next_pts > now) r = false; if (!in->wakeup_pts || next_pts < in->wakeup_pts) { @@ -830,9 +830,9 @@ void vo_wait_frame(struct vo *vo) static void wait_until(struct vo *vo, int64_t target) { struct vo_internal *in = vo->in; - struct timespec ts = mp_time_us_to_realtime(target); + struct timespec ts = mp_time_ns_to_realtime(target); pthread_mutex_lock(&in->lock); - while (target > mp_time_us()) { + while (target > mp_time_ns()) { if (in->queued_events & VO_EVENT_LIVE_RESIZING) break; if (pthread_cond_timedwait(&in->wakeup, &in->lock, &ts)) @@ -873,7 +873,7 @@ static bool render_frame(struct vo *vo) if (in->paused) frame->vsync_offset = 0; - int64_t now = mp_time_us(); + int64_t now = mp_time_ns(); int64_t pts = frame->pts; int64_t duration = frame->duration; int64_t end_time = pts + duration; @@ -889,7 +889,7 @@ static bool render_frame(struct vo *vo) in->dropped_frame &= frame->can_drop; // Even if we're hopelessly behind, rather degrade to 10 FPS playback, // instead of just freezing the display forever. - in->dropped_frame &= now - (in->prev_vsync / 1000.0) < 100 * 1000; + in->dropped_frame &= now - in->prev_vsync < 100 * 1e6; in->dropped_frame &= in->hasframe_rendered; // Setup parameters for the next time this frame is drawn. ("frame" is the @@ -907,7 +907,7 @@ static bool render_frame(struct vo *vo) bool use_vsync = in->current_frame->display_synced && !in->paused; if (use_vsync && !in->expecting_vsync) // first DS frame in a row - in->prev_vsync = now * 1000; + in->prev_vsync = now; in->expecting_vsync = use_vsync; // Store the initial value before we unlock. @@ -1064,7 +1064,7 @@ static void *vo_thread(void *ptr) stats_event(in->stats, "iterations"); vo->driver->control(vo, VOCTRL_CHECK_EVENTS, NULL); bool working = render_frame(vo); - int64_t now = mp_time_us(); + int64_t now = mp_time_ns(); int64_t wait_until = now + (working ? 0 : (int64_t)1e9); pthread_mutex_lock(&in->lock); @@ -1230,15 +1230,15 @@ void vo_get_src_dst_rects(struct vo *vo, struct mp_rect *out_src, out_src, out_dst, out_osd); } -// flip_page[_timed] will be called offset_us microseconds too early. +// flip_page[_timed] will be called offset_us nanoseconds too early. // (For vo_vdpau, which does its own timing.) // num_req_frames set the requested number of requested vo_frame.frames. // (For vo_gpu interpolation.) -void vo_set_queue_params(struct vo *vo, int64_t offset_us, int num_req_frames) +void vo_set_queue_params(struct vo *vo, int64_t offset_ns, int num_req_frames) { struct vo_internal *in = vo->in; pthread_mutex_lock(&in->lock); - in->flip_queue_offset = offset_us; + in->flip_queue_offset = offset_ns; in->req_frames = MPCLAMP(num_req_frames, 1, VO_MAX_REQ_FRAMES); pthread_mutex_unlock(&in->lock); } @@ -1261,12 +1261,11 @@ double 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 / 1e9; + double res = in->estimated_vsync_interval; pthread_mutex_unlock(&in->lock); return res; } diff --git a/video/out/vo.h b/video/out/vo.h index ca120672f6fcb..710bd6e10f109 100644 --- a/video/out/vo.h +++ b/video/out/vo.h @@ -207,10 +207,10 @@ struct vo_extra { }; struct vo_frame { - // If > 0, realtime when frame should be shown, in mp_time_us() units. + // If > 0, realtime when frame should be shown, in mp_time_ns() units. // If 0, present immediately. int64_t pts; - // Approximate frame duration, in us. + // Approximate frame duration, in ns. int duration; // Realtime of estimated distance between 2 vsync events. double vsync_interval; @@ -414,7 +414,7 @@ struct vo_driver { * immediately. */ void (*wakeup)(struct vo *vo); - void (*wait_events)(struct vo *vo, int64_t until_time_us); + void (*wait_events)(struct vo *vo, int64_t until_time_ns); /* * Closes driver. Should restore the original state of the system. @@ -508,7 +508,7 @@ void vo_query_formats(struct vo *vo, uint8_t *list); void vo_event(struct vo *vo, int event); int vo_query_and_reset_events(struct vo *vo, int events); struct mp_image *vo_get_current_frame(struct vo *vo); -void vo_set_queue_params(struct vo *vo, int64_t offset_us, int num_req_frames); +void vo_set_queue_params(struct vo *vo, int64_t offset_ns, int num_req_frames); int vo_get_num_req_frames(struct vo *vo); double vo_get_vsync_interval(struct vo *vo); double vo_get_estimated_vsync_interval(struct vo *vo); diff --git a/video/out/vo_gpu.c b/video/out/vo_gpu.c index 8939561a38a8c..c02e6e730d510 100644 --- a/video/out/vo_gpu.c +++ b/video/out/vo_gpu.c @@ -252,13 +252,13 @@ static void wakeup(struct vo *vo) p->ctx->fns->wakeup(p->ctx); } -static void wait_events(struct vo *vo, int64_t until_time_us) +static void wait_events(struct vo *vo, int64_t until_time_ns) { struct gpu_priv *p = vo->priv; if (p->ctx && p->ctx->fns->wait_events) { - p->ctx->fns->wait_events(p->ctx, until_time_us); + p->ctx->fns->wait_events(p->ctx, until_time_ns); } else { - vo_wait_default(vo, until_time_us); + vo_wait_default(vo, until_time_ns); } } diff --git a/video/out/vo_gpu_next.c b/video/out/vo_gpu_next.c index 8014f7def112d..d5c234f4bbafe 100644 --- a/video/out/vo_gpu_next.c +++ b/video/out/vo_gpu_next.c @@ -1578,13 +1578,13 @@ static void wakeup(struct vo *vo) p->ra_ctx->fns->wakeup(p->ra_ctx); } -static void wait_events(struct vo *vo, int64_t until_time_us) +static void wait_events(struct vo *vo, int64_t until_time_ns) { struct priv *p = vo->priv; if (p->ra_ctx && p->ra_ctx->fns->wait_events) { - p->ra_ctx->fns->wait_events(p->ra_ctx, until_time_us); + p->ra_ctx->fns->wait_events(p->ra_ctx, until_time_ns); } else { - vo_wait_default(vo, until_time_us); + vo_wait_default(vo, until_time_ns); } } diff --git a/video/out/vo_null.c b/video/out/vo_null.c index 2aa46f785f752..0c49062e23d38 100644 --- a/video/out/vo_null.c +++ b/video/out/vo_null.c @@ -40,14 +40,14 @@ static void flip_page(struct vo *vo) { struct priv *p = vo->priv; if (p->cfg_fps) { - int64_t ft = 1e6 / p->cfg_fps; - int64_t prev_vsync = mp_time_us() / ft; + int64_t ft = 1e9 / p->cfg_fps; + int64_t prev_vsync = mp_time_ns() / ft; int64_t target_time = (prev_vsync + 1) * ft; for (;;) { - int64_t now = mp_time_us(); + int64_t now = mp_time_ns(); if (now >= target_time) break; - mp_sleep_us(target_time - now); + mp_sleep_ns(target_time - now); } } } diff --git a/video/out/vo_sdl.c b/video/out/vo_sdl.c index b5e3d5b041e9b..e101f8d6208ba 100644 --- a/video/out/vo_sdl.c +++ b/video/out/vo_sdl.c @@ -520,10 +520,10 @@ static void wakeup(struct vo *vo) SDL_PushEvent(&event); } -static void wait_events(struct vo *vo, int64_t until_time_us) +static void wait_events(struct vo *vo, int64_t until_time_ns) { - int64_t wait_us = until_time_us - mp_time_us(); - int timeout_ms = MPCLAMP((wait_us + 500) / 1000, 0, 10000); + int64_t wait_ns = until_time_ns - mp_time_ns(); + int timeout_ms = MPCLAMP(wait_ns / 1e6, 1, 10000); SDL_Event ev; while (SDL_WaitEventTimeout(&ev, timeout_ms)) { diff --git a/video/out/vo_vdpau.c b/video/out/vo_vdpau.c index 17ee6aba7028c..d6b261f057a65 100644 --- a/video/out/vo_vdpau.c +++ b/video/out/vo_vdpau.c @@ -279,7 +279,7 @@ static void resize(struct vo *vo) vc->flip_offset_us = vo->opts->fullscreen ? 1000LL * vc->flip_offset_fs : 1000LL * vc->flip_offset_window; - vo_set_queue_params(vo, vc->flip_offset_us, 1); + vo_set_queue_params(vo, vc->flip_offset_us * 1000, 1); if (vc->output_surface_w < vo->dwidth || vc->output_surface_h < vo->dheight || vc->rotation != vo->params->rotate) diff --git a/video/out/vo_x11.c b/video/out/vo_x11.c index 9775b2394899c..1087fc249efd8 100644 --- a/video/out/vo_x11.c +++ b/video/out/vo_x11.c @@ -299,7 +299,7 @@ static void wait_for_completion(struct vo *vo, int max_outstanding) " for XShm completion events...\n"); ctx->Shm_Warned_Slow = 1; } - mp_sleep_us(1000); + mp_sleep_ns(1e6); vo_x11_check_events(vo); } } diff --git a/video/out/vo_xv.c b/video/out/vo_xv.c index 22bce037709b2..cffd3a797fb02 100644 --- a/video/out/vo_xv.c +++ b/video/out/vo_xv.c @@ -670,7 +670,7 @@ static void wait_for_completion(struct vo *vo, int max_outstanding) " for XShm completion events...\n"); ctx->Shm_Warned_Slow = 1; } - mp_sleep_us(1000); + mp_sleep_ns(1e6); vo_x11_check_events(vo); } } diff --git a/video/out/vulkan/context_display.c b/video/out/vulkan/context_display.c index da801dd9217dc..84cef1e8c2046 100644 --- a/video/out/vulkan/context_display.c +++ b/video/out/vulkan/context_display.c @@ -474,7 +474,7 @@ static void display_wakeup(struct ra_ctx *ctx) // TODO } -static void display_wait_events(struct ra_ctx *ctx, int64_t until_time_us) +static void display_wait_events(struct ra_ctx *ctx, int64_t until_time_ns) { // TODO } diff --git a/video/out/vulkan/context_wayland.c b/video/out/vulkan/context_wayland.c index 5ca6265a910d5..761ff5b12cf44 100644 --- a/video/out/vulkan/context_wayland.c +++ b/video/out/vulkan/context_wayland.c @@ -142,9 +142,9 @@ static void wayland_vk_wakeup(struct ra_ctx *ctx) vo_wayland_wakeup(ctx->vo); } -static void wayland_vk_wait_events(struct ra_ctx *ctx, int64_t until_time_us) +static void wayland_vk_wait_events(struct ra_ctx *ctx, int64_t until_time_ns) { - vo_wayland_wait_events(ctx->vo, until_time_us); + vo_wayland_wait_events(ctx->vo, until_time_ns); } static void wayland_vk_update_render_opts(struct ra_ctx *ctx) diff --git a/video/out/vulkan/context_xlib.c b/video/out/vulkan/context_xlib.c index 0c01d56fc9487..673dc312b7ff6 100644 --- a/video/out/vulkan/context_xlib.c +++ b/video/out/vulkan/context_xlib.c @@ -126,9 +126,9 @@ static void xlib_wakeup(struct ra_ctx *ctx) vo_x11_wakeup(ctx->vo); } -static void xlib_wait_events(struct ra_ctx *ctx, int64_t until_time_us) +static void xlib_wait_events(struct ra_ctx *ctx, int64_t until_time_ns) { - vo_x11_wait_events(ctx->vo, until_time_us); + vo_x11_wait_events(ctx->vo, until_time_ns); } const struct ra_ctx_fns ra_ctx_vulkan_xlib = { diff --git a/video/out/wayland_common.c b/video/out/wayland_common.c index 47dc4d9605c4c..04b7d1f7bdb80 100644 --- a/video/out/wayland_common.c +++ b/video/out/wayland_common.c @@ -2604,12 +2604,12 @@ void vo_wayland_wait_frame(struct vo_wayland_state *wl) wl->timeout_count = 0; } -void vo_wayland_wait_events(struct vo *vo, int64_t until_time_us) +void vo_wayland_wait_events(struct vo *vo, int64_t until_time_ns) { struct vo_wayland_state *wl = vo->wl; - int64_t wait_us = until_time_us - mp_time_us(); - int timeout_ms = MPCLAMP((wait_us + 999) / 1000, 0, 10000); + int64_t wait_ns = until_time_ns - mp_time_ns(); + int timeout_ms = MPCLAMP(wait_ns / 1e6, 1, 10000); wayland_dispatch_events(wl, 2, timeout_ms); } diff --git a/video/out/wayland_common.h b/video/out/wayland_common.h index 3b4366318cf6b..060583278ef33 100644 --- a/video/out/wayland_common.h +++ b/video/out/wayland_common.h @@ -180,7 +180,7 @@ void vo_wayland_handle_fractional_scale(struct vo_wayland_state *wl); void vo_wayland_set_opaque_region(struct vo_wayland_state *wl, bool alpha); void vo_wayland_sync_swap(struct vo_wayland_state *wl); void vo_wayland_uninit(struct vo *vo); -void vo_wayland_wait_events(struct vo *vo, int64_t until_time_us); +void vo_wayland_wait_events(struct vo *vo, int64_t until_time_ns); void vo_wayland_wait_frame(struct vo_wayland_state *wl); void vo_wayland_wakeup(struct vo *vo); diff --git a/video/out/x11_common.c b/video/out/x11_common.c index 78e4778ecf1fc..f77f4c86f874d 100644 --- a/video/out/x11_common.c +++ b/video/out/x11_common.c @@ -55,6 +55,7 @@ #include "vo.h" #include "win_state.h" #include "osdep/io.h" +#include "osdep/poll_wrapper.h" #include "osdep/timer.h" #include "osdep/subprocess.h" @@ -2168,7 +2169,7 @@ void vo_x11_wakeup(struct vo *vo) (void)write(x11->wakeup_pipe[1], &(char){0}, 1); } -void vo_x11_wait_events(struct vo *vo, int64_t until_time_us) +void vo_x11_wait_events(struct vo *vo, int64_t until_time_ns) { struct vo_x11_state *x11 = vo->x11; @@ -2176,10 +2177,10 @@ void vo_x11_wait_events(struct vo *vo, int64_t until_time_us) { .fd = x11->event_fd, .events = POLLIN }, { .fd = x11->wakeup_pipe[0], .events = POLLIN }, }; - int64_t wait_us = until_time_us - mp_time_us(); - int timeout_ms = MPCLAMP((wait_us + 999) / 1000, 0, 10000); + int64_t wait_ns = until_time_ns - mp_time_ns(); + int64_t timeout_ns = MPCLAMP(wait_ns, 1e6, 1e10); - poll(fds, 2, timeout_ms); + mp_poll(fds, 2, timeout_ns); if (fds[1].revents & POLLIN) mp_flush_wakeup_pipe(x11->wakeup_pipe[0]); diff --git a/video/out/x11_common.h b/video/out/x11_common.h index 0ea0cd574f8b0..d4409f14e82d6 100644 --- a/video/out/x11_common.h +++ b/video/out/x11_common.h @@ -154,7 +154,7 @@ int vo_x11_control(struct vo *vo, int *events, int request, void *arg); void vo_x11_present(struct vo *vo); void vo_x11_sync_swap(struct vo *vo); void vo_x11_wakeup(struct vo *vo); -void vo_x11_wait_events(struct vo *vo, int64_t until_time_us); +void vo_x11_wait_events(struct vo *vo, int64_t until_time_ns); void vo_x11_silence_xlib(int dir);