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

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
...@@ -267,23 +267,17 @@ static const char *type_name(enum v4l2_buf_type type) ...@@ -267,23 +267,17 @@ static const char *type_name(enum v4l2_buf_type type)
#define CLIP(__color) \ #define CLIP(__color) \
(u8)(((__color) > 0xff) ? 0xff : (((__color) < 0) ? 0 : (__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, 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; 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) { if (!reverse) {
memcpy(*dst, *src, depth << 1); memcpy(*dst, *src, depth << 1);
*src += depth << 1; *src += depth << 1;
*dst += depth << 1; *dst += depth << 1;
return 1; return;
} }
/* Copy line at reverse order - YUYV format */ /* Copy line at reverse order - YUYV format */
...@@ -303,7 +297,7 @@ static int fast_copy_two_pixels(struct vim2m_q_data *q_data_in, ...@@ -303,7 +297,7 @@ static int fast_copy_two_pixels(struct vim2m_q_data *q_data_in,
*(*dst)++ = u; *(*dst)++ = u;
*(*dst)++ = y1; *(*dst)++ = y1;
*(*dst)++ = v; *(*dst)++ = v;
return 1; return;
} }
/* copy RGB formats in reverse order */ /* copy RGB formats in reverse order */
...@@ -311,7 +305,7 @@ static int fast_copy_two_pixels(struct vim2m_q_data *q_data_in, ...@@ -311,7 +305,7 @@ static int fast_copy_two_pixels(struct vim2m_q_data *q_data_in,
memcpy(*dst + depth, *src - depth, depth); memcpy(*dst + depth, *src - depth, depth);
*src -= depth << 1; *src -= depth << 1;
*dst += depth << 1; *dst += depth << 1;
return 1; return;
} }
static void copy_two_pixels(struct vim2m_q_data *q_data_in, 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, ...@@ -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; u8 _r[2], _g[2], _b[2], *r, *g, *b;
int i, step; 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 */ /* Step 1: read two consecutive pixels from src pointer */
r = _r; r = _r;
...@@ -527,21 +516,21 @@ static int device_process(struct vim2m_ctx *ctx, ...@@ -527,21 +516,21 @@ static int device_process(struct vim2m_ctx *ctx,
struct vim2m_q_data *q_data_in, *q_data_out; struct vim2m_q_data *q_data_in, *q_data_out;
u8 *p_in, *p, *p_out; u8 *p_in, *p, *p_out;
unsigned int width, height, bytesperline; unsigned int width, height, bytesperline;
unsigned int x, y, y_out; unsigned int x, y, y_in, y_out;
int start, end, step; int start, end, step;
q_data_in = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 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; bytesperline = (q_data_in->width * q_data_in->fmt->depth) >> 3;
q_data_out = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 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 */ /* Crop to the limits of the destination image */
width = q_data_in->width;
if (width > q_data_out->width) if (width > q_data_out->width)
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_in = vb2_plane_vaddr(&in_vb->vb2_buf, 0);
p_out = vb2_plane_vaddr(&out_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, ...@@ -551,17 +540,6 @@ static int device_process(struct vim2m_ctx *ctx,
return -EFAULT; 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, out_vb->sequence = get_q_data(ctx,
V4L2_BUF_TYPE_VIDEO_CAPTURE)->sequence++; V4L2_BUF_TYPE_VIDEO_CAPTURE)->sequence++;
in_vb->sequence = q_data_in->sequence++; in_vb->sequence = q_data_in->sequence++;
...@@ -577,11 +555,32 @@ static int device_process(struct vim2m_ctx *ctx, ...@@ -577,11 +555,32 @@ static int device_process(struct vim2m_ctx *ctx,
step = 1; step = 1;
} }
y_out = 0; 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++) { for (y = start; y != end; y += step, y_out++) {
p = p_in + (y * bytesperline); p = p_in + (y * bytesperline);
if (ctx->mode & MEM2MEM_HFLIP) if (ctx->mode & MEM2MEM_HFLIP)
p += bytesperline - (q_data_in->fmt->depth >> 3); 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++) for (x = 0; x < width >> 1; x++)
copy_two_pixels(q_data_in, q_data_out, &p, copy_two_pixels(q_data_in, q_data_out, &p,
&p_out, y_out, &p_out, y_out,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment