+2005-11-24 Wim Taymans <wim@fluendo.com>
+
+ * check/gst/gstutils.c: (GST_START_TEST), (gst_utils_suite):
+ Added test for scaling.
+
+ * gst/gstclock.h:
+ Small doc fix.
+
+ * gst/gstutils.c: (gst_util_uint64_scale_int):
+ Implemented high precision scaling code.
+
2005-11-24 Stefan Kost <ensonic@users.sf.net>
* gst/gstinfo.h:
g_assert (n_data_probes_once == 1); /* let's hit it and quit!!! */
} GST_END_TEST;
+GST_START_TEST (test_math_scale)
+{
+ fail_if (gst_util_uint64_scale_int (1, 1, 1) != 1);
+
+ fail_if (gst_util_uint64_scale_int (10, 10, 1) != 100);
+ fail_if (gst_util_uint64_scale_int (10, 10, 2) != 50);
+
+ fail_if (gst_util_uint64_scale_int (0, 10, 2) != 0);
+ fail_if (gst_util_uint64_scale_int (0, 0, 2) != 0);
+
+ fail_if (gst_util_uint64_scale_int (G_MAXUINT32, 5, 1) != G_MAXUINT32 * 5LL);
+ fail_if (gst_util_uint64_scale_int (G_MAXUINT32, 10, 2) != G_MAXUINT32 * 5LL);
+
+ fail_if (gst_util_uint64_scale_int (G_MAXUINT32, 1, 5) != G_MAXUINT32 / 5LL);
+ fail_if (gst_util_uint64_scale_int (G_MAXUINT32, 2, 10) != G_MAXUINT32 / 5LL);
+
+ /* not quite overflow */
+ fail_if (gst_util_uint64_scale_int (G_MAXUINT64 - 1, 10,
+ 10) != G_MAXUINT64 - 1);
+ fail_if (gst_util_uint64_scale_int (G_MAXUINT64 - 1, G_MAXINT32,
+ G_MAXINT32) != G_MAXUINT64 - 1);
+ fail_if (gst_util_uint64_scale_int (G_MAXUINT64 - 100, G_MAXINT32,
+ G_MAXINT32) != G_MAXUINT64 - 100);
+
+ /* overflow */
+ fail_if (gst_util_uint64_scale_int (G_MAXUINT64 - 1, 10, 1) != G_MAXUINT64);
+ fail_if (gst_util_uint64_scale_int (G_MAXUINT64 - 1, G_MAXINT32,
+ 1) != G_MAXUINT64);
+
+} GST_END_TEST;
+
Suite *
gst_utils_suite (void)
{
suite_add_tcase (s, tc_chain);
tcase_add_test (tc_chain, test_buffer_probe_n_times);
tcase_add_test (tc_chain, test_buffer_probe_once);
+ tcase_add_test (tc_chain, test_math_scale);
return s;
}
/**
* GstClockID:
*
- * A datatype to hold the handle to an outstanding async clock callback.
+ * A datatype to hold the handle to an outstanding sync or async clock callback.
*/
typedef gpointer GstClockID;
}
#endif
+
+/* convenience struct for getting high an low uint32 parts of
+ * a guint64 */
+typedef union
+{
+ guint64 ll;
+ struct
+ {
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+ guint32 high, low;
+#else
+ guint32 low, high;
+#endif
+ } l;
+} GstUInt64;
+
/**
* gst_util_uint64_scale:
* @val: the number to scale
/**
* gst_util_uint64_scale_int:
- * @val: GstClockTime to scale.
+ * @val: guint64 (such as a #GstClockTime) to scale.
* @num: numerator of the scale factor.
* @denom: denominator of the scale factor.
*
- * Scale a clocktime by a factor expressed as a fraction (num/denom), avoiding
+ * Scale a guint64 by a factor expressed as a fraction (num/denom), avoiding
* overflows and loss of precision.
*
+ * @num and @denom must be positive integers. @denom cannot be 0.
+ *
* Returns: @val * @num / @denom, avoiding overflow and loss of precision
*/
guint64
gst_util_uint64_scale_int (guint64 val, gint num, gint denom)
{
- return val * num / denom;
+ GstUInt64 result;
+
+ g_return_val_if_fail (denom > 0, G_MAXUINT64);
+ g_return_val_if_fail (num >= 0, G_MAXUINT64);
+
+ if (val <= G_MAXUINT32) {
+ /* simple case */
+ result.ll = val * num / denom;
+ } else {
+ GstUInt64 gval, low, high, temp;
+
+ /* do 96 bits mult/div */
+ gval.ll = val;
+ low.ll = ((guint64) gval.l.low) * num;
+ high.ll = ((guint64) gval.l.high) * num + (low.l.high);
+ result.ll = (high.ll / denom);
+ temp.l.high = (high.ll % denom);
+ temp.l.low = (low.l.low);
+ temp.ll /= denom;
+
+ /* avoid overflow */
+ if (result.ll + temp.l.high > G_MAXUINT32)
+ goto overflow;
+
+ result.l.high = result.l.low;
+ result.l.low = 0;
+ result.ll += temp.ll;
+ }
+ return result.ll;
+
+overflow:
+ {
+ return G_MAXUINT64;
+ }
}
/* -----------------------------------------------------
g_assert (n_data_probes_once == 1); /* let's hit it and quit!!! */
} GST_END_TEST;
+GST_START_TEST (test_math_scale)
+{
+ fail_if (gst_util_uint64_scale_int (1, 1, 1) != 1);
+
+ fail_if (gst_util_uint64_scale_int (10, 10, 1) != 100);
+ fail_if (gst_util_uint64_scale_int (10, 10, 2) != 50);
+
+ fail_if (gst_util_uint64_scale_int (0, 10, 2) != 0);
+ fail_if (gst_util_uint64_scale_int (0, 0, 2) != 0);
+
+ fail_if (gst_util_uint64_scale_int (G_MAXUINT32, 5, 1) != G_MAXUINT32 * 5LL);
+ fail_if (gst_util_uint64_scale_int (G_MAXUINT32, 10, 2) != G_MAXUINT32 * 5LL);
+
+ fail_if (gst_util_uint64_scale_int (G_MAXUINT32, 1, 5) != G_MAXUINT32 / 5LL);
+ fail_if (gst_util_uint64_scale_int (G_MAXUINT32, 2, 10) != G_MAXUINT32 / 5LL);
+
+ /* not quite overflow */
+ fail_if (gst_util_uint64_scale_int (G_MAXUINT64 - 1, 10,
+ 10) != G_MAXUINT64 - 1);
+ fail_if (gst_util_uint64_scale_int (G_MAXUINT64 - 1, G_MAXINT32,
+ G_MAXINT32) != G_MAXUINT64 - 1);
+ fail_if (gst_util_uint64_scale_int (G_MAXUINT64 - 100, G_MAXINT32,
+ G_MAXINT32) != G_MAXUINT64 - 100);
+
+ /* overflow */
+ fail_if (gst_util_uint64_scale_int (G_MAXUINT64 - 1, 10, 1) != G_MAXUINT64);
+ fail_if (gst_util_uint64_scale_int (G_MAXUINT64 - 1, G_MAXINT32,
+ 1) != G_MAXUINT64);
+
+} GST_END_TEST;
+
Suite *
gst_utils_suite (void)
{
suite_add_tcase (s, tc_chain);
tcase_add_test (tc_chain, test_buffer_probe_n_times);
tcase_add_test (tc_chain, test_buffer_probe_once);
+ tcase_add_test (tc_chain, test_math_scale);
return s;
}