BACKPORT: media: v4l: move helper functions for fractions from uvc to v4l2-common

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>

(cherry picked from commit 6ba8b8d45335180523df8f1b6cd1c995a3dbf560)
arakesh: resolved minor conflicts in include/media/v4l2-common.h and
         drivers/media/v4l2-core/v4l2-common.c
Bug: 259171206
Change-Id: I17eea1ef6788ba98599b1d8a12499147ebef7d60
Signed-off-by: Avichal Rakesh <arakesh@google.com>
Signed-off-by: Cyber Knight <cyberknight755@gmail.com>
Signed-off-by: Pranav Vashi <neobuddy89@gmail.com>
This commit is contained in:
Michael Grzeschik
2022-09-10 00:13:32 +02:00
committed by Pranav Vashi
parent 7c9ac22f63
commit 3160ee7f2f
5 changed files with 93 additions and 91 deletions

View File

@@ -254,86 +254,6 @@ static __u32 uvc_colorspace(const __u8 primaries)
return 0;
}
/* 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(uint32_t *numerator, uint32_t *denominator,
unsigned int n_terms, unsigned int threshold)
{
uint32_t *an;
uint32_t x, y, r;
unsigned int i, n;
an = kmalloc(n_terms * sizeof *an, GFP_KERNEL);
if (an == NULL)
return;
/* Convert the fraction to a simple continued fraction. See
* http://mathforum.org/dr.math/faq/faq.fractions.html
* 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.
*/
uint32_t uvc_fraction_to_interval(uint32_t numerator, uint32_t denominator)
{
uint32_t multiplier;
/* Saturate the result if the operation would overflow. */
if (denominator == 0 ||
numerator/denominator >= ((uint32_t)-1)/10000000)
return (uint32_t)-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 > ((uint32_t)-1)/multiplier) {
multiplier /= 2;
denominator /= 2;
}
return denominator ? numerator * multiplier / denominator : 0;
}
/* ------------------------------------------------------------------------
* Terminal and unit management
*/

View File

@@ -376,7 +376,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;
@@ -414,7 +414,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_trace(UVC_TRACE_FORMAT, "Setting frame interval to %u/%u (%u).\n",
timeperframe.numerator, timeperframe.denominator, interval);
@@ -443,7 +443,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) {
@@ -1256,7 +1256,7 @@ static int uvc_ioctl_enum_frameintervals(struct file *file, void *fh,
fival->discrete.numerator =
frame->dwFrameInterval[fival->index];
fival->discrete.denominator = 10000000;
uvc_simplify_fraction(&fival->discrete.numerator,
v4l2_simplify_fraction(&fival->discrete.numerator,
&fival->discrete.denominator, 8, 333);
} else {
if (fival->index)
@@ -1269,11 +1269,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);
}

View File

@@ -755,10 +755,6 @@ extern int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
struct uvc_xu_control_query *xqry);
/* Utility functions */
extern void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator,
unsigned int n_terms, unsigned int threshold);
extern uint32_t uvc_fraction_to_interval(uint32_t numerator,
uint32_t denominator);
extern struct usb_host_endpoint *uvc_find_endpoint(
struct usb_host_interface *alts, __u8 epaddr);

View File

@@ -405,3 +405,85 @@ void v4l2_get_timestamp(struct timeval *tv)
tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC;
}
EXPORT_SYMBOL_GPL(v4l2_get_timestamp);
/* 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(uint32_t *numerator, uint32_t *denominator,
unsigned int n_terms, unsigned int threshold)
{
uint32_t *an;
uint32_t x, y, r;
unsigned int i, n;
an = kmalloc(n_terms * sizeof *an, GFP_KERNEL);
if (an == NULL)
return;
/* Convert the fraction to a simple continued fraction. See
* http://mathforum.org/dr.math/faq/faq.fractions.html
* 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.
*/
uint32_t v4l2_fraction_to_interval(uint32_t numerator, uint32_t denominator)
{
uint32_t multiplier;
/* Saturate the result if the operation would overflow. */
if (denominator == 0 ||
numerator/denominator >= ((uint32_t)-1)/10000000)
return (uint32_t)-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 > ((uint32_t)-1)/multiplier) {
multiplier /= 2;
denominator /= 2;
}
return denominator ? numerator * multiplier / denominator : 0;
}
EXPORT_SYMBOL_GPL(v4l2_fraction_to_interval);

View File

@@ -264,4 +264,8 @@ const struct v4l2_frmsize_discrete *v4l2_find_nearest_format(
void v4l2_get_timestamp(struct timeval *tv);
void v4l2_simplify_fraction(u32 *numerator, u32 *denominator,
unsigned int n_terms, unsigned int threshold);
u32 v4l2_fraction_to_interval(u32 numerator, u32 denominator);
#endif /* V4L2_COMMON_H_ */