mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 03:31:05 +00:00
gst: clock: Clean up code to get the monotonic / realtime clock a bit
On Windows and macOS always use the proper monotonic clock, including for gst_util_get_timestamp(), and initialize its state only once. Also on macOS use clock_gettime() for the realtime clock, if available instead of always falling back to GLib. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4658>
This commit is contained in:
parent
a8bf19deda
commit
c52212604e
4 changed files with 146 additions and 96 deletions
|
@ -534,6 +534,8 @@ init_pre (GOptionContext * context, GOptionGroup * group, gpointer data,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
priv_gst_clock_init ();
|
||||
|
||||
find_executable_path ();
|
||||
|
||||
_priv_gst_start_time = gst_util_get_timestamp ();
|
||||
|
|
|
@ -522,5 +522,9 @@ struct _GstClockEntryImpl
|
|||
char * priv_gst_get_relocated_libgstreamer (void);
|
||||
gint priv_gst_count_directories (const char *filepath);
|
||||
|
||||
void priv_gst_clock_init (void);
|
||||
GstClockTime priv_gst_get_monotonic_time (void);
|
||||
GstClockTime priv_gst_get_real_time (void);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* __GST_PRIVATE_H__ */
|
||||
|
|
|
@ -60,6 +60,108 @@
|
|||
#include <mach/mach_time.h>
|
||||
#endif
|
||||
|
||||
#if defined __APPLE__
|
||||
static struct mach_timebase_info mach_timebase;
|
||||
#endif
|
||||
|
||||
#if defined G_OS_WIN32
|
||||
static LARGE_INTEGER performance_counter_frequency;
|
||||
#endif
|
||||
|
||||
/* Small helper to make the atomics below cheaper.
|
||||
*
|
||||
* GLib always uses SEQ_CST atomic ops while here it's more than enough to use
|
||||
* ACQUIRE/RELEASE atomic ops. On x86 / x86-64 the ACQUIRE load is compiling
|
||||
* to a simple memory read.
|
||||
*/
|
||||
#if defined __APPLE__ || defined G_OS_WIN32
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS)
|
||||
#include <stdatomic.h>
|
||||
|
||||
typedef atomic_int gst_atomic_int;
|
||||
|
||||
static inline int
|
||||
gst_atomic_int_get_acquire (gst_atomic_int * x)
|
||||
{
|
||||
return atomic_load_explicit (x, memory_order_acquire);
|
||||
}
|
||||
|
||||
static inline void
|
||||
gst_atomic_int_set_release (gst_atomic_int * x, gint val)
|
||||
{
|
||||
atomic_store_explicit (x, val, memory_order_release);
|
||||
}
|
||||
#else /* defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS) */
|
||||
typedef int gst_atomic_int;
|
||||
#define gst_atomic_int_get_acquire(x) g_atomic_int_get(x)
|
||||
#define gst_atomic_int_set_release(x, val) g_atomic_int_set(x, val)
|
||||
#endif /* defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS) */
|
||||
#endif /* defined __APPLE__ || defined G_OS_WIN32 */
|
||||
|
||||
/* priv_gst_clock_init:
|
||||
*
|
||||
* Initialize internal state of the clock. This is safe to call multiple
|
||||
* times.
|
||||
*/
|
||||
void
|
||||
priv_gst_clock_init (void)
|
||||
{
|
||||
#if defined __APPLE__
|
||||
static gst_atomic_int inited = FALSE;
|
||||
|
||||
if (!gst_atomic_int_get_acquire (&inited)) {
|
||||
mach_timebase_info (&mach_timebase);
|
||||
gst_atomic_int_set_release (&inited, TRUE);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined G_OS_WIN32
|
||||
static gst_atomic_int inited = FALSE;
|
||||
|
||||
if (!gst_atomic_int_get_acquire (&inited)) {
|
||||
QueryPerformanceFrequency (&performance_counter_frequency);
|
||||
gst_atomic_int_set_release (&inited, TRUE);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
GstClockTime
|
||||
priv_gst_get_monotonic_time (void)
|
||||
{
|
||||
#if defined __APPLE__
|
||||
guint64 mach_t = mach_absolute_time ();
|
||||
return gst_util_uint64_scale (mach_t, mach_timebase.numer,
|
||||
mach_timebase.denom);
|
||||
#elif defined G_OS_WIN32
|
||||
LARGE_INTEGER now;
|
||||
QueryPerformanceCounter (&now);
|
||||
|
||||
return gst_util_uint64_scale (now.QuadPart, GST_SECOND,
|
||||
performance_counter_frequency.QuadPart);
|
||||
#elif defined (HAVE_POSIX_TIMERS) && defined(HAVE_MONOTONIC_CLOCK) &&\
|
||||
defined (HAVE_CLOCK_GETTIME)
|
||||
struct timespec now;
|
||||
|
||||
clock_gettime (CLOCK_MONOTONIC, &now);
|
||||
return GST_TIMESPEC_TO_TIME (now);
|
||||
#else
|
||||
return g_get_monotonic_time () * 1000;
|
||||
#endif
|
||||
}
|
||||
|
||||
GstClockTime
|
||||
priv_gst_get_real_time (void)
|
||||
{
|
||||
#if defined (HAVE_POSIX_TIMERS) && defined (HAVE_CLOCK_GETTIME)
|
||||
struct timespec now;
|
||||
|
||||
clock_gettime (CLOCK_REALTIME, &now);
|
||||
return GST_TIMESPEC_TO_TIME (now);
|
||||
#else
|
||||
return g_get_real_time () * 1000;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Define this to get some extra debug about jitter from each clock_wait */
|
||||
#undef WAIT_DEBUGGING
|
||||
|
||||
|
@ -300,7 +402,7 @@ gst_pthread_cond_wait_until (pthread_cond_t * cond, pthread_mutex_t * lock,
|
|||
* Since this pthreads wants the relative time, convert it back again.
|
||||
*/
|
||||
{
|
||||
gint64 now = g_get_monotonic_time () * 1000;
|
||||
gint64 now = priv_gst_get_monotonic_time ();
|
||||
gint64 relative;
|
||||
|
||||
if (end_time <= now)
|
||||
|
@ -446,13 +548,6 @@ struct _GstSystemClockPrivate
|
|||
GCond entries_changed;
|
||||
|
||||
GstClockType clock_type;
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
LARGE_INTEGER frequency;
|
||||
#endif /* G_OS_WIN32 */
|
||||
#ifdef __APPLE__
|
||||
struct mach_timebase_info mach_timebase;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef HAVE_POSIX_TIMERS
|
||||
|
@ -483,10 +578,6 @@ static void gst_system_clock_get_property (GObject * object, guint prop_id,
|
|||
GValue * value, GParamSpec * pspec);
|
||||
|
||||
static GstClockTime gst_system_clock_get_internal_time (GstClock * clock);
|
||||
#if !defined HAVE_POSIX_TIMERS || !defined HAVE_CLOCK_GETTIME
|
||||
static GstClockTime gst_system_clock_get_mono_time (GstSystemClock * clock);
|
||||
static GstClockTime gst_system_clock_get_real_time ();
|
||||
#endif
|
||||
static guint64 gst_system_clock_get_resolution (GstClock * clock);
|
||||
static GstClockReturn gst_system_clock_id_wait_jitter (GstClock * clock,
|
||||
GstClockEntry * entry, GstClockTimeDiff * jitter);
|
||||
|
@ -551,14 +642,6 @@ gst_system_clock_init (GstSystemClock * clock)
|
|||
priv->entries = NULL;
|
||||
g_cond_init (&priv->entries_changed);
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
QueryPerformanceFrequency (&priv->frequency);
|
||||
#endif /* G_OS_WIN32 */
|
||||
|
||||
#ifdef __APPLE__
|
||||
mach_timebase_info (&priv->mach_timebase);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* Uncomment this to start the async clock thread straight away */
|
||||
GST_SYSTEM_CLOCK_LOCK (clock);
|
||||
|
@ -909,7 +992,6 @@ clock_type_to_posix_id (GstClockType clock_type)
|
|||
#ifdef HAVE_MONOTONIC_CLOCK
|
||||
if (clock_type == GST_CLOCK_TYPE_MONOTONIC)
|
||||
return CLOCK_MONOTONIC;
|
||||
else
|
||||
#endif
|
||||
if (clock_type == GST_CLOCK_TYPE_TAI)
|
||||
#ifdef CLOCK_TAI
|
||||
|
@ -927,6 +1009,16 @@ static GstClockTime
|
|||
gst_system_clock_get_internal_time (GstClock * clock)
|
||||
{
|
||||
GstSystemClock *sysclock = GST_SYSTEM_CLOCK_CAST (clock);
|
||||
|
||||
/* For the monotonic and realtime clock, always directly call the specific
|
||||
* helper functions above */
|
||||
if (sysclock->priv->clock_type == GST_CLOCK_TYPE_MONOTONIC)
|
||||
return priv_gst_get_monotonic_time ();
|
||||
else if (sysclock->priv->clock_type == GST_CLOCK_TYPE_REALTIME)
|
||||
return priv_gst_get_real_time ();
|
||||
|
||||
/* If POSIX timers are available, use those for any other clock,
|
||||
* or otherwise return the monotonic time */
|
||||
#if defined HAVE_POSIX_TIMERS && defined HAVE_CLOCK_GETTIME
|
||||
// BSD and Linux' Posix timers and clock_gettime cover all of the different clock types
|
||||
// without need for special handling so we'll use those.
|
||||
|
@ -939,90 +1031,49 @@ gst_system_clock_get_internal_time (GstClock * clock)
|
|||
return GST_CLOCK_TIME_NONE;
|
||||
|
||||
return GST_TIMESPEC_TO_TIME (ts);
|
||||
#else
|
||||
if (sysclock->priv->clock_type == GST_CLOCK_TYPE_REALTIME) {
|
||||
return gst_system_clock_get_real_time ();
|
||||
} else {
|
||||
return gst_system_clock_get_mono_time (sysclock);
|
||||
}
|
||||
#else /* !HAVE_POSIX_TIMERS || !HAVE_CLOCK_GETTIME */
|
||||
return priv_gst_get_monotonic_time ();
|
||||
#endif /* !HAVE_POSIX_TIMERS || !HAVE_CLOCK_GETTIME */
|
||||
}
|
||||
|
||||
#if !defined HAVE_POSIX_TIMERS || !defined HAVE_CLOCK_GETTIME
|
||||
static GstClockTime
|
||||
gst_system_clock_get_real_time ()
|
||||
{
|
||||
gint64 rt_micros = g_get_real_time ();
|
||||
// g_get_real_time returns microseconds but we need nanos, so we'll multiply by 1000
|
||||
return ((guint64) rt_micros) * 1000;
|
||||
}
|
||||
|
||||
static GstClockTime
|
||||
gst_system_clock_get_mono_time (GstSystemClock * sysclock)
|
||||
{
|
||||
#if defined __APPLE__
|
||||
uint64_t mach_t = mach_absolute_time ();
|
||||
return gst_util_uint64_scale (mach_t, sysclock->priv->mach_timebase.numer,
|
||||
sysclock->priv->mach_timebase.denom);
|
||||
#else
|
||||
#if defined G_OS_WIN32
|
||||
if (sysclock->priv->frequency.QuadPart != 0) {
|
||||
LARGE_INTEGER now;
|
||||
|
||||
/* we prefer the highly accurate performance counters on windows */
|
||||
QueryPerformanceCounter (&now);
|
||||
|
||||
return gst_util_uint64_scale (now.QuadPart,
|
||||
GST_SECOND, sysclock->priv->frequency.QuadPart);
|
||||
} else
|
||||
#endif /* G_OS_WIN32 */
|
||||
{
|
||||
gint64 monotime;
|
||||
|
||||
monotime = g_get_monotonic_time ();
|
||||
|
||||
return monotime * 1000;
|
||||
}
|
||||
#endif /* __APPLE__ */
|
||||
}
|
||||
#endif /* !HAVE_POSIX_TIMERS || !HAVE_CLOCK_GETTIME */
|
||||
|
||||
static guint64
|
||||
gst_system_clock_get_resolution (GstClock * clock)
|
||||
{
|
||||
GstSystemClock *sysclock = GST_SYSTEM_CLOCK_CAST (clock);
|
||||
#if defined __APPLE__ || defined G_OS_WIN32
|
||||
|
||||
#if defined G_OS_WIN32
|
||||
if (sysclock->priv->clock_type == GST_CLOCK_TYPE_REALTIME) {
|
||||
return 1 * GST_USECOND;
|
||||
} else
|
||||
} else {
|
||||
return GST_SECOND / performance_counter_frequency.QuadPart;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined __APPLE__
|
||||
{
|
||||
// On Apple platforms we want to use mach_absolute_time() unconditionally
|
||||
// for the monotonic clock even if clock_gettime() support is available.
|
||||
// Only use the latter for other clock types there.
|
||||
if (sysclock->priv->clock_type == GST_CLOCK_TYPE_MONOTONIC) {
|
||||
return gst_util_uint64_scale (GST_NSECOND,
|
||||
sysclock->priv->mach_timebase.numer,
|
||||
sysclock->priv->mach_timebase.denom);
|
||||
mach_timebase.numer, mach_timebase.denom);
|
||||
}
|
||||
#elif defined G_OS_WIN32
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_POSIX_TIMERS) && defined(HAVE_CLOCK_GETTIME)
|
||||
{
|
||||
if (sysclock->priv->frequency.QuadPart != 0) {
|
||||
return GST_SECOND / sysclock->priv->frequency.QuadPart;
|
||||
} else {
|
||||
return 1 * GST_USECOND;
|
||||
}
|
||||
}
|
||||
#elif defined(HAVE_POSIX_TIMERS) && defined(HAVE_CLOCK_GETTIME)
|
||||
clockid_t ptype;
|
||||
struct timespec ts;
|
||||
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);
|
||||
#else
|
||||
return 1 * GST_USECOND;
|
||||
#endif /* __APPLE__ */
|
||||
return GST_TIMESPEC_TO_TIME (ts);
|
||||
}
|
||||
#endif /* HAVE_POSIX_TIMERS && HAVE_CLOCK_GETTIME */
|
||||
|
||||
return 1 * GST_USECOND;
|
||||
}
|
||||
|
||||
/* synchronously wait on the given GstClockEntry.
|
||||
|
|
|
@ -3528,15 +3528,8 @@ gst_parse_bin_from_description_full (const gchar * bin_description,
|
|||
GstClockTime
|
||||
gst_util_get_timestamp (void)
|
||||
{
|
||||
#if defined (HAVE_POSIX_TIMERS) && defined(HAVE_MONOTONIC_CLOCK) &&\
|
||||
defined (HAVE_CLOCK_GETTIME)
|
||||
struct timespec now;
|
||||
|
||||
clock_gettime (CLOCK_MONOTONIC, &now);
|
||||
return GST_TIMESPEC_TO_TIME (now);
|
||||
#else
|
||||
return g_get_monotonic_time () * 1000;
|
||||
#endif
|
||||
priv_gst_clock_init ();
|
||||
return priv_gst_get_monotonic_time ();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue