clapper-app: Support Windows high resolution clock

Windows high resolution clock improves accuracy of various Windows
timer APIs and precision of GstSystemClock during playback
This commit is contained in:
Rafał Dzięgiel
2025-01-12 12:52:44 +01:00
parent 60e7d56611
commit d9b20dcc18
4 changed files with 162 additions and 3 deletions

View File

@@ -23,8 +23,124 @@
#include "clapper-app-utils.h"
#include "clapper-app-media-item-box.h"
/* Useful only on Windows */
#ifdef G_OS_WIN32
#include <windows.h>
#ifdef HAVE_WIN_PROCESS_THREADS_API
#include <processthreadsapi.h>
#endif
#ifdef HAVE_WIN_TIME_API
#include <timeapi.h>
#endif
#endif
#define GST_CAT_DEFAULT clapper_app_utils_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
void
clapper_app_utils_debug_init (void)
{
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "clapperapputils", 0,
"Clapper App Utils");
}
/* Windows specific functions */
#ifdef G_OS_WIN32
/*
* clapper_app_utils_win_enforce_hi_res_clock:
*
* Enforce high resolution clock by explicitly disabling Windows
* timer resolution power throttling. When disabled, system remembers
* and honors any previous timer resolution request by the process.
*
* By default, Windows 11 may automatically ignore the timer
* resolution requests in certain scenarios.
*/
void
clapper_app_utils_win_enforce_hi_res_clock (void)
{
#ifdef HAVE_WIN_PROCESS_THREADS_API
PROCESS_POWER_THROTTLING_STATE PowerThrottling;
RtlZeroMemory (&PowerThrottling, sizeof (PowerThrottling));
gboolean success;
PowerThrottling.Version = PROCESS_POWER_THROTTLING_CURRENT_VERSION;
PowerThrottling.ControlMask = PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION;
PowerThrottling.StateMask = 0; // Always honor timer resolution requests
success = (gboolean) SetProcessInformation(
GetCurrentProcess (),
ProcessPowerThrottling,
&PowerThrottling,
sizeof (PowerThrottling));
/* Not an error. Older Windows does not have this functionality, but
* also honor hi-res clock by default anyway, so do not print then. */
GST_INFO ("Windows hi-res clock support is %senforced",
(success) ? "" : "NOT ");
#endif
}
/*
* clapper_app_utils_win_hi_res_clock_start:
*
* Start Windows high resolution clock which will improve
* accuracy of various Windows timer APIs and precision
* of #GstSystemClock during playback.
*
* On Windows 10 version 2004 (and older), this function affects
* a global Windows setting. On any other (newer) version this
* will only affect a single process.
*
* Returns: Timer resolution period value.
*/
guint
clapper_app_utils_win_hi_res_clock_start (void)
{
guint resolution = 0;
#ifdef HAVE_WIN_TIME_API
TIMECAPS time_caps;
MMRESULT res;
if ((res = timeGetDevCaps (&time_caps, sizeof (TIMECAPS))) != TIMERR_NOERROR) {
GST_WARNING ("Could not query timer resolution, code: %u", res);
return 0;
}
resolution = MIN (MAX (time_caps.wPeriodMin, 1), time_caps.wPeriodMax);
if ((res = timeBeginPeriod (resolution)) != TIMERR_NOERROR) {
GST_WARNING ("Could not request timer resolution, code: %u", res);
return 0;
}
GST_INFO ("Started Windows hi-res clock, precision: %ums", resolution);
#endif
return resolution;
}
/*
* clapper_app_utils_win_hi_res_clock_stop:
* @resolution: started resolution value (non-zero)
*
* Stop previously started Microsoft Windows high resolution clock.
*/
void
clapper_app_utils_win_hi_res_clock_stop (guint resolution)
{
#ifdef HAVE_WIN_TIME_API
MMRESULT res;
if ((res = timeEndPeriod (resolution)) == TIMERR_NOERROR)
GST_INFO ("Stopped Windows hi-res clock");
else
GST_ERROR ("Could not stop hi-res clock, code: %u", res);
#endif
}
/* Extensions are used only on Windows */
const gchar *const *
clapper_app_utils_get_extensions (void)
{
@@ -45,7 +161,7 @@ clapper_app_utils_get_subtitles_extensions (void)
return subs_extensions;
}
#endif
#endif // G_OS_WIN32
const gchar *const *
clapper_app_utils_get_mime_types (void)

View File

@@ -26,7 +26,18 @@ G_BEGIN_DECLS
typedef void (* ClapperAppUtilsIterRanks) (const gchar *feature_name, GstRank rank, gboolean from_env, gpointer user_data);
void clapper_app_utils_debug_init (void);
#ifdef G_OS_WIN32
G_GNUC_INTERNAL
void clapper_app_utils_win_enforce_hi_res_clock (void);
G_GNUC_INTERNAL
guint clapper_app_utils_win_hi_res_clock_start (void);
G_GNUC_INTERNAL
void clapper_app_utils_win_hi_res_clock_stop (guint resolution);
G_GNUC_INTERNAL
const gchar *const * clapper_app_utils_get_extensions (void);

View File

@@ -26,6 +26,7 @@
#include "clapper-app-application.h"
#include "clapper-app-types.h"
#include "clapper-app-utils.h"
gint
main (gint argc, gchar **argv)
@@ -34,6 +35,10 @@ main (gint argc, gchar **argv)
GApplication *application;
gint status;
#ifdef G_OS_WIN32
guint resolution = 0;
#endif
g_setenv ("GSK_RENDERER", "gl", FALSE);
setlocale (LC_ALL, "");
@@ -48,13 +53,24 @@ main (gint argc, gchar **argv)
adw_init ();
clapper_app_types_init ();
clapper_app_utils_debug_init ();
g_set_application_name ("Clapper");
#ifdef G_OS_WIN32
clapper_app_utils_win_enforce_hi_res_clock ();
resolution = clapper_app_utils_win_hi_res_clock_start ();
#endif
application = clapper_app_application_new ();
status = g_application_run (application, argc, argv);
g_object_unref (application);
#ifdef G_OS_WIN32
if (resolution > 0)
clapper_app_utils_win_hi_res_clock_stop (resolution);
#endif
return status;
}

View File

@@ -80,6 +80,22 @@ clapperapp_c_args = [
'-DGST_USE_UNSTABLE_API',
]
is_windows = ['windows'].contains(host_machine.system())
if is_windows
clapperapp_c_args += ['-D_WIN32_WINNT=_WIN32_WINNT_WIN8']
kernel32_dep = cc.find_library('kernel32', required: false)
if kernel32_dep.found() and cc.has_header('processthreadsapi.h')
clapperapp_deps += kernel32_dep
clapperapp_c_args += ['-DHAVE_WIN_PROCESS_THREADS_API']
endif
winmm_dep = cc.find_library('winmm', required: false)
if winmm_dep.found() and cc.has_header('timeapi.h')
clapperapp_deps += winmm_dep
clapperapp_c_args += ['-DHAVE_WIN_TIME_API']
endif
endif
executable(
meson.project_name(),
clapperapp_sources,
@@ -90,7 +106,7 @@ executable(
install_dir: bindir,
win_subsystem: 'windows',
)
if ['windows'].contains(host_machine.system())
if is_windows
executable(
meson.project_name() + '-console',
clapperapp_sources,