summaryrefslogtreecommitdiff
path: root/v4l2-apps/libv4l/libv4lconvert/processing
diff options
context:
space:
mode:
Diffstat (limited to 'v4l2-apps/libv4l/libv4lconvert/processing')
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/autogain.c140
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/gamma.c57
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h60
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c181
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.h43
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c142
6 files changed, 623 insertions, 0 deletions
diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/autogain.c b/v4l2-apps/libv4l/libv4lconvert/processing/autogain.c
new file mode 100644
index 000000000..358264c68
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/autogain.c
@@ -0,0 +1,140 @@
+/*
+# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "libv4lprocessing.h"
+#include "libv4lprocessing-priv.h"
+#include "../libv4lconvert-priv.h" /* for PIX_FMT defines */
+#include "../libv4lsyscall-priv.h"
+
+static int autogain_active(struct v4lprocessing_data *data) {
+ return v4lcontrol_get_ctrl(data->control, V4LCONTROL_AUTOGAIN);
+}
+
+/* auto gain and exposure algorithm based on the knee algorithm described here:
+ http://ytse.tricolour.net/docs/LowLightOptimization.html */
+static int autogain_calculate_lookup_tables(
+ struct v4lprocessing_data *data,
+ unsigned char *buf, const struct v4l2_format *fmt)
+{
+ int x, y, target, steps, avg_lum = 0;
+ int gain, exposure, orig_gain, orig_exposure;
+ struct v4l2_control ctrl;
+ struct v4l2_queryctrl gainctrl, expoctrl;
+ const int deadzone = 8;
+
+ ctrl.id = V4L2_CID_EXPOSURE;
+ expoctrl.id = V4L2_CID_EXPOSURE;
+ if (SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL, &expoctrl) ||
+ SYS_IOCTL(data->fd, VIDIOC_G_CTRL, &ctrl))
+ return 0;
+ exposure = orig_exposure = ctrl.value;
+
+ ctrl.id = V4L2_CID_GAIN;
+ gainctrl.id = V4L2_CID_GAIN;
+ if (SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL, &gainctrl) ||
+ SYS_IOCTL(data->fd, VIDIOC_G_CTRL, &ctrl))
+ return 0;
+ gain = orig_gain = ctrl.value;
+
+ switch (fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SGRBG8:
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SRGGB8:
+ buf += fmt->fmt.pix.height * fmt->fmt.pix.bytesperline / 4 +
+ fmt->fmt.pix.width / 4;
+
+ for (y = 0; y < fmt->fmt.pix.height / 2; y++) {
+ for (x = 0; x < fmt->fmt.pix.width / 2; x++) {
+ avg_lum += *buf++;
+ }
+ buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width / 2;
+ }
+ avg_lum /= fmt->fmt.pix.height * fmt->fmt.pix.width / 4;
+ break;
+
+ case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_BGR24:
+ buf += fmt->fmt.pix.height * fmt->fmt.pix.bytesperline / 4 +
+ fmt->fmt.pix.width * 3 / 4;
+
+ for (y = 0; y < fmt->fmt.pix.height / 2; y++) {
+ for (x = 0; x < fmt->fmt.pix.width / 2; x++) {
+ avg_lum += *buf++;
+ avg_lum += *buf++;
+ avg_lum += *buf++;
+ }
+ buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width * 3 / 2;
+ }
+ avg_lum /= fmt->fmt.pix.height * fmt->fmt.pix.width * 3 / 4;
+ break;
+ }
+
+ /* If we are off a multiple of deadzone, do multiple steps to reach the
+ desired lumination fast (with the risc of a slight overshoot) */
+ target = v4lcontrol_get_ctrl(data->control, V4LCONTROL_AUTOGAIN_TARGET);
+ steps = abs(target - avg_lum) / deadzone;
+
+ for (x = 0; x < steps; x++) {
+ if (avg_lum > target) {
+ if (exposure > expoctrl.default_value)
+ exposure--;
+ else if (gain > gainctrl.default_value)
+ gain--;
+ else if (exposure > expoctrl.minimum)
+ exposure--;
+ else if (gain > gainctrl.minimum)
+ gain--;
+ else
+ break;
+ } else {
+ if (gain < gainctrl.default_value)
+ gain++;
+ else if (exposure < expoctrl.default_value)
+ exposure++;
+ else if (gain < gainctrl.maximum)
+ gain++;
+ else if (exposure < expoctrl.maximum)
+ exposure++;
+ else
+ break;
+ }
+ }
+
+ if (gain != orig_gain) {
+ ctrl.id = V4L2_CID_GAIN;
+ ctrl.value = gain;
+ SYS_IOCTL(data->fd, VIDIOC_S_CTRL, &ctrl);
+ }
+ if (exposure != orig_exposure) {
+ ctrl.id = V4L2_CID_EXPOSURE;
+ ctrl.value = exposure;
+ SYS_IOCTL(data->fd, VIDIOC_S_CTRL, &ctrl);
+ }
+
+ return 0;
+}
+
+struct v4lprocessing_filter autogain_filter = {
+ autogain_active, autogain_calculate_lookup_tables };
diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/gamma.c b/v4l2-apps/libv4l/libv4lconvert/processing/gamma.c
new file mode 100644
index 000000000..fcb5bb0cf
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/gamma.c
@@ -0,0 +1,57 @@
+/*
+# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <math.h>
+#include "libv4lprocessing.h"
+#include "libv4lprocessing-priv.h"
+
+#define CLIP(color) (unsigned char)(((color)>0xff)?0xff:(((color)<0)?0:(color)))
+
+static int gamma_active(struct v4lprocessing_data *data) {
+ int gamma = v4lcontrol_get_ctrl(data->control, V4LCONTROL_GAMMA);
+
+ return gamma && gamma != 1000;
+}
+
+static int gamma_calculate_lookup_tables(
+ struct v4lprocessing_data *data,
+ unsigned char *buf, const struct v4l2_format *fmt)
+{
+ int i, x, gamma;
+
+ gamma = v4lcontrol_get_ctrl(data->control, V4LCONTROL_GAMMA);
+
+ if (gamma != data->last_gamma) {
+ for (i = 0; i < 256; i++) {
+ x = powf(i / 255.0, 1000.0 / gamma) * 255;
+ data->gamma_table[i] = CLIP(x);
+ }
+ data->last_gamma = gamma;
+ }
+
+ for (i = 0; i < 256; i++) {
+ data->comp1[i] = data->gamma_table[data->comp1[i]];
+ data->green[i] = data->gamma_table[data->green[i]];
+ data->comp2[i] = data->gamma_table[data->comp2[i]];
+ }
+
+ return 1;
+}
+
+struct v4lprocessing_filter gamma_filter = {
+ gamma_active, gamma_calculate_lookup_tables };
diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h
new file mode 100644
index 000000000..b73c73b53
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h
@@ -0,0 +1,60 @@
+/*
+# (C) 2008-2009 Elmar Kleijn <elmar_kleijn@hotmail.com>
+# (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com>
+# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef __LIBV4LPROCESSING_PRIV_H
+#define __LIBV4LPROCESSING_PRIV_H
+
+#include "../control/libv4lcontrol.h"
+#include "../libv4lsyscall-priv.h"
+
+#define V4L2PROCESSING_UPDATE_RATE 10
+
+struct v4lprocessing_data {
+ struct v4lcontrol_data *control;
+ int fd;
+ int do_process;
+ /* True if any of the lookup tables does not contain
+ linear 0-255 */
+ int lookup_table_active;
+ /* Counts the number of processed frames until a
+ V4L2PROCESSING_UPDATE_RATE overflow happens */
+ int lookup_table_update_counter;
+ /* RGB/BGR lookup tables */
+ unsigned char comp1[256];
+ unsigned char green[256];
+ unsigned char comp2[256];
+ /* Filter private data for filters which need it */
+ int last_gamma;
+ unsigned char gamma_table[256];
+};
+
+struct v4lprocessing_filter {
+ /* Returns 1 if the filter is active */
+ int (*active)(struct v4lprocessing_data *data);
+ /* Returns 1 if any of the lookup tables was changed */
+ int (*calculate_lookup_tables)(struct v4lprocessing_data *data,
+ unsigned char *buf, const struct v4l2_format *fmt);
+};
+
+extern struct v4lprocessing_filter whitebalance_filter;
+extern struct v4lprocessing_filter autogain_filter;
+extern struct v4lprocessing_filter gamma_filter;
+
+#endif
diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c
new file mode 100644
index 000000000..cbbcca73c
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c
@@ -0,0 +1,181 @@
+/*
+# (C) 2008-2009 Elmar Kleijn <elmar_kleijn@hotmail.com>
+# (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com>
+# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "libv4lprocessing.h"
+#include "libv4lprocessing-priv.h"
+#include "../libv4lconvert-priv.h" /* for PIX_FMT defines */
+
+static struct v4lprocessing_filter *filters[] = {
+ &whitebalance_filter,
+ &autogain_filter,
+ &gamma_filter,
+};
+
+struct v4lprocessing_data *v4lprocessing_create(int fd, struct v4lcontrol_data* control)
+{
+ struct v4lprocessing_data *data =
+ calloc(1, sizeof(struct v4lprocessing_data));
+
+ if (!data)
+ return NULL;
+
+ data->fd = fd;
+ data->control = control;
+
+ return data;
+}
+
+void v4lprocessing_destroy(struct v4lprocessing_data *data)
+{
+ free(data);
+}
+
+int v4lprocessing_pre_processing(struct v4lprocessing_data *data)
+{
+ int i;
+
+ data->do_process = 0;
+ for (i = 0; i < ARRAY_SIZE(filters); i++) {
+ if (filters[i]->active(data))
+ data->do_process = 1;
+ }
+
+ return data->do_process;
+}
+
+static void v4lprocessing_update_lookup_tables(struct v4lprocessing_data *data,
+ unsigned char *buf, const struct v4l2_format *fmt)
+{
+ int i;
+
+ for (i = 0; i < 256; i++) {
+ data->comp1[i] = i;
+ data->green[i] = i;
+ data->comp2[i] = i;
+ }
+
+ data->lookup_table_active = 0;
+ for (i = 0; i < ARRAY_SIZE(filters); i++) {
+ if (filters[i]->active(data)) {
+ if (filters[i]->calculate_lookup_tables(data, buf, fmt))
+ data->lookup_table_active = 1;
+ }
+ }
+}
+
+static void v4lprocessing_do_processing(struct v4lprocessing_data *data,
+ unsigned char *buf, const struct v4l2_format *fmt)
+{
+ int x, y;
+
+ switch (fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SGRBG8: /* Bayer patterns starting with green */
+ for (y = 0; y < fmt->fmt.pix.height / 2; y++) {
+ for (x = 0; x < fmt->fmt.pix.width / 2; x++) {
+ *buf = data->green[*buf];
+ buf++;
+ *buf = data->comp1[*buf];
+ buf++;
+ }
+ buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width;
+ for (x = 0; x < fmt->fmt.pix.width / 2; x++) {
+ *buf = data->comp2[*buf];
+ buf++;
+ *buf = data->green[*buf];
+ buf++;
+ }
+ buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width;
+ }
+ break;
+
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SRGGB8: /* Bayer patterns *NOT* starting with green */
+ for (y = 0; y < fmt->fmt.pix.height / 2; y++) {
+ for (x = 0; x < fmt->fmt.pix.width / 2; x++) {
+ *buf = data->comp1[*buf];
+ buf++;
+ *buf = data->green[*buf];
+ buf++;
+ }
+ buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width;
+ for (x = 0; x < fmt->fmt.pix.width / 2; x++) {
+ *buf = data->green[*buf];
+ buf++;
+ *buf = data->comp2[*buf];
+ buf++;
+ }
+ buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width;
+ }
+ break;
+
+ case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_BGR24:
+ for (y = 0; y < fmt->fmt.pix.height; y++) {
+ for (x = 0; x < fmt->fmt.pix.width; x++) {
+ *buf = data->comp1[*buf];
+ buf++;
+ *buf = data->green[*buf];
+ buf++;
+ *buf = data->comp2[*buf];
+ buf++;
+ }
+ buf += fmt->fmt.pix.bytesperline - 3 * fmt->fmt.pix.width;
+ }
+ break;
+ }
+}
+
+void v4lprocessing_processing(struct v4lprocessing_data *data,
+ unsigned char *buf, const struct v4l2_format *fmt)
+{
+ if (!data->do_process)
+ return;
+
+ /* Do we support the current pixformat? */
+ switch (fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SGRBG8:
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SRGGB8:
+ case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_BGR24:
+ break;
+ default:
+ return; /* Non supported pix format */
+ }
+
+ if (v4lcontrol_controls_changed(data->control) ||
+ data->lookup_table_update_counter == V4L2PROCESSING_UPDATE_RATE) {
+ v4lprocessing_update_lookup_tables(data, buf, fmt);
+ data->lookup_table_update_counter = 0;
+ } else
+ data->lookup_table_update_counter++;
+
+ if (data->lookup_table_active)
+ v4lprocessing_do_processing(data, buf, fmt);
+
+ data->do_process = 0;
+}
diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.h b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.h
new file mode 100644
index 000000000..69d8865b2
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.h
@@ -0,0 +1,43 @@
+/*
+# (C) 2008-2009 Elmar Kleijn <elmar_kleijn@hotmail.com>
+# (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com>
+# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef __LIBV4LPROCESSING_H
+#define __LIBV4LPROCESSING_H
+
+#include "../libv4lsyscall-priv.h"
+#include <linux/videodev2.h>
+
+struct v4lprocessing_data;
+struct v4lcontrol_data;
+
+struct v4lprocessing_data *v4lprocessing_create(int fd, struct v4lcontrol_data *data);
+void v4lprocessing_destroy(struct v4lprocessing_data *data);
+
+/* Prepare to process 1 frame, returns 1 if processing is necesary,
+ return 0 if no processing will be done */
+int v4lprocessing_pre_processing(struct v4lprocessing_data *data);
+
+/* Do the actual processing, this is a nop if v4lprocessing_pre_processing()
+ returned 0, or if called more then 1 time after a single
+ v4lprocessing_pre_processing() call. */
+void v4lprocessing_processing(struct v4lprocessing_data *data,
+ unsigned char *buf, const struct v4l2_format *fmt);
+
+#endif
diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c b/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c
new file mode 100644
index 000000000..64d20b3ff
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c
@@ -0,0 +1,142 @@
+/*
+# (C) 2008-2009 Elmar Kleijn <elmar_kleijn@hotmail.com>
+# (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com>
+# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "libv4lprocessing.h"
+#include "libv4lprocessing-priv.h"
+#include "../libv4lconvert-priv.h" /* for PIX_FMT defines */
+
+#define CLIP(color) (unsigned char)(((color)>0xff)?0xff:(((color)<0)?0:(color)))
+
+static int whitebalance_active(struct v4lprocessing_data *data) {
+ return v4lcontrol_get_ctrl(data->control, V4LCONTROL_WHITEBALANCE);
+}
+
+static int whitebalance_calculate_lookup_tables_bayer(
+ struct v4lprocessing_data *data, unsigned char *buf,
+ const struct v4l2_format *fmt, int starts_with_green)
+{
+ int x, y, a1 = 0, a2 = 0, b1 = 0, b2 = 0;
+ int green_avg, comp1_avg, comp2_avg, avg_avg;
+
+ for (y = 0; y < fmt->fmt.pix.height; y += 2) {
+ for (x = 0; x < fmt->fmt.pix.width; x += 2) {
+ a1 += *buf++;
+ a2 += *buf++;
+ }
+ buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width;
+ for (x = 0; x < fmt->fmt.pix.width; x += 2) {
+ b1 += *buf++;
+ b2 += *buf++;
+ }
+ buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width;
+ }
+
+ if (starts_with_green) {
+ green_avg = (a1 + b2) / 512;
+ comp1_avg = a2 / 256;
+ comp2_avg = b1 / 256;
+ } else {
+ green_avg = (a2 + b1) / 512;
+ comp1_avg = a1 / 256;
+ comp2_avg = b2 / 256;
+ }
+
+ x = fmt->fmt.pix.width * fmt->fmt.pix.height / 64;
+ if (abs(green_avg - comp1_avg) < x &&
+ abs(green_avg - comp2_avg) < x &&
+ abs(comp1_avg - comp2_avg) < x)
+ return 0;
+
+ avg_avg = (green_avg + comp1_avg + comp2_avg) / 3;
+
+ for (x = 0; x < 256; x++) {
+ data->comp1[x] = CLIP(data->comp1[x] * avg_avg / comp1_avg);
+ data->green[x] = CLIP(data->green[x] * avg_avg / green_avg);
+ data->comp2[x] = CLIP(data->comp2[x] * avg_avg / comp2_avg);
+ }
+
+ return 1;
+}
+
+static int whitebalance_calculate_lookup_tables_rgb(
+ struct v4lprocessing_data *data, unsigned char *buf,
+ const struct v4l2_format *fmt)
+{
+ int x, y, green_avg = 0, comp1_avg = 0, comp2_avg = 0, avg_avg;
+
+ for (y = 0; y < fmt->fmt.pix.height; y++) {
+ for (x = 0; x < fmt->fmt.pix.width; x++) {
+ comp1_avg += *buf++;
+ green_avg += *buf++;
+ comp2_avg += *buf++;
+ }
+ buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width * 3;
+ }
+
+ x = fmt->fmt.pix.width * fmt->fmt.pix.height * 4;
+ if (abs(green_avg - comp1_avg) < x &&
+ abs(green_avg - comp2_avg) < x &&
+ abs(comp1_avg - comp2_avg) < x)
+ return 0;
+
+ /* scale to avoid integer overflows */
+ green_avg /= 256;
+ comp1_avg /= 256;
+ comp2_avg /= 256;
+ avg_avg = (green_avg + comp1_avg + comp2_avg) / 3;
+
+ for (x = 0; x < 256; x++) {
+ data->comp1[x] = CLIP(data->comp1[x] * avg_avg / comp1_avg);
+ data->green[x] = CLIP(data->green[x] * avg_avg / green_avg);
+ data->comp2[x] = CLIP(data->comp2[x] * avg_avg / comp2_avg);
+ }
+
+ return 1;
+}
+
+
+static int whitebalance_calculate_lookup_tables(
+ struct v4lprocessing_data *data,
+ unsigned char *buf, const struct v4l2_format *fmt)
+{
+ switch (fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SGRBG8: /* Bayer patterns starting with green */
+ return whitebalance_calculate_lookup_tables_bayer(data, buf, fmt, 1);
+
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SRGGB8: /* Bayer patterns *NOT* starting with green */
+ return whitebalance_calculate_lookup_tables_bayer(data, buf, fmt, 0);
+
+ case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_BGR24:
+ return whitebalance_calculate_lookup_tables_rgb(data, buf, fmt);
+ }
+
+ return 0; /* Should never happen */
+}
+
+struct v4lprocessing_filter whitebalance_filter = {
+ whitebalance_active, whitebalance_calculate_lookup_tables };