summaryrefslogtreecommitdiff
path: root/v4l2-apps/libv4l/libv4lconvert
diff options
context:
space:
mode:
authorhans@localhost.localdomain <hans@localhost.localdomain>2009-05-21 13:08:29 +0200
committerhans@localhost.localdomain <hans@localhost.localdomain>2009-05-21 13:08:29 +0200
commit62805a6b176a0bbd17ab8fa421791765186fb77d (patch)
tree049754e1bd4e985cb443ba944e9b98dd7113c3e0 /v4l2-apps/libv4l/libv4lconvert
parent34a210b573f9c8ff8f07077f239be95d9d9248c5 (diff)
downloadmediapointer-dvb-s2-62805a6b176a0bbd17ab8fa421791765186fb77d.tar.gz
mediapointer-dvb-s2-62805a6b176a0bbd17ab8fa421791765186fb77d.tar.bz2
libv4l: rewrite video processing code
From: Hans de Goede <hdegoede@redhat.com> Rewrite video processing code to make it easier to add more video filters (and with little extra processing cost). As part of this the normalize filter has been removed as it wasn't functioning satisfactory anyways Priority: normal Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Diffstat (limited to 'v4l2-apps/libv4l/libv4lconvert')
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/Makefile2
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h7
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c107
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h7
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h1
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c3
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/bayerprocessing.c244
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h68
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c202
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/rgbprocessing.c156
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c143
11 files changed, 316 insertions, 624 deletions
diff --git a/v4l2-apps/libv4l/libv4lconvert/Makefile b/v4l2-apps/libv4l/libv4lconvert/Makefile
index ffc2e337d..49d508694 100644
--- a/v4l2-apps/libv4l/libv4lconvert/Makefile
+++ b/v4l2-apps/libv4l/libv4lconvert/Makefile
@@ -16,7 +16,7 @@ CONVERT_OBJS = libv4lconvert.o tinyjpeg.o sn9c10x.o sn9c20x.o pac207.o \
mr97310a.o flip.o crop.o jidctflt.o spca561-decompress.o \
rgbyuv.o spca501.o sq905c.o bayer.o hm12.o \
control/libv4lcontrol.o processing/libv4lprocessing.o \
- processing/rgbprocessing.o processing/bayerprocessing.o
+ processing/whitebalance.o
TARGETS = $(CONVERT_LIB) libv4lconvert.pc
INCLUDES = ../include/libv4lconvert.h
diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h
index 0157af280..14e4fe838 100644
--- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h
+++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h
@@ -24,16 +24,12 @@
#define V4LCONTROL_SHM_SIZE 4096
-#define V4LCONTROL_WANTS_WB (1 << V4LCONTROL_WHITEBALANCE)
-#define V4LCONTROL_WANTS_NORM ((1 << V4LCONTROL_NORMALIZE) | \
- (1 << V4LCONTROL_NORM_LOW_BOUND) | \
- (1 << V4LCONTROL_NORM_HIGH_BOUND))
-
struct v4lcontrol_data {
int fd; /* Device fd */
int flags; /* Special flags for this device */
int controls; /* Which controls to use for this device */
unsigned int *shm_values; /* shared memory control value store */
+ unsigned int old_values[V4LCONTROL_COUNT]; /* for controls_changed() */
};
struct v4lcontrol_flags_info {
@@ -46,7 +42,6 @@ struct v4lcontrol_flags_info {
const char *manufacturer;
const char *product; */
int flags;
- int controls;
};
#endif
diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c
index b120aa2fc..4d227c366 100644
--- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c
+++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c
@@ -56,30 +56,32 @@
static const struct v4lcontrol_flags_info v4lcontrol_flags[] = {
/* First: Upside down devices */
/* Philips SPC200NC */
- { 0x0471, 0x0325, 0, NULL, NULL, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED, 0 },
+ { 0x0471, 0x0325, 0, NULL, NULL, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
/* Philips SPC300NC */
- { 0x0471, 0x0326, 0, NULL, NULL, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED, 0 },
+ { 0x0471, 0x0326, 0, NULL, NULL, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
/* Philips SPC210NC */
- { 0x0471, 0x032d, 0, NULL, NULL, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED, 0 },
- /* Genius E-M 112 (also needs processing) */
- { 0x093a, 0x2476, 0, NULL, NULL, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED,
- V4LCONTROL_WANTS_WB },
+ { 0x0471, 0x032d, 0, NULL, NULL, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ /* Genius E-M 112 (also want whitebalance by default) */
+ { 0x093a, 0x2476, 0, NULL, NULL,
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED|V4LCONTROL_WANTS_WB },
/* Asus N50Vn laptop */
{ 0x04f2, 0xb106, 0, "ASUSTeK Computer Inc. ", "N50Vn ",
- V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED, 0 },
-/* Second: devices which can benefit from software video processing */
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+/* Second: devices which should use sw whitebalance by default */
/* Pac207 based devices */
- { 0x041e, 0x4028, 0, NULL, NULL, 0, V4LCONTROL_WANTS_WB },
- { 0x093a, 0x2460, 0x1f, NULL, NULL, 0, V4LCONTROL_WANTS_WB },
- { 0x145f, 0x013a, 0, NULL, NULL, 0, V4LCONTROL_WANTS_WB },
- { 0x2001, 0xf115, 0, NULL, NULL, 0, V4LCONTROL_WANTS_WB },
+ { 0x041e, 0x4028, 0, NULL, NULL, V4LCONTROL_WANTS_WB },
+ { 0x093a, 0x2460, 0x1f, NULL, NULL, V4LCONTROL_WANTS_WB },
+ { 0x145f, 0x013a, 0, NULL, NULL, V4LCONTROL_WANTS_WB },
+ { 0x2001, 0xf115, 0, NULL, NULL, V4LCONTROL_WANTS_WB },
/* Pac7302 based devices */
- { 0x093a, 0x2620, 0x0f, NULL, NULL, V4LCONTROL_ROTATED_90_JPEG,
- V4LCONTROL_WANTS_WB },
+ { 0x093a, 0x2620, 0x0f, NULL, NULL,
+ V4LCONTROL_ROTATED_90_JPEG|V4LCONTROL_WANTS_WB },
/* sq905 devices */
- { 0x2770, 0x9120, 0, NULL, NULL, 0, V4LCONTROL_WANTS_WB },
+ { 0x2770, 0x9120, 0, NULL, NULL, V4LCONTROL_WANTS_WB },
};
+static const struct v4l2_queryctrl fake_controls[];
+
static void v4lcontrol_init_flags(struct v4lcontrol_data *data)
{
struct stat st;
@@ -193,7 +195,6 @@ static void v4lcontrol_init_flags(struct v4lcontrol_data *data)
(v4lcontrol_flags[i].dmi_board_name == NULL ||
!strcmp(v4lcontrol_flags[i].dmi_board_name, dmi_board_name))) {
data->flags |= v4lcontrol_flags[i].flags;
- data->controls = v4lcontrol_flags[i].controls;
break;
}
}
@@ -215,21 +216,21 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion)
v4lcontrol_init_flags(data);
+ /* Allow overriding through environment */
+ if ((s = getenv("LIBV4LCONTROL_FLAGS")))
+ data->flags = strtol(s, NULL, 0);
+
/* If the device always needs conversion, we can add fake controls at no cost
(no cost when not activated by the user that is) */
if (always_needs_conversion || v4lcontrol_needs_conversion(data)) {
- ctrl.id = V4L2_CID_HFLIP;
- if (syscall(SYS_ioctl, data->fd, VIDIOC_QUERYCTRL, &ctrl) == -1)
- data->controls |= 1 << V4LCONTROL_HFLIP;
- ctrl.id = V4L2_CID_VFLIP;
- if (syscall(SYS_ioctl, data->fd, VIDIOC_QUERYCTRL, &ctrl) == -1)
- data->controls |= 1 << V4LCONTROL_VFLIP;
+ for (i = 0; i < V4LCONTROL_COUNT; i++) {
+ ctrl.id = fake_controls[i].id;
+ if (syscall(SYS_ioctl, data->fd, VIDIOC_QUERYCTRL, &ctrl) == -1)
+ data->controls |= 1 << i;
+ }
}
/* Allow overriding through environment */
- if ((s = getenv("LIBV4LCONTROL_FLAGS")))
- data->flags = strtol(s, NULL, 0);
-
if ((s = getenv("LIBV4LCONTROL_CONTROLS")))
data->controls = strtol(s, NULL, 0);
@@ -265,8 +266,8 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion)
if (init) {
/* Initialize the new shm object we created */
memset(data->shm_values, 0, sizeof(V4LCONTROL_SHM_SIZE));
- data->shm_values[V4LCONTROL_WHITEBALANCE] = 1;
- data->shm_values[V4LCONTROL_NORM_HIGH_BOUND] = 255;
+ if (data->flags & V4LCONTROL_WANTS_WB)
+ data->shm_values[V4LCONTROL_WHITEBALANCE] = 1;
}
return data;
@@ -284,21 +285,11 @@ void v4lcontrol_destroy(struct v4lcontrol_data *data)
}
/* FIXME get better CID's for normalize */
-struct v4l2_queryctrl fake_controls[V4LCONTROL_COUNT] = {
+static const struct v4l2_queryctrl fake_controls[V4LCONTROL_COUNT] = {
{
.id = V4L2_CID_AUTO_WHITE_BALANCE,
.type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Whitebalance",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
- .flags = 0
-},
-{
- .id = V4L2_CID_DO_WHITE_BALANCE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Normalize",
+ .name = "Whitebalance (software)",
.minimum = 0,
.maximum = 1,
.step = 1,
@@ -306,26 +297,6 @@ struct v4l2_queryctrl fake_controls[V4LCONTROL_COUNT] = {
.flags = 0
},
{
- .id = V4L2_CID_BLACK_LEVEL,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Normalize: low bound",
- .minimum = 0,
- .maximum = 127,
- .step = 1,
- .default_value = 0,
- .flags = 0
-},
-{
- .id = V4L2_CID_WHITENESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Normalize: high bound",
- .minimum = 128,
- .maximum = 255,
- .step = 1,
- .default_value = 255,
- .flags = 0
-},
-{
.id = V4L2_CID_HFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Horizontal flip",
@@ -359,6 +330,11 @@ int v4lcontrol_vidioc_queryctrl(struct v4lcontrol_data *data, void *arg)
if ((data->controls & (1 << i)) &&
ctrl->id == fake_controls[i].id) {
memcpy(ctrl, &fake_controls[i], sizeof(struct v4l2_queryctrl));
+ /* Hmm, not pretty */
+ if (ctrl->id == V4L2_CID_AUTO_WHITE_BALANCE &&
+ (data->flags & V4LCONTROL_WANTS_WB))
+ ctrl->default_value = 1;
+
return 0;
}
@@ -434,6 +410,19 @@ int v4lcontrol_get_ctrl(struct v4lcontrol_data *data, int ctrl)
return 0;
}
+int v4lcontrol_controls_changed(struct v4lcontrol_data *data)
+{
+ int res;
+
+ res = memcmp(data->shm_values, data->old_values,
+ V4LCONTROL_COUNT * sizeof(unsigned int));
+
+ memcpy(data->old_values, data->shm_values,
+ V4LCONTROL_COUNT * sizeof(unsigned int));
+
+ return res;
+}
+
/* See the comment about this in libv4lconvert.h */
int v4lcontrol_needs_conversion(struct v4lcontrol_data *data) {
return data->flags || data->controls;
diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h
index 43ef7c49f..85129ee4c 100644
--- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h
+++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h
@@ -26,13 +26,11 @@
#define V4LCONTROL_HFLIPPED 0x01
#define V4LCONTROL_VFLIPPED 0x02
#define V4LCONTROL_ROTATED_90_JPEG 0x04
+#define V4LCONTROL_WANTS_WB 0x08
/* Controls */
enum {
V4LCONTROL_WHITEBALANCE,
- V4LCONTROL_NORMALIZE,
- V4LCONTROL_NORM_LOW_BOUND,
- V4LCONTROL_NORM_HIGH_BOUND,
V4LCONTROL_HFLIP,
V4LCONTROL_VFLIP,
V4LCONTROL_COUNT };
@@ -45,6 +43,9 @@ void v4lcontrol_destroy(struct v4lcontrol_data *data);
/* Functions used by v4lprocessing to get the control state */
int v4lcontrol_get_flags(struct v4lcontrol_data *data);
int v4lcontrol_get_ctrl(struct v4lcontrol_data *data, int ctrl);
+/* Check if the controls have changed since the last time this function
+ was called */
+int v4lcontrol_controls_changed(struct v4lcontrol_data *data);
/* Check if we must go through the conversion path (and thus alloc conversion
buffers, etc. in libv4l2). Note this always return 1 if we *may* need
rotate90 / flipping / processing, as if we actually need this may change
diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h
index 60e62af97..407be3435 100644
--- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h
+++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h
@@ -83,6 +83,7 @@
#define V4L2_PIX_FMT_SN9C20X_I420 v4l2_fourcc('S', '9', '2', '0')
#endif
+#define ARRAY_SIZE(x) ((int)sizeof(x)/(int)sizeof((x)[0]))
#define V4LCONVERT_ERROR_MSG_SIZE 256
#define V4LCONVERT_MAX_FRAMESIZES 16
diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c
index 94539e376..1a94b53ba 100644
--- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c
+++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c
@@ -27,7 +27,6 @@
#include "libv4lconvert-priv.h"
#define MIN(a,b) (((a)<(b))?(a):(b))
-#define ARRAY_SIZE(x) ((int)sizeof(x)/(int)sizeof((x)[0]))
/* Note for proper functioning of v4lconvert_enum_fmt the first entries in
supported_src_pixfmts must match with the entries in supported_dst_pixfmts */
@@ -706,6 +705,8 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
}
/* Do processing on the tmp buffer, because doing it on bayer data is
cheaper, and bayer == rgb and our dest_fmt may be yuv */
+ tmpfmt.fmt.pix.bytesperline = width;
+ tmpfmt.fmt.pix.sizeimage = width * height;
v4lprocessing_processing(data->processing, tmpbuf, &tmpfmt);
/* Deliberate fall through to raw bayer fmt code! */
src_pix_fmt = tmpfmt.fmt.pix.pixelformat;
diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/bayerprocessing.c b/v4l2-apps/libv4l/libv4lconvert/processing/bayerprocessing.c
deleted file mode 100644
index f4cc9922b..000000000
--- a/v4l2-apps/libv4l/libv4lconvert/processing/bayerprocessing.c
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
-# (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 "libv4lprocessing-priv.h"
-#include "../libv4lconvert-priv.h" /* for PIX_FMT defines */
-
-void bayer_normalize_analyse(unsigned char *buf, int width, int height,
- struct v4lprocessing_data *data)
-{
- int value, max = 0, min = 255;
- unsigned char *buf_end = buf + width * height;
-
- while (buf < buf_end) {
- value = *buf++;
- if (max < value)
- max = value;
- if (min > value)
- min = value;
- }
-
- data->comp1 = ((data->norm_high_bound - data->norm_low_bound) << 16) / (max - min);
- data->offset1 = min;
- data->offset2 = data->norm_low_bound;
-}
-
-void bayer_whitebalance_analyse(unsigned char *src_buffer, int width,
- int height, unsigned int pix_fmt, struct v4lprocessing_data *data)
-{
- int i, j, x1 = 0, x2 = 0, y1 = 0, y2 = 0;
- float green_avg, x_avg, y_avg, avg_avg;
- unsigned char *buf = src_buffer;
-
- int start_with_green = pix_fmt == V4L2_PIX_FMT_SGBRG8 ||
- pix_fmt == V4L2_PIX_FMT_SGRBG8;
-
- for (i = 0; i < height; i += 2) {
- for (j = 0; j < width; j += 2) {
- x1 += *buf++;
- x2 += *buf++;
- }
- for (j = 0; j < width; j += 2) {
- y1 += *buf++;
- y2 += *buf++;
- }
- }
-
- if (start_with_green) {
- green_avg = (x1 + y2) / 2;
- x_avg = x2;
- y_avg = y1;
- } else {
- green_avg = (x2 + y1) / 2;
- x_avg = x1;
- y_avg = y2;
- }
-
- avg_avg = (green_avg + x_avg + y_avg) / 3;
-
- data->comp1 = (avg_avg / green_avg) * 65536;
- data->comp2 = (avg_avg / x_avg) * 65536;
- data->comp3 = (avg_avg / y_avg) * 65536;
-}
-
-void bayer_normalize_whitebalance_analyse(unsigned char *buf, int width,
- int height, unsigned int pix_fmt, struct v4lprocessing_data *data)
-{
- int i, j, value, max = 0, min = 255, n_fac, x1 = 0, x2 = 0, y1 = 0, y2 = 0;
- float green_avg, x_avg, y_avg, avg_avg;
-
- int start_with_green = pix_fmt == V4L2_PIX_FMT_SGBRG8 ||
- pix_fmt == V4L2_PIX_FMT_SGRBG8;
-
- for (i = 0; i < height; i += 2) {
- for (j = 0; j < width; j += 2) {
- x1 += *buf;
- value = *buf++;
- if (max < value)
- max = value;
- if (min > value)
- min = value;
- x2 += *buf;
- value = *buf++;
- if (max < value)
- max = value;
- if (min > value)
- min = value;
- }
- for (j = 0; j < width; j += 2) {
- y1 += *buf;
- value = *buf++;
- if (max < value)
- max = value;
- if (min > value)
- min = value;
- y2 += *buf;
- value = *buf++;
- if (max < value)
- max = value;
- if (min > value)
- min = value;
- }
- }
-
- if (start_with_green) {
- green_avg = (x1 + y2) / 2;
- x_avg = x2;
- y_avg = y1;
- } else {
- green_avg = (x2 + y1) / 2;
- x_avg = x1;
- y_avg = y2;
- }
-
- n_fac = ((data->norm_high_bound - data->norm_low_bound) << 16) / (max - min);
-
- avg_avg = (green_avg + x_avg + y_avg) / 3;
-
- data->comp1 = (avg_avg / green_avg) * n_fac;
- data->comp2 = (avg_avg / x_avg) * n_fac;
- data->comp3 = (avg_avg / y_avg) * n_fac;
-
- data->offset1 = min;
- data->offset2 = data->norm_low_bound;
-}
-
-#define CLIP(color) (unsigned char)(((color)>0xff)?0xff:(((color)<0)?0:(color)))
-#define TOP(color) (unsigned char)(((color)>0xff)?0xff:(color))
-
-void bayer_normalize(unsigned char *buf, int width,
- int height, struct v4lprocessing_data *data)
-{
- int value;
- unsigned char *buf_end = buf + width * height;
-
- while (buf < buf_end) {
- value = ((data->comp1 * (*buf - data->offset1)) >> 16) + data->offset2;
- *buf++ = CLIP(value);
- }
-}
-
-void bayer_whitebalance(unsigned char *src_buffer, int width,
- int height, unsigned int pix_fmt,
- struct v4lprocessing_data *data)
-{
- int i, j, value;
- int limit = width * height;
- unsigned char *buf = src_buffer;
-
- int start_with_green = pix_fmt == V4L2_PIX_FMT_SGBRG8 ||
- pix_fmt == V4L2_PIX_FMT_SGRBG8;
-
- if (start_with_green) {
- for (i = 0; i < height; i += 2) {
- for (j = 0; j < width; j += 2) {
- value = (*buf * data->comp1) >> 16;
- *buf++ = TOP(value);
- value = (*buf * data->comp2) >> 16;
- *buf++ = TOP(value);
- }
- for (j = 0; j < width; j += 2) {
- value = (*buf * data->comp3) >> 16;
- *buf++ = TOP(value);
- value = (*buf * data->comp1) >> 16;
- *buf++ = TOP(value);
- }
- }
- } else {
- for (i = 0; i < height; i += 2) {
- for (j = 0; j < width; j += 2) {
- value = (*buf * data->comp2) >> 16;
- *buf++ = TOP(value);
- value = (*buf * data->comp1) >> 16;
- *buf++ = TOP(value);
- }
- for (j = 0; j < width; j += 2) {
- value = (*buf * data->comp1) >> 16;
- *buf++ = TOP(value);
- value = (*buf * data->comp3) >> 16;
- *buf++ = TOP(value);
- }
- }
- }
-}
-
-void bayer_normalize_whitebalance(unsigned char *src_buffer, int width,
- int height, unsigned int pix_fmt,
- struct v4lprocessing_data *data)
-{
- int i, j, value;
- int limit = width * height;
- unsigned char *buf = src_buffer;
-
- int start_with_green = pix_fmt == V4L2_PIX_FMT_SGBRG8 ||
- pix_fmt == V4L2_PIX_FMT_SGRBG8;
-
- if (start_with_green) {
- for (i = 0; i < height; i += 2) {
- for (j = 0; j < width; j += 2) {
- value = ((data->comp1 * (*buf - data->offset1)) >> 16) + data->offset2;
- *buf++ = CLIP(value);
- value = ((data->comp2 * (*buf - data->offset1)) >> 16) + data->offset2;
- *buf++ = CLIP(value);
- }
- for (j = 0; j < width; j += 2) {
- value = ((data->comp3 * (*buf - data->offset1)) >> 16) + data->offset2;
- *buf++ = CLIP(value);
- value = ((data->comp1 * (*buf - data->offset1)) >> 16) + data->offset2;
- *buf++ = CLIP(value);
- }
- }
- } else {
- for (i = 0; i < height; i += 2) {
- for (j = 0; j < width; j += 2) {
- value = ((data->comp2 * (*buf - data->offset1)) >> 16) + data->offset2;
- *buf++ = CLIP(value);
- value = ((data->comp1 * (*buf - data->offset1)) >> 16) + data->offset2;
- *buf++ = CLIP(value);
- }
- for (j = 0; j < width; j += 2) {
- value = ((data->comp1 * (*buf - data->offset1)) >> 16) + data->offset2;
- *buf++ = CLIP(value);
- value = ((data->comp3 * (*buf - data->offset1)) >> 16) + data->offset2;
- *buf++ = CLIP(value);
- }
- }
- }
-}
diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h
index f2aae373d..fb514d7f5 100644
--- a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h
@@ -23,67 +23,31 @@
#include "../control/libv4lcontrol.h"
-#define V4L2PROCESSING_PROCESS_NONE 0x00
-#define V4L2PROCESSING_PROCESS_NORMALIZE 0x01
-#define V4L2PROCESSING_PROCESS_WHITEBALANCE 0x02
-#define V4L2PROCESSING_PROCESS_NORMALIZE_WHITEBALANCE 0x03
-#define V4L2PROCESSING_PROCESS_RGB_NORMALIZE 0x01
-#define V4L2PROCESSING_PROCESS_RGB_WHITEBALANCE 0x02
-#define V4L2PROCESSING_PROCESS_RGB_NORMALIZE_WHITEBALANCE 0x03
-#define V4L2PROCESSING_PROCESS_BAYER_NORMALIZE 0x11
-#define V4L2PROCESSING_PROCESS_BAYER_WHITEBALANCE 0x12
-#define V4L2PROCESSING_PROCESS_BAYER_NORMALIZE_WHITEBALANCE 0x13
-
#define V4L2PROCESSING_UPDATE_RATE 10
struct v4lprocessing_data {
struct v4lcontrol_data *control;
int do_process;
- /* Provides the current type of processing */
- int process;
- int norm_low_bound;
- int norm_high_bound;
+ /* 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 processing_data_update;
- /* Multiplication factors and offsets from the analyse functions */
- int comp1;
- int comp2;
- int comp3;
- int comp4;
- int offset1;
- int offset2;
+ int lookup_table_update_counter;
+ /* RGB/BGR lookup tables */
+ unsigned char comp1[256];
+ unsigned char green[256];
+ unsigned char comp2[256];
};
-/* Processing Bayer */
-void bayer_normalize_analyse(unsigned char *src_buffer, int width, int height,
- struct v4lprocessing_data *data);
-void bayer_whitebalance_analyse(unsigned char *src_buffer, int width,
- int height, unsigned int pix_fmt,
- struct v4lprocessing_data *data);
-void bayer_normalize_whitebalance_analyse(unsigned char *src_buffer,
- int width, int height, unsigned int pix_fmt,
- struct v4lprocessing_data *data);
-void bayer_normalize(unsigned char *src_buffer, int width, int height,
- struct v4lprocessing_data *data);
-void bayer_whitebalance(unsigned char *src_buffer, int width, int height,
- unsigned int pix_fmt, struct v4lprocessing_data *data);
-void bayer_normalize_whitebalance(unsigned char *src_buffer, int width,
- int height, unsigned int pix_fmt,
- struct v4lprocessing_data *data);
+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);
+};
-/* Processing RGB */
-void rgb_normalize_analyse(unsigned char *src_buffer, int width, int height,
- struct v4lprocessing_data *data);
-void rgb_whitebalance_analyse(unsigned char *src_buffer, int width, int height,
- struct v4lprocessing_data *data);
-void rgb_normalize_whitebalance_analyse(unsigned char *src_buffer,
- int width, int height, struct v4lprocessing_data *data);
-void rgb_normalize(unsigned char *src_buffer, int width, int height,
- struct v4lprocessing_data *data);
-void rgb_whitebalance(unsigned char *src_buffer, int width, int height,
- struct v4lprocessing_data *data);
-void rgb_normalize_whitebalance(unsigned char *src_buffer, int width,
- int height, struct v4lprocessing_data *data);
+extern struct v4lprocessing_filter whitebalance_filter;
#endif
diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c
index f986da02d..3a3802aab 100644
--- a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c
@@ -28,6 +28,10 @@
#include "libv4lprocessing-priv.h"
#include "../libv4lconvert-priv.h" /* for PIX_FMT defines */
+static struct v4lprocessing_filter *filters[] = {
+ &whitebalance_filter,
+};
+
struct v4lprocessing_data *v4lprocessing_create(struct v4lcontrol_data* control)
{
struct v4lprocessing_data *data =
@@ -46,136 +50,130 @@ void v4lprocessing_destroy(struct v4lprocessing_data *data)
free(data);
}
-static int v4lprocessing_get_process(struct v4lprocessing_data *data,
- unsigned int pix_fmt)
+int v4lprocessing_pre_processing(struct v4lprocessing_data *data)
{
- int process = V4L2PROCESSING_PROCESS_NONE;
+ int i;
- switch(pix_fmt) {
- case V4L2_PIX_FMT_SBGGR8:
- case V4L2_PIX_FMT_SGBRG8:
- case V4L2_PIX_FMT_SGRBG8:
- case V4L2_PIX_FMT_SRGGB8:
- if (v4lcontrol_get_ctrl(data->control, V4LCONTROL_NORMALIZE)) {
- process |= V4L2PROCESSING_PROCESS_BAYER_NORMALIZE;
- }
- if (v4lcontrol_get_ctrl(data->control, V4LCONTROL_WHITEBALANCE)) {
- process |= V4L2PROCESSING_PROCESS_BAYER_WHITEBALANCE;
- }
- break;
- case V4L2_PIX_FMT_RGB24:
- case V4L2_PIX_FMT_BGR24:
- if (v4lcontrol_get_ctrl(data->control, V4LCONTROL_NORMALIZE)) {
- process |= V4L2PROCESSING_PROCESS_RGB_NORMALIZE;
- }
- if (v4lcontrol_get_ctrl(data->control, V4LCONTROL_WHITEBALANCE)) {
- process |= V4L2PROCESSING_PROCESS_RGB_WHITEBALANCE;
- }
- break;
+ data->do_process = 0;
+ for (i = 0; i < ARRAY_SIZE(filters); i++) {
+ if (filters[i]->active(data))
+ data->do_process = 1;
}
- return process;
+ return data->do_process;
}
-static void v4lprocessing_update_processing_data(
- struct v4lprocessing_data *data,
- unsigned int pix_fmt, unsigned char *buf, unsigned int width,
- unsigned int height)
+static void v4lprocessing_update_lookup_tables(struct v4lprocessing_data *data,
+ unsigned char *buf, const struct v4l2_format *fmt)
{
- switch (data->process) {
- case V4L2PROCESSING_PROCESS_BAYER_NORMALIZE:
- bayer_normalize_analyse(buf, width, height, data);
- break;
+ int i;
- case V4L2PROCESSING_PROCESS_BAYER_WHITEBALANCE:
- bayer_whitebalance_analyse(buf, width, height, pix_fmt, data);
- break;
+ for (i = 0; i < 256; i++) {
+ data->comp1[i] = i;
+ data->green[i] = i;
+ data->comp2[i] = i;
+ }
- case V4L2PROCESSING_PROCESS_BAYER_NORMALIZE_WHITEBALANCE:
- bayer_normalize_whitebalance_analyse(buf, width, height, pix_fmt, data);
- break;
+ 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;
- case V4L2PROCESSING_PROCESS_RGB_NORMALIZE:
- rgb_normalize_analyse(buf, width, height, data);
+ 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 V4L2PROCESSING_PROCESS_RGB_WHITEBALANCE:
- rgb_whitebalance_analyse(buf, width, height, data);
+ 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 V4L2PROCESSING_PROCESS_RGB_NORMALIZE_WHITEBALANCE:
- rgb_normalize_whitebalance_analyse(buf, width, height, data);
+ 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;
}
}
-int v4lprocessing_pre_processing(struct v4lprocessing_data *data)
-{
- data->do_process =
- v4lcontrol_get_ctrl(data->control, V4LCONTROL_WHITEBALANCE) ||
- v4lcontrol_get_ctrl(data->control, V4LCONTROL_NORMALIZE);
-
- if (!data->do_process)
- data->process = V4L2PROCESSING_PROCESS_NONE;
-
- return data->do_process;
-}
-
void v4lprocessing_processing(struct v4lprocessing_data *data,
unsigned char *buf, const struct v4l2_format *fmt)
{
- int low_bound, high_bound, process;
-
if (!data->do_process)
return;
- process = v4lprocessing_get_process(data, fmt->fmt.pix.pixelformat);
- if (process == V4L2PROCESSING_PROCESS_NONE) {
- return;
- }
-
- low_bound = v4lcontrol_get_ctrl(data->control, V4LCONTROL_NORM_LOW_BOUND);
- high_bound = v4lcontrol_get_ctrl(data->control, V4LCONTROL_NORM_HIGH_BOUND);
-
- if (process != data->process || low_bound != data->norm_low_bound ||
- high_bound != data->norm_high_bound) {
- data->process = process;
- data->norm_low_bound = low_bound;
- data->norm_high_bound = high_bound;
- data->processing_data_update = V4L2PROCESSING_UPDATE_RATE;
+ /* 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 (data->processing_data_update == V4L2PROCESSING_UPDATE_RATE) {
- data->processing_data_update = 0;
- v4lprocessing_update_processing_data(data, fmt->fmt.pix.pixelformat, buf, fmt->fmt.pix.width, fmt->fmt.pix.height);
+ 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->processing_data_update++;
-
- switch (data->process) {
- case V4L2PROCESSING_PROCESS_BAYER_NORMALIZE:
- bayer_normalize(buf, fmt->fmt.pix.width, fmt->fmt.pix.height, data);
- break;
-
- case V4L2PROCESSING_PROCESS_BAYER_WHITEBALANCE:
- bayer_whitebalance(buf, fmt->fmt.pix.width, fmt->fmt.pix.height, fmt->fmt.pix.pixelformat, data);
- break;
-
- case V4L2PROCESSING_PROCESS_BAYER_NORMALIZE_WHITEBALANCE:
- bayer_normalize_whitebalance(buf, fmt->fmt.pix.width, fmt->fmt.pix.height, fmt->fmt.pix.pixelformat,
- data);
- break;
-
- case V4L2PROCESSING_PROCESS_RGB_NORMALIZE:
- rgb_normalize(buf, fmt->fmt.pix.width, fmt->fmt.pix.height, data);
- break;
+ data->lookup_table_update_counter++;
- case V4L2PROCESSING_PROCESS_RGB_WHITEBALANCE:
- rgb_whitebalance(buf, fmt->fmt.pix.width, fmt->fmt.pix.height, data);
- break;
+ if (data->lookup_table_active)
+ v4lprocessing_do_processing(data, buf, fmt);
- case V4L2PROCESSING_PROCESS_RGB_NORMALIZE_WHITEBALANCE:
- rgb_normalize_whitebalance(buf, fmt->fmt.pix.width, fmt->fmt.pix.height, data);
- break;
- }
data->do_process = 0;
}
diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/rgbprocessing.c b/v4l2-apps/libv4l/libv4lconvert/processing/rgbprocessing.c
deleted file mode 100644
index 4e0fc3f4a..000000000
--- a/v4l2-apps/libv4l/libv4lconvert/processing/rgbprocessing.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
-# (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 "libv4lprocessing-priv.h"
-
-void rgb_normalize_analyse(unsigned char *buf, int width, int height,
- struct v4lprocessing_data *data)
-{
- int value, max = 0, min = 255;
- unsigned char *buf_end = buf + width * height * 3;
-
- while (buf < buf_end) {
- value = *buf++;
- if (max < value)
- max = value;
- if (min > value)
- min = value;
- }
-
- data->comp1 = ((data->norm_high_bound - data->norm_low_bound) << 16) / (max - min);
- data->offset1 = min;
- data->offset2 = data->norm_low_bound;
-}
-
-void rgb_whitebalance_analyse(unsigned char *buf, int width, int height,
- struct v4lprocessing_data *data)
-{
- int value, x = 0, y = 0, z = 0;
- float x_avg, y_avg, z_avg, avg_avg;
- unsigned char *buf_end = buf + width * height * 3;
-
- while (buf < buf_end) {
- x += *buf++;
- y += *buf++;
- z += *buf++;
- }
-
- x_avg = x;
- y_avg = y;
- z_avg = z;
- avg_avg = (x_avg + y_avg + z_avg) / 3;
-
- data->comp1 = (avg_avg / x_avg) * 65536;
- data->comp2 = (avg_avg / y_avg) * 65536;
- data->comp3 = (avg_avg / z_avg) * 65536;
-}
-
-void rgb_normalize_whitebalance_analyse(unsigned char *buf,
- int width, int height, struct v4lprocessing_data *data)
-{
- int value, max = 0, min = 255;
- int n_fac, wb_max, x = 0, y = 0, z = 0;
- float x_avg, y_avg, z_avg, avg_avg;
- unsigned char *buf_end = buf + width * height * 3;
-
- while (buf < buf_end) {
- x += *buf;
- value = *buf++;
- if (max < value)
- max = value;
- if (min > value)
- min = value;
- y += *buf;
- value = *buf++;
- if (max < value)
- max = value;
- if (min > value)
- min = value;
- z += *buf;
- value = *buf++;
- if (max < value)
- max = value;
- if (min > value)
- min = value;
- }
-
- x_avg = x;
- y_avg = y;
- z_avg = z;
- avg_avg = (x_avg + y_avg + z_avg) / 3;
-
- n_fac = ((data->norm_high_bound - data->norm_low_bound) << 16) / (max - min);
-
- data->comp1 = (avg_avg / x_avg) * n_fac;
- data->comp2 = (avg_avg / y_avg) * n_fac;
- data->comp3 = (avg_avg / z_avg) * n_fac;
-
- data->offset1 = min;
- data->offset2 = data->norm_low_bound;
-}
-
-#define CLIP(color) (unsigned char)(((color)>0xff)?0xff:(((color)<0)?0:(color)))
-#define TOP(color) (unsigned char)(((color)>0xff)?0xff:(color))
-
-void rgb_normalize(unsigned char *buf, int width, int height,
- struct v4lprocessing_data *data)
-{
- int value;
- unsigned char *buf_end = buf + width * height * 3;
-
- while (buf < buf_end) {
- value = ((data->comp1 * (*buf - data->offset1)) >> 16) +
- data->offset2;
- *buf++ = CLIP(value);
- }
-}
-
-void rgb_whitebalance(unsigned char *buf, int width, int height,
- struct v4lprocessing_data *data)
-{
- int value;
- unsigned char *buf_end = buf + width * height * 3;
-
- while (buf < buf_end) {
- value = (*buf * data->comp1) >> 16;
- *buf++ = TOP(value);
- value = (*buf * data->comp2) >> 16;
- *buf++ = TOP(value);
- value = (*buf * data->comp3) >> 16;
- *buf++ = TOP(value);
- }
-}
-
-void rgb_normalize_whitebalance(unsigned char *buf, int width, int height,
- struct v4lprocessing_data *data)
-{
- int i, value;
- int limit = width * height * 3;
- unsigned char *buf_end = buf + width * height * 3;
-
- while (buf < buf_end) {
- value = ((data->comp1 * (*buf - data->offset1)) >> 16) + data->offset2;
- *buf++ = CLIP(value);
- value = ((data->comp2 * (*buf - data->offset1)) >> 16) + data->offset2;
- *buf++ = CLIP(value);
- value = ((data->comp3 * (*buf - data->offset1)) >> 16) + data->offset2;
- *buf++ = CLIP(value);
- }
-}
diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c b/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c
new file mode 100644
index 000000000..f5bfd961c
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c
@@ -0,0 +1,143 @@
+/*
+# (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 <syscall.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 };