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: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
This commit is contained in:
Родитель
24cc418b5b
Коммит
0b390d0c2e
|
@ -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,
|
||||||
*(*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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче