From: Hans de Goede <hdegoede@redhat.com>
To: Vasily Khoruzhick <anarsoul@gmail.com>,
linux-media@vger.kernel.org,
Mauro Carvalho Chehab <mchehab@osg.samsung.com>
Subject: Re: [PATCH 2/2] gspca: sn9c2028: Add gain and autogain controls Genius Videocam Live v2
Date: Tue, 21 Apr 2015 16:32:15 +0200 [thread overview]
Message-ID: <55365F6F.3040904@redhat.com> (raw)
In-Reply-To: <1429469565-2695-2-git-send-email-anarsoul@gmail.com>
Hi,
On 19-04-15 20:52, Vasily Khoruzhick wrote:
> Autogain algorithm is very simple, if average luminance is low - increase gain,
> if it's high - decrease gain. Gain granularity is low enough for this algo to
> stabilize quickly.
>
> Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
> ---
> drivers/media/usb/gspca/sn9c2028.c | 121 +++++++++++++++++++++++++++++++++++++
> drivers/media/usb/gspca/sn9c2028.h | 20 +++++-
> 2 files changed, 138 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/media/usb/gspca/sn9c2028.c b/drivers/media/usb/gspca/sn9c2028.c
> index 317b02c..0ff390f 100644
> --- a/drivers/media/usb/gspca/sn9c2028.c
> +++ b/drivers/media/usb/gspca/sn9c2028.c
> @@ -34,6 +34,16 @@ struct sd {
> struct gspca_dev gspca_dev; /* !! must be the first item */
> u8 sof_read;
> u16 model;
> +
> +#define MIN_AVG_LUM 8500
> +#define MAX_AVG_LUM 10000
> + int avg_lum;
> + u8 avg_lum_l;
> +
> + struct { /* autogain and gain control cluster */
> + struct v4l2_ctrl *autogain;
> + struct v4l2_ctrl *gain;
> + };
> };
>
> struct init_command {
> @@ -252,6 +262,77 @@ static int run_start_commands(struct gspca_dev *gspca_dev,
> return 0;
> }
>
> +static void set_gain(struct gspca_dev *gspca_dev, s32 g)
> +{
> + struct sd *sd = (struct sd *) gspca_dev;
> +
> + struct init_command genius_vcam_live_gain_cmds[] = {
> + {{0x1d, 0x25, 0x10, 0x20, 0xab, 0x00}, 0},
> + };
> + if (!gspca_dev->streaming)
> + return;
> +
> + switch (sd->model) {
> + case 0x7003:
> + genius_vcam_live_gain_cmds[0].instruction[2] = g;
> + run_start_commands(gspca_dev, genius_vcam_live_gain_cmds,
> + ARRAY_SIZE(genius_vcam_live_gain_cmds));
> + break;
> + default:
> + break;
> + }
> +}
> +
> +static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
> +{
> + struct gspca_dev *gspca_dev =
> + container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
> + struct sd *sd = (struct sd *)gspca_dev;
> +
> + gspca_dev->usb_err = 0;
> +
> + if (!gspca_dev->streaming)
> + return 0;
> +
> + switch (ctrl->id) {
> + /* standalone gain control */
> + case V4L2_CID_GAIN:
> + set_gain(gspca_dev, ctrl->val);
> + break;
> + /* autogain */
> + case V4L2_CID_AUTOGAIN:
> + set_gain(gspca_dev, sd->gain->val);
> + break;
> + }
> + return gspca_dev->usb_err;
> +}
> +
> +static const struct v4l2_ctrl_ops sd_ctrl_ops = {
> + .s_ctrl = sd_s_ctrl,
> +};
> +
> +
> +static int sd_init_controls(struct gspca_dev *gspca_dev)
> +{
> + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
> + struct sd *sd = (struct sd *)gspca_dev;
> +
> + gspca_dev->vdev.ctrl_handler = hdl;
> + v4l2_ctrl_handler_init(hdl, 2);
> +
> + switch (sd->model) {
> + case 0x7003:
> + sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
> + V4L2_CID_GAIN, 0, 20, 1, 0);
> + sd->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
> + V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
> + break;
> + default:
> + break;
> + }
> +
> + return 0;
> +}
> static int start_spy_cam(struct gspca_dev *gspca_dev)
> {
> struct init_command spy_start_commands[] = {
> @@ -641,6 +722,9 @@ static int start_genius_videocam_live(struct gspca_dev *gspca_dev)
> if (r < 0)
> return r;
>
> + if (sd->gain)
> + set_gain(gspca_dev, v4l2_ctrl_g_ctrl(sd->gain));
> +
> return r;
> }
>
> @@ -757,6 +841,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
> return -ENXIO;
> }
>
> + sd->avg_lum = -1;
> +
> return err_code;
> }
>
> @@ -776,6 +862,39 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
> PERR("Camera Stop command failed");
> }
>
> +static void do_autogain(struct gspca_dev *gspca_dev, int avg_lum)
> +{
> + struct sd *sd = (struct sd *) gspca_dev;
> + s32 cur_gain = v4l2_ctrl_g_ctrl(sd->gain);
> +
> + if (avg_lum == -1)
> + return;
> +
> + if (avg_lum < MIN_AVG_LUM) {
> + if (cur_gain == sd->gain->maximum)
> + return;
> + cur_gain++;
> + v4l2_ctrl_s_ctrl(sd->gain, cur_gain);
> + }
> + if (avg_lum > MAX_AVG_LUM) {
> + if (cur_gain == sd->gain->minimum)
> + return;
> + cur_gain--;
> + v4l2_ctrl_s_ctrl(sd->gain, cur_gain);
> + }
> +
> +}
> +
> +static void sd_dqcallback(struct gspca_dev *gspca_dev)
> +{
> + struct sd *sd = (struct sd *) gspca_dev;
> +
> + if (sd->autogain == NULL || !v4l2_ctrl_g_ctrl(sd->autogain))
> + return;
> +
> + do_autogain(gspca_dev, sd->avg_lum);
> +}
> +
> /* Include sn9c2028 sof detection functions */
> #include "sn9c2028.h"
>
> @@ -810,8 +929,10 @@ static const struct sd_desc sd_desc = {
> .name = MODULE_NAME,
> .config = sd_config,
> .init = sd_init,
> + .init_controls = sd_init_controls,
> .start = sd_start,
> .stopN = sd_stopN,
> + .dq_callback = sd_dqcallback,
> .pkt_scan = sd_pkt_scan,
> };
>
> diff --git a/drivers/media/usb/gspca/sn9c2028.h b/drivers/media/usb/gspca/sn9c2028.h
> index 8fd1d3e..6f20c0f 100644
> --- a/drivers/media/usb/gspca/sn9c2028.h
> +++ b/drivers/media/usb/gspca/sn9c2028.h
> @@ -21,8 +21,17 @@
> *
> */
>
> -static const unsigned char sn9c2028_sof_marker[5] =
> - { 0xff, 0xff, 0x00, 0xc4, 0xc4 };
> +static const unsigned char sn9c2028_sof_marker[] = {
> + 0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96,
> + 0x00,
> + 0x00, /* seq */
> + 0x00,
> + 0x00,
> + 0x00, /* avg luminance lower 8 bit */
> + 0x00, /* avg luminance higher 8 bit */
> + 0x00,
> + 0x00,
> +};
>
This seems wrong, the header is only 12 bytes the extra 2 0x00 bytes you add are
actually part of the compressed data and are parsed by the userspace code,
please drop them.
> static unsigned char *sn9c2028_find_sof(struct gspca_dev *gspca_dev,
> unsigned char *m, int len)
> @@ -32,8 +41,13 @@ static unsigned char *sn9c2028_find_sof(struct gspca_dev *gspca_dev,
>
> /* Search for the SOF marker (fixed part) in the header */
> for (i = 0; i < len; i++) {
> - if (m[i] == sn9c2028_sof_marker[sd->sof_read]) {
> + if ((m[i] == sn9c2028_sof_marker[sd->sof_read]) ||
> + (sd->sof_read > 5)) {
> sd->sof_read++;
> + if (sd->sof_read == 11)
> + sd->avg_lum_l = m[i];
> + if (sd->sof_read == 12)
> + sd->avg_lum = (m[i] << 8) + sd->avg_lum_l;
> if (sd->sof_read == sizeof(sn9c2028_sof_marker)) {
> PDEBUG(D_FRAM,
> "SOF found, bytes to analyze: %u."
>
Otherwise this looks good.
Regards,
Hans
next prev parent reply other threads:[~2015-04-21 14:32 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-04-19 18:52 [PATCH 1/2] gspca: sn9c2028: Add support for Genius Videocam Live v2 Vasily Khoruzhick
2015-04-19 18:52 ` [PATCH 2/2] gspca: sn9c2028: Add gain and autogain controls " Vasily Khoruzhick
2015-04-19 21:09 ` Theodore Kilgore
2015-04-21 14:32 ` Hans de Goede [this message]
2015-04-21 15:00 ` Vasily Khoruzhick
2015-04-21 14:21 ` [PATCH 1/2] gspca: sn9c2028: Add support for " Hans de Goede
2015-04-21 14:50 ` Vasily Khoruzhick
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=55365F6F.3040904@redhat.com \
--to=hdegoede@redhat.com \
--cc=anarsoul@gmail.com \
--cc=linux-media@vger.kernel.org \
--cc=mchehab@osg.samsung.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox