diff --git a/subprojects/gstreamer/gst/gst.c b/subprojects/gstreamer/gst/gst.c index 4e34d0ccb9..c068314d3e 100644 --- a/subprojects/gstreamer/gst/gst.c +++ b/subprojects/gstreamer/gst/gst.c @@ -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 (); diff --git a/subprojects/gstreamer/gst/gst_private.h b/subprojects/gstreamer/gst/gst_private.h index 1471fb0e30..9be91ef96e 100644 --- a/subprojects/gstreamer/gst/gst_private.h +++ b/subprojects/gstreamer/gst/gst_private.h @@ -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__ */ diff --git a/subprojects/gstreamer/gst/gstsystemclock.c b/subprojects/gstreamer/gst/gstsystemclock.c index 7d8efb171e..403cc3d170 100644 --- a/subprojects/gstreamer/gst/gstsystemclock.c +++ b/subprojects/gstreamer/gst/gstsystemclock.c @@ -60,6 +60,108 @@ #include #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 + +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. diff --git a/subprojects/gstreamer/gst/gstutils.c b/subprojects/gstreamer/gst/gstutils.c index bd552e59de..83c3f485e3 100644 --- a/subprojects/gstreamer/gst/gstutils.c +++ b/subprojects/gstreamer/gst/gstutils.c @@ -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 (); } /**