From: Sebastian Dröge Date: Wed, 3 Jun 2015 11:16:15 +0000 (+0200) Subject: clock: Add GST_CLOCK_FLAG_NEEDS_STARTUP_SYNC and related API X-Git-Tag: 1.6.1~302 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=fe3249b0e1092c442e0889640295569eb012177d;p=platform%2Fupstream%2Fgstreamer.git clock: Add GST_CLOCK_FLAG_NEEDS_STARTUP_SYNC and related API gst_clock_wait_for_sync(), gst_clock_is_synced() and gst_clock_set_synced() plus a signal to asynchronously wait for the clock to be synced. This can be used by clocks to signal that they need initial synchronization before they can report any time, and that this synchronization can also get completely lost at some point. Network clocks, like the GStreamer netclientclock, NTP or PTP clocks are examples for clocks where this is useful to have as they can't report any time at all before they're synced. https://bugzilla.gnome.org/show_bug.cgi?id=749391 --- diff --git a/docs/gst/gstreamer-sections.txt b/docs/gst/gstreamer-sections.txt index 204296e..3273fc6 100644 --- a/docs/gst/gstreamer-sections.txt +++ b/docs/gst/gstreamer-sections.txt @@ -617,6 +617,9 @@ gst_clock_get_calibration gst_clock_set_calibration gst_clock_get_timeout gst_clock_set_timeout +gst_clock_wait_for_sync +gst_clock_is_synced +gst_clock_set_synced gst_clock_id_get_time gst_clock_id_wait gst_clock_id_wait_async diff --git a/gst/gstclock.c b/gst/gstclock.c index 2d8de0f..6faade6 100644 --- a/gst/gstclock.c +++ b/gst/gstclock.c @@ -128,6 +128,12 @@ enum PROP_TIMEOUT }; +enum +{ + SIGNAL_SYNCED, + SIGNAL_LAST +}; + #define GST_CLOCK_SLAVE_LOCK(clock) g_mutex_lock (&GST_CLOCK_CAST (clock)->priv->slave_lock) #define GST_CLOCK_SLAVE_UNLOCK(clock) g_mutex_unlock (&GST_CLOCK_CAST (clock)->priv->slave_lock) @@ -135,6 +141,8 @@ struct _GstClockPrivate { GMutex slave_lock; /* order: SLAVE_LOCK, OBJECT_LOCK */ + GCond sync_cond; + /* with LOCK */ GstClockTime internal_calibration; GstClockTime external_calibration; @@ -159,6 +167,8 @@ struct _GstClockPrivate gint pre_count; gint post_count; + + gboolean synced; }; /* seqlocks */ @@ -227,7 +237,7 @@ static void gst_clock_set_property (GObject * object, guint prop_id, static void gst_clock_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -/* static guint gst_clock_signals[LAST_SIGNAL] = { 0 }; */ +static guint gst_clock_signals[SIGNAL_LAST] = { 0 }; static GstClockID gst_clock_entry_new (GstClock * clock, GstClockTime time, @@ -694,6 +704,25 @@ gst_clock_class_init (GstClockClass * klass) 0, G_MAXUINT64, DEFAULT_TIMEOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstClock::synced: + * @clock: the clock + * @synced: if the clock is synced now + * + * Signaled on clocks with GST_CLOCK_FLAG_NEEDS_STARTUP_SYNC set once + * the clock is synchronized, or when it completely lost synchronization. + * This signal will not be emitted on clocks without the flag. + * + * This signal will be emitted from an arbitrary thread, most likely not + * the application's main thread. + * + * Since: 1.6 + */ + gst_clock_signals[SIGNAL_SYNCED] = + g_signal_new ("synced", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, + 0, NULL, NULL, + g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); + g_type_class_add_private (klass, sizeof (GstClockPrivate)); } @@ -713,6 +742,7 @@ gst_clock_init (GstClock * clock) priv->rate_denominator = 1; g_mutex_init (&priv->slave_lock); + g_cond_init (&priv->sync_cond); priv->window_size = DEFAULT_WINDOW_SIZE; priv->window_threshold = DEFAULT_WINDOW_THRESHOLD; priv->filling = TRUE; @@ -754,6 +784,7 @@ gst_clock_finalize (GObject * object) GST_CLOCK_SLAVE_UNLOCK (clock); g_mutex_clear (&clock->priv->slave_lock); + g_cond_clear (&clock->priv->sync_cond); G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -972,6 +1003,11 @@ gst_clock_get_internal_time (GstClock * clock) g_return_val_if_fail (GST_IS_CLOCK (clock), GST_CLOCK_TIME_NONE); + if (G_UNLIKELY (GST_OBJECT_FLAG_IS_SET (clock, + GST_CLOCK_FLAG_NEEDS_STARTUP_SYNC) && !clock->priv->synced)) + GST_CAT_WARNING_OBJECT (GST_CAT_CLOCK, clock, + "clocked is not synchronized yet"); + cclass = GST_CLOCK_GET_CLASS (clock); if (G_UNLIKELY (cclass->get_internal_time == NULL)) @@ -1492,3 +1528,109 @@ gst_clock_get_property (GObject * object, guint prop_id, break; } } + + +/** + * gst_clock_wait_for_sync: + * @clock: a GstClock + * @timeout: timeout for waiting or %GST_CLOCK_TIME_NONE + * + * Waits until @clock is synced for reporting the current time. If @timeout + * is %GST_CLOCK_TIME_NONE it will wait forever, otherwise it will time out + * after @timeout nanoseconds. + * + * For asynchronous waiting, the GstClock::synced signal can be used. + * + * + * This returns immediately with TRUE if GST_CLOCK_FLAG_NEEDS_STARTUP_SYNC + * is not set on the clock, or if the clock is already synced. + * + * Returns: %TRUE if waiting was successful, or %FALSE on timeout + * + * Since: 1.6 + */ +gboolean +gst_clock_wait_for_sync (GstClock * clock, GstClockTime timeout) +{ + gboolean timed_out = FALSE; + + g_return_val_if_fail (GST_IS_CLOCK (clock), FALSE); + + GST_OBJECT_LOCK (clock); + if (!GST_OBJECT_FLAG_IS_SET (clock, GST_CLOCK_FLAG_NEEDS_STARTUP_SYNC) + || clock->priv->synced) { + GST_OBJECT_UNLOCK (clock); + return TRUE; + } + + if (timeout != GST_CLOCK_TIME_NONE) { + gint64 end_time = g_get_monotonic_time () + gst_util_uint64_scale (timeout, + G_TIME_SPAN_SECOND, GST_SECOND); + + while (!clock->priv->synced && !timed_out) { + timed_out = + !g_cond_wait_until (&clock->priv->sync_cond, + GST_OBJECT_GET_LOCK (clock), end_time); + } + } else { + timed_out = FALSE; + while (!clock->priv->synced) { + g_cond_wait (&clock->priv->sync_cond, GST_OBJECT_GET_LOCK (clock)); + } + } + GST_OBJECT_UNLOCK (clock); + + return !timed_out; +} + +/** + * gst_clock_is_synced: + * @clock: a GstClock + * + * Checks if the clock is currently synced. + * + * This returns if GST_CLOCK_FLAG_NEEDS_STARTUP_SYNC is not set on the clock. + * + * Returns: %TRUE if the clock is currently synced + * + * Since: 1.6 + */ +gboolean +gst_clock_is_synced (GstClock * clock) +{ + g_return_val_if_fail (GST_IS_CLOCK (clock), TRUE); + + return !GST_OBJECT_FLAG_IS_SET (clock, GST_CLOCK_FLAG_NEEDS_STARTUP_SYNC) + || clock->priv->synced; +} + +/** + * gst_clock_set_synced: + * @clock: a GstClock + * @synced: if the clock is synced + * + * Sets @clock to synced and emits the GstClock::synced signal, and wakes up any + * thread waiting in gst_clock_wait_synced(). + * + * This function must only be called if GST_CLOCK_FLAG_NEEDS_STARTUP_SYNC + * is set on the clock, and is intended to be called by subclasses only. + * + * Since: 1.6 + */ +void +gst_clock_set_synced (GstClock * clock, gboolean synced) +{ + g_return_if_fail (GST_IS_CLOCK (clock)); + g_return_if_fail (GST_OBJECT_FLAG_IS_SET (clock, + GST_CLOCK_FLAG_NEEDS_STARTUP_SYNC)); + + GST_OBJECT_LOCK (clock); + if (clock->priv->synced != ! !synced) { + clock->priv->synced = ! !synced; + g_cond_signal (&clock->priv->sync_cond); + GST_OBJECT_UNLOCK (clock); + g_signal_emit (clock, gst_clock_signals[SIGNAL_SYNCED], 0, ! !synced); + } else { + GST_OBJECT_UNLOCK (clock); + } +} diff --git a/gst/gstclock.h b/gst/gstclock.h index c2239e5..9369755 100644 --- a/gst/gstclock.h +++ b/gst/gstclock.h @@ -375,6 +375,8 @@ struct _GstClockEntry { * @GST_CLOCK_FLAG_CAN_DO_PERIODIC_ASYNC: clock can do async periodic timeout callbacks * @GST_CLOCK_FLAG_CAN_SET_RESOLUTION: clock's resolution can be changed * @GST_CLOCK_FLAG_CAN_SET_MASTER: clock can be slaved to a master clock + * @GST_CLOCK_FLAG_NEEDS_STARTUP_SYNC: clock needs to be synced before it can be used + * Since: 1.6 * @GST_CLOCK_FLAG_LAST: subclasses can add additional flags starting from this flag * * The capabilities of this clock @@ -386,6 +388,7 @@ typedef enum { GST_CLOCK_FLAG_CAN_DO_PERIODIC_ASYNC = (GST_OBJECT_FLAG_LAST << 3), GST_CLOCK_FLAG_CAN_SET_RESOLUTION = (GST_OBJECT_FLAG_LAST << 4), GST_CLOCK_FLAG_CAN_SET_MASTER = (GST_OBJECT_FLAG_LAST << 5), + GST_CLOCK_FLAG_NEEDS_STARTUP_SYNC = (GST_OBJECT_FLAG_LAST << 6), /* padding */ GST_CLOCK_FLAG_LAST = (GST_OBJECT_FLAG_LAST << 8) } GstClockFlags; @@ -496,6 +499,12 @@ GstClockTime gst_clock_adjust_with_calibration (GstClock *clock, GstClockTime cdenom); GstClockTime gst_clock_unadjust_unlocked (GstClock * clock, GstClockTime external); +/* waiting for, signalling and checking for synchronization */ +gboolean gst_clock_wait_for_sync (GstClock * clock, GstClockTime timeout); +gboolean gst_clock_is_synced (GstClock * clock); + +/* to be used by subclasses only */ +void gst_clock_set_synced (GstClock * clock, gboolean synced); /* creating IDs that can be used to get notifications */ GstClockID gst_clock_new_single_shot_id (GstClock *clock, diff --git a/win32/common/libgstreamer.def b/win32/common/libgstreamer.def index c130747..76dcb07 100644 --- a/win32/common/libgstreamer.def +++ b/win32/common/libgstreamer.def @@ -321,6 +321,7 @@ EXPORTS gst_clock_id_unschedule gst_clock_id_wait gst_clock_id_wait_async + gst_clock_is_synced gst_clock_new_periodic_id gst_clock_new_single_shot_id gst_clock_periodic_id_reinit @@ -328,10 +329,12 @@ EXPORTS gst_clock_set_calibration gst_clock_set_master gst_clock_set_resolution + gst_clock_set_synced gst_clock_set_timeout gst_clock_single_shot_id_reinit gst_clock_type_get_type gst_clock_unadjust_unlocked + gst_clock_wait_for_sync gst_context_get_context_type gst_context_get_structure gst_context_get_type