media: vim2m: add vertical linear scaler
authorMauro Carvalho Chehab <mchehab+samsung@kernel.org>
Fri, 1 Mar 2019 10:25:43 +0000 (05:25 -0500)
committerMauro Carvalho Chehab <mchehab+samsung@kernel.org>
Fri, 1 Mar 2019 16:16:21 +0000 (11:16 -0500)
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

index f61e1fc..27ac796 100644 (file)
@@ -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,
-                               struct vim2m_q_data *q_data_out,
-                               u8 **src, u8 **dst, int ypos, bool reverse)
+static void fast_copy_two_pixels(struct vim2m_q_data *q_data_in,
+                                struct vim2m_q_data *q_data_out,
+                                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,8 +555,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);