diff options
-rw-r--r-- | docs/gst/gstreamer-sections.txt | 1 | ||||
-rw-r--r-- | gst/Makefile.am | 1 | ||||
-rw-r--r-- | gst/gst_private.h | 6 | ||||
-rw-r--r-- | gst/gstclock-linreg.c | 241 | ||||
-rw-r--r-- | gst/gstclock.c | 14 | ||||
-rw-r--r-- | gst/gstutils.c | 263 | ||||
-rw-r--r-- | gst/gstutils.h | 6 | ||||
-rw-r--r-- | tests/check/gst/gstclock.c | 199 | ||||
-rw-r--r-- | tests/check/gst/gstutils.c | 207 | ||||
-rw-r--r-- | win32/common/libgstreamer.def | 1 |
10 files changed, 488 insertions, 451 deletions
diff --git a/docs/gst/gstreamer-sections.txt b/docs/gst/gstreamer-sections.txt index d85b065bd..30150feac 100644 --- a/docs/gst/gstreamer-sections.txt +++ b/docs/gst/gstreamer-sections.txt @@ -3547,6 +3547,7 @@ gst_util_guint64_to_gdouble gst_util_gdouble_to_guint64 GST_TYPE_SEARCH_MODE gst_search_mode_get_type +gst_calculate_linear_regression </SECTION> <SECTION> diff --git a/gst/Makefile.am b/gst/Makefile.am index 91e0e70d5..b06ec4fbb 100644 --- a/gst/Makefile.am +++ b/gst/Makefile.am @@ -59,7 +59,6 @@ libgstreamer_@GST_API_VERSION@_la_SOURCES = \ gstcapsfeatures.c \ gstchildproxy.c \ gstclock.c \ - gstclock-linreg.c \ gstcontext.c \ gstcontrolbinding.c \ gstcontrolsource.c \ diff --git a/gst/gst_private.h b/gst/gst_private.h index d84cb5a29..b08688041 100644 --- a/gst/gst_private.h +++ b/gst/gst_private.h @@ -209,12 +209,6 @@ gint __gst_date_time_compare (const GstDateTime * dt1, const GstDateTime * dt2); G_GNUC_INTERNAL 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 */ G_GNUC_INTERNAL GstCapsFeatures * __gst_caps_get_features_unchecked (const GstCaps * caps, guint idx); diff --git a/gst/gstclock-linreg.c b/gst/gstclock-linreg.c deleted file mode 100644 index 874917fef..000000000 --- a/gst/gstclock-linreg.c +++ /dev/null @@ -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; - } -} diff --git a/gst/gstclock.c b/gst/gstclock.c index 395fe7652..e17d23253 100644 --- a/gst/gstclock.c +++ b/gst/gstclock.c @@ -157,6 +157,7 @@ struct _GstClockPrivate gint time_index; GstClockTime timeout; GstClockTime *times; + GstClockTime *times_temp; GstClockID clockid; gint pre_count; @@ -738,6 +739,8 @@ gst_clock_init (GstClock * clock) priv->time_index = 0; priv->timeout = DEFAULT_TIMEOUT; priv->times = g_new0 (GstClockTime, 4 * priv->window_size); + priv->times_temp = + priv->times + 2 * priv->window_size * sizeof (GstClockTime); /* clear floating flag */ gst_object_ref_sink (clock); @@ -770,6 +773,7 @@ gst_clock_finalize (GObject * object) } g_free (clock->priv->times); clock->priv->times = NULL; + clock->priv->times_temp = NULL; GST_CLOCK_SLAVE_UNLOCK (clock); g_mutex_clear (&clock->priv->slave_lock); @@ -1420,8 +1424,8 @@ gst_clock_add_observation_unapplied (GstClock * clock, GstClockTime slave, "adding observation slave %" GST_TIME_FORMAT ", master %" GST_TIME_FORMAT, GST_TIME_ARGS (slave), GST_TIME_ARGS (master)); - priv->times[(4 * priv->time_index)] = slave; - priv->times[(4 * priv->time_index) + 2] = master; + priv->times[(2 * priv->time_index)] = slave; + priv->times[(2 * priv->time_index) + 1] = master; priv->time_index++; if (G_UNLIKELY (priv->time_index == priv->window_size)) { @@ -1433,8 +1437,8 @@ gst_clock_add_observation_unapplied (GstClock * clock, GstClockTime slave, goto filling; n = priv->filling ? priv->time_index : priv->window_size; - if (!_priv_gst_do_linear_regression (priv->times, n, &m_num, &m_denom, &b, - &xbase, r_squared)) + if (!gst_calculate_linear_regression (priv->times, priv->times_temp, n, + &m_num, &m_denom, &b, &xbase, r_squared)) goto invalid; GST_CLOCK_SLAVE_UNLOCK (clock); @@ -1523,6 +1527,8 @@ gst_clock_set_property (GObject * object, guint prop_id, priv->window_size = g_value_get_int (value); priv->window_threshold = MIN (priv->window_threshold, priv->window_size); priv->times = g_renew (GstClockTime, priv->times, 4 * priv->window_size); + priv->times_temp = + priv->times + 2 * priv->window_size * sizeof (GstClockTime); /* restart calibration */ priv->filling = TRUE; priv->time_index = 0; diff --git a/gst/gstutils.c b/gst/gstutils.c index e1265a09f..bd06dcabf 100644 --- a/gst/gstutils.c +++ b/gst/gstutils.c @@ -2,6 +2,8 @@ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu> * 2000 Wim Taymans <wtay@chello.be> * 2002 Thomas Vander Stichele <thomas@apestaart.org> + * 2004 Wim Taymans <wim@fluendo.com> + * 2015 Jan Schmidt <jan@centricular.com> * * gstutils.c: Utility functions * @@ -4045,3 +4047,264 @@ gst_util_group_id_next (void) static gint counter = 0; 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; + } +} diff --git a/gst/gstutils.h b/gst/gstutils.h index 523ee2012..e3ab89005 100644 --- a/gst/gstutils.h +++ b/gst/gstutils.h @@ -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 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 diff --git a/tests/check/gst/gstclock.c b/tests/check/gst/gstclock.c index e72bbc975..a6ec723ca 100644 --- a/tests/check/gst/gstclock.c +++ b/tests/check/gst/gstclock.c @@ -17,8 +17,6 @@ * Boston, MA 02110-1301, USA. */ -/* Include the non-public linear regression function */ -#include "../../gst/gstclock-linreg.c" #include <gst/check/gstcheck.h> typedef struct @@ -111,202 +109,6 @@ GST_START_TEST (test_set_master_refcount) 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 * gst_clock_suite (void) { @@ -315,7 +117,6 @@ gst_clock_suite (void) suite_add_tcase (s, tc_chain); tcase_add_test (tc_chain, test_set_master_refcount); - tcase_add_test (tc_chain, test_regression); return s; } diff --git a/tests/check/gst/gstutils.c b/tests/check/gst/gstutils.c index 3a5de6424..18ba199b9 100644 --- a/tests/check/gst/gstutils.c +++ b/tests/check/gst/gstutils.c @@ -1747,6 +1747,212 @@ GST_START_TEST (test_element_link_with_ghost_pads) 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 * 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_write_macros); + tcase_add_test (tc_chain, test_regression); return s; } diff --git a/win32/common/libgstreamer.def b/win32/common/libgstreamer.def index 9b29c7997..f63ffee4b 100644 --- a/win32/common/libgstreamer.def +++ b/win32/common/libgstreamer.def @@ -224,6 +224,7 @@ EXPORTS gst_bus_sync_signal_handler gst_bus_timed_pop gst_bus_timed_pop_filtered + gst_calculate_linear_regression gst_caps_append gst_caps_append_structure gst_caps_append_structure_full |