media: v4l: move helper functions for fractions from uvc to v4l2-common
authorMichael Grzeschik <m.grzeschik@pengutronix.de>
Fri, 9 Sep 2022 22:13:32 +0000 (00:13 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 22 Sep 2022 13:52:30 +0000 (15:52 +0200)
The functions uvc_simplify_fraction and uvc_fraction_to_interval are
generic helpers which are also useful for other v4l2 drivers. This patch
moves them to v4l2-common.

Tested-by: Daniel Scally <dan.scally@ideasonboard.com>
Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com>
Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
Link: https://lore.kernel.org/r/20220909221335.15033-2-m.grzeschik@pengutronix.de
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/media/usb/uvc/uvc_driver.c
drivers/media/usb/uvc/uvc_v4l2.c
drivers/media/usb/uvc/uvcvideo.h
drivers/media/v4l2-core/v4l2-common.c
include/media/v4l2-common.h

index 9c05776..0f14dee 100644 (file)
@@ -329,90 +329,6 @@ static enum v4l2_ycbcr_encoding uvc_ycbcr_enc(const u8 matrix_coefficients)
        return V4L2_YCBCR_ENC_DEFAULT;  /* Reserved */
 }
 
-/*
- * Simplify a fraction using a simple continued fraction decomposition. The
- * idea here is to convert fractions such as 333333/10000000 to 1/30 using
- * 32 bit arithmetic only. The algorithm is not perfect and relies upon two
- * arbitrary parameters to remove non-significative terms from the simple
- * continued fraction decomposition. Using 8 and 333 for n_terms and threshold
- * respectively seems to give nice results.
- */
-void uvc_simplify_fraction(u32 *numerator, u32 *denominator,
-               unsigned int n_terms, unsigned int threshold)
-{
-       u32 *an;
-       u32 x, y, r;
-       unsigned int i, n;
-
-       an = kmalloc_array(n_terms, sizeof(*an), GFP_KERNEL);
-       if (an == NULL)
-               return;
-
-       /*
-        * Convert the fraction to a simple continued fraction. See
-        * https://en.wikipedia.org/wiki/Continued_fraction
-        * Stop if the current term is bigger than or equal to the given
-        * threshold.
-        */
-       x = *numerator;
-       y = *denominator;
-
-       for (n = 0; n < n_terms && y != 0; ++n) {
-               an[n] = x / y;
-               if (an[n] >= threshold) {
-                       if (n < 2)
-                               n++;
-                       break;
-               }
-
-               r = x - an[n] * y;
-               x = y;
-               y = r;
-       }
-
-       /* Expand the simple continued fraction back to an integer fraction. */
-       x = 0;
-       y = 1;
-
-       for (i = n; i > 0; --i) {
-               r = y;
-               y = an[i-1] * y + x;
-               x = r;
-       }
-
-       *numerator = y;
-       *denominator = x;
-       kfree(an);
-}
-
-/*
- * Convert a fraction to a frame interval in 100ns multiples. The idea here is
- * to compute numerator / denominator * 10000000 using 32 bit fixed point
- * arithmetic only.
- */
-u32 uvc_fraction_to_interval(u32 numerator, u32 denominator)
-{
-       u32 multiplier;
-
-       /* Saturate the result if the operation would overflow. */
-       if (denominator == 0 ||
-           numerator/denominator >= ((u32)-1)/10000000)
-               return (u32)-1;
-
-       /*
-        * Divide both the denominator and the multiplier by two until
-        * numerator * multiplier doesn't overflow. If anyone knows a better
-        * algorithm please let me know.
-        */
-       multiplier = 10000000;
-       while (numerator > ((u32)-1)/multiplier) {
-               multiplier /= 2;
-               denominator /= 2;
-       }
-
-       return denominator ? numerator * multiplier / denominator : 0;
-}
-
 /* ------------------------------------------------------------------------
  * Terminal and unit management
  */
index 4cc3fa6..f4d4c33 100644 (file)
@@ -386,7 +386,7 @@ static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream,
        mutex_unlock(&stream->mutex);
 
        denominator = 10000000;
-       uvc_simplify_fraction(&numerator, &denominator, 8, 333);
+       v4l2_simplify_fraction(&numerator, &denominator, 8, 333);
 
        memset(parm, 0, sizeof(*parm));
        parm->type = stream->type;
@@ -427,7 +427,7 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
        else
                timeperframe = parm->parm.output.timeperframe;
 
-       interval = uvc_fraction_to_interval(timeperframe.numerator,
+       interval = v4l2_fraction_to_interval(timeperframe.numerator,
                timeperframe.denominator);
        uvc_dbg(stream->dev, FORMAT, "Setting frame interval to %u/%u (%u)\n",
                timeperframe.numerator, timeperframe.denominator, interval);
@@ -481,7 +481,7 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
        /* Return the actual frame period. */
        timeperframe.numerator = probe.dwFrameInterval;
        timeperframe.denominator = 10000000;
-       uvc_simplify_fraction(&timeperframe.numerator,
+       v4l2_simplify_fraction(&timeperframe.numerator,
                &timeperframe.denominator, 8, 333);
 
        if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
@@ -1275,7 +1275,7 @@ static int uvc_ioctl_enum_frameintervals(struct file *file, void *fh,
                fival->discrete.numerator =
                        frame->dwFrameInterval[index];
                fival->discrete.denominator = 10000000;
-               uvc_simplify_fraction(&fival->discrete.numerator,
+               v4l2_simplify_fraction(&fival->discrete.numerator,
                        &fival->discrete.denominator, 8, 333);
        } else {
                fival->type = V4L2_FRMIVAL_TYPE_STEPWISE;
@@ -1285,11 +1285,11 @@ static int uvc_ioctl_enum_frameintervals(struct file *file, void *fh,
                fival->stepwise.max.denominator = 10000000;
                fival->stepwise.step.numerator = frame->dwFrameInterval[2];
                fival->stepwise.step.denominator = 10000000;
-               uvc_simplify_fraction(&fival->stepwise.min.numerator,
+               v4l2_simplify_fraction(&fival->stepwise.min.numerator,
                        &fival->stepwise.min.denominator, 8, 333);
-               uvc_simplify_fraction(&fival->stepwise.max.numerator,
+               v4l2_simplify_fraction(&fival->stepwise.max.numerator,
                        &fival->stepwise.max.denominator, 8, 333);
-               uvc_simplify_fraction(&fival->stepwise.step.numerator,
+               v4l2_simplify_fraction(&fival->stepwise.step.numerator,
                        &fival->stepwise.step.denominator, 8, 333);
        }
 
index 24c911a..ff710bd 100644 (file)
@@ -911,9 +911,6 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
                      struct uvc_xu_control_query *xqry);
 
 /* Utility functions */
-void uvc_simplify_fraction(u32 *numerator, u32 *denominator,
-                          unsigned int n_terms, unsigned int threshold);
-u32 uvc_fraction_to_interval(u32 numerator, u32 denominator);
 struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts,
                                            u8 epaddr);
 u16 uvc_endpoint_max_bpi(struct usb_device *dev, struct usb_host_endpoint *ep);
index e0fbe6b..40f56e0 100644 (file)
@@ -484,3 +484,89 @@ s64 v4l2_get_link_freq(struct v4l2_ctrl_handler *handler, unsigned int mul,
        return freq > 0 ? freq : -EINVAL;
 }
 EXPORT_SYMBOL_GPL(v4l2_get_link_freq);
+
+/*
+ * Simplify a fraction using a simple continued fraction decomposition. The
+ * idea here is to convert fractions such as 333333/10000000 to 1/30 using
+ * 32 bit arithmetic only. The algorithm is not perfect and relies upon two
+ * arbitrary parameters to remove non-significative terms from the simple
+ * continued fraction decomposition. Using 8 and 333 for n_terms and threshold
+ * respectively seems to give nice results.
+ */
+void v4l2_simplify_fraction(u32 *numerator, u32 *denominator,
+               unsigned int n_terms, unsigned int threshold)
+{
+       u32 *an;
+       u32 x, y, r;
+       unsigned int i, n;
+
+       an = kmalloc_array(n_terms, sizeof(*an), GFP_KERNEL);
+       if (an == NULL)
+               return;
+
+       /*
+        * Convert the fraction to a simple continued fraction. See
+        * https://en.wikipedia.org/wiki/Continued_fraction
+        * Stop if the current term is bigger than or equal to the given
+        * threshold.
+        */
+       x = *numerator;
+       y = *denominator;
+
+       for (n = 0; n < n_terms && y != 0; ++n) {
+               an[n] = x / y;
+               if (an[n] >= threshold) {
+                       if (n < 2)
+                               n++;
+                       break;
+               }
+
+               r = x - an[n] * y;
+               x = y;
+               y = r;
+       }
+
+       /* Expand the simple continued fraction back to an integer fraction. */
+       x = 0;
+       y = 1;
+
+       for (i = n; i > 0; --i) {
+               r = y;
+               y = an[i-1] * y + x;
+               x = r;
+       }
+
+       *numerator = y;
+       *denominator = x;
+       kfree(an);
+}
+EXPORT_SYMBOL_GPL(v4l2_simplify_fraction);
+
+/*
+ * Convert a fraction to a frame interval in 100ns multiples. The idea here is
+ * to compute numerator / denominator * 10000000 using 32 bit fixed point
+ * arithmetic only.
+ */
+u32 v4l2_fraction_to_interval(u32 numerator, u32 denominator)
+{
+       u32 multiplier;
+
+       /* Saturate the result if the operation would overflow. */
+       if (denominator == 0 ||
+           numerator/denominator >= ((u32)-1)/10000000)
+               return (u32)-1;
+
+       /*
+        * Divide both the denominator and the multiplier by two until
+        * numerator * multiplier doesn't overflow. If anyone knows a better
+        * algorithm please let me know.
+        */
+       multiplier = 10000000;
+       while (numerator > ((u32)-1)/multiplier) {
+               multiplier /= 2;
+               denominator /= 2;
+       }
+
+       return denominator ? numerator * multiplier / denominator : 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_fraction_to_interval);
index b708d63..725ff91 100644 (file)
@@ -540,6 +540,10 @@ int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, u32 pixelformat,
 s64 v4l2_get_link_freq(struct v4l2_ctrl_handler *handler, unsigned int mul,
                       unsigned int div);
 
+void v4l2_simplify_fraction(u32 *numerator, u32 *denominator,
+               unsigned int n_terms, unsigned int threshold);
+u32 v4l2_fraction_to_interval(u32 numerator, u32 denominator);
+
 static inline u64 v4l2_buffer_get_timestamp(const struct v4l2_buffer *buf)
 {
        /*