Skip to content

Commit

Permalink
Merge pull request #515 from Rafostar/win-hi-clock
Browse files Browse the repository at this point in the history
clapper-app: Support high resolution clock on MS Windows
  • Loading branch information
Rafostar authored Jan 12, 2025
2 parents 60e7d56 + 09b3ef8 commit d4d8203
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 3 deletions.
120 changes: 118 additions & 2 deletions src/bin/clapper-app/clapper-app-utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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)
Expand Down
11 changes: 11 additions & 0 deletions src/bin/clapper-app/clapper-app-utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
18 changes: 18 additions & 0 deletions src/bin/clapper-app/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -34,7 +35,13 @@ main (gint argc, gchar **argv)
GApplication *application;
gint status;

#ifdef G_OS_WIN32
guint resolution = 0;
#endif

#ifndef G_OS_WIN32
g_setenv ("GSK_RENDERER", "gl", FALSE);
#endif

setlocale (LC_ALL, "");
if (!(clapper_ldir = g_getenv ("CLAPPER_APP_OVERRIDE_LOCALEDIR")))
Expand All @@ -48,13 +55,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;
}
18 changes: 17 additions & 1 deletion src/bin/clapper-app/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand Down

0 comments on commit d4d8203

Please sign in to comment.