[media] vivid: add downsampling support
authorHans Verkuil <hans.verkuil@cisco.com>
Mon, 9 Mar 2015 15:06:27 +0000 (12:06 -0300)
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>
Thu, 2 Apr 2015 23:55:12 +0000 (20:55 -0300)
Add support in vivid for downsampling. Most of the changes are in
vivid_copy_buffer which needs to know about the right line widths.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
drivers/media/platform/vivid/vivid-kthread-cap.c
drivers/media/platform/vivid/vivid-vid-out.c

index 22e17847e67f90cd1aa3001ad4d7a67db2d211e4..1727f5453f0bb33c77dc5b3fc7422466ced39408 100644 (file)
@@ -249,8 +249,9 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf,
        bool blank = dev->must_blank[vid_cap_buf->vb.v4l2_buf.index];
        struct tpg_data *tpg = &dev->tpg;
        struct vivid_buffer *vid_out_buf = NULL;
-       unsigned pixsize = tpg_g_twopixelsize(tpg, p) / 2;
-       unsigned img_width = dev->compose_cap.width;
+       unsigned vdiv = dev->fmt_out->vdownsampling[p];
+       unsigned twopixsize = tpg_g_twopixelsize(tpg, p);
+       unsigned img_width = tpg_hdiv(tpg, p, dev->compose_cap.width);
        unsigned img_height = dev->compose_cap.height;
        unsigned stride_cap = tpg->bytesperline[p];
        unsigned stride_out = dev->bytesperline_out[p];
@@ -269,6 +270,7 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf,
        unsigned vid_overlay_fract_part = 0;
        unsigned vid_overlay_y = 0;
        unsigned vid_overlay_error = 0;
+       unsigned vid_cap_left = tpg_hdiv(tpg, p, dev->loop_vid_cap.left);
        unsigned vid_cap_right;
        bool quick;
 
@@ -287,23 +289,25 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf,
                              dev->bytesperline_out, dev->fmt_out_rect.height);
        if (p < dev->fmt_out->buffers)
                voutbuf += vid_out_buf->vb.v4l2_planes[p].data_offset;
-       voutbuf += dev->loop_vid_out.left * pixsize + dev->loop_vid_out.top * stride_out;
-       vcapbuf += dev->compose_cap.left * pixsize + dev->compose_cap.top * stride_cap;
+       voutbuf += tpg_hdiv(tpg, p, dev->loop_vid_out.left) +
+               (dev->loop_vid_out.top / vdiv) * stride_out;
+       vcapbuf += tpg_hdiv(tpg, p, dev->compose_cap.left) +
+               (dev->compose_cap.top / vdiv) * stride_cap;
 
        if (dev->loop_vid_copy.width == 0 || dev->loop_vid_copy.height == 0) {
                /*
                 * If there is nothing to copy, then just fill the capture window
                 * with black.
                 */
-               for (y = 0; y < hmax; y++, vcapbuf += stride_cap)
-                       memcpy(vcapbuf, tpg->black_line[p], img_width * pixsize);
+               for (y = 0; y < hmax / vdiv; y++, vcapbuf += stride_cap)
+                       memcpy(vcapbuf, tpg->black_line[p], img_width);
                return 0;
        }
 
        if (dev->overlay_out_enabled &&
            dev->loop_vid_overlay.width && dev->loop_vid_overlay.height) {
                vosdbuf = dev->video_vbase;
-               vosdbuf += dev->loop_fb_copy.left * pixsize +
+               vosdbuf += (dev->loop_fb_copy.left * twopixsize) / 2 +
                           dev->loop_fb_copy.top * stride_osd;
                vid_overlay_int_part = dev->loop_vid_overlay.height /
                                       dev->loop_vid_overlay_cap.height;
@@ -311,12 +315,12 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf,
                                         dev->loop_vid_overlay_cap.height;
        }
 
-       vid_cap_right = dev->loop_vid_cap.left + dev->loop_vid_cap.width;
+       vid_cap_right = tpg_hdiv(tpg, p, dev->loop_vid_cap.left + dev->loop_vid_cap.width);
        /* quick is true if no video scaling is needed */
        quick = dev->loop_vid_out.width == dev->loop_vid_cap.width;
 
        dev->cur_scaled_line = dev->loop_vid_out.height;
-       for (y = 0; y < hmax; y++, vcapbuf += stride_cap) {
+       for (y = 0; y < hmax; y += vdiv, vcapbuf += stride_cap) {
                /* osdline is true if this line requires overlay blending */
                bool osdline = vosdbuf && y >= dev->loop_vid_overlay_cap.top &&
                          y < dev->loop_vid_overlay_cap.top + dev->loop_vid_overlay_cap.height;
@@ -327,34 +331,34 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf,
                 */
                if (y < dev->loop_vid_cap.top ||
                    y >= dev->loop_vid_cap.top + dev->loop_vid_cap.height) {
-                       memcpy(vcapbuf, tpg->black_line[p], img_width * pixsize);
+                       memcpy(vcapbuf, tpg->black_line[p], img_width);
                        continue;
                }
 
                /* fill the left border with black */
                if (dev->loop_vid_cap.left)
-                       memcpy(vcapbuf, tpg->black_line[p], dev->loop_vid_cap.left * pixsize);
+                       memcpy(vcapbuf, tpg->black_line[p], vid_cap_left);
 
                /* fill the right border with black */
                if (vid_cap_right < img_width)
-                       memcpy(vcapbuf + vid_cap_right * pixsize,
-                               tpg->black_line[p], (img_width - vid_cap_right) * pixsize);
+                       memcpy(vcapbuf + vid_cap_right, tpg->black_line[p],
+                               img_width - vid_cap_right);
 
                if (quick && !osdline) {
-                       memcpy(vcapbuf + dev->loop_vid_cap.left * pixsize,
+                       memcpy(vcapbuf + vid_cap_left,
                               voutbuf + vid_out_y * stride_out,
-                              dev->loop_vid_cap.width * pixsize);
+                              tpg_hdiv(tpg, p, dev->loop_vid_cap.width));
                        goto update_vid_out_y;
                }
                if (dev->cur_scaled_line == vid_out_y) {
-                       memcpy(vcapbuf + dev->loop_vid_cap.left * pixsize,
-                              dev->scaled_line,
-                              dev->loop_vid_cap.width * pixsize);
+                       memcpy(vcapbuf + vid_cap_left, dev->scaled_line,
+                              tpg_hdiv(tpg, p, dev->loop_vid_cap.width));
                        goto update_vid_out_y;
                }
                if (!osdline) {
                        scale_line(voutbuf + vid_out_y * stride_out, dev->scaled_line,
-                               dev->loop_vid_out.width, dev->loop_vid_cap.width,
+                               tpg_hdiv(tpg, p, dev->loop_vid_out.width),
+                               tpg_hdiv(tpg, p, dev->loop_vid_cap.width),
                                tpg_g_twopixelsize(tpg, p));
                } else {
                        /*
@@ -362,7 +366,8 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf,
                         * loop_vid_overlay rectangle.
                         */
                        unsigned offset =
-                               (dev->loop_vid_overlay.left - dev->loop_vid_copy.left) * pixsize;
+                               ((dev->loop_vid_overlay.left - dev->loop_vid_copy.left) *
+                                twopixsize) / 2;
                        u8 *osd = vosdbuf + vid_overlay_y * stride_osd;
 
                        scale_line(voutbuf + vid_out_y * stride_out, dev->blended_line,
@@ -372,18 +377,17 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf,
                                blend_line(dev, vid_overlay_y + dev->loop_vid_overlay.top,
                                           dev->loop_vid_overlay.left,
                                           dev->blended_line + offset, osd,
-                                          dev->loop_vid_overlay.width, pixsize);
+                                          dev->loop_vid_overlay.width, twopixsize / 2);
                        else
                                memcpy(dev->blended_line + offset,
-                                      osd, dev->loop_vid_overlay.width * pixsize);
+                                      osd, (dev->loop_vid_overlay.width * twopixsize) / 2);
                        scale_line(dev->blended_line, dev->scaled_line,
                                        dev->loop_vid_copy.width, dev->loop_vid_cap.width,
                                        tpg_g_twopixelsize(tpg, p));
                }
                dev->cur_scaled_line = vid_out_y;
-               memcpy(vcapbuf + dev->loop_vid_cap.left * pixsize,
-                      dev->scaled_line,
-                      dev->loop_vid_cap.width * pixsize);
+               memcpy(vcapbuf + vid_cap_left, dev->scaled_line,
+                      tpg_hdiv(tpg, p, dev->loop_vid_cap.width));
 
 update_vid_out_y:
                if (osdline) {
@@ -396,16 +400,16 @@ update_vid_out_y:
                }
                vid_out_y += vid_out_int_part;
                vid_out_error += vid_out_fract_part;
-               if (vid_out_error >= dev->loop_vid_cap.height) {
-                       vid_out_error -= dev->loop_vid_cap.height;
+               if (vid_out_error >= dev->loop_vid_cap.height / vdiv) {
+                       vid_out_error -= dev->loop_vid_cap.height / vdiv;
                        vid_out_y++;
                }
        }
 
        if (!blank)
                return 0;
-       for (; y < img_height; y++, vcapbuf += stride_cap)
-               memcpy(vcapbuf, tpg->contrast_line[p], img_width * pixsize);
+       for (; y < img_height; y += vdiv, vcapbuf += stride_cap)
+               memcpy(vcapbuf, tpg->contrast_line[p], img_width);
        return 0;
 }
 
