From: Sebastian Dröge Date: Mon, 16 Nov 2009 08:29:10 +0000 (+0100) Subject: gstutils: API: Add fraction helper functions X-Git-Tag: RELEASE-0.10.26~186 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e4257e8d5f4cc4eac60f981fc1fab522781373b0;p=platform%2Fupstream%2Fgstreamer.git gstutils: API: Add fraction helper functions gst_util_greatest_common_divisor() gst_util_double_to_fraction() gst_util_fraction_to_double() Using these instead of going over GValue has much lower overhead. Also add float<->fraction transform functions for GValue. --- diff --git a/docs/gst/gstreamer-sections.txt b/docs/gst/gstreamer-sections.txt index 9de1399..40c4069 100644 --- a/docs/gst/gstreamer-sections.txt +++ b/docs/gst/gstreamer-sections.txt @@ -2525,6 +2525,9 @@ gst_util_uint64_scale_ceil gst_util_uint64_scale_int gst_util_uint64_scale_int_round gst_util_uint64_scale_int_ceil +gst_util_greatest_common_divisor +gst_util_fraction_to_double +gst_util_double_to_fraction gst_util_seqnum_next gst_util_seqnum_compare gst_util_set_object_arg diff --git a/gst/gstutils.c b/gst/gstutils.c index ef9d1ca..d12aa9f 100644 --- a/gst/gstutils.c +++ b/gst/gstutils.c @@ -39,6 +39,7 @@ #include "gstparse.h" #include "gstvalue.h" #include "gst-i18n-lib.h" +#include /** * gst_util_dump_mem: @@ -3798,3 +3799,154 @@ gst_util_array_binary_search (gpointer array, guint num_elements, } } } + +/* Finds the greatest common divisor. + * Returns 1 if none other found. + * This is Euclid's algorithm. */ + +/** gst_util_greatest_common_divisor: + * @a: First value as #gint + * @b: Second value as #gint + * + * Calculates the greatest common divisor of @a + * and @b. + * + * Returns: Greatest common divisor of @a and @b + * + * Since: 0.10.26 + */ +gint +gst_util_greatest_common_divisor (gint a, gint b) +{ + while (b != 0) { + int temp = a; + + a = b; + b = temp % b; + } + + return ABS (a); +} + +/** gst_util_fraction_to_double: + * @src_n: Fraction numerator as #gint + * @src_d: Fraction denominator #gint + * @dest: pointer to a #gdouble for the result + * + * Transforms a #gdouble to a #GstFraction and simplifies + * the result. + * + * Since: 0.10.26 + */ +void +gst_util_fraction_to_double (gint src_n, gint src_d, gdouble * dest) +{ + g_return_if_fail (dest != NULL); + g_return_if_fail (src_d != 0); + + *dest = ((gdouble) src_n) / ((gdouble) src_d); +} + +#define MAX_TERMS 30 +#define MIN_DIVISOR 1.0e-10 +#define MAX_ERROR 1.0e-20 + +/* use continued fractions to transform a double into a fraction, + * see http://mathforum.org/dr.math/faq/faq.fractions.html#decfrac. + * This algorithm takes care of overflows. + */ + +/** gst_util_double_to_fraction: + * @src: #gdouble to transform + * @dest_n: pointer to a #gint to hold the result numerator + * @dest_d: pointer to a #gint to hold the result denominator + * + * Transforms a #gdouble to a #GstFraction and simplifies + * the result. + * + * Since: 0.10.26 + */ +void +gst_util_double_to_fraction (gdouble src, gint * dest_n, gint * dest_d) +{ + + gdouble V, F; /* double being converted */ + gint N, D; /* will contain the result */ + gint A; /* current term in continued fraction */ + gint64 N1, D1; /* numerator, denominator of last approx */ + gint64 N2, D2; /* numerator, denominator of previous approx */ + gint i; + gint gcd; + gboolean negative = FALSE; + + g_return_if_fail (dest_n != NULL); + g_return_if_fail (dest_d != NULL); + + /* initialize fraction being converted */ + F = src; + if (F < 0.0) { + F = -F; + negative = TRUE; + } + + V = F; + /* initialize fractions with 1/0, 0/1 */ + N1 = 1; + D1 = 0; + N2 = 0; + D2 = 1; + N = 1; + D = 1; + + for (i = 0; i < MAX_TERMS; i++) { + /* get next term */ + A = (gint) F; /* no floor() needed, F is always >= 0 */ + /* get new divisor */ + F = F - A; + + /* calculate new fraction in temp */ + N2 = N1 * A + N2; + D2 = D1 * A + D2; + + /* guard against overflow */ + if (N2 > G_MAXINT || D2 > G_MAXINT) { + break; + } + + N = N2; + D = D2; + + /* save last two fractions */ + N2 = N1; + D2 = D1; + N1 = N; + D1 = D; + + /* quit if dividing by zero or close enough to target */ + if (F < MIN_DIVISOR || fabs (V - ((gdouble) N) / D) < MAX_ERROR) { + break; + } + + /* Take reciprocal */ + F = 1 / F; + } + /* fix for overflow */ + if (D == 0) { + N = G_MAXINT; + D = 1; + } + /* fix for negative */ + if (negative) + N = -N; + + /* simplify */ + gcd = gst_util_greatest_common_divisor (N, D); + if (gcd) { + N /= gcd; + D /= gcd; + } + + /* set results */ + *dest_n = N; + *dest_d = D; +} diff --git a/gst/gstutils.h b/gst/gstutils.h index 0760183..4fa4c02 100644 --- a/gst/gstutils.h +++ b/gst/gstutils.h @@ -1166,6 +1166,10 @@ gpointer gst_util_array_binary_search (gpointer array, guint GstSearchMode mode, gconstpointer search_data, gpointer user_data); +gint gst_util_greatest_common_divisor (gint a, gint b); +void gst_util_fraction_to_double (gint src_n, gint src_d, gdouble *dest); +void gst_util_double_to_fraction (gdouble src, gint *dest_n, gint *dest_d); + G_END_DECLS #endif /* __GST_UTILS_H__ */ diff --git a/gst/gstvalue.c b/gst/gstvalue.c index 9dc3b2d..257cff3 100644 --- a/gst/gstvalue.c +++ b/gst/gstvalue.c @@ -43,6 +43,7 @@ #include "glib-compat-private.h" #include #include +#include "gstutils.h" typedef struct _GstValueUnionInfo GstValueUnionInfo; struct _GstValueUnionInfo @@ -81,7 +82,6 @@ static GArray *gst_value_intersect_funcs; static GArray *gst_value_subtract_funcs; /* Forward declarations */ -static gint gst_greatest_common_divisor (gint a, gint b); static gchar *gst_value_serialize_fraction (const GValue * value); static GstValueCompareFunc gst_value_get_compare_func (const GValue * value1); @@ -3476,23 +3476,6 @@ gst_value_is_fixed (const GValue * value) ************/ /* helper functions */ - -/* Finds the greatest common divisor. - * Returns 1 if none other found. - * This is Euclid's algorithm. */ -static gint -gst_greatest_common_divisor (gint a, gint b) -{ - while (b != 0) { - int temp = a; - - a = b; - b = temp % b; - } - - return ABS (a); -} - static void gst_value_init_fraction (GValue * value) { @@ -3564,7 +3547,7 @@ gst_value_set_fraction (GValue * value, gint numerator, gint denominator) } /* check for reduction */ - gcd = gst_greatest_common_divisor (numerator, denominator); + gcd = gst_util_greatest_common_divisor (numerator, denominator); if (gcd) { numerator /= gcd; denominator /= gcd; @@ -3633,10 +3616,10 @@ gst_value_fraction_multiply (GValue * product, const GValue * factor1, d1 = factor1->data[1].v_int; d2 = factor2->data[1].v_int; - gcd = gst_greatest_common_divisor (n1, d2); + gcd = gst_util_greatest_common_divisor (n1, d2); n1 /= gcd; d2 /= gcd; - gcd = gst_greatest_common_divisor (n2, d1); + gcd = gst_util_greatest_common_divisor (n2, d1); n2 /= gcd; d1 /= gcd; @@ -3759,85 +3742,26 @@ gst_value_transform_string_fraction (const GValue * src_value, gst_value_set_fraction (dest_value, 0, 1); } -#define MAX_TERMS 30 -#define MIN_DIVISOR 1.0e-10 -#define MAX_ERROR 1.0e-20 - -/* use continued fractions to transform a double into a fraction, - * see http://mathforum.org/dr.math/faq/faq.fractions.html#decfrac. - * This algorithm takes care of overflows. - */ static void gst_value_transform_double_fraction (const GValue * src_value, GValue * dest_value) { - gdouble V, F; /* double being converted */ - gint N, D; /* will contain the result */ - gint A; /* current term in continued fraction */ - gint64 N1, D1; /* numerator, denominator of last approx */ - gint64 N2, D2; /* numerator, denominator of previous approx */ - gint i; - gboolean negative = FALSE; - - /* initialize fraction being converted */ - F = src_value->data[0].v_double; - if (F < 0.0) { - F = -F; - negative = TRUE; - } - - V = F; - /* initialize fractions with 1/0, 0/1 */ - N1 = 1; - D1 = 0; - N2 = 0; - D2 = 1; - N = 1; - D = 1; - - for (i = 0; i < MAX_TERMS; i++) { - /* get next term */ - A = (gint) F; /* no floor() needed, F is always >= 0 */ - /* get new divisor */ - F = F - A; - - /* calculate new fraction in temp */ - N2 = N1 * A + N2; - D2 = D1 * A + D2; - - /* guard against overflow */ - if (N2 > G_MAXINT || D2 > G_MAXINT) { - break; - } - - N = N2; - D = D2; + gdouble src = g_value_get_double (src_value); + gint n, d; - /* save last two fractions */ - N2 = N1; - D2 = D1; - N1 = N; - D1 = D; - - /* quit if dividing by zero or close enough to target */ - if (F < MIN_DIVISOR || fabs (V - ((gdouble) N) / D) < MAX_ERROR) { - break; - } + gst_util_double_to_fraction (src, &n, &d); + gst_value_set_fraction (dest_value, n, d); +} - /* Take reciprocal */ - F = 1 / F; - } - /* fix for overflow */ - if (D == 0) { - N = G_MAXINT; - D = 1; - } - /* fix for negative */ - if (negative) - N = -N; +static void +gst_value_transform_float_fraction (const GValue * src_value, + GValue * dest_value) +{ + gfloat src = g_value_get_float (src_value); + gint n, d; - /* will also simplify */ - gst_value_set_fraction (dest_value, N, D); + gst_util_double_to_fraction (src, &n, &d); + gst_value_set_fraction (dest_value, n, d); } static void @@ -3848,6 +3772,14 @@ gst_value_transform_fraction_double (const GValue * src_value, ((double) src_value->data[1].v_int); } +static void +gst_value_transform_fraction_float (const GValue * src_value, + GValue * dest_value) +{ + dest_value->data[0].v_float = ((float) src_value->data[0].v_int) / + ((float) src_value->data[1].v_int); +} + static gint gst_value_compare_fraction (const GValue * value1, const GValue * value2) { @@ -4354,8 +4286,12 @@ _gst_value_initialize (void) gst_value_transform_string_fraction); g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_DOUBLE, gst_value_transform_fraction_double); + g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_FLOAT, + gst_value_transform_fraction_float); g_value_register_transform_func (G_TYPE_DOUBLE, GST_TYPE_FRACTION, gst_value_transform_double_fraction); + g_value_register_transform_func (G_TYPE_FLOAT, GST_TYPE_FRACTION, + gst_value_transform_float_fraction); g_value_register_transform_func (GST_TYPE_DATE, G_TYPE_STRING, gst_value_transform_date_string); g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_DATE, diff --git a/win32/common/libgstreamer.def b/win32/common/libgstreamer.def index c9e5069..6e8ede0 100644 --- a/win32/common/libgstreamer.def +++ b/win32/common/libgstreamer.def @@ -1056,9 +1056,12 @@ EXPORTS gst_uri_protocol_is_valid gst_uri_type_get_type gst_util_array_binary_search + gst_util_double_to_fraction gst_util_dump_mem + gst_util_fraction_to_double gst_util_gdouble_to_guint64 gst_util_get_timestamp + gst_util_greatest_common_divisor gst_util_guint64_to_gdouble gst_util_seqnum_compare gst_util_seqnum_next