gst/net/gstnetclientclock.c (do_linear_regression): Use all integer arithmetic. Return the minimum of the domain, whi...

Original commit message from CVS:
2005-11-18  Andy Wingo  <wingo@pobox.com>

* gst/net/gstnetclientclock.c (do_linear_regression): Use all
integer arithmetic. Return the minimum of the domain, which can be
set as "internal" for gst_clock_set_calibration.
(gst_net_client_clock_observe_times): Call _set_calibration.
(gst_net_client_clock_new): Call _set_calibration instead of
rate_offset.

* check/net/gstnetclientclock.c (test_functioning): Use the right
adjustment api.

* gst/gstclock.h:
* gst/gstclock.c (gst_clock_get_calibration)
(gst_clock_set_calibration): New functions, obsolete the ones I
added yesterday. Doh. Precision issues mean we have to extrapolate
from a point in the more recent past than 1970.
(gst_clock_get_rate_offset, gst_clock_set_rate_offset): Mark as
obsolete.
(gst_clock_adjust_unlocked): Use the right calibration data.
This commit is contained in:
Andy Wingo 2005-11-18 15:30:18 +00:00
parent d32702193e
commit fa09daa3d2
7 changed files with 156 additions and 126 deletions

View file

@ -1,3 +1,24 @@
2005-11-18 Andy Wingo <wingo@pobox.com>
* gst/net/gstnetclientclock.c (do_linear_regression): Use all
integer arithmetic. Return the minimum of the domain, which can be
set as "internal" for gst_clock_set_calibration.
(gst_net_client_clock_observe_times): Call _set_calibration.
(gst_net_client_clock_new): Call _set_calibration instead of
rate_offset.
* check/net/gstnetclientclock.c (test_functioning): Use the right
adjustment api.
* gst/gstclock.h:
* gst/gstclock.c (gst_clock_get_calibration)
(gst_clock_set_calibration): New functions, obsolete the ones I
added yesterday. Doh. Precision issues mean we have to extrapolate
from a point in the more recent past than 1970.
(gst_clock_get_rate_offset, gst_clock_set_rate_offset): Mark as
obsolete.
(gst_clock_adjust_unlocked): Use the right calibration data.
2005-11-18 Edward Hervey <edward@fluendo.com>
* gst/base/gstbasesink.c: (gst_base_sink_change_state):

View file

@ -50,7 +50,7 @@ GST_START_TEST (test_functioning)
{
GstNetTimeProvider *ntp;
GstClock *client, *server;
GstClockTimeDiff offset;
GstClockTime basex, basey;
GstClockTime servint; //, servtime, localtime;
gint port;
gdouble rate;
@ -59,9 +59,9 @@ GST_START_TEST (test_functioning)
fail_unless (server != NULL, "failed to get system clock");
/* move the clock ahead 100 seconds */
gst_clock_get_rate_offset (server, &rate, &offset);
offset += 100 * GST_SECOND;
gst_clock_set_rate_offset (server, rate, offset);
gst_clock_get_calibration (server, &basex, &basey, &rate);
basey += 100 * GST_SECOND;
gst_clock_set_calibration (server, basex, basey, rate);
servint = gst_clock_get_internal_time (GST_CLOCK (server));
ntp = gst_net_time_provider_new (server, "127.0.0.1", 0);

View file

@ -604,9 +604,9 @@ gst_clock_get_resolution (GstClock * clock)
* @internal: a clock time
*
* Converts the given @internal clock time to the real time, adjusting for the
* rate and offset set with gst_clock_set_rate_offset() and making sure that the
* returned time is increasing. This function should be called with the clock
* LOCK held and is mainly used by clock subclasses.
* rate and reference time set with gst_clock_set_calibration() and making sure
* that the returned time is increasing. This function should be called with the
* clock LOCK held and is mainly used by clock subclasses.
*
* Returns: the converted time of the clock.
*
@ -617,25 +617,8 @@ gst_clock_adjust_unlocked (GstClock * clock, GstClockTime internal)
{
GstClockTime ret;
/* internal is uint64, rate is double, offset is int64, ret is uint64 */
ret = internal * clock->A.rate;
if (clock->A.offset < 0) {
if ((clock->A.offset == G_MININT64 && ret <= G_MAXINT64)
|| (clock->A.offset + ((gint64) ret) < 0))
/* underflow */
ret = 0;
else
ret -= (guint64) (-clock->A.offset);
} else {
if (clock->A.offset > 0 && ret >= G_MAXINT64
&& G_MAXUINT64 - ret - 1 <= clock->A.offset)
/* overflow, but avoiding CLOCK_TIME_NONE which is MAXUINT64 */
ret = G_MAXUINT64 - 1;
else
ret += (guint64) clock->A.offset;
}
ret = (internal - clock->adjust) * clock->A.rate;
ret += clock->A.offset;
/* make sure the time is increasing */
clock->last_time = MAX (ret, clock->last_time);
@ -734,21 +717,7 @@ gst_clock_set_time_adjust (GstClock * clock, GstClockTime adjust)
* @rate: the new rate
* @offset: the "initial" offset of @clock relative to its internal time
*
* Adjusts the internal rate and offset of @clock.
*
* A @rate of 1.0 is the normal speed of the clock. Values bigger than 1.0 make
* the clock go faster. @rate must be positive.
*
* Subsequent calls to gst_clock_get_time() will return clock times computed as
* follows:
*
* <programlisting>
* time = internal_time * @rate + @offset
* </programlisting>
*
* Note that gst_clock_get_time() always returns increasing values so when you
* move the clock backwards, gst_clock_get_time() will report the previous value
* until the clock catches up.
* Adjusts the internal rate and offset of @clock. Obsolete, do not use.
*
* MT safe.
*/
@ -771,12 +740,9 @@ gst_clock_set_rate_offset (GstClock * clock, gdouble rate,
* @rate: a location to store the rate
* @offset: a location to store the offset
*
* Gets the internal rate and offset of @clock. The rate and offset are relative
* to the clock's internal time.
* Obsolete, do not use.
*
* MT safe.
*
* See also: gst_clock_set_rate_offset().
*/
void
gst_clock_get_rate_offset (GstClock * clock, gdouble * rate,
@ -792,6 +758,79 @@ gst_clock_get_rate_offset (GstClock * clock, gdouble * rate,
GST_UNLOCK (clock);
}
/**
* gst_clock_set_calibration
* @clock: a #GstClock to calibrate
* @internal: a reference internal time
* @external: a reference external time
* @rate: the rate of the clock relative to its internal time
*
* Adjusts the rate and time of @clock. A @rate of 1.0 is the normal speed of
* the clock. Values bigger than 1.0 make the clock go faster. @rate must be
* positive.
*
* @internal and @external are calibration parameters that arrange that
* gst_clock_get_time() should have been @external at internal time @internal.
* This internal time should not be in the future; that is, it should be less
* than the value of gst_clock_get_internal_time() when this function is called.
*
* Subsequent calls to gst_clock_get_time() will return clock times computed as
* follows:
*
* <programlisting>
* time = (internal_time - @internal) * @rate + @external
* </programlisting>
*
* Note that gst_clock_get_time() always returns increasing values so when you
* move the clock backwards, gst_clock_get_time() will report the previous value
* until the clock catches up.
*
* MT safe.
*/
void
gst_clock_set_calibration (GstClock * clock, GstClockTime internal, GstClockTime
external, gdouble rate)
{
g_return_if_fail (GST_IS_CLOCK (clock));
g_return_if_fail (rate > 0.0);
g_return_if_fail (internal < gst_clock_get_internal_time (clock));
GST_LOCK (clock);
/* these need to be reworked for the api freeze break, we're really abusing
* them now */
clock->adjust = internal;
clock->A.rate = rate;
clock->A.offset = external;
GST_UNLOCK (clock);
}
/**
* gst_clock_get_rate_offset
* @clock: a #GstClock to adjust
* @rate: a location to store the rate
* @offset: a location to store the offset
*
* Gets the internal rate and reference time of @clock. See
* gst_clock_set_calibration() for more information.
*
* MT safe.
*/
void
gst_clock_get_calibration (GstClock * clock, GstClockTime * internal,
GstClockTime * external, gdouble * rate)
{
g_return_if_fail (GST_IS_CLOCK (clock));
g_return_if_fail (rate != NULL);
g_return_if_fail (internal != NULL);
g_return_if_fail (external != NULL);
GST_LOCK (clock);
*rate = clock->A.rate;
*external = clock->A.offset;
*internal = clock->adjust;
GST_UNLOCK (clock);
}
static void
gst_clock_update_stats (GstClock * clock)
{

View file

@ -373,7 +373,7 @@ struct _GstClock {
GstClockFlags flags;
/*< protected >*/ /* with LOCK */
GstClockTime adjust; /* remove me */
GstClockTime adjust; /* rename me... */
GstClockTime last_time;
GList *entries;
GCond *entries_changed;
@ -423,6 +423,10 @@ void gst_clock_set_rate_offset (GstClock *clock, gdouble rate,
GstClockTimeDiff offset);
void gst_clock_get_rate_offset (GstClock *clock, gdouble *rate,
GstClockTimeDiff *offset);
void gst_clock_set_calibration (GstClock *clock, GstClockTime internal,
GstClockTime external, gdouble rate);
void gst_clock_get_calibration (GstClock *clock, GstClockTime *internal,
GstClockTime *external, gdouble *rate);
/* remove me */
void gst_clock_set_time_adjust (GstClock *clock, GstClockTime adjust);

View file

@ -34,7 +34,7 @@
GST_DEBUG_CATEGORY (ncc_debug);
#define GST_CAT_DEFAULT (ncc_debug)
/* #define DEBUGGING_ENABLED */
#define DEBUGGING_ENABLED
#ifdef DEBUGGING_ENABLED
#define DEBUG(x, args...) g_print (x "\n", ##args)
@ -236,14 +236,14 @@ gst_net_client_clock_get_property (GObject * object, guint prop_id,
/* http://mathworld.wolfram.com/LeastSquaresFitting.html */
static gboolean
do_linear_regression (GstClockTime * x, GstClockTime * y, gint n, gdouble * m,
GstClockTimeDiff * b, gdouble * r_squared)
GstClockTime * b, GstClockTime * xbase, gdouble * r_squared)
{
gint64 *newx, *newy;
gint64 xbar, ybar, sxx, sxy, syy;
GstClockTime xmin, ymin;
GstClockTime *newx, *newy;
GstClockTime xmin, ymin, xbar, ybar;
GstClockTimeDiff sxx, sxy, syy;
gint i;
sxx = syy = sxy = xbar = ybar = 0;
xbar = ybar = sxx = syy = sxy = 0;
#ifdef DEBUGGING_ENABLED
DEBUG ("doing regression on:");
@ -251,7 +251,7 @@ do_linear_regression (GstClockTime * x, GstClockTime * y, gint n, gdouble * m,
DEBUG (" %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT, x[i], y[i]);
#endif
xmin = ymin = G_MAXINT64;
xmin = ymin = G_MAXUINT64;
for (i = 0; i < n; i++) {
xmin = MIN (xmin, x[i]);
ymin = MIN (ymin, y[i]);
@ -260,8 +260,8 @@ do_linear_regression (GstClockTime * x, GstClockTime * y, gint n, gdouble * m,
DEBUG ("min x: %" G_GUINT64_FORMAT, xmin);
DEBUG ("min y: %" G_GUINT64_FORMAT, ymin);
newx = g_new (gint64, n);
newy = g_new (gint64, n);
newx = g_new (GstClockTime, n);
newy = g_new (GstClockTime, n);
/* strip off unnecessary bits of precision */
for (i = 0; i < n; i++) {
@ -287,8 +287,8 @@ do_linear_regression (GstClockTime * x, GstClockTime * y, gint n, gdouble * m,
xbar /= n;
ybar /= n;
DEBUG (" xbar = %" G_GINT64_FORMAT, xbar);
DEBUG (" ybar = %" G_GINT64_FORMAT, ybar);
DEBUG (" xbar = %" G_GUINT64_FORMAT, xbar);
DEBUG (" ybar = %" G_GUINT64_FORMAT, ybar);
/* multiplying directly would give quantities on the order of 1e20 -> 60 bits;
times the window size that's 70 which is too much. Instead we (1) subtract
@ -303,13 +303,14 @@ do_linear_regression (GstClockTime * x, GstClockTime * y, gint n, gdouble * m,
}
*m = ((double) sxy) / sxx;
*b = ((GstClockTimeDiff) (ybar + ymin)) - (GstClockTimeDiff) ((xbar +
xmin) * *m);
*xbase = xmin;
*b = (ybar + ymin) - (GstClockTime) (xbar * *m);
*r_squared = ((double) sxy * (double) sxy) / ((double) sxx * (double) syy);
DEBUG (" m = %g", *m);
DEBUG (" b = %" G_GINT64_FORMAT, *b);
DEBUG (" r2 = %g", *r_squared);
DEBUG (" m = %g", *m);
DEBUG (" b = %" G_GUINT64_FORMAT, *b);
DEBUG (" xbase = %" G_GUINT64_FORMAT, *xbase);
DEBUG (" r2 = %g", *r_squared);
g_free (newx);
g_free (newy);
@ -322,7 +323,7 @@ gst_net_client_clock_observe_times (GstNetClientClock * self,
GstClockTime local_1, GstClockTime remote, GstClockTime local_2)
{
GstClockTime local_avg;
GstClockTimeDiff b;
GstClockTime b, xbase;
gdouble m, r_squared;
if (local_2 < local_1)
@ -344,12 +345,12 @@ gst_net_client_clock_observe_times (GstNetClientClock * self,
* before beginning to adjust the clock */
do_linear_regression (self->local_times, self->remote_times,
self->filling ? self->time_index : self->window_size, &m, &b,
&r_squared);
&xbase, &r_squared);
GST_LOG_OBJECT (self, "adjusting clock to m=%g, b=%" G_GINT64_FORMAT
" (rsquared=%g)", m, b, r_squared);
gst_clock_set_rate_offset (GST_CLOCK (self), m, b);
gst_clock_set_calibration (GST_CLOCK (self), xbase, b, m);
}
if (self->filling) {
@ -633,7 +634,6 @@ gst_net_client_clock_new (gchar * name, const gchar * remote_address,
{
GstNetClientClock *ret;
GstClockTime internal;
GstClockTimeDiff offset;
gint iret;
g_return_val_if_fail (remote_address != NULL, NULL);
@ -653,16 +653,7 @@ gst_net_client_clock_new (gchar * name, const gchar * remote_address,
/* update our internal time so get_time() give something around base_time.
assume that the rate is 1 in the beginning. */
internal = gst_clock_get_internal_time (GST_CLOCK (ret));
/* MAXINT64 + 1 so as to avoid overflow */
if ((base_time > internal
&& base_time - internal > ((guint64) G_MAXINT64) + 1)
|| (base_time < internal && internal - base_time > G_MAXINT64))
goto bad_base_time;
offset = base_time > internal ? (base_time - internal)
: -(gint64) (internal - base_time);
gst_clock_set_rate_offset (GST_CLOCK (ret), 1.0, offset);
gst_clock_set_calibration (GST_CLOCK (ret), internal, base_time, 1.0);
{
GstClockTime now = gst_clock_get_time (GST_CLOCK (ret));
@ -684,14 +675,6 @@ gst_net_client_clock_new (gchar * name, const gchar * remote_address,
/* all systems go, cap'n */
return (GstClock *) ret;
bad_base_time:
{
GST_ERROR_OBJECT (ret, "base time (%" GST_TIME_FORMAT ") too far off from "
"internal time (%" GST_TIME_FORMAT ")", GST_TIME_ARGS (base_time),
GST_TIME_ARGS (internal));
gst_object_unref (ret);
return NULL;
}
no_socket_pair:
{
GST_ERROR_OBJECT (ret, "no socket pair %d: %s (%d)", iret,

View file

@ -34,7 +34,7 @@
GST_DEBUG_CATEGORY (ncc_debug);
#define GST_CAT_DEFAULT (ncc_debug)
/* #define DEBUGGING_ENABLED */
#define DEBUGGING_ENABLED
#ifdef DEBUGGING_ENABLED
#define DEBUG(x, args...) g_print (x "\n", ##args)
@ -236,14 +236,14 @@ gst_net_client_clock_get_property (GObject * object, guint prop_id,
/* http://mathworld.wolfram.com/LeastSquaresFitting.html */
static gboolean
do_linear_regression (GstClockTime * x, GstClockTime * y, gint n, gdouble * m,
GstClockTimeDiff * b, gdouble * r_squared)
GstClockTime * b, GstClockTime * xbase, gdouble * r_squared)
{
gint64 *newx, *newy;
gint64 xbar, ybar, sxx, sxy, syy;
GstClockTime xmin, ymin;
GstClockTime *newx, *newy;
GstClockTime xmin, ymin, xbar, ybar;
GstClockTimeDiff sxx, sxy, syy;
gint i;
sxx = syy = sxy = xbar = ybar = 0;
xbar = ybar = sxx = syy = sxy = 0;
#ifdef DEBUGGING_ENABLED
DEBUG ("doing regression on:");
@ -251,7 +251,7 @@ do_linear_regression (GstClockTime * x, GstClockTime * y, gint n, gdouble * m,
DEBUG (" %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT, x[i], y[i]);
#endif
xmin = ymin = G_MAXINT64;
xmin = ymin = G_MAXUINT64;
for (i = 0; i < n; i++) {
xmin = MIN (xmin, x[i]);
ymin = MIN (ymin, y[i]);
@ -260,8 +260,8 @@ do_linear_regression (GstClockTime * x, GstClockTime * y, gint n, gdouble * m,
DEBUG ("min x: %" G_GUINT64_FORMAT, xmin);
DEBUG ("min y: %" G_GUINT64_FORMAT, ymin);
newx = g_new (gint64, n);
newy = g_new (gint64, n);
newx = g_new (GstClockTime, n);
newy = g_new (GstClockTime, n);
/* strip off unnecessary bits of precision */
for (i = 0; i < n; i++) {
@ -287,8 +287,8 @@ do_linear_regression (GstClockTime * x, GstClockTime * y, gint n, gdouble * m,
xbar /= n;
ybar /= n;
DEBUG (" xbar = %" G_GINT64_FORMAT, xbar);
DEBUG (" ybar = %" G_GINT64_FORMAT, ybar);
DEBUG (" xbar = %" G_GUINT64_FORMAT, xbar);
DEBUG (" ybar = %" G_GUINT64_FORMAT, ybar);
/* multiplying directly would give quantities on the order of 1e20 -> 60 bits;
times the window size that's 70 which is too much. Instead we (1) subtract
@ -303,13 +303,14 @@ do_linear_regression (GstClockTime * x, GstClockTime * y, gint n, gdouble * m,
}
*m = ((double) sxy) / sxx;
*b = ((GstClockTimeDiff) (ybar + ymin)) - (GstClockTimeDiff) ((xbar +
xmin) * *m);
*xbase = xmin;
*b = (ybar + ymin) - (GstClockTime) (xbar * *m);
*r_squared = ((double) sxy * (double) sxy) / ((double) sxx * (double) syy);
DEBUG (" m = %g", *m);
DEBUG (" b = %" G_GINT64_FORMAT, *b);
DEBUG (" r2 = %g", *r_squared);
DEBUG (" m = %g", *m);
DEBUG (" b = %" G_GUINT64_FORMAT, *b);
DEBUG (" xbase = %" G_GUINT64_FORMAT, *xbase);
DEBUG (" r2 = %g", *r_squared);
g_free (newx);
g_free (newy);
@ -322,7 +323,7 @@ gst_net_client_clock_observe_times (GstNetClientClock * self,
GstClockTime local_1, GstClockTime remote, GstClockTime local_2)
{
GstClockTime local_avg;
GstClockTimeDiff b;
GstClockTime b, xbase;
gdouble m, r_squared;
if (local_2 < local_1)
@ -344,12 +345,12 @@ gst_net_client_clock_observe_times (GstNetClientClock * self,
* before beginning to adjust the clock */
do_linear_regression (self->local_times, self->remote_times,
self->filling ? self->time_index : self->window_size, &m, &b,
&r_squared);
&xbase, &r_squared);
GST_LOG_OBJECT (self, "adjusting clock to m=%g, b=%" G_GINT64_FORMAT
" (rsquared=%g)", m, b, r_squared);
gst_clock_set_rate_offset (GST_CLOCK (self), m, b);
gst_clock_set_calibration (GST_CLOCK (self), xbase, b, m);
}
if (self->filling) {
@ -633,7 +634,6 @@ gst_net_client_clock_new (gchar * name, const gchar * remote_address,
{
GstNetClientClock *ret;
GstClockTime internal;
GstClockTimeDiff offset;
gint iret;
g_return_val_if_fail (remote_address != NULL, NULL);
@ -653,16 +653,7 @@ gst_net_client_clock_new (gchar * name, const gchar * remote_address,
/* update our internal time so get_time() give something around base_time.
assume that the rate is 1 in the beginning. */
internal = gst_clock_get_internal_time (GST_CLOCK (ret));
/* MAXINT64 + 1 so as to avoid overflow */
if ((base_time > internal
&& base_time - internal > ((guint64) G_MAXINT64) + 1)
|| (base_time < internal && internal - base_time > G_MAXINT64))
goto bad_base_time;
offset = base_time > internal ? (base_time - internal)
: -(gint64) (internal - base_time);
gst_clock_set_rate_offset (GST_CLOCK (ret), 1.0, offset);
gst_clock_set_calibration (GST_CLOCK (ret), internal, base_time, 1.0);
{
GstClockTime now = gst_clock_get_time (GST_CLOCK (ret));
@ -684,14 +675,6 @@ gst_net_client_clock_new (gchar * name, const gchar * remote_address,
/* all systems go, cap'n */
return (GstClock *) ret;
bad_base_time:
{
GST_ERROR_OBJECT (ret, "base time (%" GST_TIME_FORMAT ") too far off from "
"internal time (%" GST_TIME_FORMAT ")", GST_TIME_ARGS (base_time),
GST_TIME_ARGS (internal));
gst_object_unref (ret);
return NULL;
}
no_socket_pair:
{
GST_ERROR_OBJECT (ret, "no socket pair %d: %s (%d)", iret,

View file

@ -50,7 +50,7 @@ GST_START_TEST (test_functioning)
{
GstNetTimeProvider *ntp;
GstClock *client, *server;
GstClockTimeDiff offset;
GstClockTime basex, basey;
GstClockTime servint; //, servtime, localtime;
gint port;
gdouble rate;
@ -59,9 +59,9 @@ GST_START_TEST (test_functioning)
fail_unless (server != NULL, "failed to get system clock");
/* move the clock ahead 100 seconds */
gst_clock_get_rate_offset (server, &rate, &offset);
offset += 100 * GST_SECOND;
gst_clock_set_rate_offset (server, rate, offset);
gst_clock_get_calibration (server, &basex, &basey, &rate);
basey += 100 * GST_SECOND;
gst_clock_set_calibration (server, basex, basey, rate);
servint = gst_clock_get_internal_time (GST_CLOCK (server));
ntp = gst_net_time_provider_new (server, "127.0.0.1", 0);