X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gst%2Fgstclock.c;h=279b1f8bc5a75bd55300d9c646971c6ba6ec96fa;hb=5470f6df00595f4ab44871e0e633bf15006abc5c;hp=d3eaf9df57e9431074281e901ac803aa220e8ab4;hpb=ab827eca2ea64fb15ab8add85c72128f77abb923;p=platform%2Fupstream%2Fgstreamer.git diff --git a/gst/gstclock.c b/gst/gstclock.c index d3eaf9d..279b1f8 100644 --- a/gst/gstclock.c +++ b/gst/gstclock.c @@ -23,6 +23,7 @@ /** * SECTION:gstclock + * @title: GstClock * @short_description: Abstract class for global clocks * @see_also: #GstSystemClock, #GstPipeline * @@ -74,7 +75,7 @@ * for unreffing the ids itself. This holds for both periodic and single shot * notifications. The reason being that the owner of the #GstClockID has to * keep a handle to the #GstClockID to unblock the wait on FLUSHING events or - * state changes and if the entry would be unreffed automatically, the handle + * state changes and if the entry would be unreffed automatically, the handle * might become invalid without any notification. * * These clock operations do not operate on the running time, so the callbacks @@ -90,7 +91,7 @@ * plugins that have an internal clock but must operate with another clock * selected by the #GstPipeline. They can track the offset and rate difference * of their internal clock relative to the master clock by using the - * gst_clock_get_calibration() function. + * gst_clock_get_calibration() function. * * The master/slave synchronisation can be tuned with the #GstClock:timeout, * #GstClock:window-size and #GstClock:window-threshold properties. @@ -108,12 +109,6 @@ #include "gstutils.h" #include "glib-compat-private.h" -#ifndef GST_DISABLE_TRACE -/* #define GST_WITH_ALLOC_TRACE */ -#include "gsttrace.h" -static GstAllocTrace *_gst_clock_entry_trace; -#endif - /* #define DEBUGGING_ENABLED */ #define DEFAULT_WINDOW_SIZE 32 @@ -163,6 +158,7 @@ struct _GstClockPrivate gint time_index; GstClockTime timeout; GstClockTime *times; + GstClockTime *times_temp; GstClockID clockid; gint pre_count; @@ -171,6 +167,14 @@ struct _GstClockPrivate gboolean synced; }; +typedef struct +{ + GstClockEntry entry; + GWeakRef clock; +} GstClockEntryImpl; + +#define GST_CLOCK_ENTRY_CLOCK_WEAK_REF(entry) (&((GstClockEntryImpl *)(entry))->clock) + /* seqlocks */ #define read_seqbegin(clock) \ g_atomic_int_get (&clock->priv->post_count); @@ -245,15 +249,22 @@ gst_clock_entry_new (GstClock * clock, GstClockTime time, { GstClockEntry *entry; - entry = g_slice_new (GstClockEntry); -#ifndef GST_DISABLE_TRACE - _gst_alloc_trace_new (_gst_clock_entry_trace, entry); -#endif + entry = (GstClockEntry *) g_slice_new (GstClockEntryImpl); + + /* FIXME: add tracer hook for struct allocations such as clock entries */ + GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "created entry %p, time %" GST_TIME_FORMAT, entry, GST_TIME_ARGS (time)); entry->refcount = 1; +#ifndef GST_REMOVE_DEPRECATED +#ifndef GST_DISABLE_DEPRECATED entry->clock = clock; +#else + entry->_clock = clock; +#endif +#endif + g_weak_ref_init (GST_CLOCK_ENTRY_CLOCK_WEAK_REF (entry), clock); entry->type = type; entry->time = time; entry->interval = interval; @@ -274,7 +285,8 @@ gst_clock_entry_reinit (GstClock * clock, GstClockEntry * entry, GstClockTime time, GstClockTime interval, GstClockEntryType type) { g_return_val_if_fail (entry->status != GST_CLOCK_BUSY, FALSE); - g_return_val_if_fail (entry->clock == clock, FALSE); + g_return_val_if_fail (gst_clock_id_uses_clock ((GstClockID) entry, clock), + FALSE); entry->type = type; entry->time = time; @@ -358,10 +370,11 @@ _gst_clock_id_free (GstClockID id) if (entry->destroy_data) entry->destroy_data (entry->user_data); -#ifndef GST_DISABLE_TRACE - _gst_alloc_trace_free (_gst_clock_entry_trace, id); -#endif - g_slice_free (GstClockEntry, id); + g_weak_ref_clear (GST_CLOCK_ENTRY_CLOCK_WEAK_REF (entry)); + + /* FIXME: add tracer hook for struct allocations such as clock entries */ + + g_slice_free (GstClockEntryImpl, (GstClockEntryImpl *) id); } /** @@ -496,23 +509,23 @@ gst_clock_id_get_time (GstClockID id) * @jitter: (out) (allow-none): a pointer that will contain the jitter, * can be %NULL. * - * Perform a blocking wait on @id. + * Perform a blocking wait on @id. * @id should have been created with gst_clock_new_single_shot_id() * or gst_clock_new_periodic_id() and should not have been unscheduled - * with a call to gst_clock_id_unschedule(). + * with a call to gst_clock_id_unschedule(). * * If the @jitter argument is not %NULL and this function returns #GST_CLOCK_OK * or #GST_CLOCK_EARLY, it will contain the difference * against the clock and the time of @id when this method was - * called. + * called. * Positive values indicate how late @id was relative to the clock - * (in which case this function will return #GST_CLOCK_EARLY). - * Negative values indicate how much time was spent waiting on the clock + * (in which case this function will return #GST_CLOCK_EARLY). + * Negative values indicate how much time was spent waiting on the clock * before this function returned. * * Returns: the result of the blocking wait. #GST_CLOCK_EARLY will be returned - * if the current clock time is past the time of @id, #GST_CLOCK_OK if - * @id was scheduled in time. #GST_CLOCK_UNSCHEDULED if @id was + * if the current clock time is past the time of @id, #GST_CLOCK_OK if + * @id was scheduled in time. #GST_CLOCK_UNSCHEDULED if @id was * unscheduled with gst_clock_id_unschedule(). * * MT safe. @@ -531,7 +544,9 @@ gst_clock_id_wait (GstClockID id, GstClockTimeDiff * jitter) entry = (GstClockEntry *) id; requested = GST_CLOCK_ENTRY_TIME (entry); - clock = GST_CLOCK_ENTRY_CLOCK (entry); + clock = g_weak_ref_get (GST_CLOCK_ENTRY_CLOCK_WEAK_REF (entry)); + if (G_UNLIKELY (clock == NULL)) + goto invalid_entry; /* can't sync on invalid times */ if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (requested))) @@ -554,6 +569,7 @@ gst_clock_id_wait (GstClockID id, GstClockTimeDiff * jitter) if (entry->type == GST_CLOCK_ENTRY_PERIODIC) entry->time = requested + entry->interval; + gst_object_unref (clock); return res; /* ERRORS */ @@ -561,13 +577,20 @@ invalid_time: { GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "invalid time requested, returning _BADTIME"); + gst_object_unref (clock); return GST_CLOCK_BADTIME; } not_supported: { GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "clock wait is not supported"); + gst_object_unref (clock); return GST_CLOCK_UNSUPPORTED; } +invalid_entry: + { + GST_CAT_DEBUG (GST_CAT_CLOCK, "clock entry %p lost its clock", id); + return GST_CLOCK_ERROR; + } } /** @@ -605,7 +628,9 @@ gst_clock_id_wait_async (GstClockID id, entry = (GstClockEntry *) id; requested = GST_CLOCK_ENTRY_TIME (entry); - clock = GST_CLOCK_ENTRY_CLOCK (entry); + clock = g_weak_ref_get (GST_CLOCK_ENTRY_CLOCK_WEAK_REF (entry)); + if (G_UNLIKELY (clock == NULL)) + goto invalid_entry; /* can't sync on invalid times */ if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (requested))) @@ -622,6 +647,7 @@ gst_clock_id_wait_async (GstClockID id, res = cclass->wait_async (clock, entry); + gst_object_unref (clock); return res; /* ERRORS */ @@ -630,13 +656,20 @@ invalid_time: (func) (clock, GST_CLOCK_TIME_NONE, id, user_data); GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "invalid time requested, returning _BADTIME"); + gst_object_unref (clock); return GST_CLOCK_BADTIME; } not_supported: { GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "clock wait is not supported"); + gst_object_unref (clock); return GST_CLOCK_UNSUPPORTED; } +invalid_entry: + { + GST_CAT_DEBUG (GST_CAT_CLOCK, "clock entry %p lost its clock", id); + return GST_CLOCK_ERROR; + } } /** @@ -660,12 +693,23 @@ gst_clock_id_unschedule (GstClockID id) g_return_if_fail (id != NULL); entry = (GstClockEntry *) id; - clock = entry->clock; + clock = g_weak_ref_get (GST_CLOCK_ENTRY_CLOCK_WEAK_REF (entry)); + if (G_UNLIKELY (clock == NULL)) + goto invalid_entry; cclass = GST_CLOCK_GET_CLASS (clock); if (G_LIKELY (cclass->unschedule)) cclass->unschedule (clock, entry); + + gst_object_unref (clock); + return; + +invalid_entry: + { + GST_CAT_DEBUG (GST_CAT_CLOCK, "clock entry %p lost its clock", id); + return; + } } @@ -673,17 +717,13 @@ gst_clock_id_unschedule (GstClockID id) * GstClock abstract base class implementation */ #define gst_clock_parent_class parent_class -G_DEFINE_ABSTRACT_TYPE (GstClock, gst_clock, GST_TYPE_OBJECT); +G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GstClock, gst_clock, GST_TYPE_OBJECT); static void gst_clock_class_init (GstClockClass * klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); -#ifndef GST_DISABLE_TRACE - _gst_clock_entry_trace = _gst_alloc_trace_register ("GstClockEntry", -1); -#endif - gobject_class->dispose = gst_clock_dispose; gobject_class->finalize = gst_clock_finalize; gobject_class->set_property = gst_clock_set_property; @@ -722,8 +762,6 @@ gst_clock_class_init (GstClockClass * klass) 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)); } static void @@ -731,8 +769,7 @@ gst_clock_init (GstClock * clock) { GstClockPrivate *priv; - clock->priv = priv = - G_TYPE_INSTANCE_GET_PRIVATE (clock, GST_TYPE_CLOCK, GstClockPrivate); + clock->priv = priv = gst_clock_get_instance_private (clock); priv->last_time = 0; @@ -749,9 +786,7 @@ gst_clock_init (GstClock * clock) priv->time_index = 0; priv->timeout = DEFAULT_TIMEOUT; priv->times = g_new0 (GstClockTime, 4 * priv->window_size); - - /* clear floating flag */ - gst_object_ref_sink (clock); + priv->times_temp = priv->times + 2 * priv->window_size; } static void @@ -781,6 +816,7 @@ gst_clock_finalize (GObject * object) } g_free (clock->priv->times); clock->priv->times = NULL; + clock->priv->times_temp = NULL; GST_CLOCK_SLAVE_UNLOCK (clock); g_mutex_clear (&clock->priv->slave_lock); @@ -847,9 +883,10 @@ gst_clock_get_resolution (GstClock * clock) return 1; } +/* FIXME 2.0: Remove clock parameter below */ /** * gst_clock_adjust_with_calibration: - * @clock: a #GstClock to use + * @clock: (allow-none): a #GstClock to use * @internal_target: a clock time * @cinternal: a reference internal time * @cexternal: a reference external time @@ -863,6 +900,8 @@ gst_clock_get_resolution (GstClock * clock) * current calibration parameters, but doesn't ensure a monotonically * increasing result as gst_clock_adjust_unlocked() does. * + * Note: The @clock parameter is unused and can be NULL + * * Returns: the converted time of the clock. * * Since: 1.6 @@ -937,6 +976,56 @@ gst_clock_adjust_unlocked (GstClock * clock, GstClockTime internal) return priv->last_time; } +/* FIXME 2.0: Remove clock parameter below */ +/** + * gst_clock_unadjust_with_calibration: + * @clock: (allow-none): a #GstClock to use + * @external_target: a clock time + * @cinternal: a reference internal time + * @cexternal: a reference external time + * @cnum: the numerator of the rate of the clock relative to its + * internal time + * @cdenom: the denominator of the rate of the clock + * + * Converts the given @external_target clock time to the internal time, + * using the passed calibration parameters. This function performs the + * same calculation as gst_clock_unadjust_unlocked() when called using the + * current calibration parameters. + * + * Note: The @clock parameter is unused and can be NULL + * + * Returns: the converted time of the clock. + * + * Since: 1.8 + */ +GstClockTime +gst_clock_unadjust_with_calibration (GstClock * clock, + GstClockTime external_target, GstClockTime cinternal, + GstClockTime cexternal, GstClockTime cnum, GstClockTime cdenom) +{ + GstClockTime ret; + + /* avoid divide by 0 */ + if (G_UNLIKELY (cnum == 0)) + cnum = cdenom = 1; + + /* The formula is (external - cexternal) * cdenom / cnum + cinternal */ + if (G_LIKELY (external_target >= cexternal)) { + ret = external_target - cexternal; + ret = gst_util_uint64_scale (ret, cdenom, cnum); + ret += cinternal; + } else { + ret = cexternal - external_target; + ret = gst_util_uint64_scale (ret, cdenom, cnum); + if (G_LIKELY (cinternal > ret)) + ret = cinternal - ret; + else + ret = 0; + } + + return ret; +} + /** * gst_clock_unadjust_unlocked: * @clock: a #GstClock to use @@ -954,7 +1043,7 @@ gst_clock_adjust_unlocked (GstClock * clock, GstClockTime internal) GstClockTime gst_clock_unadjust_unlocked (GstClock * clock, GstClockTime external) { - GstClockTime ret, cinternal, cexternal, cnum, cdenom; + GstClockTime cinternal, cexternal, cnum, cdenom; GstClockPrivate *priv = clock->priv; /* get calibration values for readability */ @@ -963,24 +1052,8 @@ gst_clock_unadjust_unlocked (GstClock * clock, GstClockTime external) cnum = priv->rate_numerator; cdenom = priv->rate_denominator; - /* avoid divide by 0 */ - if (G_UNLIKELY (cnum == 0)) - cnum = cdenom = 1; - - /* The formula is (external - cexternal) * cdenom / cnum + cinternal */ - if (G_LIKELY (external >= cexternal)) { - ret = external - cexternal; - ret = gst_util_uint64_scale (ret, cdenom, cnum); - ret += cinternal; - } else { - ret = cexternal - external; - ret = gst_util_uint64_scale (ret, cdenom, cnum); - if (G_LIKELY (cinternal > ret)) - ret = cinternal - ret; - else - ret = 0; - } - return ret; + return gst_clock_unadjust_with_calibration (clock, external, cinternal, + cexternal, cnum, cdenom); } /** @@ -1006,7 +1079,7 @@ gst_clock_get_internal_time (GstClock * clock) 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"); + "clock is not synchronized yet"); cclass = GST_CLOCK_GET_CLASS (clock); @@ -1072,7 +1145,7 @@ gst_clock_get_time (GstClock * clock) * @internal: a reference internal time * @external: a reference external time * @rate_num: the numerator of the rate of the clock relative to its - * internal time + * internal time * @rate_denom: the denominator of the rate of the clock * * Adjusts the rate and time of @clock. A rate of 1/1 is the normal speed of @@ -1086,9 +1159,9 @@ gst_clock_get_time (GstClock * clock) * Subsequent calls to gst_clock_get_time() will return clock times computed as * follows: * - * + * |[ * time = (internal_time - internal) * rate_num / rate_denom + external - * + * ]| * * This formula is implemented in gst_clock_adjust_unlocked(). Of course, it * tries to do the integer arithmetic as precisely as possible. @@ -1127,7 +1200,7 @@ gst_clock_set_calibration (GstClock * clock, GstClockTime internal, GstClockTime /** * gst_clock_get_calibration: - * @clock: a #GstClock + * @clock: a #GstClock * @internal: (out) (allow-none): a location to store the internal time * @external: (out) (allow-none): a location to store the external time * @rate_num: (out) (allow-none): a location to store the rate numerator @@ -1197,22 +1270,22 @@ gst_clock_slave_callback (GstClock * master, GstClockTime time, /** * gst_clock_set_master: - * @clock: a #GstClock - * @master: (allow-none): a master #GstClock + * @clock: a #GstClock + * @master: (allow-none): a master #GstClock * * Set @master as the master clock for @clock. @clock will be automatically * calibrated so that gst_clock_get_time() reports the same time as the - * master clock. - * + * master clock. + * * A clock provider that slaves its clock to a master can get the current * calibration values with gst_clock_get_calibration(). * * @master can be %NULL in which case @clock will not be slaved anymore. It will - * however keep reporting its time adjusted with the last configured rate + * however keep reporting its time adjusted with the last configured rate * and time offsets. * - * Returns: %TRUE if the clock is capable of being slaved to a master clock. - * Trying to set a master on a clock without the + * Returns: %TRUE if the clock is capable of being slaved to a master clock. + * Trying to set a master on a clock without the * #GST_CLOCK_FLAG_CAN_SET_MASTER flag will make this function return %FALSE. * * MT safe. @@ -1230,6 +1303,9 @@ gst_clock_set_master (GstClock * clock, GstClock * master) /* we always allow setting the master to NULL */ if (master && !GST_OBJECT_FLAG_IS_SET (clock, GST_CLOCK_FLAG_CAN_SET_MASTER)) goto not_supported; + if (master && !gst_clock_is_synced (master)) + goto master_not_synced; + GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "slaving %p to master clock %p", clock, master); GST_OBJECT_UNLOCK (clock); @@ -1270,11 +1346,19 @@ not_supported: GST_OBJECT_UNLOCK (clock); return FALSE; } + +master_not_synced: + { + GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, master, + "master clock is not synced yet"); + GST_OBJECT_UNLOCK (clock); + return FALSE; + } } /** * gst_clock_get_master: - * @clock: a #GstClock + * @clock: a #GstClock * * Get the master clock that @clock is slaved to or %NULL when the clock is * not slaved to any master clock. @@ -1304,8 +1388,70 @@ gst_clock_get_master (GstClock * clock) } /** + * gst_clock_id_get_clock: + * @id: a #GstClockID + * + * This function returns the underlying clock. + * + * Returns: (transfer full) (nullable): a #GstClock or %NULL when the + * underlying clock has been freed. Unref after usage. + * + * MT safe. + * + * Since: 1.16 + */ +GstClock * +gst_clock_id_get_clock (GstClockID id) +{ + GstClockEntry *entry; + + g_return_val_if_fail (id != NULL, NULL); + + entry = (GstClockEntry *) id; + return g_weak_ref_get (GST_CLOCK_ENTRY_CLOCK_WEAK_REF (entry)); +} + +/** + * gst_clock_id_uses_clock: + * @id: a #GstClockID to check + * @clock: a #GstClock to compare against + * + * This function returns whether @id uses @clock as the underlying clock. + * @clock can be NULL, in which case the return value indicates whether + * the underlying clock has been freed. If this is the case, the @id is + * no longer usable and should be freed. + * + * Returns: whether the clock @id uses the same underlying #GstClock @clock. + * + * MT safe. + * + * Since: 1.16 + */ +gboolean +gst_clock_id_uses_clock (GstClockID id, GstClock * clock) +{ + GstClockEntry *entry; + GstClock *entry_clock; + gboolean ret = FALSE; + + g_return_val_if_fail (id != NULL, FALSE); + g_return_val_if_fail (clock != NULL, FALSE); + + entry = (GstClockEntry *) id; + entry_clock = g_weak_ref_get (GST_CLOCK_ENTRY_CLOCK_WEAK_REF (entry)); + if (entry_clock == clock) + ret = TRUE; + + if (G_LIKELY (entry_clock != NULL)) + gst_object_unref (entry_clock); + + return ret; +} + + +/** * gst_clock_add_observation: - * @clock: a #GstClock + * @clock: a #GstClock * @slave: a time on the slave * @master: a time on the master * @r_squared: (out): a pointer to hold the result @@ -1315,13 +1461,13 @@ gst_clock_get_master (GstClock * clock) * are available, a linear regression algorithm is run on the * observations and @clock is recalibrated. * - * If this functions returns %TRUE, @r_squared will contain the + * If this functions returns %TRUE, @r_squared will contain the * correlation coefficient of the interpolation. A value of 1.0 * means a perfect regression was performed. This value can * be used to control the sampling frequency of the master and slave * clocks. * - * Returns: %TRUE if enough observations were added to run the + * Returns: %TRUE if enough observations were added to run the * regression algorithm. * * MT safe. @@ -1383,8 +1529,8 @@ gst_clock_add_observation_unapplied (GstClock * clock, GstClockTime slave, "adding observation slave %" GST_TIME_FORMAT ", master %" GST_TIME_FORMAT, GST_TIME_ARGS (slave), GST_TIME_ARGS (master)); - priv->times[(4 * priv->time_index)] = slave; - priv->times[(4 * priv->time_index) + 2] = master; + priv->times[(2 * priv->time_index)] = slave; + priv->times[(2 * priv->time_index) + 1] = master; priv->time_index++; if (G_UNLIKELY (priv->time_index == priv->window_size)) { @@ -1396,8 +1542,8 @@ gst_clock_add_observation_unapplied (GstClock * clock, GstClockTime slave, goto filling; n = priv->filling ? priv->time_index : priv->window_size; - if (!_priv_gst_do_linear_regression (priv->times, n, &m_num, &m_denom, &b, - &xbase, r_squared)) + if (!gst_calculate_linear_regression (priv->times, priv->times_temp, n, + &m_num, &m_denom, &b, &xbase, r_squared)) goto invalid; GST_CLOCK_SLAVE_UNLOCK (clock); @@ -1426,7 +1572,7 @@ invalid: { /* no valid regression has been done, ignore the result then */ GST_CLOCK_SLAVE_UNLOCK (clock); - return TRUE; + return FALSE; } } @@ -1486,6 +1632,7 @@ gst_clock_set_property (GObject * object, guint prop_id, priv->window_size = g_value_get_int (value); priv->window_threshold = MIN (priv->window_threshold, priv->window_size); priv->times = g_renew (GstClockTime, priv->times, 4 * priv->window_size); + priv->times_temp = priv->times + 2 * priv->window_size; /* restart calibration */ priv->filling = TRUE; priv->time_index = 0; @@ -1547,7 +1694,6 @@ gst_clock_get_property (GObject * object, guint prop_id, * * 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. *