Merge pull request #515 from Rafostar/win-hi-clock

clapper-app: Support high resolution clock on MS Windows
This commit is contained in:
Rafał Dzięgiel
2025-01-12 20:47:59 +01:00
committed by GitHub
4 changed files with 164 additions and 3 deletions

View File

@@ -23,8 +23,124 @@
#include "clapper-app-utils.h" #include "clapper-app-utils.h"
#include "clapper-app-media-item-box.h" #include "clapper-app-media-item-box.h"
/* Useful only on Windows */
#ifdef G_OS_WIN32 #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 * const gchar *const *
clapper_app_utils_get_extensions (void) clapper_app_utils_get_extensions (void)
{ {
@@ -45,7 +161,7 @@ clapper_app_utils_get_subtitles_extensions (void)
return subs_extensions; return subs_extensions;
} }
#endif #endif // G_OS_WIN32
const gchar *const * const gchar *const *
clapper_app_utils_get_mime_types (void) 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); 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 #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 G_GNUC_INTERNAL
const gchar *const * clapper_app_utils_get_extensions (void); const gchar *const * clapper_app_utils_get_extensions (void);

View File

@@ -26,6 +26,7 @@
#include "clapper-app-application.h" #include "clapper-app-application.h"
#include "clapper-app-types.h" #include "clapper-app-types.h"
#include "clapper-app-utils.h"
gint gint
main (gint argc, gchar **argv) main (gint argc, gchar **argv)
@@ -34,7 +35,13 @@ main (gint argc, gchar **argv)
GApplication *application; GApplication *application;
gint status; gint status;
#ifdef G_OS_WIN32
guint resolution = 0;
#endif
#ifndef G_OS_WIN32
g_setenv ("GSK_RENDERER", "gl", FALSE); g_setenv ("GSK_RENDERER", "gl", FALSE);
#endif
setlocale (LC_ALL, ""); setlocale (LC_ALL, "");
if (!(clapper_ldir = g_getenv ("CLAPPER_APP_OVERRIDE_LOCALEDIR"))) if (!(clapper_ldir = g_getenv ("CLAPPER_APP_OVERRIDE_LOCALEDIR")))
@@ -48,13 +55,24 @@ main (gint argc, gchar **argv)
adw_init (); adw_init ();
clapper_app_types_init (); clapper_app_types_init ();
clapper_app_utils_debug_init ();
g_set_application_name ("Clapper"); 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 (); application = clapper_app_application_new ();
status = g_application_run (application, argc, argv); status = g_application_run (application, argc, argv);
g_object_unref (application); g_object_unref (application);
#ifdef G_OS_WIN32
if (resolution > 0)
clapper_app_utils_win_hi_res_clock_stop (resolution);
#endif
return status; return status;
} }

View File

@@ -80,6 +80,22 @@ clapperapp_c_args = [
'-DGST_USE_UNSTABLE_API', '-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( executable(
meson.project_name(), meson.project_name(),
clapperapp_sources, clapperapp_sources,
@@ -90,7 +106,7 @@ executable(
install_dir: bindir, install_dir: bindir,
win_subsystem: 'windows', win_subsystem: 'windows',
) )
if ['windows'].contains(host_machine.system()) if is_windows
executable( executable(
meson.project_name() + '-console', meson.project_name() + '-console',
clapperapp_sources, clapperapp_sources,