mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 06:54:49 +00:00
utils: Export linear regression calculation as public function
It is useful outside the GstClock code too. https://bugzilla.gnome.org/show_bug.cgi?id=774916
This commit is contained in:
parent
b8d75d4f4d
commit
a7d282d272
10 changed files with 488 additions and 451 deletions
|
@ -3547,6 +3547,7 @@ gst_util_guint64_to_gdouble
|
||||||
gst_util_gdouble_to_guint64
|
gst_util_gdouble_to_guint64
|
||||||
GST_TYPE_SEARCH_MODE
|
GST_TYPE_SEARCH_MODE
|
||||||
gst_search_mode_get_type
|
gst_search_mode_get_type
|
||||||
|
gst_calculate_linear_regression
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
|
|
|
@ -59,7 +59,6 @@ libgstreamer_@GST_API_VERSION@_la_SOURCES = \
|
||||||
gstcapsfeatures.c \
|
gstcapsfeatures.c \
|
||||||
gstchildproxy.c \
|
gstchildproxy.c \
|
||||||
gstclock.c \
|
gstclock.c \
|
||||||
gstclock-linreg.c \
|
|
||||||
gstcontext.c \
|
gstcontext.c \
|
||||||
gstcontrolbinding.c \
|
gstcontrolbinding.c \
|
||||||
gstcontrolsource.c \
|
gstcontrolsource.c \
|
||||||
|
|
|
@ -209,12 +209,6 @@ gint __gst_date_time_compare (const GstDateTime * dt1, const GstDateTime * dt2);
|
||||||
G_GNUC_INTERNAL
|
G_GNUC_INTERNAL
|
||||||
gchar * __gst_date_time_serialize (GstDateTime * datetime, gboolean with_usecs);
|
gchar * __gst_date_time_serialize (GstDateTime * datetime, gboolean with_usecs);
|
||||||
|
|
||||||
/* Non-static, for access from the testsuite, but not for external use */
|
|
||||||
gboolean
|
|
||||||
_priv_gst_do_linear_regression (GstClockTime *times, guint n,
|
|
||||||
GstClockTime * m_num, GstClockTime * m_denom, GstClockTime * b,
|
|
||||||
GstClockTime * xbase, gdouble * r_squared);
|
|
||||||
|
|
||||||
/* For use in gstdebugutils */
|
/* For use in gstdebugutils */
|
||||||
G_GNUC_INTERNAL
|
G_GNUC_INTERNAL
|
||||||
GstCapsFeatures * __gst_caps_get_features_unchecked (const GstCaps * caps, guint idx);
|
GstCapsFeatures * __gst_caps_get_features_unchecked (const GstCaps * caps, guint idx);
|
||||||
|
|
|
@ -1,241 +0,0 @@
|
||||||
/* GStreamer
|
|
||||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
|
||||||
* 2000 Wim Taymans <wtay@chello.be>
|
|
||||||
* 2004 Wim Taymans <wim@fluendo.com>
|
|
||||||
* 2015 Jan Schmidt <jan@centricular.com>
|
|
||||||
*
|
|
||||||
* gstclock-linreg.c: Linear regression implementation, used in clock slaving
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Library General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Library General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Library General Public
|
|
||||||
* License along with this library; if not, write to the
|
|
||||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
||||||
* Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "gst_private.h"
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
#include "gstclock.h"
|
|
||||||
#include "gstinfo.h"
|
|
||||||
#include "gstutils.h"
|
|
||||||
#include "glib-compat-private.h"
|
|
||||||
|
|
||||||
/* Compute log2 of the passed 64-bit number by finding the highest set bit */
|
|
||||||
static guint
|
|
||||||
gst_log2 (GstClockTime in)
|
|
||||||
{
|
|
||||||
const guint64 b[] =
|
|
||||||
{ 0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000, 0xFFFFFFFF00000000LL };
|
|
||||||
const guint64 S[] = { 1, 2, 4, 8, 16, 32 };
|
|
||||||
int i;
|
|
||||||
|
|
||||||
guint count = 0;
|
|
||||||
for (i = 5; i >= 0; i--) {
|
|
||||||
if (in & b[i]) {
|
|
||||||
in >>= S[i];
|
|
||||||
count |= S[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* http://mathworld.wolfram.com/LeastSquaresFitting.html
|
|
||||||
* with SLAVE_LOCK
|
|
||||||
*/
|
|
||||||
gboolean
|
|
||||||
_priv_gst_do_linear_regression (GstClockTime * times, guint n,
|
|
||||||
GstClockTime * m_num, GstClockTime * m_denom, GstClockTime * b,
|
|
||||||
GstClockTime * xbase, gdouble * r_squared)
|
|
||||||
{
|
|
||||||
GstClockTime *newx, *newy;
|
|
||||||
GstClockTime xmin, ymin, xbar, ybar, xbar4, ybar4;
|
|
||||||
GstClockTime xmax, ymax;
|
|
||||||
GstClockTimeDiff sxx, sxy, syy;
|
|
||||||
GstClockTime *x, *y;
|
|
||||||
gint i, j;
|
|
||||||
gint pshift = 0;
|
|
||||||
gint max_bits;
|
|
||||||
|
|
||||||
xbar = ybar = sxx = syy = sxy = 0;
|
|
||||||
|
|
||||||
x = times;
|
|
||||||
y = times + 2;
|
|
||||||
|
|
||||||
xmin = ymin = G_MAXUINT64;
|
|
||||||
xmax = ymax = 0;
|
|
||||||
for (i = j = 0; i < n; i++, j += 4) {
|
|
||||||
xmin = MIN (xmin, x[j]);
|
|
||||||
ymin = MIN (ymin, y[j]);
|
|
||||||
|
|
||||||
xmax = MAX (xmax, x[j]);
|
|
||||||
ymax = MAX (ymax, y[j]);
|
|
||||||
}
|
|
||||||
|
|
||||||
newx = times + 1;
|
|
||||||
newy = times + 3;
|
|
||||||
|
|
||||||
/* strip off unnecessary bits of precision */
|
|
||||||
for (i = j = 0; i < n; i++, j += 4) {
|
|
||||||
newx[j] = x[j] - xmin;
|
|
||||||
newy[j] = y[j] - ymin;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUGGING_ENABLED
|
|
||||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "reduced numbers:");
|
|
||||||
for (i = j = 0; i < n; i++, j += 4)
|
|
||||||
GST_CAT_DEBUG (GST_CAT_CLOCK,
|
|
||||||
" %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT, newx[j], newy[j]);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* have to do this precisely otherwise the results are pretty much useless.
|
|
||||||
* should guarantee that none of these accumulators can overflow */
|
|
||||||
|
|
||||||
/* quantities on the order of 1e10 to 1e13 -> 30-35 bits;
|
|
||||||
* window size a max of 2^10, so
|
|
||||||
this addition could end up around 2^45 or so -- ample headroom */
|
|
||||||
for (i = j = 0; i < n; i++, j += 4) {
|
|
||||||
/* Just in case assumptions about headroom prove false, let's check */
|
|
||||||
if ((newx[j] > 0 && G_MAXUINT64 - xbar <= newx[j]) ||
|
|
||||||
(newy[j] > 0 && G_MAXUINT64 - ybar <= newy[j])) {
|
|
||||||
GST_CAT_WARNING (GST_CAT_CLOCK,
|
|
||||||
"Regression overflowed in clock slaving! xbar %"
|
|
||||||
G_GUINT64_FORMAT " newx[j] %" G_GUINT64_FORMAT " ybar %"
|
|
||||||
G_GUINT64_FORMAT " newy[j] %" G_GUINT64_FORMAT, xbar, newx[j], ybar,
|
|
||||||
newy[j]);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
xbar += newx[j];
|
|
||||||
ybar += newy[j];
|
|
||||||
}
|
|
||||||
xbar /= n;
|
|
||||||
ybar /= n;
|
|
||||||
|
|
||||||
/* multiplying directly would give quantities on the order of 1e20-1e26 ->
|
|
||||||
* 60 bits to 70 bits times the window size that's 80 which is too much.
|
|
||||||
* Instead we (1) subtract off the xbar*ybar in the loop instead of after,
|
|
||||||
* to avoid accumulation; (2) shift off some estimated number of bits from
|
|
||||||
* each multiplicand to limit the expected ceiling. For strange
|
|
||||||
* distributions of input values, things can still overflow, in which
|
|
||||||
* case we drop precision and retry - at most a few times, in practice rarely
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Guess how many bits we might need for the usual distribution of input,
|
|
||||||
* with a fallback loop that drops precision if things go pear-shaped */
|
|
||||||
max_bits = gst_log2 (MAX (xmax - xmin, ymax - ymin)) * 7 / 8 + gst_log2 (n);
|
|
||||||
if (max_bits > 64)
|
|
||||||
pshift = max_bits - 64;
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
do {
|
|
||||||
#ifdef DEBUGGING_ENABLED
|
|
||||||
GST_CAT_DEBUG (GST_CAT_CLOCK,
|
|
||||||
"Restarting regression with precision shift %u", pshift);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
xbar4 = xbar >> pshift;
|
|
||||||
ybar4 = ybar >> pshift;
|
|
||||||
sxx = syy = sxy = 0;
|
|
||||||
for (i = j = 0; i < n; i++, j += 4) {
|
|
||||||
GstClockTime newx4, newy4;
|
|
||||||
GstClockTimeDiff tmp;
|
|
||||||
|
|
||||||
newx4 = newx[j] >> pshift;
|
|
||||||
newy4 = newy[j] >> pshift;
|
|
||||||
|
|
||||||
tmp = (newx4 + xbar4) * (newx4 - xbar4);
|
|
||||||
if (G_UNLIKELY (tmp > 0 && sxx > 0 && (G_MAXINT64 - sxx <= tmp))) {
|
|
||||||
do {
|
|
||||||
/* Drop some precision and restart */
|
|
||||||
pshift++;
|
|
||||||
sxx /= 4;
|
|
||||||
tmp /= 4;
|
|
||||||
} while (G_MAXINT64 - sxx <= tmp);
|
|
||||||
break;
|
|
||||||
} else if (G_UNLIKELY (tmp < 0 && sxx < 0 && (G_MAXINT64 - sxx >= tmp))) {
|
|
||||||
do {
|
|
||||||
/* Drop some precision and restart */
|
|
||||||
pshift++;
|
|
||||||
sxx /= 4;
|
|
||||||
tmp /= 4;
|
|
||||||
} while (G_MININT64 - sxx >= tmp);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
sxx += tmp;
|
|
||||||
|
|
||||||
tmp = newy4 * newy4 - ybar4 * ybar4;
|
|
||||||
if (G_UNLIKELY (tmp > 0 && syy > 0 && (G_MAXINT64 - syy <= tmp))) {
|
|
||||||
do {
|
|
||||||
pshift++;
|
|
||||||
syy /= 4;
|
|
||||||
tmp /= 4;
|
|
||||||
} while (G_MAXINT64 - syy <= tmp);
|
|
||||||
break;
|
|
||||||
} else if (G_UNLIKELY (tmp < 0 && syy < 0 && (G_MAXINT64 - syy >= tmp))) {
|
|
||||||
do {
|
|
||||||
pshift++;
|
|
||||||
syy /= 4;
|
|
||||||
tmp /= 4;
|
|
||||||
} while (G_MININT64 - syy >= tmp);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
syy += tmp;
|
|
||||||
|
|
||||||
tmp = newx4 * newy4 - xbar4 * ybar4;
|
|
||||||
if (G_UNLIKELY (tmp > 0 && sxy > 0 && (G_MAXINT64 - sxy <= tmp))) {
|
|
||||||
do {
|
|
||||||
pshift++;
|
|
||||||
sxy /= 4;
|
|
||||||
tmp /= 4;
|
|
||||||
} while (G_MAXINT64 - sxy <= tmp);
|
|
||||||
break;
|
|
||||||
} else if (G_UNLIKELY (tmp < 0 && sxy < 0 && (G_MININT64 - sxy >= tmp))) {
|
|
||||||
do {
|
|
||||||
pshift++;
|
|
||||||
sxy /= 4;
|
|
||||||
tmp /= 4;
|
|
||||||
} while (G_MININT64 - sxy >= tmp);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
sxy += tmp;
|
|
||||||
}
|
|
||||||
} while (i < n);
|
|
||||||
|
|
||||||
if (G_UNLIKELY (sxx == 0))
|
|
||||||
goto invalid;
|
|
||||||
|
|
||||||
*m_num = sxy;
|
|
||||||
*m_denom = sxx;
|
|
||||||
*b = (ymin + ybar) - gst_util_uint64_scale (xbar, *m_num, *m_denom);
|
|
||||||
/* Report base starting from the most recent observation */
|
|
||||||
*xbase = xmax;
|
|
||||||
*b += gst_util_uint64_scale (xmax - xmin, *m_num, *m_denom);
|
|
||||||
|
|
||||||
*r_squared = ((double) sxy * (double) sxy) / ((double) sxx * (double) syy);
|
|
||||||
|
|
||||||
#ifdef DEBUGGING_ENABLED
|
|
||||||
GST_CAT_DEBUG (GST_CAT_CLOCK, " m = %g", ((double) *m_num) / *m_denom);
|
|
||||||
GST_CAT_DEBUG (GST_CAT_CLOCK, " b = %" G_GUINT64_FORMAT, *b);
|
|
||||||
GST_CAT_DEBUG (GST_CAT_CLOCK, " xbase = %" G_GUINT64_FORMAT, *xbase);
|
|
||||||
GST_CAT_DEBUG (GST_CAT_CLOCK, " r2 = %g", *r_squared);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
invalid:
|
|
||||||
{
|
|
||||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "sxx == 0, regression failed");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -157,6 +157,7 @@ struct _GstClockPrivate
|
||||||
gint time_index;
|
gint time_index;
|
||||||
GstClockTime timeout;
|
GstClockTime timeout;
|
||||||
GstClockTime *times;
|
GstClockTime *times;
|
||||||
|
GstClockTime *times_temp;
|
||||||
GstClockID clockid;
|
GstClockID clockid;
|
||||||
|
|
||||||
gint pre_count;
|
gint pre_count;
|
||||||
|
@ -738,6 +739,8 @@ gst_clock_init (GstClock * clock)
|
||||||
priv->time_index = 0;
|
priv->time_index = 0;
|
||||||
priv->timeout = DEFAULT_TIMEOUT;
|
priv->timeout = DEFAULT_TIMEOUT;
|
||||||
priv->times = g_new0 (GstClockTime, 4 * priv->window_size);
|
priv->times = g_new0 (GstClockTime, 4 * priv->window_size);
|
||||||
|
priv->times_temp =
|
||||||
|
priv->times + 2 * priv->window_size * sizeof (GstClockTime);
|
||||||
|
|
||||||
/* clear floating flag */
|
/* clear floating flag */
|
||||||
gst_object_ref_sink (clock);
|
gst_object_ref_sink (clock);
|
||||||
|
@ -770,6 +773,7 @@ gst_clock_finalize (GObject * object)
|
||||||
}
|
}
|
||||||
g_free (clock->priv->times);
|
g_free (clock->priv->times);
|
||||||
clock->priv->times = NULL;
|
clock->priv->times = NULL;
|
||||||
|
clock->priv->times_temp = NULL;
|
||||||
GST_CLOCK_SLAVE_UNLOCK (clock);
|
GST_CLOCK_SLAVE_UNLOCK (clock);
|
||||||
|
|
||||||
g_mutex_clear (&clock->priv->slave_lock);
|
g_mutex_clear (&clock->priv->slave_lock);
|
||||||
|
@ -1420,8 +1424,8 @@ gst_clock_add_observation_unapplied (GstClock * clock, GstClockTime slave,
|
||||||
"adding observation slave %" GST_TIME_FORMAT ", master %" GST_TIME_FORMAT,
|
"adding observation slave %" GST_TIME_FORMAT ", master %" GST_TIME_FORMAT,
|
||||||
GST_TIME_ARGS (slave), GST_TIME_ARGS (master));
|
GST_TIME_ARGS (slave), GST_TIME_ARGS (master));
|
||||||
|
|
||||||
priv->times[(4 * priv->time_index)] = slave;
|
priv->times[(2 * priv->time_index)] = slave;
|
||||||
priv->times[(4 * priv->time_index) + 2] = master;
|
priv->times[(2 * priv->time_index) + 1] = master;
|
||||||
|
|
||||||
priv->time_index++;
|
priv->time_index++;
|
||||||
if (G_UNLIKELY (priv->time_index == priv->window_size)) {
|
if (G_UNLIKELY (priv->time_index == priv->window_size)) {
|
||||||
|
@ -1433,8 +1437,8 @@ gst_clock_add_observation_unapplied (GstClock * clock, GstClockTime slave,
|
||||||
goto filling;
|
goto filling;
|
||||||
|
|
||||||
n = priv->filling ? priv->time_index : priv->window_size;
|
n = priv->filling ? priv->time_index : priv->window_size;
|
||||||
if (!_priv_gst_do_linear_regression (priv->times, n, &m_num, &m_denom, &b,
|
if (!gst_calculate_linear_regression (priv->times, priv->times_temp, n,
|
||||||
&xbase, r_squared))
|
&m_num, &m_denom, &b, &xbase, r_squared))
|
||||||
goto invalid;
|
goto invalid;
|
||||||
|
|
||||||
GST_CLOCK_SLAVE_UNLOCK (clock);
|
GST_CLOCK_SLAVE_UNLOCK (clock);
|
||||||
|
@ -1523,6 +1527,8 @@ gst_clock_set_property (GObject * object, guint prop_id,
|
||||||
priv->window_size = g_value_get_int (value);
|
priv->window_size = g_value_get_int (value);
|
||||||
priv->window_threshold = MIN (priv->window_threshold, priv->window_size);
|
priv->window_threshold = MIN (priv->window_threshold, priv->window_size);
|
||||||
priv->times = g_renew (GstClockTime, priv->times, 4 * priv->window_size);
|
priv->times = g_renew (GstClockTime, priv->times, 4 * priv->window_size);
|
||||||
|
priv->times_temp =
|
||||||
|
priv->times + 2 * priv->window_size * sizeof (GstClockTime);
|
||||||
/* restart calibration */
|
/* restart calibration */
|
||||||
priv->filling = TRUE;
|
priv->filling = TRUE;
|
||||||
priv->time_index = 0;
|
priv->time_index = 0;
|
||||||
|
|
263
gst/gstutils.c
263
gst/gstutils.c
|
@ -2,6 +2,8 @@
|
||||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||||
* 2000 Wim Taymans <wtay@chello.be>
|
* 2000 Wim Taymans <wtay@chello.be>
|
||||||
* 2002 Thomas Vander Stichele <thomas@apestaart.org>
|
* 2002 Thomas Vander Stichele <thomas@apestaart.org>
|
||||||
|
* 2004 Wim Taymans <wim@fluendo.com>
|
||||||
|
* 2015 Jan Schmidt <jan@centricular.com>
|
||||||
*
|
*
|
||||||
* gstutils.c: Utility functions
|
* gstutils.c: Utility functions
|
||||||
*
|
*
|
||||||
|
@ -4045,3 +4047,264 @@ gst_util_group_id_next (void)
|
||||||
static gint counter = 0;
|
static gint counter = 0;
|
||||||
return g_atomic_int_add (&counter, 1);
|
return g_atomic_int_add (&counter, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Compute log2 of the passed 64-bit number by finding the highest set bit */
|
||||||
|
static guint
|
||||||
|
gst_log2 (GstClockTime in)
|
||||||
|
{
|
||||||
|
const guint64 b[] =
|
||||||
|
{ 0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000, 0xFFFFFFFF00000000LL };
|
||||||
|
const guint64 S[] = { 1, 2, 4, 8, 16, 32 };
|
||||||
|
int i;
|
||||||
|
|
||||||
|
guint count = 0;
|
||||||
|
for (i = 5; i >= 0; i--) {
|
||||||
|
if (in & b[i]) {
|
||||||
|
in >>= S[i];
|
||||||
|
count |= S[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_calculate_linear_regression:
|
||||||
|
* @xy: Pairs of (x,y) values
|
||||||
|
* @temp: Temporary scratch space used by the function
|
||||||
|
* @n: number of (x,y) pairs
|
||||||
|
* @m_num: (out): numerator of calculated slope
|
||||||
|
* @m_denom: (out): denominator of calculated slope
|
||||||
|
* @b: (out): Offset at Y-axis
|
||||||
|
* @xbase: (out): Offset at X-axis
|
||||||
|
* @r_squared: (out): R-squared
|
||||||
|
*
|
||||||
|
* Calculates the linear regression of the values @xy and places the
|
||||||
|
* result in @m_num, @m_denom, @b and @xbase, representing the function
|
||||||
|
* y(x) = m_num/m_denom * (x - xbase) + b
|
||||||
|
* that has the least-square distance from all points @x and @y.
|
||||||
|
*
|
||||||
|
* @r_squared will contain the remaining error.
|
||||||
|
*
|
||||||
|
* If @temp is not %NULL, it will be used as temporary space for the function,
|
||||||
|
* in which case the function works without any allocation at all. If @temp is
|
||||||
|
* %NULL, an allocation will take place. @temp should have at least the same
|
||||||
|
* amount of memory allocated as @xy, i.e. 2*n*sizeof(GstClockTime).
|
||||||
|
*
|
||||||
|
* <note>This function assumes (x,y) values with reasonable large differences
|
||||||
|
* between them. It will not calculate the exact results if the differences
|
||||||
|
* between neighbouring values are too small due to not being able to
|
||||||
|
* represent sub-integer values during the calculations.</note>
|
||||||
|
*
|
||||||
|
* Returns: %TRUE if the linear regression was successfully calculated
|
||||||
|
*
|
||||||
|
* Since: 1.12
|
||||||
|
*/
|
||||||
|
/* http://mathworld.wolfram.com/LeastSquaresFitting.html
|
||||||
|
* with SLAVE_LOCK
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
gst_calculate_linear_regression (const GstClockTime * xy,
|
||||||
|
GstClockTime * temp, guint n,
|
||||||
|
GstClockTime * m_num, GstClockTime * m_denom,
|
||||||
|
GstClockTime * b, GstClockTime * xbase, gdouble * r_squared)
|
||||||
|
{
|
||||||
|
const GstClockTime *x, *y;
|
||||||
|
GstClockTime *newx, *newy;
|
||||||
|
GstClockTime xmin, ymin, xbar, ybar, xbar4, ybar4;
|
||||||
|
GstClockTime xmax, ymax;
|
||||||
|
GstClockTimeDiff sxx, sxy, syy;
|
||||||
|
gint i, j;
|
||||||
|
gint pshift = 0;
|
||||||
|
gint max_bits;
|
||||||
|
|
||||||
|
g_return_val_if_fail (xy != NULL, FALSE);
|
||||||
|
g_return_val_if_fail (m_num != NULL, FALSE);
|
||||||
|
g_return_val_if_fail (m_denom != NULL, FALSE);
|
||||||
|
g_return_val_if_fail (b != NULL, FALSE);
|
||||||
|
g_return_val_if_fail (xbase != NULL, FALSE);
|
||||||
|
g_return_val_if_fail (r_squared != NULL, FALSE);
|
||||||
|
|
||||||
|
x = xy;
|
||||||
|
y = xy + 1;
|
||||||
|
|
||||||
|
xbar = ybar = sxx = syy = sxy = 0;
|
||||||
|
|
||||||
|
xmin = ymin = G_MAXUINT64;
|
||||||
|
xmax = ymax = 0;
|
||||||
|
for (i = j = 0; i < n; i++, j += 2) {
|
||||||
|
xmin = MIN (xmin, x[j]);
|
||||||
|
ymin = MIN (ymin, y[j]);
|
||||||
|
|
||||||
|
xmax = MAX (xmax, x[j]);
|
||||||
|
ymax = MAX (ymax, y[j]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (temp == NULL) {
|
||||||
|
/* Allocate up to 1kb on the stack, otherwise heap */
|
||||||
|
newx = n > 64 ? g_new (GstClockTime, 2 * n) : g_newa (GstClockTime, 2 * n);
|
||||||
|
newy = newx + 1;
|
||||||
|
} else {
|
||||||
|
newx = temp;
|
||||||
|
newy = temp + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* strip off unnecessary bits of precision */
|
||||||
|
for (i = j = 0; i < n; i++, j += 2) {
|
||||||
|
newx[j] = x[j] - xmin;
|
||||||
|
newy[j] = y[j] - ymin;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUGGING_ENABLED
|
||||||
|
GST_CAT_DEBUG (GST_CAT_CLOCK, "reduced numbers:");
|
||||||
|
for (i = j = 0; i < n; i++, j += 2)
|
||||||
|
GST_CAT_DEBUG (GST_CAT_CLOCK,
|
||||||
|
" %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT, newx[j], newy[j]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* have to do this precisely otherwise the results are pretty much useless.
|
||||||
|
* should guarantee that none of these accumulators can overflow */
|
||||||
|
|
||||||
|
/* quantities on the order of 1e10 to 1e13 -> 30-35 bits;
|
||||||
|
* window size a max of 2^10, so
|
||||||
|
this addition could end up around 2^45 or so -- ample headroom */
|
||||||
|
for (i = j = 0; i < n; i++, j += 2) {
|
||||||
|
/* Just in case assumptions about headroom prove false, let's check */
|
||||||
|
if ((newx[j] > 0 && G_MAXUINT64 - xbar <= newx[j]) ||
|
||||||
|
(newy[j] > 0 && G_MAXUINT64 - ybar <= newy[j])) {
|
||||||
|
GST_CAT_WARNING (GST_CAT_CLOCK,
|
||||||
|
"Regression overflowed in clock slaving! xbar %"
|
||||||
|
G_GUINT64_FORMAT " newx[j] %" G_GUINT64_FORMAT " ybar %"
|
||||||
|
G_GUINT64_FORMAT " newy[j] %" G_GUINT64_FORMAT, xbar, newx[j], ybar,
|
||||||
|
newy[j]);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
xbar += newx[j];
|
||||||
|
ybar += newy[j];
|
||||||
|
}
|
||||||
|
xbar /= n;
|
||||||
|
ybar /= n;
|
||||||
|
|
||||||
|
/* multiplying directly would give quantities on the order of 1e20-1e26 ->
|
||||||
|
* 60 bits to 70 bits times the window size that's 80 which is too much.
|
||||||
|
* Instead we (1) subtract off the xbar*ybar in the loop instead of after,
|
||||||
|
* to avoid accumulation; (2) shift off some estimated number of bits from
|
||||||
|
* each multiplicand to limit the expected ceiling. For strange
|
||||||
|
* distributions of input values, things can still overflow, in which
|
||||||
|
* case we drop precision and retry - at most a few times, in practice rarely
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Guess how many bits we might need for the usual distribution of input,
|
||||||
|
* with a fallback loop that drops precision if things go pear-shaped */
|
||||||
|
max_bits = gst_log2 (MAX (xmax - xmin, ymax - ymin)) * 7 / 8 + gst_log2 (n);
|
||||||
|
if (max_bits > 64)
|
||||||
|
pshift = max_bits - 64;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
do {
|
||||||
|
#ifdef DEBUGGING_ENABLED
|
||||||
|
GST_CAT_DEBUG (GST_CAT_CLOCK,
|
||||||
|
"Restarting regression with precision shift %u", pshift);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
xbar4 = xbar >> pshift;
|
||||||
|
ybar4 = ybar >> pshift;
|
||||||
|
sxx = syy = sxy = 0;
|
||||||
|
for (i = j = 0; i < n; i++, j += 2) {
|
||||||
|
GstClockTime newx4, newy4;
|
||||||
|
GstClockTimeDiff tmp;
|
||||||
|
|
||||||
|
newx4 = newx[j] >> pshift;
|
||||||
|
newy4 = newy[j] >> pshift;
|
||||||
|
|
||||||
|
tmp = (newx4 + xbar4) * (newx4 - xbar4);
|
||||||
|
if (G_UNLIKELY (tmp > 0 && sxx > 0 && (G_MAXINT64 - sxx <= tmp))) {
|
||||||
|
do {
|
||||||
|
/* Drop some precision and restart */
|
||||||
|
pshift++;
|
||||||
|
sxx /= 4;
|
||||||
|
tmp /= 4;
|
||||||
|
} while (G_MAXINT64 - sxx <= tmp);
|
||||||
|
break;
|
||||||
|
} else if (G_UNLIKELY (tmp < 0 && sxx < 0 && (G_MAXINT64 - sxx >= tmp))) {
|
||||||
|
do {
|
||||||
|
/* Drop some precision and restart */
|
||||||
|
pshift++;
|
||||||
|
sxx /= 4;
|
||||||
|
tmp /= 4;
|
||||||
|
} while (G_MININT64 - sxx >= tmp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sxx += tmp;
|
||||||
|
|
||||||
|
tmp = newy4 * newy4 - ybar4 * ybar4;
|
||||||
|
if (G_UNLIKELY (tmp > 0 && syy > 0 && (G_MAXINT64 - syy <= tmp))) {
|
||||||
|
do {
|
||||||
|
pshift++;
|
||||||
|
syy /= 4;
|
||||||
|
tmp /= 4;
|
||||||
|
} while (G_MAXINT64 - syy <= tmp);
|
||||||
|
break;
|
||||||
|
} else if (G_UNLIKELY (tmp < 0 && syy < 0 && (G_MAXINT64 - syy >= tmp))) {
|
||||||
|
do {
|
||||||
|
pshift++;
|
||||||
|
syy /= 4;
|
||||||
|
tmp /= 4;
|
||||||
|
} while (G_MININT64 - syy >= tmp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
syy += tmp;
|
||||||
|
|
||||||
|
tmp = newx4 * newy4 - xbar4 * ybar4;
|
||||||
|
if (G_UNLIKELY (tmp > 0 && sxy > 0 && (G_MAXINT64 - sxy <= tmp))) {
|
||||||
|
do {
|
||||||
|
pshift++;
|
||||||
|
sxy /= 4;
|
||||||
|
tmp /= 4;
|
||||||
|
} while (G_MAXINT64 - sxy <= tmp);
|
||||||
|
break;
|
||||||
|
} else if (G_UNLIKELY (tmp < 0 && sxy < 0 && (G_MININT64 - sxy >= tmp))) {
|
||||||
|
do {
|
||||||
|
pshift++;
|
||||||
|
sxy /= 4;
|
||||||
|
tmp /= 4;
|
||||||
|
} while (G_MININT64 - sxy >= tmp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sxy += tmp;
|
||||||
|
}
|
||||||
|
} while (i < n);
|
||||||
|
|
||||||
|
if (G_UNLIKELY (sxx == 0))
|
||||||
|
goto invalid;
|
||||||
|
|
||||||
|
*m_num = sxy;
|
||||||
|
*m_denom = sxx;
|
||||||
|
*b = (ymin + ybar) - gst_util_uint64_scale_round (xbar, *m_num, *m_denom);
|
||||||
|
/* Report base starting from the most recent observation */
|
||||||
|
*xbase = xmax;
|
||||||
|
*b += gst_util_uint64_scale_round (xmax - xmin, *m_num, *m_denom);
|
||||||
|
|
||||||
|
*r_squared = ((double) sxy * (double) sxy) / ((double) sxx * (double) syy);
|
||||||
|
|
||||||
|
#ifdef DEBUGGING_ENABLED
|
||||||
|
GST_CAT_DEBUG (GST_CAT_CLOCK, " m = %g", ((double) *m_num) / *m_denom);
|
||||||
|
GST_CAT_DEBUG (GST_CAT_CLOCK, " b = %" G_GUINT64_FORMAT, *b);
|
||||||
|
GST_CAT_DEBUG (GST_CAT_CLOCK, " xbase = %" G_GUINT64_FORMAT, *xbase);
|
||||||
|
GST_CAT_DEBUG (GST_CAT_CLOCK, " r2 = %g", *r_squared);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (temp == NULL && n > 64)
|
||||||
|
g_free (newx);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
invalid:
|
||||||
|
{
|
||||||
|
GST_CAT_DEBUG (GST_CAT_CLOCK, "sxx == 0, regression failed");
|
||||||
|
if (temp == NULL && n > 64)
|
||||||
|
g_free (newx);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1055,6 +1055,12 @@ gboolean gst_util_fraction_add (gint a_n, gint a_d, gint b_n, g
|
||||||
gint *res_n, gint *res_d);
|
gint *res_n, gint *res_d);
|
||||||
gint gst_util_fraction_compare (gint a_n, gint a_d, gint b_n, gint b_d);
|
gint gst_util_fraction_compare (gint a_n, gint a_d, gint b_n, gint b_d);
|
||||||
|
|
||||||
|
gboolean gst_calculate_linear_regression (const GstClockTime * xy,
|
||||||
|
GstClockTime * temp, guint n,
|
||||||
|
GstClockTime * m_num, GstClockTime * m_denom,
|
||||||
|
GstClockTime * b, GstClockTime * xbase,
|
||||||
|
gdouble * r_squared);
|
||||||
|
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,6 @@
|
||||||
* Boston, MA 02110-1301, USA.
|
* Boston, MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Include the non-public linear regression function */
|
|
||||||
#include "../../gst/gstclock-linreg.c"
|
|
||||||
#include <gst/check/gstcheck.h>
|
#include <gst/check/gstcheck.h>
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -111,202 +109,6 @@ GST_START_TEST (test_set_master_refcount)
|
||||||
|
|
||||||
GST_END_TEST;
|
GST_END_TEST;
|
||||||
|
|
||||||
GstClockTime times1[] = {
|
|
||||||
257116899087539, 0, 120632754291904, 0,
|
|
||||||
257117935914250, 0, 120633825367344, 0,
|
|
||||||
257119448289434, 0, 120635306141271, 0,
|
|
||||||
257120493671524, 0, 120636384357825, 0,
|
|
||||||
257121550784861, 0, 120637417438878, 0,
|
|
||||||
257123042669403, 0, 120638895344150, 0,
|
|
||||||
257124089184865, 0, 120639971729651, 0,
|
|
||||||
257125545836474, 0, 120641406788243, 0,
|
|
||||||
257127030618490, 0, 120642885914220, 0,
|
|
||||||
257128033712770, 0, 120643888843907, 0,
|
|
||||||
257129081768074, 0, 120644981892002, 0,
|
|
||||||
257130145383845, 0, 120646016376867, 0,
|
|
||||||
257131532530200, 0, 120647389850987, 0,
|
|
||||||
257132578136034, 0, 120648472767247, 0,
|
|
||||||
257134102475722, 0, 120649953785315, 0,
|
|
||||||
257135142994788, 0, 120651028858556, 0,
|
|
||||||
257136585079868, 0, 120652441303624, 0,
|
|
||||||
257137618260656, 0, 120653491627112, 0,
|
|
||||||
257139108694546, 0, 120654963978184, 0,
|
|
||||||
257140644022048, 0, 120656500233068, 0,
|
|
||||||
257141685671825, 0, 120657578510655, 0,
|
|
||||||
257142741238288, 0, 120658610889805, 0,
|
|
||||||
257144243633074, 0, 120660093098060, 0,
|
|
||||||
257145287962271, 0, 120661172901525, 0,
|
|
||||||
257146740596716, 0, 120662591572179, 0,
|
|
||||||
257147757607150, 0, 120663622822179, 0,
|
|
||||||
257149263992401, 0, 120665135578527, 0,
|
|
||||||
257150303719290, 0, 120666176166905, 0,
|
|
||||||
257151355569906, 0, 120667217304601, 0,
|
|
||||||
257152430578406, 0, 120668326099768, 0,
|
|
||||||
257153490501095, 0, 120669360554111, 0,
|
|
||||||
257154512360784, 0, 120670365497960, 0,
|
|
||||||
257155530610577, 0, 120671399006259, 0,
|
|
||||||
257156562091659, 0, 120672432728185, 0,
|
|
||||||
257157945388742, 0, 120673800312414, 0,
|
|
||||||
257159287547073, 0, 120675142444983, 0,
|
|
||||||
257160324912880, 0, 120676215076817, 0,
|
|
||||||
257345408328042, 0, 120861261738196, 0,
|
|
||||||
257346412270919, 0, 120862265613926, 0,
|
|
||||||
257347420532284, 0, 120863278644933, 0,
|
|
||||||
257348431187638, 0, 120864284412754, 0,
|
|
||||||
257349439018028, 0, 120865293110265, 0,
|
|
||||||
257351796217938, 0, 120867651111973, 0,
|
|
||||||
257352803038092, 0, 120868659107578, 0,
|
|
||||||
257354152688899, 0, 120870008594883, 0,
|
|
||||||
257355157088906, 0, 120871011097327, 0,
|
|
||||||
257356162439182, 0, 120872016346348, 0,
|
|
||||||
257357167872040, 0, 120873021656407, 0,
|
|
||||||
257358182440058, 0, 120874048633945, 0,
|
|
||||||
257359198881356, 0, 120875052265538, 0,
|
|
||||||
257100756525466, 0, 120616619282139, 0,
|
|
||||||
257101789337770, 0, 120617655475988, 0,
|
|
||||||
257102816323472, 0, 120618674000157, 0,
|
|
||||||
257103822485250, 0, 120619679005039, 0,
|
|
||||||
257104840760423, 0, 120620710743321, 0,
|
|
||||||
257105859459496, 0, 120621715351476, 0,
|
|
||||||
257106886662470, 0, 120622764942539, 0,
|
|
||||||
257108387497864, 0, 120624244221106, 0,
|
|
||||||
257109428859191, 0, 120625321461096, 0,
|
|
||||||
257110485892785, 0, 120626356892003, 0,
|
|
||||||
257111869872141, 0, 120627726459874, 0,
|
|
||||||
257112915903774, 0, 120628813190830, 0,
|
|
||||||
257114329982208, 0, 120630187061682, 0,
|
|
||||||
257115376666026, 0, 120631271992101, 0
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
GstClockTime times2[] = {
|
|
||||||
291678579009762, 0, 162107345029507, 0,
|
|
||||||
291679770464405, 0, 162108597684538, 0,
|
|
||||||
291680972924370, 0, 162109745816863, 0,
|
|
||||||
291682278949629, 0, 162111000577605, 0,
|
|
||||||
291683590706117, 0, 162112357724822, 0,
|
|
||||||
291684792322541, 0, 162113613156950, 0,
|
|
||||||
291685931362506, 0, 162114760556854, 0,
|
|
||||||
291687132156589, 0, 162115909238493, 0,
|
|
||||||
291688265012060, 0, 162117120603240, 0,
|
|
||||||
291689372183047, 0, 162118126279508, 0,
|
|
||||||
291705506022294, 0, 162134329373992, 0,
|
|
||||||
291667914301004, 0, 162096795553658, 0,
|
|
||||||
291668119537668, 0, 162096949051905, 0,
|
|
||||||
291668274671455, 0, 162097049238371, 0,
|
|
||||||
291668429435600, 0, 162097256356719, 0,
|
|
||||||
291668586128535, 0, 162097355689763, 0,
|
|
||||||
291668741306233, 0, 162097565678460, 0,
|
|
||||||
291668893789203, 0, 162097661044916, 0,
|
|
||||||
291669100256555, 0, 162097865694145, 0,
|
|
||||||
291669216417563, 0, 162098069214693, 0,
|
|
||||||
291669836394620, 0, 162098677275530, 0,
|
|
||||||
291669990447821, 0, 162098792601263, 0,
|
|
||||||
291670149426086, 0, 162098916899184, 0,
|
|
||||||
291670300232152, 0, 162099114225621, 0,
|
|
||||||
291670411261917, 0, 162099236784112, 0,
|
|
||||||
291670598483507, 0, 162099402158751, 0,
|
|
||||||
291671716582687, 0, 162100558744122, 0,
|
|
||||||
291672600759788, 0, 162101499326359, 0,
|
|
||||||
291673919988307, 0, 162102751981384, 0,
|
|
||||||
291675174441643, 0, 162104005551939, 0,
|
|
||||||
291676271562197, 0, 162105105252898, 0,
|
|
||||||
291677376345374, 0, 162106195737516, 0
|
|
||||||
};
|
|
||||||
|
|
||||||
GstClockTime times3[] = {
|
|
||||||
291881924291688, 0, 162223997578228, 0,
|
|
||||||
291883318122262, 0, 162224167198360, 0,
|
|
||||||
291884786394838, 0, 162224335172501, 0,
|
|
||||||
291886004374386, 0, 162224503695531, 0,
|
|
||||||
291887224353285, 0, 162224673560021, 0,
|
|
||||||
291888472403367, 0, 162224843760361, 0,
|
|
||||||
291889727977561, 0, 162225014479362, 0,
|
|
||||||
291890989982306, 0, 162225174554558, 0,
|
|
||||||
291892247875763, 0, 162225339753039, 0,
|
|
||||||
291893502163547, 0, 162225673230987, 0,
|
|
||||||
291894711382216, 0, 162225829494101, 0,
|
|
||||||
291895961021506, 0, 162225964530832, 0,
|
|
||||||
291897251690854, 0, 162226127287981, 0,
|
|
||||||
291898508630785, 0, 162226303710406, 0,
|
|
||||||
291899740172868, 0, 162226472478047, 0,
|
|
||||||
291900998878873, 0, 162226637402085, 0,
|
|
||||||
291902334919875, 0, 162226797873245, 0,
|
|
||||||
291903572196610, 0, 162226964352963, 0,
|
|
||||||
291904727342699, 0, 162227125312525, 0,
|
|
||||||
291906071189108, 0, 162228361337153, 0,
|
|
||||||
291907308146005, 0, 162229560625638, 0,
|
|
||||||
291908351925126, 0, 162230604986650, 0,
|
|
||||||
291909396411423, 0, 162231653690543, 0,
|
|
||||||
291910453965348, 0, 162232698550995, 0,
|
|
||||||
291912096870744, 0, 162233475264947, 0,
|
|
||||||
291913234148395, 0, 162233606516855, 0,
|
|
||||||
291915448096576, 0, 162233921145559, 0,
|
|
||||||
291916707748827, 0, 162234047154298, 0,
|
|
||||||
291918737451070, 0, 162234370837425, 0,
|
|
||||||
291919896016205, 0, 162234705504337, 0,
|
|
||||||
291921098663980, 0, 162234872320397, 0,
|
|
||||||
291922315691409, 0, 162235031023366, 0
|
|
||||||
};
|
|
||||||
|
|
||||||
struct test_entry
|
|
||||||
{
|
|
||||||
gint n;
|
|
||||||
GstClockTime *v;
|
|
||||||
GstClockTime expect_internal;
|
|
||||||
GstClockTime expect_external;
|
|
||||||
guint64 expect_num;
|
|
||||||
guint64 expect_denom;
|
|
||||||
} times[] = {
|
|
||||||
{
|
|
||||||
32, times1, 257154512360784, 120670380469753, 4052622913376634109,
|
|
||||||
4052799313904261962}, {
|
|
||||||
64, times1, 257359198881356, 120875054227405, 2011895759027682422,
|
|
||||||
2012014931360215503}, {
|
|
||||||
32, times2, 291705506022294, 162134297192792, 2319535707505209857,
|
|
||||||
2321009753483354451}, {
|
|
||||||
32, times3, 291922315691409, 162234934150296, 1370930728180888261,
|
|
||||||
4392719527011673456}
|
|
||||||
};
|
|
||||||
|
|
||||||
GST_START_TEST (test_regression)
|
|
||||||
{
|
|
||||||
GstClockTime m_num, m_den, internal, external;
|
|
||||||
gdouble r_squared, rate, expect_rate;
|
|
||||||
gint i;
|
|
||||||
|
|
||||||
for (i = 0; i < G_N_ELEMENTS (times); i++) {
|
|
||||||
fail_unless (_priv_gst_do_linear_regression (times[i].v, times[i].n,
|
|
||||||
&m_num, &m_den, &external, &internal, &r_squared));
|
|
||||||
|
|
||||||
GST_LOG ("xbase %" G_GUINT64_FORMAT " ybase %" G_GUINT64_FORMAT " rate = %"
|
|
||||||
G_GUINT64_FORMAT " / %" G_GUINT64_FORMAT " = %.10f r_squared %f\n",
|
|
||||||
internal, external, m_num, m_den, (gdouble) (m_num) / (m_den),
|
|
||||||
r_squared);
|
|
||||||
|
|
||||||
/* Require high correlation */
|
|
||||||
fail_unless (r_squared >= 0.9);
|
|
||||||
|
|
||||||
fail_unless (internal == times[i].expect_internal,
|
|
||||||
"Regression params %d fail. internal %" G_GUINT64_FORMAT
|
|
||||||
" != expected %" G_GUINT64_FORMAT, i, internal,
|
|
||||||
times[i].expect_internal);
|
|
||||||
/* Rate must be within 1% tolerance */
|
|
||||||
expect_rate = ((gdouble) (times[i].expect_num) / times[i].expect_denom);
|
|
||||||
rate = ((gdouble) (m_num) / m_den);
|
|
||||||
fail_unless ((expect_rate - rate) >= -0.1 && (expect_rate - rate) <= 0.1,
|
|
||||||
"Regression params %d fail. Rate out of range. Expected %f, got %f",
|
|
||||||
i, expect_rate, rate);
|
|
||||||
fail_unless (external >= times[i].expect_external * 0.99 &&
|
|
||||||
external <= times[i].expect_external * 1.01,
|
|
||||||
"Regression params %d fail. external %" G_GUINT64_FORMAT
|
|
||||||
" != expected %" G_GUINT64_FORMAT, i, external,
|
|
||||||
times[i].expect_external);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GST_END_TEST;
|
|
||||||
|
|
||||||
static Suite *
|
static Suite *
|
||||||
gst_clock_suite (void)
|
gst_clock_suite (void)
|
||||||
{
|
{
|
||||||
|
@ -315,7 +117,6 @@ gst_clock_suite (void)
|
||||||
|
|
||||||
suite_add_tcase (s, tc_chain);
|
suite_add_tcase (s, tc_chain);
|
||||||
tcase_add_test (tc_chain, test_set_master_refcount);
|
tcase_add_test (tc_chain, test_set_master_refcount);
|
||||||
tcase_add_test (tc_chain, test_regression);
|
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1747,6 +1747,212 @@ GST_START_TEST (test_element_link_with_ghost_pads)
|
||||||
|
|
||||||
GST_END_TEST;
|
GST_END_TEST;
|
||||||
|
|
||||||
|
static const GstClockTime times1[] = {
|
||||||
|
257116899087539, 120632754291904,
|
||||||
|
257117935914250, 120633825367344,
|
||||||
|
257119448289434, 120635306141271,
|
||||||
|
257120493671524, 120636384357825,
|
||||||
|
257121550784861, 120637417438878,
|
||||||
|
257123042669403, 120638895344150,
|
||||||
|
257124089184865, 120639971729651,
|
||||||
|
257125545836474, 120641406788243,
|
||||||
|
257127030618490, 120642885914220,
|
||||||
|
257128033712770, 120643888843907,
|
||||||
|
257129081768074, 120644981892002,
|
||||||
|
257130145383845, 120646016376867,
|
||||||
|
257131532530200, 120647389850987,
|
||||||
|
257132578136034, 120648472767247,
|
||||||
|
257134102475722, 120649953785315,
|
||||||
|
257135142994788, 120651028858556,
|
||||||
|
257136585079868, 120652441303624,
|
||||||
|
257137618260656, 120653491627112,
|
||||||
|
257139108694546, 120654963978184,
|
||||||
|
257140644022048, 120656500233068,
|
||||||
|
257141685671825, 120657578510655,
|
||||||
|
257142741238288, 120658610889805,
|
||||||
|
257144243633074, 120660093098060,
|
||||||
|
257145287962271, 120661172901525,
|
||||||
|
257146740596716, 120662591572179,
|
||||||
|
257147757607150, 120663622822179,
|
||||||
|
257149263992401, 120665135578527,
|
||||||
|
257150303719290, 120666176166905,
|
||||||
|
257151355569906, 120667217304601,
|
||||||
|
257152430578406, 120668326099768,
|
||||||
|
257153490501095, 120669360554111,
|
||||||
|
257154512360784, 120670365497960,
|
||||||
|
257155530610577, 120671399006259,
|
||||||
|
257156562091659, 120672432728185,
|
||||||
|
257157945388742, 120673800312414,
|
||||||
|
257159287547073, 120675142444983,
|
||||||
|
257160324912880, 120676215076817,
|
||||||
|
257345408328042, 120861261738196,
|
||||||
|
257346412270919, 120862265613926,
|
||||||
|
257347420532284, 120863278644933,
|
||||||
|
257348431187638, 120864284412754,
|
||||||
|
257349439018028, 120865293110265,
|
||||||
|
257351796217938, 120867651111973,
|
||||||
|
257352803038092, 120868659107578,
|
||||||
|
257354152688899, 120870008594883,
|
||||||
|
257355157088906, 120871011097327,
|
||||||
|
257356162439182, 120872016346348,
|
||||||
|
257357167872040, 120873021656407,
|
||||||
|
257358182440058, 120874048633945,
|
||||||
|
257359198881356, 120875052265538,
|
||||||
|
257100756525466, 120616619282139,
|
||||||
|
257101789337770, 120617655475988,
|
||||||
|
257102816323472, 120618674000157,
|
||||||
|
257103822485250, 120619679005039,
|
||||||
|
257104840760423, 120620710743321,
|
||||||
|
257105859459496, 120621715351476,
|
||||||
|
257106886662470, 120622764942539,
|
||||||
|
257108387497864, 120624244221106,
|
||||||
|
257109428859191, 120625321461096,
|
||||||
|
257110485892785, 120626356892003,
|
||||||
|
257111869872141, 120627726459874,
|
||||||
|
257112915903774, 120628813190830,
|
||||||
|
257114329982208, 120630187061682,
|
||||||
|
257115376666026, 120631271992101
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static const GstClockTime times2[] = {
|
||||||
|
291678579009762, 162107345029507,
|
||||||
|
291679770464405, 162108597684538,
|
||||||
|
291680972924370, 162109745816863,
|
||||||
|
291682278949629, 162111000577605,
|
||||||
|
291683590706117, 162112357724822,
|
||||||
|
291684792322541, 162113613156950,
|
||||||
|
291685931362506, 162114760556854,
|
||||||
|
291687132156589, 162115909238493,
|
||||||
|
291688265012060, 162117120603240,
|
||||||
|
291689372183047, 162118126279508,
|
||||||
|
291705506022294, 162134329373992,
|
||||||
|
291667914301004, 162096795553658,
|
||||||
|
291668119537668, 162096949051905,
|
||||||
|
291668274671455, 162097049238371,
|
||||||
|
291668429435600, 162097256356719,
|
||||||
|
291668586128535, 162097355689763,
|
||||||
|
291668741306233, 162097565678460,
|
||||||
|
291668893789203, 162097661044916,
|
||||||
|
291669100256555, 162097865694145,
|
||||||
|
291669216417563, 162098069214693,
|
||||||
|
291669836394620, 162098677275530,
|
||||||
|
291669990447821, 162098792601263,
|
||||||
|
291670149426086, 162098916899184,
|
||||||
|
291670300232152, 162099114225621,
|
||||||
|
291670411261917, 162099236784112,
|
||||||
|
291670598483507, 162099402158751,
|
||||||
|
291671716582687, 162100558744122,
|
||||||
|
291672600759788, 162101499326359,
|
||||||
|
291673919988307, 162102751981384,
|
||||||
|
291675174441643, 162104005551939,
|
||||||
|
291676271562197, 162105105252898,
|
||||||
|
291677376345374, 162106195737516
|
||||||
|
};
|
||||||
|
|
||||||
|
static const GstClockTime times3[] = {
|
||||||
|
291881924291688, 162223997578228,
|
||||||
|
291883318122262, 162224167198360,
|
||||||
|
291884786394838, 162224335172501,
|
||||||
|
291886004374386, 162224503695531,
|
||||||
|
291887224353285, 162224673560021,
|
||||||
|
291888472403367, 162224843760361,
|
||||||
|
291889727977561, 162225014479362,
|
||||||
|
291890989982306, 162225174554558,
|
||||||
|
291892247875763, 162225339753039,
|
||||||
|
291893502163547, 162225673230987,
|
||||||
|
291894711382216, 162225829494101,
|
||||||
|
291895961021506, 162225964530832,
|
||||||
|
291897251690854, 162226127287981,
|
||||||
|
291898508630785, 162226303710406,
|
||||||
|
291899740172868, 162226472478047,
|
||||||
|
291900998878873, 162226637402085,
|
||||||
|
291902334919875, 162226797873245,
|
||||||
|
291903572196610, 162226964352963,
|
||||||
|
291904727342699, 162227125312525,
|
||||||
|
291906071189108, 162228361337153,
|
||||||
|
291907308146005, 162229560625638,
|
||||||
|
291908351925126, 162230604986650,
|
||||||
|
291909396411423, 162231653690543,
|
||||||
|
291910453965348, 162232698550995,
|
||||||
|
291912096870744, 162233475264947,
|
||||||
|
291913234148395, 162233606516855,
|
||||||
|
291915448096576, 162233921145559,
|
||||||
|
291916707748827, 162234047154298,
|
||||||
|
291918737451070, 162234370837425,
|
||||||
|
291919896016205, 162234705504337,
|
||||||
|
291921098663980, 162234872320397,
|
||||||
|
291922315691409, 162235031023366
|
||||||
|
};
|
||||||
|
|
||||||
|
static const GstClockTime times4[] = {
|
||||||
|
10, 0,
|
||||||
|
20, 20,
|
||||||
|
30, 40,
|
||||||
|
40, 60,
|
||||||
|
50, 80,
|
||||||
|
60, 100
|
||||||
|
};
|
||||||
|
|
||||||
|
struct test_entry
|
||||||
|
{
|
||||||
|
gint n;
|
||||||
|
const GstClockTime *v;
|
||||||
|
GstClockTime expect_internal;
|
||||||
|
GstClockTime expect_external;
|
||||||
|
guint64 expect_num;
|
||||||
|
guint64 expect_denom;
|
||||||
|
} times[] = {
|
||||||
|
{
|
||||||
|
32, times1, 257154512360784, 120670380469753, 4052622913376634109,
|
||||||
|
4052799313904261962}, {
|
||||||
|
64, times1, 257359198881356, 120875054227405, 2011895759027682422,
|
||||||
|
2012014931360215503}, {
|
||||||
|
32, times2, 291705506022294, 162134297192792, 2319535707505209857,
|
||||||
|
2321009753483354451}, {
|
||||||
|
32, times3, 291922315691409, 162234934150296, 1370930728180888261,
|
||||||
|
4392719527011673456}, {
|
||||||
|
6, times4, 60, 100, 2, 1}
|
||||||
|
};
|
||||||
|
|
||||||
|
GST_START_TEST (test_regression)
|
||||||
|
{
|
||||||
|
GstClockTime m_num, m_den, internal, external;
|
||||||
|
gdouble r_squared, rate, expect_rate;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
for (i = 0; i < G_N_ELEMENTS (times); i++) {
|
||||||
|
fail_unless (gst_calculate_linear_regression (times[i].v, NULL, times[i].n,
|
||||||
|
&m_num, &m_den, &external, &internal, &r_squared));
|
||||||
|
|
||||||
|
GST_LOG ("xbase %" G_GUINT64_FORMAT " ybase %" G_GUINT64_FORMAT " rate = %"
|
||||||
|
G_GUINT64_FORMAT " / %" G_GUINT64_FORMAT " = %.10f r_squared %f\n",
|
||||||
|
internal, external, m_num, m_den, (gdouble) (m_num) / (m_den),
|
||||||
|
r_squared);
|
||||||
|
|
||||||
|
/* Require high correlation */
|
||||||
|
fail_unless (r_squared >= 0.9);
|
||||||
|
|
||||||
|
fail_unless (internal == times[i].expect_internal,
|
||||||
|
"Regression params %d fail. internal %" G_GUINT64_FORMAT
|
||||||
|
" != expected %" G_GUINT64_FORMAT, i, internal,
|
||||||
|
times[i].expect_internal);
|
||||||
|
/* Rate must be within 1% tolerance */
|
||||||
|
expect_rate = ((gdouble) (times[i].expect_num) / times[i].expect_denom);
|
||||||
|
rate = ((gdouble) (m_num) / m_den);
|
||||||
|
fail_unless ((expect_rate - rate) >= -0.1 && (expect_rate - rate) <= 0.1,
|
||||||
|
"Regression params %d fail. Rate out of range. Expected %f, got %f",
|
||||||
|
i, expect_rate, rate);
|
||||||
|
fail_unless (external >= times[i].expect_external * 0.99 &&
|
||||||
|
external <= times[i].expect_external * 1.01,
|
||||||
|
"Regression params %d fail. external %" G_GUINT64_FORMAT
|
||||||
|
" != expected %" G_GUINT64_FORMAT, i, external,
|
||||||
|
times[i].expect_external);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_END_TEST;
|
||||||
|
|
||||||
static Suite *
|
static Suite *
|
||||||
gst_utils_suite (void)
|
gst_utils_suite (void)
|
||||||
{
|
{
|
||||||
|
@ -1786,6 +1992,7 @@ gst_utils_suite (void)
|
||||||
|
|
||||||
tcase_add_test (tc_chain, test_read_macros);
|
tcase_add_test (tc_chain, test_read_macros);
|
||||||
tcase_add_test (tc_chain, test_write_macros);
|
tcase_add_test (tc_chain, test_write_macros);
|
||||||
|
tcase_add_test (tc_chain, test_regression);
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
|
@ -224,6 +224,7 @@ EXPORTS
|
||||||
gst_bus_sync_signal_handler
|
gst_bus_sync_signal_handler
|
||||||
gst_bus_timed_pop
|
gst_bus_timed_pop
|
||||||
gst_bus_timed_pop_filtered
|
gst_bus_timed_pop_filtered
|
||||||
|
gst_calculate_linear_regression
|
||||||
gst_caps_append
|
gst_caps_append
|
||||||
gst_caps_append_structure
|
gst_caps_append_structure
|
||||||
gst_caps_append_structure_full
|
gst_caps_append_structure_full
|
||||||
|
|
Loading…
Reference in a new issue