gst-launch: Enable Windows high-resolution clock
authorSeungha Yang <seungha@centricular.com>
Tue, 11 May 2021 15:54:43 +0000 (00:54 +0900)
committerSeungha Yang <seungha@centricular.com>
Wed, 28 Jul 2021 11:19:10 +0000 (20:19 +0900)
Default timer precision of Windows is dependent on system, but
usually it's known to be about 15ms in worst case.
That's not an enough precision for multimedia application.

Enable high-resolution clock in gst-launch to demonstrate
the usage of Windows high-precision clock for application developers.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/817>

tools/gst-launch.c
tools/meson.build

index 2e8efa5..d38ea9f 100644 (file)
@@ -46,6 +46,9 @@
 #endif
 #include <locale.h>             /* for LC_ALL */
 #include "tools.h"
+#ifdef HAVE_WINMM
+#include <timeapi.h>
+#endif
 
 extern volatile gboolean glib_on_error_halt;
 
@@ -1030,6 +1033,43 @@ query_pipeline_position (gpointer user_data)
   return G_SOURCE_CONTINUE;
 }
 
+#ifdef HAVE_WINMM
+static guint
+enable_winmm_timer_resolution (void)
+{
+  TIMECAPS time_caps;
+  guint resolution = 0;
+  MMRESULT res;
+
+  res = timeGetDevCaps (&time_caps, sizeof (TIMECAPS));
+  if (res != TIMERR_NOERROR) {
+    g_warning ("timeGetDevCaps() returned non-zero code %d", res);
+    return 0;
+  }
+
+  resolution = MIN (MAX (time_caps.wPeriodMin, 1), time_caps.wPeriodMax);
+  res = timeBeginPeriod (resolution);
+  if (res != TIMERR_NOERROR) {
+    g_warning ("timeBeginPeriod() returned non-zero code %d", res);
+    return 0;
+  }
+
+  PRINT (_("Use Windows high-resolution clock, precision: %u ms\n"),
+      resolution);
+
+  return resolution;
+}
+
+static void
+clear_winmm_timer_resolution (guint resolution)
+{
+  if (resolution == 0)
+    return;
+
+  timeEndPeriod (resolution);
+}
+#endif
+
 int
 main (int argc, char *argv[])
 {
@@ -1092,6 +1132,9 @@ main (int argc, char *argv[])
   gulong deep_notify_id = 0;
   guint bus_watch_id = 0;
   GSource *position_source = NULL;
+#ifdef HAVE_WINMM
+  guint winmm_timer_resolution = 0;
+#endif
 
   free (malloc (8));            /* -lefence */
 
@@ -1174,6 +1217,23 @@ main (int argc, char *argv[])
       gst_bin_add (GST_BIN (real_pipeline), pipeline);
       pipeline = real_pipeline;
     }
+#ifdef HAVE_WINMM
+    /* Enable high-precision clock which will improve accuracy of various
+     * Windows timer APIs (e.g., Sleep()), and it will increase the precision
+     * of GstSystemClock as well
+     */
+
+    /* NOTE: Once timer resolution is updated via timeBeginPeriod(),
+     * application should undo it by calling timeEndPeriod()
+     *
+     * Prior to Windows 10, version 2004, timeBeginPeriod() affects global
+     * Windows setting (meaning that it will affect other processes),
+     * but starting with Windows 10, version 2004, this function no longer
+     * affects global timer resolution
+     */
+    winmm_timer_resolution = enable_winmm_timer_resolution ();
+#endif
+
     if (verbose) {
       deep_notify_id =
           gst_element_add_property_deep_notify_watch (pipeline, NULL, TRUE);
@@ -1285,6 +1345,11 @@ main (int argc, char *argv[])
 #endif
     g_source_remove (bus_watch_id);
     g_main_loop_unref (loop);
+
+#ifdef HAVE_WINMM
+    /* Undo timeBeginPeriod() if required */
+    clear_winmm_timer_resolution (winmm_timer_resolution);
+#endif
   }
 
   PRINT (_("Freeing pipeline ...\n"));
index 1e33811..e22721d 100644 (file)
@@ -1,19 +1,37 @@
 tools = ['gst-inspect', 'gst-stats', 'gst-typefind']
 
+extra_launch_dep = []
+extra_launch_arg = []
+
 if gst_parse
+  if host_system == 'windows'
+    winmm_lib = cc.find_library('winmm', required: false)
+    if winmm_lib.found() and cc.has_header('timeapi.h')
+      extra_launch_dep += [winmm_lib]
+      extra_launch_arg += ['-DHAVE_WINMM']
+    endif
+  endif
+
   tools += ['gst-launch']
 endif
 
 foreach tool : tools
   exe_name = '@0@-@1@'.format(tool, apiversion)
   src_file = '@0@.c'.format(tool)
+  extra_deps = []
+  extra_c_args = []
+
+  if tool == 'gst-launch'
+    extra_deps += extra_launch_dep
+    extra_c_args += extra_launch_arg
+  endif
 
   executable(exe_name,
     src_file,
     install: true,
     include_directories : [configinc],
-    dependencies : [glib_dep, gobject_dep, gmodule_dep, mathlib, gst_dep],
-    c_args: gst_c_args,
+    dependencies : [glib_dep, gobject_dep, gmodule_dep, mathlib, gst_dep] + extra_deps,
+    c_args: gst_c_args + extra_c_args,
   )
 
   man_page = '@0@-1.0.1'.format(tool)