Commit eb84682e authored by Wim Taymans's avatar Wim Taymans

clock: make more stuff private

Expose methods to get and set the timeout because subclasses uses this.
parent 8909205b
......@@ -131,8 +131,35 @@ enum
PROP_TIMEOUT
};
#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)
struct _GstClockPrivate
{
GMutex slave_lock; /* order: SLAVE_LOCK, OBJECT_LOCK */
/* with LOCK */
GstClockTime internal_calibration;
GstClockTime external_calibration;
GstClockTime rate_numerator;
GstClockTime rate_denominator;
GstClockTime last_time;
/* with LOCK */
GstClockTime resolution;
/* for master/slave clocks */
GstClock *master;
/* with SLAVE_LOCK */
gboolean filling;
gint window_size;
gint window_threshold;
gint time_index;
GstClockTime timeout;
GstClockTime *times;
GstClockID clockid;
gint pre_count;
gint post_count;
};
......@@ -679,25 +706,25 @@ gst_clock_class_init (GstClockClass * klass)
static void
gst_clock_init (GstClock * clock)
{
clock->last_time = 0;
clock->entries = NULL;
g_cond_init (&clock->entries_changed);
GstClockPrivate *priv;
clock->priv =
clock->priv = priv =
G_TYPE_INSTANCE_GET_PRIVATE (clock, GST_TYPE_CLOCK, GstClockPrivate);
clock->internal_calibration = 0;
clock->external_calibration = 0;
clock->rate_numerator = 1;
clock->rate_denominator = 1;
g_mutex_init (&clock->slave_lock);
clock->window_size = DEFAULT_WINDOW_SIZE;
clock->window_threshold = DEFAULT_WINDOW_THRESHOLD;
clock->filling = TRUE;
clock->time_index = 0;
clock->timeout = DEFAULT_TIMEOUT;
clock->times = g_new0 (GstClockTime, 4 * clock->window_size);
priv->last_time = 0;
priv->internal_calibration = 0;
priv->external_calibration = 0;
priv->rate_numerator = 1;
priv->rate_denominator = 1;
g_mutex_init (&priv->slave_lock);
priv->window_size = DEFAULT_WINDOW_SIZE;
priv->window_threshold = DEFAULT_WINDOW_THRESHOLD;
priv->filling = TRUE;
priv->time_index = 0;
priv->timeout = DEFAULT_TIMEOUT;
priv->times = g_new0 (GstClockTime, 4 * priv->window_size);
}
static void
......@@ -707,7 +734,7 @@ gst_clock_dispose (GObject * object)
GstClock **master_p;
GST_OBJECT_LOCK (clock);
master_p = &clock->master;
master_p = &clock->priv->master;
gst_object_replace ((GstObject **) master_p, NULL);
GST_OBJECT_UNLOCK (clock);
......@@ -720,17 +747,16 @@ gst_clock_finalize (GObject * object)
GstClock *clock = GST_CLOCK (object);
GST_CLOCK_SLAVE_LOCK (clock);
if (clock->clockid) {
gst_clock_id_unschedule (clock->clockid);
gst_clock_id_unref (clock->clockid);
clock->clockid = NULL;
if (clock->priv->clockid) {
gst_clock_id_unschedule (clock->priv->clockid);
gst_clock_id_unref (clock->priv->clockid);
clock->priv->clockid = NULL;
}
g_free (clock->times);
clock->times = NULL;
g_free (clock->priv->times);
clock->priv->times = NULL;
GST_CLOCK_SLAVE_UNLOCK (clock);
g_cond_clear (&clock->entries_changed);
g_mutex_clear (&clock->slave_lock);
g_mutex_clear (&clock->priv->slave_lock);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
......@@ -751,18 +777,20 @@ gst_clock_finalize (GObject * object)
GstClockTime
gst_clock_set_resolution (GstClock * clock, GstClockTime resolution)
{
GstClockPrivate *priv;
GstClockClass *cclass;
g_return_val_if_fail (GST_IS_CLOCK (clock), 0);
g_return_val_if_fail (resolution != 0, 0);
cclass = GST_CLOCK_GET_CLASS (clock);
priv = clock->priv;
if (cclass->change_resolution)
clock->resolution =
cclass->change_resolution (clock, clock->resolution, resolution);
priv->resolution =
cclass->change_resolution (clock, priv->resolution, resolution);
return clock->resolution;
return priv->resolution;
}
/**
......@@ -809,12 +837,13 @@ GstClockTime
gst_clock_adjust_unlocked (GstClock * clock, GstClockTime internal)
{
GstClockTime ret, cinternal, cexternal, cnum, cdenom;
GstClockPrivate *priv = clock->priv;
/* get calibration values for readability */
cinternal = clock->internal_calibration;
cexternal = clock->external_calibration;
cnum = clock->rate_numerator;
cdenom = clock->rate_denominator;
cinternal = priv->internal_calibration;
cexternal = priv->external_calibration;
cnum = priv->rate_numerator;
cdenom = priv->rate_denominator;
/* avoid divide by 0 */
if (G_UNLIKELY (cdenom == 0))
......@@ -841,9 +870,9 @@ gst_clock_adjust_unlocked (GstClock * clock, GstClockTime internal)
}
/* make sure the time is increasing */
clock->last_time = MAX (ret, clock->last_time);
priv->last_time = MAX (ret, priv->last_time);
return clock->last_time;
return priv->last_time;
}
/**
......@@ -866,12 +895,13 @@ GstClockTime
gst_clock_unadjust_unlocked (GstClock * clock, GstClockTime external)
{
GstClockTime ret, cinternal, cexternal, cnum, cdenom;
GstClockPrivate *priv = clock->priv;
/* get calibration values for readability */
cinternal = clock->internal_calibration;
cexternal = clock->external_calibration;
cnum = clock->rate_numerator;
cdenom = clock->rate_denominator;
cinternal = priv->internal_calibration;
cexternal = priv->external_calibration;
cnum = priv->rate_numerator;
cdenom = priv->rate_denominator;
/* avoid divide by 0 */
if (G_UNLIKELY (cnum == 0))
......@@ -1008,10 +1038,14 @@ void
gst_clock_set_calibration (GstClock * clock, GstClockTime internal, GstClockTime
external, GstClockTime rate_num, GstClockTime rate_denom)
{
GstClockPrivate *priv;
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);
priv = clock->priv;
write_seqlock (clock);
GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock,
"internal %" GST_TIME_FORMAT " external %" GST_TIME_FORMAT " %"
......@@ -1019,10 +1053,10 @@ gst_clock_set_calibration (GstClock * clock, GstClockTime internal, GstClockTime
GST_TIME_ARGS (external), rate_num, rate_denom,
gst_guint64_to_gdouble (rate_num) / gst_guint64_to_gdouble (rate_denom));
clock->internal_calibration = internal;
clock->external_calibration = external;
clock->rate_numerator = rate_num;
clock->rate_denominator = rate_denom;
priv->internal_calibration = internal;
priv->external_calibration = external;
priv->rate_numerator = rate_num;
priv->rate_denominator = rate_denom;
write_sequnlock (clock);
}
......@@ -1047,19 +1081,22 @@ gst_clock_get_calibration (GstClock * clock, GstClockTime * internal,
GstClockTime * external, GstClockTime * rate_num, GstClockTime * rate_denom)
{
gint seq;
GstClockPrivate *priv;
g_return_if_fail (GST_IS_CLOCK (clock));
priv = clock->priv;
do {
seq = read_seqbegin (clock);
if (rate_num)
*rate_num = clock->rate_numerator;
*rate_num = priv->rate_numerator;
if (rate_denom)
*rate_denom = clock->rate_denominator;
*rate_denom = priv->rate_denominator;
if (external)
*external = clock->external_calibration;
*external = priv->external_calibration;
if (internal)
*internal = clock->internal_calibration;
*internal = priv->internal_calibration;
} while (read_seqretry (clock, seq));
}
......@@ -1113,6 +1150,7 @@ gboolean
gst_clock_set_master (GstClock * clock, GstClock * master)
{
GstClock **master_p;
GstClockPrivate *priv;
g_return_val_if_fail (GST_IS_CLOCK (clock), FALSE);
g_return_val_if_fail (master != clock, FALSE);
......@@ -1125,27 +1163,29 @@ gst_clock_set_master (GstClock * clock, GstClock * master)
"slaving %p to master clock %p", clock, master);
GST_OBJECT_UNLOCK (clock);
priv = clock->priv;
GST_CLOCK_SLAVE_LOCK (clock);
if (clock->clockid) {
gst_clock_id_unschedule (clock->clockid);
gst_clock_id_unref (clock->clockid);
clock->clockid = NULL;
if (priv->clockid) {
gst_clock_id_unschedule (priv->clockid);
gst_clock_id_unref (priv->clockid);
priv->clockid = NULL;
}
if (master) {
clock->filling = TRUE;
clock->time_index = 0;
priv->filling = TRUE;
priv->time_index = 0;
/* use the master periodic id to schedule sampling and
* clock calibration. */
clock->clockid = gst_clock_new_periodic_id (master,
gst_clock_get_time (master), clock->timeout);
gst_clock_id_wait_async_full (clock->clockid,
priv->clockid = gst_clock_new_periodic_id (master,
gst_clock_get_time (master), priv->timeout);
gst_clock_id_wait_async_full (priv->clockid,
(GstClockCallback) gst_clock_slave_callback,
gst_object_ref (clock), (GDestroyNotify) gst_object_unref);
}
GST_CLOCK_SLAVE_UNLOCK (clock);
GST_OBJECT_LOCK (clock);
master_p = &clock->master;
master_p = &priv->master;
gst_object_replace ((GstObject **) master_p, (GstObject *) master);
GST_OBJECT_UNLOCK (clock);
......@@ -1177,12 +1217,15 @@ GstClock *
gst_clock_get_master (GstClock * clock)
{
GstClock *result = NULL;
GstClockPrivate *priv;
g_return_val_if_fail (GST_IS_CLOCK (clock), NULL);
priv = clock->priv;
GST_OBJECT_LOCK (clock);
if (clock->master)
result = gst_object_ref (clock->master);
if (priv->master)
result = gst_object_ref (priv->master);
GST_OBJECT_UNLOCK (clock);
return result;
......@@ -1202,12 +1245,15 @@ do_linear_regression (GstClock * clock, GstClockTime * m_num,
GstClockTime *x, *y;
gint i, j;
guint n;
GstClockPrivate *priv;
xbar = ybar = sxx = syy = sxy = 0;
x = clock->times;
y = clock->times + 2;
n = clock->filling ? clock->time_index : clock->window_size;
priv = clock->priv;
x = priv->times;
y = priv->times + 2;
n = priv->filling ? priv->time_index : priv->window_size;
#ifdef DEBUGGING_ENABLED
GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "doing regression on:");
......@@ -1229,8 +1275,8 @@ do_linear_regression (GstClock * clock, GstClockTime * m_num,
ymin);
#endif
newx = clock->times + 1;
newy = clock->times + 3;
newx = priv->times + 1;
newy = priv->times + 3;
/* strip off unnecessary bits of precision */
for (i = j = 0; i < n; i++, j += 4) {
......@@ -1339,27 +1385,29 @@ gst_clock_add_observation (GstClock * clock, GstClockTime slave,
GstClockTime master, gdouble * r_squared)
{
GstClockTime m_num, m_denom, b, xbase;
GstClockPrivate *priv;
g_return_val_if_fail (GST_IS_CLOCK (clock), FALSE);
g_return_val_if_fail (r_squared != NULL, FALSE);
priv = clock->priv;
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;
priv->times[(4 * priv->time_index)] = slave;
priv->times[(4 * priv->time_index) + 2] = master;
clock->time_index++;
if (G_UNLIKELY (clock->time_index == clock->window_size)) {
clock->filling = FALSE;
clock->time_index = 0;
priv->time_index++;
if (G_UNLIKELY (priv->time_index == priv->window_size)) {
priv->filling = FALSE;
priv->time_index = 0;
}
if (G_UNLIKELY (clock->filling
&& clock->time_index < clock->window_threshold))
if (G_UNLIKELY (priv->filling && priv->time_index < priv->window_threshold))
goto filling;
if (!do_linear_regression (clock, &m_num, &m_denom, &b, &xbase, r_squared))
......@@ -1389,36 +1437,47 @@ invalid:
}
}
void
gst_clock_set_timeout (GstClock * clock, GstClockTime timeout)
{
clock->priv->timeout = timeout;
}
GstClockTime
gst_clock_get_timeout (GstClock * clock)
{
return clock->priv->timeout;
}
static void
gst_clock_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstClock *clock;
GstClockPrivate *priv;
clock = GST_CLOCK (object);
priv = clock->priv;
switch (prop_id) {
case PROP_WINDOW_SIZE:
GST_CLOCK_SLAVE_LOCK (clock);
clock->window_size = g_value_get_int (value);
clock->window_threshold =
MIN (clock->window_threshold, clock->window_size);
clock->times =
g_renew (GstClockTime, clock->times, 4 * clock->window_size);
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);
/* restart calibration */
clock->filling = TRUE;
clock->time_index = 0;
priv->filling = TRUE;
priv->time_index = 0;
GST_CLOCK_SLAVE_UNLOCK (clock);
break;
case PROP_WINDOW_THRESHOLD:
GST_CLOCK_SLAVE_LOCK (clock);
clock->window_threshold =
MIN (g_value_get_int (value), clock->window_size);
priv->window_threshold = MIN (g_value_get_int (value), priv->window_size);
GST_CLOCK_SLAVE_UNLOCK (clock);
break;
case PROP_TIMEOUT:
GST_CLOCK_SLAVE_LOCK (clock);
clock->timeout = g_value_get_uint64 (value);
priv->timeout = g_value_get_uint64 (value);
GST_CLOCK_SLAVE_UNLOCK (clock);
break;
default:
......@@ -1432,23 +1491,25 @@ gst_clock_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstClock *clock;
GstClockPrivate *priv;
clock = GST_CLOCK (object);
priv = clock->priv;
switch (prop_id) {
case PROP_WINDOW_SIZE:
GST_CLOCK_SLAVE_LOCK (clock);
g_value_set_int (value, clock->window_size);
g_value_set_int (value, priv->window_size);
GST_CLOCK_SLAVE_UNLOCK (clock);
break;
case PROP_WINDOW_THRESHOLD:
GST_CLOCK_SLAVE_LOCK (clock);
g_value_set_int (value, clock->window_threshold);
g_value_set_int (value, priv->window_threshold);
GST_CLOCK_SLAVE_UNLOCK (clock);
break;
case PROP_TIMEOUT:
GST_CLOCK_SLAVE_LOCK (clock);
g_value_set_uint64 (value, clock->timeout);
g_value_set_uint64 (value, priv->timeout);
GST_CLOCK_SLAVE_UNLOCK (clock);
break;
default:
......
......@@ -35,9 +35,6 @@ G_BEGIN_DECLS
#define GST_CLOCK_GET_CLASS(clock) (G_TYPE_INSTANCE_GET_CLASS ((clock), GST_TYPE_CLOCK, GstClockClass))
#define GST_CLOCK_CAST(clock) ((GstClock*)(clock))
#define GST_CLOCK_SLAVE_LOCK(clock) g_mutex_lock (&GST_CLOCK_CAST (clock)->slave_lock)
#define GST_CLOCK_SLAVE_UNLOCK(clock) g_mutex_unlock (&GST_CLOCK_CAST (clock)->slave_lock)
/**
* GstClockTime:
*
......@@ -401,38 +398,6 @@ typedef enum {
*/
#define GST_CLOCK_FLAGS(clock) GST_OBJECT_FLAGS(clock)
/**
* GST_CLOCK_GET_COND:
* @clock: the clock to query
*
* Gets the #GCond that gets signalled when the entries of the clock
* changed.
*/
#define GST_CLOCK_GET_COND(clock) (&GST_CLOCK_CAST(clock)->entries_changed)
/**
* GST_CLOCK_WAIT:
* @clock: the clock to wait on
*
* Wait on the clock until the entries changed.
*/
#define GST_CLOCK_WAIT(clock) g_cond_wait(GST_CLOCK_GET_COND(clock),GST_OBJECT_GET_LOCK(clock))
/**
* GST_CLOCK_TIMED_WAIT:
* @clock: the clock to wait on
* @tv: a #GTimeVal to wait.
*
* Wait on the clock until the entries changed or the specified timeout
* occurred.
*/
#define GST_CLOCK_TIMED_WAIT(clock,tv) g_cond_timed_wait(GST_CLOCK_GET_COND(clock),GST_OBJECT_GET_LOCK(clock),tv)
/**
* GST_CLOCK_BROADCAST:
* @clock: the clock to broadcast
*
* Signal that the entries in the clock have changed.
*/
#define GST_CLOCK_BROADCAST(clock) g_cond_broadcast(GST_CLOCK_GET_COND(clock))
/**
* GstClock:
*
......@@ -442,32 +407,6 @@ typedef enum {
struct _GstClock {
GstObject object;
GMutex slave_lock; /* order: SLAVE_LOCK, OBJECT_LOCK */
/*< protected >*/ /* with LOCK */
GstClockTime internal_calibration;
GstClockTime external_calibration;
GstClockTime rate_numerator;
GstClockTime rate_denominator;
GstClockTime last_time;
GList *entries;
GCond entries_changed;
/*< private >*/ /* with LOCK */
GstClockTime resolution;
/* for master/slave clocks */
GstClock *master;
/* with SLAVE_LOCK */
gboolean filling;
gint window_size;
gint window_threshold;
gint time_index;
GstClockTime timeout;
GstClockTime *times;
GstClockID clockid;
/*< private >*/
GstClockPrivate *priv;
......@@ -531,6 +470,11 @@ void gst_clock_get_calibration (GstClock *clock, GstClo
/* master/slave clocks */
gboolean gst_clock_set_master (GstClock *clock, GstClock *master);
GstClock* gst_clock_get_master (GstClock *clock);
void gst_clock_set_timeout (GstClock *clock,
GstClockTime timeout);
GstClockTime gst_clock_get_timeout (GstClock *clock);
gboolean gst_clock_add_observation (GstClock *clock, GstClockTime slave,
GstClockTime master, gdouble *r_squared);
......
......@@ -63,11 +63,18 @@
/* Define this to get some extra debug about jitter from each clock_wait */
#undef WAIT_DEBUGGING
#define GST_SYSTEM_CLOCK_GET_COND(clock) (&GST_SYSTEM_CLOCK_CAST(clock)->priv->entries_changed)
#define GST_SYSTEM_CLOCK_WAIT(clock) g_cond_wait(GST_SYSTEM_CLOCK_GET_COND(clock),GST_OBJECT_GET_LOCK(clock))
#define GST_SYSTEM_CLOCK_TIMED_WAIT(clock,tv) g_cond_timed_wait(GST_SYSTEM_CLOCK_GET_COND(clock),GST_OBJECT_GET_LOCK(clock),tv)
#define GST_SYSTEM_CLOCK_BROADCAST(clock) g_cond_broadcast(GST_SYSTEM_CLOCK_GET_COND(clock))
struct _GstSystemClockPrivate
{
GThread *thread; /* thread for async notify */
gboolean stopping;
GList *entries;
GCond entries_changed;
GstClockType clock_type;
GstPoll *timer;
......@@ -163,23 +170,28 @@ gst_system_clock_class_init (GstSystemClockClass * klass)
static void
gst_system_clock_init (GstSystemClock * clock)
{
GstSystemClockPrivate *priv;
GST_OBJECT_FLAG_SET (clock,
GST_CLOCK_FLAG_CAN_DO_SINGLE_SYNC |
GST_CLOCK_FLAG_CAN_DO_SINGLE_ASYNC |
GST_CLOCK_FLAG_CAN_DO_PERIODIC_SYNC |
GST_CLOCK_FLAG_CAN_DO_PERIODIC_ASYNC);
clock->priv = GST_SYSTEM_CLOCK_GET_PRIVATE (clock);
clock->priv = priv = GST_SYSTEM_CLOCK_GET_PRIVATE (clock);
priv->clock_type = DEFAULT_CLOCK_TYPE;
priv->timer = gst_poll_new_timer ();
clock->priv->clock_type = DEFAULT_CLOCK_TYPE;
clock->priv->timer = gst_poll_new_timer ();
priv->entries = NULL;
g_cond_init (&priv->entries_changed);
#ifdef G_OS_WIN32
QueryPerformanceFrequency (&clock->priv->frequency);
QueryPerformanceFrequency (&priv->frequency);
/* can be 0 if the hardware does not have hardware support */
if (clock->priv->frequency.QuadPart != 0)
if (priv->frequency.QuadPart != 0)
/* we take a base time so that time starts from 0 to ease debugging */
QueryPerformanceCounter (&clock->priv->start);
QueryPerformanceCounter (&priv->start);
#endif /* G_OS_WIN32 */
#if 0
......@@ -195,32 +207,34 @@ gst_system_clock_dispose (GObject * object)
{
GstClock *clock = (GstClock *) object;
GstSystemClock *sysclock = GST_SYSTEM_CLOCK_CAST (clock);
GstSystemClockPrivate *priv = sysclock->priv;
GList *entries;
/* else we have to stop the thread */
GST_OBJECT_LOCK (clock);
sysclock->priv->stopping = TRUE;
priv->stopping = TRUE;
/* unschedule all entries */
for (entries = clock->entries; entries; entries = g_list_next (entries)) {
for (entries = priv->entries; entries; entries = g_list_next (entries)) {
GstClockEntry *entry = (GstClockEntry *) entries->data;
GST_CAT_DEBUG (GST_CAT_CLOCK, "unscheduling entry %p", entry);
SET_ENTRY_STATUS (entry, GST_CLOCK_UNSCHEDULED);
}
GST_CLOCK_BROADCAST (clock);
GST_SYSTEM_CLOCK_BROADCAST (clock);
gst_system_clock_add_wakeup (sysclock);
GST_OBJECT_UNLOCK (clock);
if (sysclock->priv->thread)
g_thread_join (sysclock->priv->thread);
sysclock->priv->thread = NULL;
if (priv->thread)
g_thread_join (priv->thread);
priv->thread = NULL;
GST_CAT_DEBUG (GST_CAT_CLOCK, "joined thread");
g_list_foreach (clock->entries, (GFunc) gst_clock_id_unref, NULL);
g_list_free (clock->entries);
clock->entries = NULL;
g_list_foreach (priv->entries, (GFunc) gst_clock_id_unref, NULL);
g_list_free (priv->entries);
priv->entries = NULL;
gst_poll_free (sysclock->priv->timer);
gst_poll_free (priv->timer);
g_cond_clear (&priv->entries_changed);
G_OBJECT_CLASS (parent_class)->dispose (object);
......@@ -316,7 +330,7 @@ gst_system_clock_remove_wakeup (GstSystemClock * sysclock)
while (!gst_poll_read_control (sysclock->priv->timer)) {
g_warning ("gstsystemclock: read control failed, trying again\n");
}
GST_CLOCK_BROADCAST (sysclock);
GST_SYSTEM_CLOCK_BROADCAST (sysclock);
}