Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

convert more things to nanoseconds #12419

Merged
merged 9 commits into from
Oct 10, 2023
2 changes: 2 additions & 0 deletions DOCS/client-api-changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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 ---
Expand Down
6 changes: 3 additions & 3 deletions audio/out/ao_wasapi_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really important for this PR. But maybe we could have macros for defining wait times in more readable way

like

#define MP_TIME_S(s) ((s) * 1000000000)
#define MP_TIME_MS(ms) ((ms) * 1000000)
#define MP_TIME_US(ms) ((ms) * 1000)
#define MP_TIME_NS(ns) ((ns))

then we can abstract all zeros and multiplications. and just do MP_TIME_MS(1), especially we do a lot MP_TIME_S(1) conversions.

Copy link
Member Author

@Dudemanguy Dudemanguy Sep 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amusingly, MP_SECOND_US already exists apparently. What an awful name. But yes, having such macros sounds like a good idea.

bool align_hack = false;
HRESULT hr;

Expand Down Expand Up @@ -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;
}
Expand Down
11 changes: 9 additions & 2 deletions libmpv/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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);

/**
Expand Down Expand Up @@ -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)
Expand Down
5 changes: 4 additions & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 <poll.h>')}

cd_devices = {
'windows': 'D:',
'cygwin': 'D:',
Expand Down
20 changes: 16 additions & 4 deletions osdep/polldev.c → osdep/poll_wrapper.c
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -22,9 +20,23 @@
#include <sys/select.h>
#include <stdio.h>

#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;
Expand Down
5 changes: 5 additions & 0 deletions osdep/polldev.h → osdep/poll_wrapper.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
#pragma once

#include <poll.h>
#include <stdint.h>

// 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);
2 changes: 1 addition & 1 deletion osdep/terminal-unix.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
5 changes: 2 additions & 3 deletions osdep/timer-darwin.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
8 changes: 4 additions & 4 deletions osdep/timer-linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@
#include <time.h>
#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);
}

Expand Down
42 changes: 33 additions & 9 deletions osdep/timer-win2.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
6 changes: 3 additions & 3 deletions osdep/timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,16 @@ 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);

// Provided by OS specific functions (timer-linux.c)
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
Expand Down
5 changes: 5 additions & 0 deletions player/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion player/command.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion player/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
4 changes: 2 additions & 2 deletions player/playloop.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions player/video.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
15 changes: 8 additions & 7 deletions video/out/drm_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);
}
}

Expand Down
2 changes: 1 addition & 1 deletion video/out/drm_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
2 changes: 1 addition & 1 deletion video/out/gpu/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions video/out/opengl/context_drm_egl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions video/out/opengl/context_glx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
Loading