--- a/gstreamer_core/gst/gstclock.c Tue Aug 31 15:30:33 2010 +0300
+++ b/gstreamer_core/gst/gstclock.c Wed Sep 01 12:16:41 2010 +0100
@@ -28,7 +28,7 @@
*
* GStreamer uses a global clock to synchronize the plugins in a pipeline.
* Different clock implementations are possible by implementing this abstract
- * base class or, more conveniently, by subclassing #GstSystemClock.
+ * base class.
*
* The #GstClock returns a monotonically increasing time with the method
* gst_clock_get_time(). Its accuracy and base time depend on the specific
@@ -37,7 +37,7 @@
* meaningful in itself, what matters are the deltas between two clock times.
* The time returned by a clock is called the absolute time.
*
- * The pipeline uses the clock to calculate the running time. Usually all
+ * The pipeline uses the clock to calculate the stream time. Usually all
* renderers synchronize to the global clock using the buffer timestamps, the
* newsegment events and the element's base time, see #GstPipeline.
*
@@ -52,18 +52,18 @@
* gst_clock_id_wait(). To receive a callback when the specific time is reached
* in the clock use gst_clock_id_wait_async(). Both these calls can be
* interrupted with the gst_clock_id_unschedule() call. If the blocking wait is
- * unscheduled a return value of #GST_CLOCK_UNSCHEDULED is returned.
+ * unscheduled a return value of GST_CLOCK_UNSCHEDULED is returned.
*
- * Periodic callbacks scheduled async will be repeatedly called automatically
+ * Periodic callbacks scheduled async will be repeadedly called automatically
* until it is unscheduled. To schedule a sync periodic callback,
- * gst_clock_id_wait() should be called repeatedly.
+ * gst_clock_id_wait() should be called repeadedly.
*
* The async callbacks can happen from any thread, either provided by the core
* or from a streaming thread. The application should be prepared for this.
*
* A #GstClockID that has been unscheduled cannot be used again for any wait
* operation, a new #GstClockID should be created and the old unscheduled one
- * should be destroyed with gst_clock_id_unref().
+ * should be destroyed wirth gst_clock_id_unref().
*
* It is possible to perform a blocking wait on the same #GstClockID from
* multiple threads. However, registering the same #GstClockID for multiple
@@ -77,14 +77,14 @@
* 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
+ * These clock operations do not operate on the stream time, so the callbacks
* will also occur when not in PLAYING state as if the clock just keeps on
* running. Some clocks however do not progress when the element that provided
* the clock is not PLAYING.
*
- * When a clock has the #GST_CLOCK_FLAG_CAN_SET_MASTER flag set, it can be
+ * When a clock has the GST_CLOCK_FLAG_CAN_SET_MASTER flag set, it can be
* slaved to another #GstClock with the gst_clock_set_master(). The clock will
- * then automatically be synchronized to this master clock by repeatedly
+ * then automatically be synchronized to this master clock by repeadedly
* sampling the master clock and the slave clock and recalibrating the slave
* clock with gst_clock_set_calibration(). This feature is mostly useful for
* plugins that have an internal clock but must operate with another clock
@@ -92,14 +92,14 @@
* of their internal clock relative to the master clock by using the
* gst_clock_get_calibration() function.
*
- * The master/slave synchronisation can be tuned with the #GstClock:timeout,
- * #GstClock:window-size and #GstClock:window-threshold properties.
- * The #GstClock:timeout property defines the interval to sample the master
- * clock and run the calibration functions. #GstClock:window-size defines the
- * number of samples to use when calibrating and #GstClock:window-threshold
- * defines the minimum number of samples before the calibration is performed.
+ * The master/slave synchronisation can be tuned with the "timeout", "window-size"
+ * and "window-threshold" properties. The "timeout" property defines the interval
+ * to sample the master clock and run the calibration functions.
+ * "window-size" defines the number of samples to use when calibrating and
+ * "window-threshold" defines the minimum number of samples before the
+ * calibration is performed.
*
- * Last reviewed on 2009-05-21 (0.10.24)
+ * Last reviewed on 2006-08-11 (0.10.10)
*/
@@ -119,6 +119,15 @@
#ifdef __SYMBIAN32__
#include <glib_global.h>
#endif
+
+#if GLIB_CHECK_VERSION (2, 10, 0)
+#define ALLOC_ENTRY() g_slice_new (GstClockEntry)
+#define FREE_ENTRY(entry) g_slice_free (GstClockEntry, entry)
+#else
+#define ALLOC_ENTRY() g_new (GstClockEntry, 1)
+#define FREE_ENTRY(entry) g_free (entry)
+#endif
+
/* #define DEBUGGING_ENABLED */
#define DEFAULT_STATS FALSE
@@ -135,41 +144,6 @@
PROP_TIMEOUT
};
-struct _GstClockPrivate
-{
- gint pre_count;
- gint post_count;
-};
-
-/* seqlocks */
-#define read_seqbegin(clock) \
- g_atomic_int_get (&clock->ABI.priv->post_count);
-
-static inline gboolean
-read_seqretry (GstClock * clock, gint seq)
-{
- /* no retry if the seqnum did not change */
- if (G_LIKELY (seq == g_atomic_int_get (&clock->ABI.priv->pre_count)))
- return FALSE;
-
- /* wait for the writer to finish and retry */
- GST_OBJECT_LOCK (clock);
- GST_OBJECT_UNLOCK (clock);
- return TRUE;
-}
-
-#define write_seqlock(clock) \
-G_STMT_START { \
- GST_OBJECT_LOCK (clock); \
- g_atomic_int_inc (&clock->ABI.priv->pre_count); \
-} G_STMT_END;
-
-#define write_sequnlock(clock) \
-G_STMT_START { \
- g_atomic_int_inc (&clock->ABI.priv->post_count); \
- GST_OBJECT_UNLOCK (clock); \
-} G_STMT_END;
-
static void gst_clock_class_init (GstClockClass * klass);
static void gst_clock_init (GstClock * clock);
static void gst_clock_dispose (GObject * object);
@@ -192,19 +166,19 @@
{
GstClockEntry *entry;
- entry = g_slice_new (GstClockEntry);
+ entry = ALLOC_ENTRY ();
#ifndef GST_DISABLE_TRACE
gst_alloc_trace_new (_gst_clock_entry_trace, entry);
#endif
GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock,
"created entry %p, time %" GST_TIME_FORMAT, entry, GST_TIME_ARGS (time));
- entry->refcount = 1;
+ gst_atomic_int_set (&entry->refcount, 1);
entry->clock = clock;
entry->type = type;
entry->time = time;
entry->interval = interval;
- entry->status = GST_CLOCK_OK;
+ entry->status = GST_CLOCK_BUSY;
entry->func = NULL;
entry->user_data = NULL;
@@ -245,7 +219,7 @@
#ifndef GST_DISABLE_TRACE
gst_alloc_trace_free (_gst_clock_entry_trace, id);
#endif
- g_slice_free (GstClockEntry, id);
+ FREE_ENTRY (id);
}
/**
@@ -308,8 +282,8 @@
* @interval: the requested interval
*
* Get an ID from @clock to trigger a periodic notification.
- * The periodic notifications will start at time @start_time and
- * will then be fired with the given @interval. @id should be unreffed
+ * The periodeic notifications will be start at time start_time and
+ * will then be fired with the given interval. @id should be unreffed
* after usage.
*
* Returns: A #GstClockID that can be used to request the time notification.
@@ -391,14 +365,14 @@
/**
* gst_clock_id_wait
* @id: The #GstClockID to wait on
- * @jitter: A pointer that will contain the jitter, can be %NULL.
+ * @jitter: A pointer that will contain the jitter, can be NULL.
*
* 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().
*
- * If the @jitter argument is not %NULL and this function returns #GST_CLOCK_OK
+ * 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.
@@ -438,6 +412,10 @@
if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (requested)))
goto invalid_time;
+ /* a previously unscheduled entry cannot be scheduled again */
+ if (G_UNLIKELY (entry->status == GST_CLOCK_UNSCHEDULED))
+ goto unscheduled;
+
cclass = GST_CLOCK_GET_CLASS (clock);
GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "waiting on clock entry %p", id);
@@ -470,7 +448,7 @@
if (entry->type == GST_CLOCK_ENTRY_PERIODIC)
entry->time = requested + entry->interval;
- if (G_UNLIKELY (clock->stats))
+ if (clock->stats)
gst_clock_update_stats (clock);
return res;
@@ -482,6 +460,12 @@
"invalid time requested, returning _BADTIME");
return GST_CLOCK_BADTIME;
}
+unscheduled:
+ {
+ GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock,
+ "entry was unscheduled return _UNSCHEDULED");
+ return GST_CLOCK_UNSCHEDULED;
+ }
not_supported:
{
GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "clock wait is not supported");
@@ -493,17 +477,14 @@
* gst_clock_id_wait_async:
* @id: a #GstClockID to wait on
* @func: The callback function
- * @user_data: User data passed in the callback
+ * @user_data: User data passed in the calback
*
* Register a callback on the given #GstClockID @id with the given
* function and user_data. When passing a #GstClockID with an invalid
- * time to this function, the callback will be called immediately
+ * time to this function, the callback will be called immediatly
* with a time set to GST_CLOCK_TIME_NONE. The callback will
* be called when the time of @id has been reached.
*
- * The callback @func can be invoked from any thread, either provided by the
- * core or from a streaming thread. The application should be prepared for this.
- *
* Returns: the result of the non blocking wait.
*
* MT safe.
@@ -533,6 +514,10 @@
if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (requested)))
goto invalid_time;
+ /* a previously unscheduled entry cannot be scheduled again */
+ if (G_UNLIKELY (entry->status == GST_CLOCK_UNSCHEDULED))
+ goto unscheduled;
+
cclass = GST_CLOCK_GET_CLASS (clock);
if (G_UNLIKELY (cclass->wait_async == NULL))
@@ -553,6 +538,12 @@
"invalid time requested, returning _BADTIME");
return GST_CLOCK_BADTIME;
}
+unscheduled:
+ {
+ GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock,
+ "entry was unscheduled return _UNSCHEDULED");
+ return GST_CLOCK_UNSCHEDULED;
+ }
not_supported:
{
GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "clock wait is not supported");
@@ -594,18 +585,52 @@
}
-/*
+/**
* GstClock abstract base class implementation
*/
-G_DEFINE_TYPE (GstClock, gst_clock, GST_TYPE_OBJECT);
+#ifdef __SYMBIAN32__
+EXPORT_C
+#endif
+
+GType
+gst_clock_get_type (void)
+{
+ static GType clock_type = 0;
+
+ if (G_UNLIKELY (clock_type == 0)) {
+ static const GTypeInfo clock_info = {
+ sizeof (GstClockClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) gst_clock_class_init,
+ NULL,
+ NULL,
+ sizeof (GstClock),
+ 0,
+ (GInstanceInitFunc) gst_clock_init,
+ NULL
+ };
+
+ clock_type = g_type_register_static (GST_TYPE_OBJECT, "GstClock",
+ &clock_info, G_TYPE_FLAG_ABSTRACT);
+ }
+ return clock_type;
+}
static void
gst_clock_class_init (GstClockClass * klass)
{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GObjectClass *gobject_class;
+ GstObjectClass *gstobject_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ gstobject_class = GST_OBJECT_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
+ if (!g_thread_supported ())
+ g_thread_init (NULL);
+
#ifndef GST_DISABLE_TRACE
_gst_clock_entry_trace =
gst_alloc_trace_register (GST_CLOCK_ENTRY_TRACE_NAME);
@@ -619,23 +644,19 @@
g_object_class_install_property (gobject_class, PROP_STATS,
g_param_spec_boolean ("stats", "Stats",
"Enable clock stats (unimplemented)", DEFAULT_STATS,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_WINDOW_SIZE,
g_param_spec_int ("window-size", "Window size",
"The size of the window used to calculate rate and offset", 2, 1024,
- DEFAULT_WINDOW_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ DEFAULT_WINDOW_SIZE, G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_WINDOW_THRESHOLD,
g_param_spec_int ("window-threshold", "Window threshold",
"The threshold to start calculating rate and offset", 2, 1024,
- DEFAULT_WINDOW_THRESHOLD,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ DEFAULT_WINDOW_THRESHOLD, G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_TIMEOUT,
g_param_spec_uint64 ("timeout", "Timeout",
"The amount of time, in nanoseconds, to sample master and slave clocks",
- 0, G_MAXUINT64, DEFAULT_TIMEOUT,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- g_type_class_add_private (klass, sizeof (GstClockPrivate));
+ 0, G_MAXUINT64, DEFAULT_TIMEOUT, G_PARAM_READWRITE));
}
static void
@@ -646,9 +667,6 @@
clock->entries_changed = g_cond_new ();
clock->stats = FALSE;
- clock->ABI.priv =
- G_TYPE_INSTANCE_GET_PRIVATE (clock, GST_TYPE_CLOCK, GstClockPrivate);
-
clock->internal_calibration = 0;
clock->external_calibration = 0;
clock->rate_numerator = 1;
@@ -772,7 +790,7 @@
* that the returned time is increasing. This function should be called with the
* clock's OBJECT_LOCK held and is mainly used by clock subclasses.
*
- * This function is the reverse of gst_clock_unadjust_unlocked().
+ * This function is te reverse of gst_clock_unadjust_unlocked().
*
* Returns: the converted time of the clock.
*/
@@ -792,24 +810,22 @@
cdenom = clock->rate_denominator;
/* avoid divide by 0 */
- if (G_UNLIKELY (cdenom == 0))
+ if (cdenom == 0)
cnum = cdenom = 1;
/* The formula is (internal - cinternal) * cnum / cdenom + cexternal
*
* Since we do math on unsigned 64-bit ints we have to special case for
- * internal < cinternal to get the sign right. this case is not very common,
+ * interal < cinternal to get the sign right. this case is not very common,
* though.
*/
if (G_LIKELY (internal >= cinternal)) {
- ret = internal - cinternal;
- ret = gst_util_uint64_scale (ret, cnum, cdenom);
+ ret = gst_util_uint64_scale (internal - cinternal, cnum, cdenom);
ret += cexternal;
} else {
- ret = cinternal - internal;
- ret = gst_util_uint64_scale (ret, cnum, cdenom);
+ ret = gst_util_uint64_scale (cinternal - internal, cnum, cdenom);
/* clamp to 0 */
- if (G_LIKELY (cexternal > ret))
+ if (cexternal > ret)
ret = cexternal - ret;
else
ret = 0;
@@ -831,7 +847,7 @@
* This function should be called with the clock's OBJECT_LOCK held and
* is mainly used by clock subclasses.
*
- * This function is the reverse of gst_clock_adjust_unlocked().
+ * This function is te reverse of gst_clock_adjust_unlocked().
*
* Returns: the internal time of the clock corresponding to @external.
*
@@ -853,18 +869,16 @@
cdenom = clock->rate_denominator;
/* avoid divide by 0 */
- if (G_UNLIKELY (cnum == 0))
+ if (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);
+ if (external >= cexternal) {
+ ret = gst_util_uint64_scale (external - cexternal, cdenom, cnum);
ret += cinternal;
} else {
- ret = cexternal - external;
- ret = gst_util_uint64_scale (ret, cdenom, cnum);
- if (G_LIKELY (cinternal > ret))
+ ret = gst_util_uint64_scale (cexternal - external, cdenom, cnum);
+ if (cinternal > ret)
ret = cinternal - ret;
else
ret = 0;
@@ -880,7 +894,7 @@
* unadjusted for the offset and the rate.
*
* Returns: the internal time of the clock. Or GST_CLOCK_TIME_NONE when
- * given invalid input.
+ * giving wrong input.
*
* MT safe.
*/
@@ -926,7 +940,7 @@
* offset and rate.
*
* Returns: the time of the clock. Or GST_CLOCK_TIME_NONE when
- * given invalid input.
+ * giving wrong input.
*
* MT safe.
*/
@@ -938,19 +952,15 @@
gst_clock_get_time (GstClock * clock)
{
GstClockTime ret;
- gint seq;
g_return_val_if_fail (GST_IS_CLOCK (clock), GST_CLOCK_TIME_NONE);
- do {
- /* reget the internal time when we retry to get the most current
- * timevalue */
- ret = gst_clock_get_internal_time (clock);
+ ret = gst_clock_get_internal_time (clock);
- seq = read_seqbegin (clock);
- /* this will scale for rate and offset */
- ret = gst_clock_adjust_unlocked (clock, ret);
- } while (read_seqretry (clock, seq));
+ GST_OBJECT_LOCK (clock);
+ /* this will scale for rate and offset */
+ ret = gst_clock_adjust_unlocked (clock, ret);
+ GST_OBJECT_UNLOCK (clock);
GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "adjusted time %" GST_TIME_FORMAT,
GST_TIME_ARGS (ret));
@@ -979,7 +989,7 @@
* follows:
*
* <programlisting>
- * time = (internal_time - internal) * rate_num / rate_denom + external
+ * time = (internal_time - @internal) * @rate_num / @rate_denom + @external
* </programlisting>
*
* This formula is implemented in gst_clock_adjust_unlocked(). Of course, it
@@ -1000,21 +1010,22 @@
external, GstClockTime rate_num, GstClockTime rate_denom)
{
g_return_if_fail (GST_IS_CLOCK (clock));
- g_return_if_fail (rate_num != GST_CLOCK_TIME_NONE);
- g_return_if_fail (rate_denom > 0 && rate_denom != GST_CLOCK_TIME_NONE);
+ g_return_if_fail (rate_num >= 0);
+ g_return_if_fail (rate_denom > 0);
+ g_return_if_fail (internal <= gst_clock_get_internal_time (clock));
- write_seqlock (clock);
+ GST_OBJECT_LOCK (clock);
GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock,
"internal %" GST_TIME_FORMAT " external %" GST_TIME_FORMAT " %"
G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT " = %f", GST_TIME_ARGS (internal),
GST_TIME_ARGS (external), rate_num, rate_denom,
- gst_guint64_to_gdouble (rate_num) / gst_guint64_to_gdouble (rate_denom));
+ gst_guint64_to_gdouble (rate_num / rate_denom));
clock->internal_calibration = internal;
clock->external_calibration = external;
clock->rate_numerator = rate_num;
clock->rate_denominator = rate_denom;
- write_sequnlock (clock);
+ GST_OBJECT_UNLOCK (clock);
}
/**
@@ -1028,7 +1039,7 @@
* Gets the internal rate and reference time of @clock. See
* gst_clock_set_calibration() for more information.
*
- * @internal, @external, @rate_num, and @rate_denom can be left %NULL if the
+ * @internal, @external, @rate_num, and @rate_denom can be left NULL if the
* caller is not interested in the values.
*
* MT safe.
@@ -1041,24 +1052,21 @@
gst_clock_get_calibration (GstClock * clock, GstClockTime * internal,
GstClockTime * external, GstClockTime * rate_num, GstClockTime * rate_denom)
{
- gint seq;
-
g_return_if_fail (GST_IS_CLOCK (clock));
- do {
- seq = read_seqbegin (clock);
- if (rate_num)
- *rate_num = clock->rate_numerator;
- if (rate_denom)
- *rate_denom = clock->rate_denominator;
- if (external)
- *external = clock->external_calibration;
- if (internal)
- *internal = clock->internal_calibration;
- } while (read_seqretry (clock, seq));
+ GST_OBJECT_LOCK (clock);
+ if (rate_num)
+ *rate_num = clock->rate_numerator;
+ if (rate_denom)
+ *rate_denom = clock->rate_denominator;
+ if (external)
+ *external = clock->external_calibration;
+ if (internal)
+ *internal = clock->internal_calibration;
+ GST_OBJECT_UNLOCK (clock);
}
-/* will be called repeatedly to sample the master and slave clock
+/* will be called repeadedly to sample the master and slave clock
* to recalibrate the clock */
static gboolean
gst_clock_slave_callback (GstClock * master, GstClockTime time,
@@ -1094,13 +1102,13 @@
* 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
+ * @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
* and time offsets.
*
- * Returns: %TRUE if the clock is capable of being slaved to a master clock.
+ * 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.
+ * GST_CLOCK_FLAG_CAN_SET_MASTER flag will make this function return FALSE.
*
* MT safe.
*/
@@ -1161,11 +1169,11 @@
* gst_clock_get_master
* @clock: a #GstClock
*
- * Get the master clock that @clock is slaved to or %NULL when the clock is
+ * Get the master clock that @clock is slaved to or NULL when the clock is
* not slaved to any master clock.
*
- * Returns: a master #GstClock or %NULL when this clock is not slaved to a
- * master clock. Unref after usage.
+ * Returns: a master #GstClock or NULL when this clock is not slaved to a master
+ * clock. Unref after usage.
*
* MT safe.
*/
@@ -1324,12 +1332,12 @@
* observations and @clock is recalibrated.
*
* If this functions returns %TRUE, @r_squared will contain the
- * correlation coefficient of the interpolation. A value of 1.0
+ * correlation coefficient of the interpollation. 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.
@@ -1349,10 +1357,6 @@
GST_CLOCK_SLAVE_LOCK (clock);
- GST_CAT_LOG_OBJECT (GST_CAT_CLOCK, clock,
- "adding observation slave %" GST_TIME_FORMAT ", master %" GST_TIME_FORMAT,
- GST_TIME_ARGS (slave), GST_TIME_ARGS (master));
-
clock->times[(4 * clock->time_index)] = slave;
clock->times[(4 * clock->time_index) + 2] = master;