check/gst/gstutils.c: Added test for scaling.
authorWim Taymans <wim.taymans@gmail.com>
Thu, 24 Nov 2005 17:44:57 +0000 (17:44 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Thu, 24 Nov 2005 17:44:57 +0000 (17:44 +0000)
Original commit message from CVS:
* 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.

ChangeLog
check/gst/gstutils.c
gst/gstclock.h
gst/gstutils.c
tests/check/gst/gstutils.c

index 5e72ee9..8fe32c9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+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:
index 9deafe0..a6ca771 100644 (file)
@@ -167,6 +167,37 @@ GST_START_TEST (test_buffer_probe_once)
   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)
 {
@@ -176,6 +207,7 @@ 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;
 }
 
index e9dd2af..b844577 100644 (file)
@@ -63,7 +63,7 @@ typedef gint64 GstClockTimeDiff;
 /**
  * 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;
 
index 4c8900b..d955719 100644 (file)
@@ -340,6 +340,22 @@ gst_gdouble_to_guint64 (gdouble value)
 }
 #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
@@ -360,19 +376,54 @@ gst_util_uint64_scale (guint64 val, guint64 num, guint64 denom)
 
 /**
  * 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;
+  }
 }
 
 /* -----------------------------------------------------
index 9deafe0..a6ca771 100644 (file)
@@ -167,6 +167,37 @@ GST_START_TEST (test_buffer_probe_once)
   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)
 {
@@ -176,6 +207,7 @@ 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;
 }