Re: [PATCH] Add framescaling support to stk1160

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Dale,

Don't forget to Cc the media mailing list. See below.

On Tue, Feb 24, 2015 at 2:33 PM, Dale Hamel <dale.hamel@xxxxxxxxxx> wrote:
> From: Michael Stegemann <michael@xxxxxxxxxxxx>
>
> Implements frame scaling support for stk1160 to support format changes instead of a static frame size.
>
> This is effectively a dumb sampling, and could perhaps benefit from being an averaging instead.
>
> This was a requested "TO DO" for this driver, and allows support for userspace programs like Hyperion and Boblight.
>
> Submitted on behalf of the original author, Michael Stegemann <michael@xxxxxxxxxxxx>
>
> Signed-off-by: Michael Stegemann <michael@xxxxxxxxxxxx>
> Signed-off-by: Dale Hamel <dale.hamel@xxxxxxxxxx>
> ---
>  drivers/media/usb/stk1160/stk1160-core.c  |   1 +
>  drivers/media/usb/stk1160/stk1160-reg.h   |  26 +++++++
>  drivers/media/usb/stk1160/stk1160-v4l.c   | 112 +++++++++++++++++++++++-------
>  drivers/media/usb/stk1160/stk1160-video.c |  17 ++++-
>  drivers/media/usb/stk1160/stk1160.h       |   1 +
>  5 files changed, 130 insertions(+), 27 deletions(-)
>
> diff --git a/drivers/media/usb/stk1160/stk1160-core.c b/drivers/media/usb/stk1160/stk1160-core.c
> index 03504dc..1881770 100644
> --- a/drivers/media/usb/stk1160/stk1160-core.c
> +++ b/drivers/media/usb/stk1160/stk1160-core.c
> @@ -418,6 +418,7 @@ static void stk1160_disconnect(struct usb_interface *interface)
>         stk1160_ac97_unregister(dev);
>
>         stk1160_clear_queue(dev);
> +       vb2_queue_release(&dev->vb_vidq);
>

Is this fixing a real bug? Wasn't aware of any leaks in this driver,
but who knows...

>         video_unregister_device(&dev->vdev);
>         v4l2_device_disconnect(&dev->v4l2_dev);
> diff --git a/drivers/media/usb/stk1160/stk1160-reg.h b/drivers/media/usb/stk1160/stk1160-reg.h
> index 3e49da6..b1fa11d 100644
> --- a/drivers/media/usb/stk1160/stk1160-reg.h
> +++ b/drivers/media/usb/stk1160/stk1160-reg.h
> @@ -33,6 +33,32 @@
>   */
>  #define STK1160_DCTRL                  0x100
>
> +/*
> + * Decimation Control Register:
> + * Byte 104:
> + * Horizontal Decimation Line Unit Count
> + * Byte 105:
> + * Vertical   Decimation Line Unit Count
> + * Byte 106:
> + * Bit 0 - Horizontal Decimation Control
> + *      0 Horizontal decimation is disabled.
> + *      1 Horizontal decimation is enabled.
> + * Bit 1 - Decimates Half or More Column
> + *   0 Decimates less than half from original column,
> + *     -> send count unit (0x105) before each unit skipped.
> + *   1 Decimates half or more from original column,
> + *     -> skip count unit (0x105) before each unit sent.
> + * Bit 2 - Vertical Decimation Control
> + *      see Bit 0, only vertical
> + * Bit 3 - Vertical Greater or Equal to Half
> + *      see Bit 1, only vertical
> + * Bit 4 - Decimation Unit
> + *     0 Decimation will work with 2 rows or columns per unit.
> + *     1 Decimation will work with 4 rows or columns per unit.
> + */
> +#define STK1160_DMCTRL                 0x104
> +

Great, thanks for documenting this fully.

