linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/3] media: vim2m: add vertical linear scaler
@ 2019-03-01 12:52 Mauro Carvalho Chehab
  2019-03-01 12:52 ` [PATCH 2/3] media: vim2m: don't accept YUYV anymore as output format Mauro Carvalho Chehab
  2019-03-01 12:52 ` [PATCH 3/3] media: vim2m: add an horizontal scaler Mauro Carvalho Chehab
  0 siblings, 2 replies; 3+ messages in thread
From: Mauro Carvalho Chehab @ 2019-03-01 12:52 UTC (permalink / raw)
  To: Linux Media Mailing List
  Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, Hans Verkuil,
	Ezequiel Garcia

When resolutions are different, the expected behavior is to
scale the image. Implement a vertical scaler as the first step.

Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
---
 drivers/media/platform/vim2m.c | 65 +++++++++++++++++-----------------
 1 file changed, 32 insertions(+), 33 deletions(-)

diff --git a/drivers/media/platform/vim2m.c b/drivers/media/platform/vim2m.c
index ec177de144b6..1708becbaa9d 100644
--- a/drivers/media/platform/vim2m.c
+++ b/drivers/media/platform/vim2m.c
@@ -267,23 +267,17 @@ static const char *type_name(enum v4l2_buf_type type)
 #define CLIP(__color) \
 	(u8)(((__color) > 0xff) ? 0xff : (((__color) < 0) ? 0 : (__color)))
 
-static int fast_copy_two_pixels(struct vim2m_q_data *q_data_in,
+static void fast_copy_two_pixels(struct vim2m_q_data *q_data_in,
 				 struct vim2m_q_data *q_data_out,
-				 u8 **src, u8 **dst, int ypos, bool reverse)
+				 u8 **src, u8 **dst, bool reverse)
 {
 	int depth = q_data_out->fmt->depth >> 3;
 
-	/* Only do fast copy when format and resolution are identical */
-	if (q_data_in->fmt->fourcc != q_data_out->fmt->fourcc ||
-	    q_data_in->width != q_data_out->width ||
-	    q_data_in->height != q_data_out->height)
-		return 0;
-
 	if (!reverse) {
 		memcpy(*dst, *src, depth << 1);
 		*src += depth << 1;
 		*dst += depth << 1;
-		return 1;
+		return;
 	}
 
 	/* Copy line at reverse order - YUYV format */
@@ -303,7 +297,7 @@ static int fast_copy_two_pixels(struct vim2m_q_data *q_data_in,
 		*(*dst)++ = u;
 		*(*dst)++ = y1;
 		*(*dst)++ = v;
-		return 1;
+		return;
 	}
 
 	/* copy RGB formats in reverse order */
@@ -311,7 +305,7 @@ static int fast_copy_two_pixels(struct vim2m_q_data *q_data_in,
 	memcpy(*dst + depth, *src - depth, depth);
 	*src -= depth << 1;
 	*dst += depth << 1;
-	return 1;
+	return;
 }
 
 static void copy_two_pixels(struct vim2m_q_data *q_data_in,
@@ -323,11 +317,6 @@ static void copy_two_pixels(struct vim2m_q_data *q_data_in,
 	u8 _r[2], _g[2], _b[2], *r, *g, *b;
 	int i, step;
 
-	// If format is the same just copy the data, respecting the width
-	if (fast_copy_two_pixels(q_data_in, q_data_out,
-				 src, dst, ypos, reverse))
-	  return;
-
 	/* Step 1: read two consecutive pixels from src pointer */
 
 	r = _r;
@@ -527,25 +516,25 @@ static int device_process(struct vim2m_ctx *ctx,
 	struct vim2m_q_data *q_data_in, *q_data_out;
 	u8 *p_in, *p, *p_out;
 	unsigned int width, height, bytesperline, bytesperline_out;
-	unsigned int x, y, y_out;
+	unsigned int x, y, y_in, y_out;
 	int start, end, step;
 	struct vim2m_fmt *in, *out;
 
 	q_data_in = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
 	in = q_data_in->fmt;
-	width = q_data_in->width;
-	height = q_data_in->height;
 	bytesperline = (q_data_in->width * q_data_in->fmt->depth) >> 3;
 
 	q_data_out = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
 	bytesperline_out = (q_data_out->width * q_data_out->fmt->depth) >> 3;
 	out = q_data_out->fmt;
 
+	/* As we're doing vertical scaling use the out height here */
+	height = q_data_out->height;
+
 	/* Crop to the limits of the destination image */
+	width = q_data_in->width;
 	if (width > q_data_out->width)
 		width = q_data_out->width;
-	if (height > q_data_out->height)
-		height = q_data_out->height;
 
 	p_in = vb2_plane_vaddr(&in_vb->vb2_buf, 0);
 	p_out = vb2_plane_vaddr(&out_vb->vb2_buf, 0);
@@ -555,17 +544,6 @@ static int device_process(struct vim2m_ctx *ctx,
 		return -EFAULT;
 	}
 
-	/*
-	 * FIXME: instead of cropping the image and zeroing any
-	 * extra data, the proper behavior is to either scale the
-	 * data or report that scale is not supported (with depends
-	 * on some API for such purpose).
-	 */
-
-	/* Image size is different. Zero buffer first */
-	if (q_data_in->width  != q_data_out->width ||
-	    q_data_in->height != q_data_out->height)
-		memset(p_out, 0, q_data_out->sizeimage);
 	out_vb->sequence = get_q_data(ctx,
 				      V4L2_BUF_TYPE_VIDEO_CAPTURE)->sequence++;
 	in_vb->sequence = q_data_in->sequence++;
@@ -581,8 +559,29 @@ static int device_process(struct vim2m_ctx *ctx,
 		step = 1;
 	}
 	y_out = 0;
+
+	/* Faster copy logic,  when format and resolution are identical */
+	if (q_data_in->fmt->fourcc == q_data_out->fmt->fourcc &&
+	    q_data_in->width == q_data_out->width &&
+	    q_data_in->height == q_data_out->height) {
+		for (y = start; y != end; y += step, y_out++) {
+			p = p_in + (y * bytesperline);
+			if (ctx->mode & MEM2MEM_HFLIP)
+				p += bytesperline - (q_data_in->fmt->depth >> 3);
+
+			for (x = 0; x < width >> 1; x++)
+				fast_copy_two_pixels(q_data_in, q_data_out,
+						     &p, &p_out,
+						     ctx->mode & MEM2MEM_HFLIP);
+		}
+		return 0;
+	}
+
+	/* Slower algorithm with format conversion and scaler */
 	for (y = start; y != end; y += step, y_out++) {
-		p = p_in + (y * bytesperline);
+		y_in = (y * q_data_in->height) / q_data_out->height;
+
+		p = p_in + (y_in * bytesperline);
 		if (ctx->mode & MEM2MEM_HFLIP)
 			p += bytesperline - (q_data_in->fmt->depth >> 3);
 
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH 2/3] media: vim2m: don't accept YUYV anymore as output format
  2019-03-01 12:52 [PATCH 1/3] media: vim2m: add vertical linear scaler Mauro Carvalho Chehab
@ 2019-03-01 12:52 ` Mauro Carvalho Chehab
  2019-03-01 12:52 ` [PATCH 3/3] media: vim2m: add an horizontal scaler Mauro Carvalho Chehab
  1 sibling, 0 replies; 3+ messages in thread
From: Mauro Carvalho Chehab @ 2019-03-01 12:52 UTC (permalink / raw)
  To: Linux Media Mailing List
  Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, Hans Verkuil,
	Ezequiel Garcia

Handling any Y,Cr,Cb formats require some extra logic, as it
handles a group of two pixels. That's easy while we don't do
horizontal scaling.

However, doing horizontal scaling with such formats would require
a lot more code, in order to avoid distortions, as, if it scales
to two non-consecutive points, the logic would need to read 4
points in order to properly convert to RGB.

As this is just a test driver, and we want fast algorithms,
let's just get rid of this format as an output one.

Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
---
 drivers/media/platform/vim2m.c | 57 ++--------------------------------
 1 file changed, 2 insertions(+), 55 deletions(-)

diff --git a/drivers/media/platform/vim2m.c b/drivers/media/platform/vim2m.c
index 1708becbaa9d..a0e52eb205e3 100644
--- a/drivers/media/platform/vim2m.c
+++ b/drivers/media/platform/vim2m.c
@@ -113,7 +113,7 @@ static struct vim2m_fmt formats[] = {
 	}, {
 		.fourcc	= V4L2_PIX_FMT_YUYV,
 		.depth	= 16,
-		.types  = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
+		.types  = MEM2MEM_CAPTURE,
 	}, {
 		.fourcc	= V4L2_PIX_FMT_SBGGR8,
 		.depth	= 8,
@@ -280,26 +280,6 @@ static void fast_copy_two_pixels(struct vim2m_q_data *q_data_in,
 		return;
 	}
 
-	/* Copy line at reverse order - YUYV format */
-	if (q_data_in->fmt->fourcc == V4L2_PIX_FMT_YUYV) {
-		int u, v, y, y1;
-
-		*src -= 2;
-
-		y1 = (*src)[0]; /* copy as second point */
-		u  = (*src)[1];
-		y  = (*src)[2]; /* copy as first point */
-		v  = (*src)[3];
-
-		*src -= 2;
-
-		*(*dst)++ = y;
-		*(*dst)++ = u;
-		*(*dst)++ = y1;
-		*(*dst)++ = v;
-		return;
-	}
-
 	/* copy RGB formats in reverse order */
 	memcpy(*dst, *src, depth);
 	memcpy(*dst + depth, *src - depth, depth);
@@ -352,6 +332,7 @@ static void copy_two_pixels(struct vim2m_q_data *q_data_in,
 			*src += step << 1;
 		}
 		break;
+	default:
 	case V4L2_PIX_FMT_RGB24:
 		for (i = 0; i < 2; i++) {
 			*r++ = (*src)[0];
@@ -370,40 +351,6 @@ static void copy_two_pixels(struct vim2m_q_data *q_data_in,
 			*src += step * 3;
 		}
 		break;
-	default: /* V4L2_PIX_FMT_YUYV */
-	{
-		int u, v, y, y1, u1, v1, tmp;
-
-		if (reverse) {
-			*src -= 2;
-
-			y1 = (*src)[0]; /* copy as second point */
-			u  = (*src)[1];
-			y  = (*src)[2]; /* copy as first point */
-			v  = (*src)[3];
-
-			*src -= 2;
-		} else {
-			y  = *(*src)++;
-			u  = *(*src)++;
-			y1 = *(*src)++;
-			v  = *(*src)++;
-		}
-
-		u1 = (((u - 128) << 7) +  (u - 128)) >> 6;
-		tmp = (((u - 128) << 1) + (u - 128) +
-		       ((v - 128) << 2) + ((v - 128) << 1)) >> 3;
-		v1 = (((v - 128) << 1) +  (v - 128)) >> 1;
-
-		*r++ = CLIP(y + v1);
-		*g++ = CLIP(y - tmp);
-		*b++ = CLIP(y + u1);
-
-		*r = CLIP(y1 + v1);
-		*g = CLIP(y1 - tmp);
-		*b = CLIP(y1 + u1);
-		break;
-	}
 	}
 
 	/* Step 2: store two consecutive points, reversing them if needed */
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH 3/3] media: vim2m: add an horizontal scaler
  2019-03-01 12:52 [PATCH 1/3] media: vim2m: add vertical linear scaler Mauro Carvalho Chehab
  2019-03-01 12:52 ` [PATCH 2/3] media: vim2m: don't accept YUYV anymore as output format Mauro Carvalho Chehab
@ 2019-03-01 12:52 ` Mauro Carvalho Chehab
  1 sibling, 0 replies; 3+ messages in thread
From: Mauro Carvalho Chehab @ 2019-03-01 12:52 UTC (permalink / raw)
  To: Linux Media Mailing List
  Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, Hans Verkuil,
	Ezequiel Garcia

Add an horizontal linear scaler using Breseham algorithm in
order to speep up its calculus.

Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
---
 drivers/media/platform/vim2m.c | 95 ++++++++++++++++++++--------------
 1 file changed, 55 insertions(+), 40 deletions(-)

diff --git a/drivers/media/platform/vim2m.c b/drivers/media/platform/vim2m.c
index a0e52eb205e3..6bcc0c9f9910 100644
--- a/drivers/media/platform/vim2m.c
+++ b/drivers/media/platform/vim2m.c
@@ -290,12 +290,12 @@ static void fast_copy_two_pixels(struct vim2m_q_data *q_data_in,
 
 static void copy_two_pixels(struct vim2m_q_data *q_data_in,
 			    struct vim2m_q_data *q_data_out,
-			    u8 **src, u8 **dst, int ypos, bool reverse)
+			    u8 *src[2], u8 **dst, int ypos, bool reverse)
 {
 	struct vim2m_fmt *out = q_data_out->fmt;
 	struct vim2m_fmt *in = q_data_in->fmt;
 	u8 _r[2], _g[2], _b[2], *r, *g, *b;
-	int i, step;
+	int i;
 
 	/* Step 1: read two consecutive pixels from src pointer */
 
@@ -303,52 +303,39 @@ static void copy_two_pixels(struct vim2m_q_data *q_data_in,
 	g = _g;
 	b = _b;
 
-	if (reverse)
-		step = -1;
-	else
-		step = 1;
-
 	switch (in->fourcc) {
 	case V4L2_PIX_FMT_RGB565: /* rrrrrggg gggbbbbb */
 		for (i = 0; i < 2; i++) {
-			u16 pix = *(u16 *)*src;
+			u16 pix = *(u16 *)(src[i]);
 
 			*r++ = (u8)(((pix & 0xf800) >> 11) << 3) | 0x07;
 			*g++ = (u8)((((pix & 0x07e0) >> 5)) << 2) | 0x03;
 			*b++ = (u8)((pix & 0x1f) << 3) | 0x07;
-
-			*src += step << 1;
 		}
 		break;
 	case V4L2_PIX_FMT_RGB565X: /* gggbbbbb rrrrrggg */
 		for (i = 0; i < 2; i++) {
-			u16 pix = *(u16 *)*src;
+			u16 pix = *(u16 *)(src[i]);
 
 			*r++ = (u8)(((0x00f8 & pix) >> 3) << 3) | 0x07;
 			*g++ = (u8)(((pix & 0x7) << 2) |
 				    ((pix & 0xe000) >> 5)) | 0x03;
 			*b++ = (u8)(((pix & 0x1f00) >> 8) << 3) | 0x07;
-
-			*src += step << 1;
 		}
 		break;
 	default:
 	case V4L2_PIX_FMT_RGB24:
 		for (i = 0; i < 2; i++) {
-			*r++ = (*src)[0];
-			*g++ = (*src)[1];
-			*b++ = (*src)[2];
-
-			*src += step * 3;
+			*r++ = src[i][0];
+			*g++ = src[i][1];
+			*b++ = src[i][2];
 		}
 		break;
 	case V4L2_PIX_FMT_BGR24:
 		for (i = 0; i < 2; i++) {
-			*b++ = (*src)[0];
-			*g++ = (*src)[1];
-			*r++ = (*src)[2];
-
-			*src += step * 3;
+			*b++ = src[i][0];
+			*g++ = src[i][1];
+			*r++ = src[i][2];
 		}
 		break;
 	}
@@ -461,27 +448,24 @@ static int device_process(struct vim2m_ctx *ctx,
 {
 	struct vim2m_dev *dev = ctx->dev;
 	struct vim2m_q_data *q_data_in, *q_data_out;
-	u8 *p_in, *p, *p_out;
-	unsigned int width, height, bytesperline, bytesperline_out;
-	unsigned int x, y, y_in, y_out;
+	u8 *p_in, *p_line, *p_in_x[2], *p, *p_out;
+	unsigned int width, height, bytesperline, bytesperline_out, bytes_per_pixel;
+	unsigned int x, y, y_in, y_out, x_int, x_fract, x_err, x_offset;
 	int start, end, step;
 	struct vim2m_fmt *in, *out;
 
 	q_data_in = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
 	in = q_data_in->fmt;
 	bytesperline = (q_data_in->width * q_data_in->fmt->depth) >> 3;
+	bytes_per_pixel = q_data_in->fmt->depth >> 3;
 
 	q_data_out = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
 	bytesperline_out = (q_data_out->width * q_data_out->fmt->depth) >> 3;
 	out = q_data_out->fmt;
 
-	/* As we're doing vertical scaling use the out height here */
+	/* As we're doing scaling, use the output dimensions here */
 	height = q_data_out->height;
-
-	/* Crop to the limits of the destination image */
-	width = q_data_in->width;
-	if (width > q_data_out->width)
-		width = q_data_out->width;
+	width = q_data_out->width;
 
 	p_in = vb2_plane_vaddr(&in_vb->vb2_buf, 0);
 	p_out = vb2_plane_vaddr(&out_vb->vb2_buf, 0);
@@ -525,21 +509,52 @@ static int device_process(struct vim2m_ctx *ctx,
 	}
 
 	/* Slower algorithm with format conversion and scaler */
+
+	/* To speed scaler up, use Bresenham for X dimension */
+	x_int = q_data_in->width / q_data_out->width;
+	x_fract = q_data_in->width % q_data_out->width;
+
 	for (y = start; y != end; y += step, y_out++) {
 		y_in = (y * q_data_in->height) / q_data_out->height;
+		x_offset = 0;
+		x_err = 0;
 
-		p = p_in + (y_in * bytesperline);
+		p_line = p_in + (y_in * bytesperline);
 		if (ctx->mode & MEM2MEM_HFLIP)
-			p += bytesperline - (q_data_in->fmt->depth >> 3);
+			p_line += bytesperline - (q_data_in->fmt->depth >> 3);
+		p_in_x[0] = p_line;
 
-		for (x = 0; x < width >> 1; x++)
-			copy_two_pixels(q_data_in, q_data_out, &p, &p_out, y_out,
+		for (x = 0; x < width >> 1; x++) {
+			x_offset += x_int;
+			x_err += x_fract;
+			if (x_err > width) {
+				x_offset++;
+				x_err -= width;
+			}
+
+			if (ctx->mode & MEM2MEM_HFLIP)
+				p_in_x[1] = p_line - x_offset * bytes_per_pixel;
+			else
+				p_in_x[1] = p_line + x_offset * bytes_per_pixel;
+
+			copy_two_pixels(q_data_in, q_data_out,
+					p_in_x, &p_out, y_out,
 					ctx->mode & MEM2MEM_HFLIP);
 
-		/* Go to the next line at the out buffer */
-		if (width < q_data_out->width)
-			p_out += ((q_data_out->width - width)
-				  * q_data_out->fmt->depth) >> 3;
+			/* Calculate the next p_in_x0 */
+			x_offset += x_int;
+			x_err += x_fract;
+			if (x_err > width) {
+				x_offset++;
+				x_err -= width;
+			}
+
+			if (ctx->mode & MEM2MEM_HFLIP)
+				p_in_x[0] = p_line - x_offset * bytes_per_pixel;
+			else
+				p_in_x[0] = p_line + x_offset * bytes_per_pixel;
+		}
+
 	}
 
 	return 0;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2019-03-01 12:52 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-03-01 12:52 [PATCH 1/3] media: vim2m: add vertical linear scaler Mauro Carvalho Chehab
2019-03-01 12:52 ` [PATCH 2/3] media: vim2m: don't accept YUYV anymore as output format Mauro Carvalho Chehab
2019-03-01 12:52 ` [PATCH 3/3] media: vim2m: add an horizontal scaler Mauro Carvalho Chehab

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).