Skip to content

Commit d4d8203

Browse files
authored
Merge pull request #515 from Rafostar/win-hi-clock
clapper-app: Support high resolution clock on MS Windows
2 parents 60e7d56 + 09b3ef8 commit d4d8203

File tree

4 files changed

+164
-3
lines changed

4 files changed

+164
-3
lines changed

src/bin/clapper-app/clapper-app-utils.c

Lines changed: 118 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,124 @@
2323
#include "clapper-app-utils.h"
2424
#include "clapper-app-media-item-box.h"
2525

26-
/* Useful only on Windows */
2726
#ifdef G_OS_WIN32
27+
#include <windows.h>
28+
#ifdef HAVE_WIN_PROCESS_THREADS_API
29+
#include <processthreadsapi.h>
30+
#endif
31+
#ifdef HAVE_WIN_TIME_API
32+
#include <timeapi.h>
33+
#endif
34+
#endif
35+
36+
#define GST_CAT_DEFAULT clapper_app_utils_debug
37+
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
38+
39+
void
40+
clapper_app_utils_debug_init (void)
41+
{
42+
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "clapperapputils", 0,
43+
"Clapper App Utils");
44+
}
45+
46+
/* Windows specific functions */
47+
#ifdef G_OS_WIN32
48+
49+
/*
50+
* clapper_app_utils_win_enforce_hi_res_clock:
51+
*
52+
* Enforce high resolution clock by explicitly disabling Windows
53+
* timer resolution power throttling. When disabled, system remembers
54+
* and honors any previous timer resolution request by the process.
55+
*
56+
* By default, Windows 11 may automatically ignore the timer
57+
* resolution requests in certain scenarios.
58+
*/
59+
void
60+
clapper_app_utils_win_enforce_hi_res_clock (void)
61+
{
62+
#ifdef HAVE_WIN_PROCESS_THREADS_API
63+
PROCESS_POWER_THROTTLING_STATE PowerThrottling;
64+
RtlZeroMemory (&PowerThrottling, sizeof (PowerThrottling));
65+
gboolean success;
66+
67+
PowerThrottling.Version = PROCESS_POWER_THROTTLING_CURRENT_VERSION;
68+
PowerThrottling.ControlMask = PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION;
69+
PowerThrottling.StateMask = 0; // Always honor timer resolution requests
70+
71+
success = (gboolean) SetProcessInformation(
72+
GetCurrentProcess (),
73+
ProcessPowerThrottling,
74+
&PowerThrottling,
75+
sizeof (PowerThrottling));
76+
77+
/* Not an error. Older Windows does not have this functionality, but
78+
* also honor hi-res clock by default anyway, so do not print then. */
79+
GST_INFO ("Windows hi-res clock support is %senforced",
80+
(success) ? "" : "NOT ");
81+
#endif
82+
}
83+
84+
/*
85+
* clapper_app_utils_win_hi_res_clock_start:
86+
*
87+
* Start Windows high resolution clock which will improve
88+
* accuracy of various Windows timer APIs and precision
89+
* of #GstSystemClock during playback.
90+
*
91+
* On Windows 10 version 2004 (and older), this function affects
92+
* a global Windows setting. On any other (newer) version this
93+
* will only affect a single process.
94+
*
95+
* Returns: Timer resolution period value.
96+
*/
97+
guint
98+
clapper_app_utils_win_hi_res_clock_start (void)
99+
{
100+
guint resolution = 0;
101+
102+
#ifdef HAVE_WIN_TIME_API
103+
TIMECAPS time_caps;
104+
MMRESULT res;
105+
106+
if ((res = timeGetDevCaps (&time_caps, sizeof (TIMECAPS))) != TIMERR_NOERROR) {
107+
GST_WARNING ("Could not query timer resolution, code: %u", res);
108+
return 0;
109+
}
110+
111+
resolution = MIN (MAX (time_caps.wPeriodMin, 1), time_caps.wPeriodMax);
112+
113+
if ((res = timeBeginPeriod (resolution)) != TIMERR_NOERROR) {
114+
GST_WARNING ("Could not request timer resolution, code: %u", res);
115+
return 0;
116+
}
117+
118+
GST_INFO ("Started Windows hi-res clock, precision: %ums", resolution);
119+
#endif
120+
121+
return resolution;
122+
}
123+
124+
/*
125+
* clapper_app_utils_win_hi_res_clock_stop:
126+
* @resolution: started resolution value (non-zero)
127+
*
128+
* Stop previously started Microsoft Windows high resolution clock.
129+
*/
130+
void
131+
clapper_app_utils_win_hi_res_clock_stop (guint resolution)
132+
{
133+
#ifdef HAVE_WIN_TIME_API
134+
MMRESULT res;
135+
136+
if ((res = timeEndPeriod (resolution)) == TIMERR_NOERROR)
137+
GST_INFO ("Stopped Windows hi-res clock");
138+
else
139+
GST_ERROR ("Could not stop hi-res clock, code: %u", res);
140+
#endif
141+
}
142+
143+
/* Extensions are used only on Windows */
28144
const gchar *const *
29145
clapper_app_utils_get_extensions (void)
30146
{
@@ -45,7 +161,7 @@ clapper_app_utils_get_subtitles_extensions (void)
45161

46162
return subs_extensions;
47163
}
48-
#endif
164+
#endif // G_OS_WIN32
49165

50166
const gchar *const *
51167
clapper_app_utils_get_mime_types (void)

src/bin/clapper-app/clapper-app-utils.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,18 @@ G_BEGIN_DECLS
2626

2727
typedef void (* ClapperAppUtilsIterRanks) (const gchar *feature_name, GstRank rank, gboolean from_env, gpointer user_data);
2828

29+
void clapper_app_utils_debug_init (void);
30+
2931
#ifdef G_OS_WIN32
32+
G_GNUC_INTERNAL
33+
void clapper_app_utils_win_enforce_hi_res_clock (void);
34+
35+
G_GNUC_INTERNAL
36+
guint clapper_app_utils_win_hi_res_clock_start (void);
37+
38+
G_GNUC_INTERNAL
39+
void clapper_app_utils_win_hi_res_clock_stop (guint resolution);
40+
3041
G_GNUC_INTERNAL
3142
const gchar *const * clapper_app_utils_get_extensions (void);
3243

src/bin/clapper-app/main.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
#include "clapper-app-application.h"
2828
#include "clapper-app-types.h"
29+
#include "clapper-app-utils.h"
2930

3031
gint
3132
main (gint argc, gchar **argv)
@@ -34,7 +35,13 @@ main (gint argc, gchar **argv)
3435
GApplication *application;
3536
gint status;
3637

38+
#ifdef G_OS_WIN32
39+
guint resolution = 0;
40+
#endif
41+
42+
#ifndef G_OS_WIN32
3743
g_setenv ("GSK_RENDERER", "gl", FALSE);
44+
#endif
3845

3946
setlocale (LC_ALL, "");
4047
if (!(clapper_ldir = g_getenv ("CLAPPER_APP_OVERRIDE_LOCALEDIR")))
@@ -48,13 +55,24 @@ main (gint argc, gchar **argv)
4855
adw_init ();
4956

5057
clapper_app_types_init ();
58+
clapper_app_utils_debug_init ();
5159

5260
g_set_application_name ("Clapper");
5361

62+
#ifdef G_OS_WIN32
63+
clapper_app_utils_win_enforce_hi_res_clock ();
64+
resolution = clapper_app_utils_win_hi_res_clock_start ();
65+
#endif
66+
5467
application = clapper_app_application_new ();
5568

5669
status = g_application_run (application, argc, argv);
5770
g_object_unref (application);
5871

72+
#ifdef G_OS_WIN32
73+
if (resolution > 0)
74+
clapper_app_utils_win_hi_res_clock_stop (resolution);
75+
#endif
76+
5977
return status;
6078
}

src/bin/clapper-app/meson.build

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,22 @@ clapperapp_c_args = [
8080
'-DGST_USE_UNSTABLE_API',
8181
]
8282

83+
is_windows = ['windows'].contains(host_machine.system())
84+
85+
if is_windows
86+
clapperapp_c_args += ['-D_WIN32_WINNT=_WIN32_WINNT_WIN8']
87+
kernel32_dep = cc.find_library('kernel32', required: false)
88+
if kernel32_dep.found() and cc.has_header('processthreadsapi.h')
89+
clapperapp_deps += kernel32_dep
90+
clapperapp_c_args += ['-DHAVE_WIN_PROCESS_THREADS_API']
91+
endif
92+
winmm_dep = cc.find_library('winmm', required: false)
93+
if winmm_dep.found() and cc.has_header('timeapi.h')
94+
clapperapp_deps += winmm_dep
95+
clapperapp_c_args += ['-DHAVE_WIN_TIME_API']
96+
endif
97+
endif
98+
8399
executable(
84100
meson.project_name(),
85101
clapperapp_sources,
@@ -90,7 +106,7 @@ executable(
90106
install_dir: bindir,
91107
win_subsystem: 'windows',
92108
)
93-
if ['windows'].contains(host_machine.system())
109+
if is_windows
94110
executable(
95111
meson.project_name() + '-console',
96112
clapperapp_sources,

0 commit comments

Comments
 (0)