systemclock: use preformance counters on windows
authorWim Taymans <wim.taymans@collabora.co.uk>
Fri, 28 Aug 2009 15:02:30 +0000 (17:02 +0200)
committerWim Taymans <wim.taymans@collabora.co.uk>
Fri, 28 Aug 2009 15:02:30 +0000 (17:02 +0200)
Based on clock implementation by HÃ¥vard Graff <havard.graff@tandberg.com>

Try to get the time on windows using the performance counters. These have a much
higher resolution and accuracy than the regular getcurrenttime(). Be careful to
fall back to regular getcurrenttime() or posix clocks when performance counters
are not available.

gst/gstsystemclock.c

index 2a74fed494067beb20c36b2dc734bb19389a782b..2b2ef0b8d5986b96b4c652b1599c015a29cc823f 100644 (file)
 
 #include <errno.h>
 
+#ifdef G_OS_WIN32
+#  define WIN32_LEAN_AND_MEAN   /* prevents from including too many things */
+#  include <windows.h>          /* QueryPerformance* stuff */
+#  undef WIN32_LEAN_AND_MEAN
+#endif /* G_OS_WIN32 */
+
 /* Define this to get some extra debug about jitter from each clock_wait */
 #undef WAIT_DEBUGGING
 
@@ -55,6 +61,11 @@ struct _GstSystemClockPrivate
   GstPoll *timer;
   gint wakeup_count;            /* the number of entries with a pending wakeup */
   gboolean async_wakeup;        /* if the wakeup was because of a async list change */
+
+#ifdef G_OS_WIN32
+  LARGE_INTEGER start;
+  LARGE_INTEGER frequency;
+#endif                          /* G_OS_WIN32 */
 };
 
 #define GST_SYSTEM_CLOCK_GET_PRIVATE(obj)  \
@@ -155,6 +166,14 @@ gst_system_clock_init (GstSystemClock * clock)
   clock->priv->clock_type = DEFAULT_CLOCK_TYPE;
   clock->priv->timer = gst_poll_new_timer ();
 
+#ifdef G_OS_WIN32
+  QueryPerformanceFrequency (&clock->priv->frequency);
+  /* can be 0 if the hardware does not have hardware support */
+  if (clock->priv->frequency.QuadPart != 0)
+    /* we take a base time so that time starts from 0 to ease debugging */
+    QueryPerformanceCounter (&clock->priv->start);
+#endif /* G_OS_WIN32 */
+
 #if 0
   /* Uncomment this to start the async clock thread straight away */
   GST_OBJECT_LOCK (clock);
@@ -459,42 +478,67 @@ clock_type_to_posix_id (GstClockType clock_type)
 static GstClockTime
 gst_system_clock_get_internal_time (GstClock * clock)
 {
-#ifdef HAVE_POSIX_TIMERS
-  GstSystemClock *sysclock = GST_SYSTEM_CLOCK_CAST (clock);
-  clockid_t ptype;
-  struct timespec ts;
-
-  ptype = clock_type_to_posix_id (sysclock->priv->clock_type);
+#ifdef G_OS_WIN32
+  if (clock->priv->frequency.QuadPart != 0) {
+    GstSystemClock *sysclock = GST_SYSTEM_CLOCK_CAST (clock);
+    LARGE_INTEGER now;
+
+    /* we prefer the highly accurate performance counters on windows */
+    QueryPerformanceCounter (&now);
+
+    return gst_util_uint64_scale (now.QuadPart - sysclock->priv->start.QuadPart,
+        GST_SECOND, sysclock->priv->frequency.QuadPart);
+  } else
+#endif /* G_OS_WIN32 */
+#if !defined HAVE_POSIX_TIMERS
+  {
+    GTimeVal timeval;
 
-  if (G_UNLIKELY (clock_gettime (ptype, &ts)))
-    return GST_CLOCK_TIME_NONE;
+    g_get_current_time (&timeval);
 
-  return GST_TIMESPEC_TO_TIME (ts);
+    return GST_TIMEVAL_TO_TIME (timeval);
+  }
 #else
-  GTimeVal timeval;
+  {
+    GstSystemClock *sysclock = GST_SYSTEM_CLOCK_CAST (clock);
+    clockid_t ptype;
+    struct timespec ts;
+
+    ptype = clock_type_to_posix_id (sysclock->priv->clock_type);
 
-  g_get_current_time (&timeval);
+    if (G_UNLIKELY (clock_gettime (ptype, &ts)))
+      return GST_CLOCK_TIME_NONE;
 
-  return GST_TIMEVAL_TO_TIME (timeval);
+    return GST_TIMESPEC_TO_TIME (ts);
+  }
 #endif
 }
 
 static guint64
 gst_system_clock_get_resolution (GstClock * clock)
 {
+#ifdef G_OS_WIN32
+  if (clock->priv->frequency.QuadPart != 0) {
+    return GST_SECOND / sysclock->priv->frequency.QuadPart;
+  } else
+#endif /* G_OS_WIN32 */
 #ifdef HAVE_POSIX_TIMERS
-  GstSystemClock *sysclock = GST_SYSTEM_CLOCK_CAST (clock);
-  clockid_t ptype;
-  struct timespec ts;
+  {
+    GstSystemClock *sysclock = GST_SYSTEM_CLOCK_CAST (clock);
+    clockid_t ptype;
+    struct timespec ts;
 
-  ptype = clock_type_to_posix_id (sysclock->priv->clock_type);
+    ptype = clock_type_to_posix_id (sysclock->priv->clock_type);
 
-  if (G_UNLIKELY (clock_getres (ptype, &ts)))
-    return GST_CLOCK_TIME_NONE;
+    if (G_UNLIKELY (clock_getres (ptype, &ts)))
+      return GST_CLOCK_TIME_NONE;
 
-  return GST_TIMESPEC_TO_TIME (ts);
+    return GST_TIMESPEC_TO_TIME (ts);
+  }
 #else
-  return 1 * GST_USECOND;
+  {
+    return 1 * GST_USECOND;
+  }
 #endif
 }