@@ -604,6 +608,12 @@ static void vivid_overlay(struct vivid_dev *dev, struct vivid_buffer *buf)
        bool quick = dev->bitmap_cap == NULL && dev->clipcount_cap == 0;
        int x, y, w, out_x = 0;
 
+       /*
+        * Overlay support is only supported for formats that have a twopixelsize
+        * that's >= 2. Warn and bail out if that's not the case.
+        */
+       if (WARN_ON(pixsize == 0))
+               return;
        if ((dev->overlay_cap_field == V4L2_FIELD_TOP ||
             dev->overlay_cap_field == V4L2_FIELD_BOTTOM) &&
            dev->overlay_cap_field != buf->vb.v4l2_buf.field)
index eeafb6c93c644151d597dd5b111eb1951b6a876c..6c6deef3521c59325a441830bf7a41fd724e5e84 100644 (file)
@@ -43,7 +43,7 @@ static int vid_out_queue_setup(struct vb2_queue *vq, const struct v4l2_format *f
        unsigned p;
 
        for (p = vfmt->buffers; p < vfmt->planes; p++)
-               size += dev->bytesperline_out[p] * h;
+               size += dev->bytesperline_out[p] * h / vfmt->vdownsampling[p];
 
        if (dev->field_out == V4L2_FIELD_ALTERNATE) {
                /*
@@ -331,7 +331,8 @@ int vivid_g_fmt_vid_out(struct file *file, void *priv,
        for (p = fmt->buffers; p < fmt->planes; p++) {
                unsigned stride = dev->bytesperline_out[p];
 
-               mp->plane_fmt[0].sizeimage += stride * mp->height;
+               mp->plane_fmt[0].sizeimage +=
+                       (stride * mp->height) / fmt->vdownsampling[p];
        }
        return 0;
 }
@@ -405,7 +406,7 @@ int vivid_try_fmt_vid_out(struct file *file, void *priv,
        }
        for (p = fmt->buffers; p < fmt->planes; p++)
                pfmt[0].sizeimage += (pfmt[0].bytesperline * fmt->bit_depth[p]) /
-                                    fmt->bit_depth[0];
+                                    (fmt->bit_depth[0] * fmt->vdownsampling[p]);
        mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
        mp->quantization = V4L2_QUANTIZATION_DEFAULT;
        if (vivid_is_svid_out(dev)) {