summaryrefslogtreecommitdiff
path: root/v4l2-apps/libv4l/libv4lconvert
diff options
context:
space:
mode:
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 };