> +
>  /* Capture Frame Start Position */
>  #define STK116_CFSPO                   0x110
>  #define STK116_CFSPO_STX_L             0x110
> diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c
> index 65a326c..94dafeb 100644
> --- a/drivers/media/usb/stk1160/stk1160-v4l.c
> +++ b/drivers/media/usb/stk1160/stk1160-v4l.c
> @@ -106,6 +106,76 @@ static void stk1160_set_std(struct stk1160 *dev)
>
>  }
>
> +static void stk1160_try_fmt(struct stk1160 *dev, struct v4l2_format *f, bool try)
> +{
> +       int base_width, base_height;
> +
> +       if (dev->norm & V4L2_STD_525_60){
> +               base_width = 720;
> +               base_height = 480;
> +       } else {
> +               base_width = 720;
> +               base_height = 576;
> +       }
> +
> +       if (f->fmt.pix.width <= (base_width / 3)
> +           || f->fmt.pix.height <= (base_height / 3)){
> +               f->fmt.pix.width = base_width / 3;
> +               f->fmt.pix.height = base_height / 3;
> +               if (!try){
> +                       dev->decimate = 3;
> +               }
> +       } else if ((f->fmt.pix.width >= base_width >> 1
> +                        && f->fmt.pix.width < base_width)
> +                        ||((f->fmt.pix.height >= base_height >> 1
> +                        && f->fmt.pix.height < base_height))){
> +               f->fmt.pix.width = base_width >> 1;
> +               f->fmt.pix.height = base_height >> 1;
> +               if (!try){
> +                       dev->decimate = 2;
> +               }
> +       } else {
> +               f->fmt.pix.width = base_width;
> +               f->fmt.pix.height = base_height;
> +               if (!try){
> +                       dev->decimate = 0;
> +               }
> +       }

These if/else if/else block looks really ugly.

> +}
> +
> +static void stk1160_set_fmt(struct stk1160 *dev)
> +{
> +       if (dev->norm & V4L2_STD_525_60){
> +               dev->width = 720;
> +               dev->height = 480;
> +       } else {
> +               dev->width = 720;
> +               dev->height = 576;
> +       }
> +
> +       switch (dev->decimate){
> +               case 0:
> +                       stk1160_write_reg(dev, STK1160_DMCTRL,   0x00);
> +                       stk1160_write_reg(dev, STK1160_DMCTRL+1, 0x00);
> +                       stk1160_write_reg(dev, STK1160_DMCTRL+2, 0x00);
> +                       break;
> +               case 2:
> +                       stk1160_write_reg(dev, STK1160_DMCTRL,   0x01);
> +                       stk1160_write_reg(dev, STK1160_DMCTRL+1, 0x01);
> +                       stk1160_write_reg(dev, STK1160_DMCTRL+2, 0x1f);
> +                       dev->width = dev->width >> 1;
> +                       dev->height = dev->height >> 1;
> +                       break;
> +               case 3:
> +                       stk1160_write_reg(dev, STK1160_DMCTRL,   0x02);
> +                       stk1160_write_reg(dev, STK1160_DMCTRL+1, 0x02);
> +                       stk1160_write_reg(dev, STK1160_DMCTRL+2, 0x1f);
> +                       dev->width = dev->width / 3;
> +                       dev->height = dev->height / 3;

Seems there's room for simplification here.

> +                       break;
> +       }
> +}
> +
>  /*
>   * Set a new alternate setting.
>   * Returns true is dev->max_pkt_size has changed, false otherwise.
> @@ -321,17 +391,10 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
>  {
>         struct stk1160 *dev = video_drvdata(file);
>
> -       /*
> -        * User can't choose size at his own will,
> -        * so we just return him the current size chosen
> -        * at standard selection.
> -        * TODO: Implement frame scaling?
> -        */
> +       stk1160_try_fmt(dev, f, true);
>
> -       f->fmt.pix.pixelformat = dev->fmt->fourcc;
> -       f->fmt.pix.width = dev->width;
> -       f->fmt.pix.height = dev->height;
>         f->fmt.pix.field = V4L2_FIELD_INTERLACED;
> +       f->fmt.pix.pixelformat = dev->fmt->fourcc;

This is just churn. You are just moving this line.

