Commit 0b390d0c authored by Mauro Carvalho Chehab's avatar Mauro Carvalho Chehab
Browse files

media: vim2m: add vertical linear scaler



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

Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+samsung@kernel.org>
parent 24cc418b
Loading
Loading
Loading
Loading
+33 −34
Original line number Diff line number Diff line
@@ -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,21 +516,21 @@ 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;
	unsigned int x, y, y_out;
	unsigned int x, y, y_in, y_out;
	int start, end, step;

	q_data_in = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
	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);

	/* 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);
@@ -551,17 +540,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++;
@@ -577,11 +555,32 @@ 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++) {
		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);

		for (x = 0; x < width >> 1; x++)
			copy_two_pixels(q_data_in, q_data_out, &p,
					&p_out, y_out,