summaryrefslogtreecommitdiff
path: root/v4l2-apps/libv4l/libv4lconvert/processing
diff options
context:
space:
mode:
authorhans@rhel5-devel.localdomain <hans@rhel5-devel.localdomain>2009-04-13 20:02:34 +0200
committerhans@rhel5-devel.localdomain <hans@rhel5-devel.localdomain>2009-04-13 20:02:34 +0200
commitfa59c01eadd849ed2e5b0cf1406347bf632c80ed (patch)
treea692af6a62ac3e7f1800d59c9bab4ecd29cd2b30 /v4l2-apps/libv4l/libv4lconvert/processing
parent47b68b12ace2d6414547991a02fda32a4ae748f7 (diff)
downloadmediapointer-dvb-s2-fa59c01eadd849ed2e5b0cf1406347bf632c80ed.tar.gz
mediapointer-dvb-s2-fa59c01eadd849ed2e5b0cf1406347bf632c80ed.tar.bz2
libv4l: add video processing: whitebalance and normalize
From: Hans de Goede <hdegoede@redhat.com> As the version number shows this work is the basis for a beta release of the 0.6.x series, the big change here is the addition of video processing to libv4l currently this only does whitebalance and normalizing (which turns out to be useless for most cams) but the basic framework for doing video processing, and being able to control it through fake v4l2 controls using for example v4l2ucp is there. The initial version of this code was written by 3 of my computer science students: Elmar Kleijn, Sjoerd Piepenbrink and Radjnies Bhansingh. This initial hg commit is a cleaned up and somewhat bug fixed version of their code. Priority: normal Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Diffstat (limited to 'v4l2-apps/libv4l/libv4lconvert/processing')
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/bayerprocessing.c244
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h89
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c179
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.h48
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/rgbprocessing.c156
5 files changed, 716 insertions, 0 deletions
diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/bayerprocessing.c b/v4l2-apps/libv4l/libv4lconvert/processing/bayerprocessing.c
new file mode 100644
index 000000000..f4cc9922b
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/bayerprocessing.c
@@ -0,0 +1,244 @@
+/*
+# (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
new file mode 100644
index 000000000..f2aae373d
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h
@@ -0,0 +1,89 @@
+/*
+# (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"
+
+#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;
+ /* 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;
+};
+
+/* 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);
+
+/* 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);
+
+#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..d61c29275
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c
@@ -0,0 +1,179 @@
+/*
+# (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 */
+
+struct v4lprocessing_data *v4lprocessing_create(struct v4lcontrol_data* control)
+{
+ struct v4lprocessing_data *data =
+ calloc(1, sizeof(struct v4lprocessing_data));
+
+ if (!data)
+ return NULL;
+
+ data->control = control;
+
+ return data;
+}
+
+void v4lprocessing_destroy(struct v4lprocessing_data *data)
+{
+ free(data);
+}
+
+static int v4lprocessing_get_process(struct v4lprocessing_data *data,
+ unsigned int pix_fmt)
+{
+ int process = V4L2PROCESSING_PROCESS_NONE;
+
+ 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;
+ }
+
+ return process;
+}
+
+static void v4lprocessing_update_processing_data(
+ struct v4lprocessing_data *data,
+ unsigned int pix_fmt, unsigned char *buf, unsigned int width,
+ unsigned int height)
+{
+ switch (data->process) {
+ case V4L2PROCESSING_PROCESS_BAYER_NORMALIZE:
+ bayer_normalize_analyse(buf, width, height, data);
+ break;
+
+ case V4L2PROCESSING_PROCESS_BAYER_WHITEBALANCE:
+ bayer_whitebalance_analyse(buf, width, height, pix_fmt, data);
+ break;
+
+ case V4L2PROCESSING_PROCESS_BAYER_NORMALIZE_WHITEBALANCE:
+ bayer_normalize_whitebalance_analyse(buf, width, height, pix_fmt, data);
+ break;
+
+ case V4L2PROCESSING_PROCESS_RGB_NORMALIZE:
+ rgb_normalize_analyse(buf, width, height, data);
+ break;
+
+ case V4L2PROCESSING_PROCESS_RGB_WHITEBALANCE:
+ rgb_whitebalance_analyse(buf, width, height, data);
+ break;
+
+ case V4L2PROCESSING_PROCESS_RGB_NORMALIZE_WHITEBALANCE:
+ rgb_normalize_whitebalance_analyse(buf, width, height, data);
+ 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);
+
+ 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) {
+ data->process = process;
+ 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;
+ }
+
+ 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);
+ } 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;
+
+ case V4L2PROCESSING_PROCESS_RGB_WHITEBALANCE:
+ rgb_whitebalance(buf, fmt->fmt.pix.width, fmt->fmt.pix.height, data);
+ break;
+
+ 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/libv4lprocessing.h b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.h
new file mode 100644
index 000000000..3c50d9fb9
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.h
@@ -0,0 +1,48 @@
+/*
+# (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
+
+/* These headers are not needed by us, but by linux/videodev2.h,
+ which is broken on some systems and doesn't include them itself :( */
+#include <sys/time.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+/* end broken header workaround includes */
+#include <linux/videodev2.h>
+
+struct v4lprocessing_data;
+struct v4lcontrol_data;
+
+struct v4lprocessing_data *v4lprocessing_create(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/rgbprocessing.c b/v4l2-apps/libv4l/libv4lconvert/processing/rgbprocessing.c
new file mode 100644
index 000000000..4e0fc3f4a
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/rgbprocessing.c
@@ -0,0 +1,156 @@
+/*
+# (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);
+ }
+}