>         f->fmt.pix.bytesperline = dev->width * 2;
>         f->fmt.pix.sizeimage = dev->height * f->fmt.pix.bytesperline;
>         f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
> @@ -348,9 +411,14 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
>         if (vb2_is_busy(q))
>                 return -EBUSY;
>
> -       vidioc_try_fmt_vid_cap(file, priv, f);
> +       stk1160_try_fmt(dev, f, false);
> +       stk1160_set_fmt(dev);
>
> -       /* We don't support any format changes */
> +       f->fmt.pix.field = V4L2_FIELD_INTERLACED;
> +       f->fmt.pix.pixelformat = dev->fmt->fourcc;
> +       f->fmt.pix.bytesperline = dev->width * 2;
> +       f->fmt.pix.sizeimage = dev->height * f->fmt.pix.bytesperline;
> +       f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
>
>         return 0;
>  }
> @@ -389,23 +457,18 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
>         dev->norm = norm;
>
>         /* This is taken from saa7115 video decoder */
> -       if (dev->norm & V4L2_STD_525_60) {
> -               dev->width = 720;
> -               dev->height = 480;
> -       } else if (dev->norm & V4L2_STD_625_50) {
> -               dev->width = 720;
> -               dev->height = 576;
> +       if (dev->norm & V4L2_STD_525_60 || dev->norm & V4L2_STD_625_50) {
> +               stk1160_set_std(dev);
> +               stk1160_set_fmt(dev);
> +
> +               v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std,
> +                               dev->norm);
> +
> +               return 0;
>         } else {
>                 stk1160_err("invalid standard\n");
>                 return -EINVAL;
>         }
> -
> -       stk1160_set_std(dev);
> -
> -       v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std,
> -                       dev->norm);
> -
> -       return 0;

This removal looks unneeded.

>  }
>
>
> @@ -671,6 +734,7 @@ int stk1160_video_register(struct stk1160 *dev)
>         dev->norm = V4L2_STD_NTSC_M;
>         dev->width = 720;
>         dev->height = 480;
> +       dev->decimate = 0;
>
>         /* set default format */
>         dev->fmt = &format[0];
> diff --git a/drivers/media/usb/stk1160/stk1160-video.c b/drivers/media/usb/stk1160/stk1160-video.c
> index 39f1aae..5a55028 100644
> --- a/drivers/media/usb/stk1160/stk1160-video.c
> +++ b/drivers/media/usb/stk1160/stk1160-video.c
> @@ -84,7 +84,6 @@ struct stk1160_buffer *stk1160_next_buffer(struct stk1160 *dev)
>         if (!list_empty(&dev->avail_bufs)) {
>                 buf = list_first_entry(&dev->avail_bufs,
>                                 struct stk1160_buffer, list);
> -               list_del(&buf->list);

What's this?

>         }
>         spin_unlock_irqrestore(&dev->buf_lock, flags);
>
> @@ -95,7 +94,7 @@ static inline
>  void stk1160_buffer_done(struct stk1160 *dev)
>  {
>         struct stk1160_buffer *buf = dev->isoc_ctl.buf;
> -
> +       unsigned long flags = 0;

You need an empty line between variables and code.

>         dev->field_count++;
>
>         buf->vb.v4l2_buf.sequence = dev->field_count >> 1;
> @@ -104,7 +103,19 @@ void stk1160_buffer_done(struct stk1160 *dev)
>         v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
>
>         vb2_set_plane_payload(&buf->vb, 0, buf->bytesused);
> -       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
> +
> +       spin_lock_irqsave(&dev->buf_lock, flags);

Seems like taking the lock here could be correct.
This is a fix, and it's not related to this patch,
so you need to send a separate patch for it.

> +       if (buf->bytesused == vb2_plane_size(&buf->vb, 0))
> +               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
> +       else
> +               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
> +
> +       if (!list_empty(&dev->avail_bufs)) {
> +               list_del(&buf->list);
> +       }

Hm.. why do you remove the buffer from the list here?

> +
> +       spin_unlock_irqrestore(&dev->buf_lock, flags);
> +
>
>         dev->isoc_ctl.buf = NULL;
>  }
> diff --git a/drivers/media/usb/stk1160/stk1160.h b/drivers/media/usb/stk1160/stk1160.h
> index abdea48..895ed35 100644
> --- a/drivers/media/usb/stk1160/stk1160.h
> +++ b/drivers/media/usb/stk1160/stk1160.h
> @@ -150,6 +150,7 @@ struct stk1160 {
>         unsigned int ctl_input;   /* selected input */
>         v4l2_std_id norm;         /* current norm */
>         struct stk1160_fmt *fmt;  /* selected format */
> +       int decimate;
>
>         unsigned int field_count; /* not sure ??? */
>         enum v4l2_field field;    /* also not sure :/ */
> --
> 2.1.1
>

-- 
    Ezequiel
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux