summaryrefslogtreecommitdiff
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
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>
-rw-r--r--v4l2-apps/libv4l/ChangeLog13
-rw-r--r--v4l2-apps/libv4l/README28
-rw-r--r--v4l2-apps/libv4l/TODO3
-rw-r--r--v4l2-apps/libv4l/include/libv4lconvert.h8
-rw-r--r--v4l2-apps/libv4l/libv4l2/Makefile2
-rw-r--r--v4l2-apps/libv4l/libv4l2/libv4l2.c15
-rw-r--r--v4l2-apps/libv4l/libv4l2/log.c4
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/Makefile7
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h33
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c210
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h41
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/flip.c57
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h43
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c230
-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
19 files changed, 1300 insertions, 110 deletions
diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog
index 9c9a5a3b2..52b429687 100644
--- a/v4l2-apps/libv4l/ChangeLog
+++ b/v4l2-apps/libv4l/ChangeLog
@@ -1,11 +1,16 @@
-libv4l-0.5.11
+libv4l-0.5.97
-------------
+* As the version number shows this is 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
* Add dependency generation to libv4l by: Gilles Gigan <gilles.gigan@gmail.com>
* Add support to use orientation from VIDIOC_ENUMINPUT by:
Adam Baker <linux@baker-net.org.uk>
-
-libv4l-0.5.10
--------------
* sn9c20x cams have occasional bad jpeg frames, drop these to avoid the
flickering effect they cause, by: Brian Johnson <brijohn@gmail.com>
* adjust libv4l's upside down cam detection to also work with devices
diff --git a/v4l2-apps/libv4l/README b/v4l2-apps/libv4l/README
index 3a2059224..481d5b92e 100644
--- a/v4l2-apps/libv4l/README
+++ b/v4l2-apps/libv4l/README
@@ -15,14 +15,26 @@ libv4l consists of 3 different libraries:
libv4lconvert
-------------
-libv4lconvert offers functions to convert from any (known) pixelformat
-to V4l2_PIX_FMT_BGR24 or V4l2_PIX_FMT_YUV420.
-
-Currently the following source formats are supported:
-jpeg, mjpeg, bayer (all 4 variants: bggr, rggb, gbrg, grbg),
-spca501 (chip specific yuv 420 with interlaced components),
-spca561 (chip specific compressed gbrg bayer)
-For more details on the v4lconvert_ functions see libv4lconvert.h .
+libv4lconvert started as a library to convert from any (known) pixelformat to
+V4l2_PIX_FMT_BGR24, RGB24, YUV420 or YVU420.
+
+The list of know source formats is large and continually growing, so instead
+of keeping an (almost always outdated) list here in the README, I refer you
+to the source, see the list of defines at the top of
+libv4lconvert/libv4lconvert.c for the full list.
+For more details on the v4lconvert_ functions see libv4lconvert.h.
+
+Later on libv4lconvert was expanded to also be able to do various video
+processing functions improve webcam video quality on a software basis. So
+the name no longer 100% covers the functionality. The video processing is
+split in to 2 parts, libv4lconvert/control and libv4lconvert/processing.
+
+The control part is used to offer video controls which can be used to control
+the video processing functions made available by libv4lconvert/processing.
+These controls are stored application wide (untill reboot) by using a
+persistent shared memory object.
+
+libv4lconvert/processing offers the actual video processing functionality.
libv4l1
diff --git a/v4l2-apps/libv4l/TODO b/v4l2-apps/libv4l/TODO
index debb9c78c..2bd2fc992 100644
--- a/v4l2-apps/libv4l/TODO
+++ b/v4l2-apps/libv4l/TODO
@@ -8,3 +8,6 @@
necessary to implement CGMBUF in the kernel for each driver.
-take the possibility of pitch != width into account everywhere
+
+-only report faked formats in list formats and only allow setting fake
+ formats when processing or flipping.
diff --git a/v4l2-apps/libv4l/include/libv4lconvert.h b/v4l2-apps/libv4l/include/libv4lconvert.h
index 626c43473..fcc31dace 100644
--- a/v4l2-apps/libv4l/include/libv4lconvert.h
+++ b/v4l2-apps/libv4l/include/libv4lconvert.h
@@ -81,6 +81,14 @@ LIBV4L_PUBLIC int v4lconvert_enum_framesizes(struct v4lconvert_data *data,
LIBV4L_PUBLIC int v4lconvert_enum_frameintervals(struct v4lconvert_data *data,
struct v4l2_frmivalenum *frmival);
+/* Pass calls to query, get and set video controls to the libv4lcontrol class */
+LIBV4L_PUBLIC int v4lconvert_vidioc_queryctrl(struct v4lconvert_data *data,
+ void *arg);
+LIBV4L_PUBLIC int v4lconvert_vidioc_g_ctrl(struct v4lconvert_data *data,
+ void *arg);
+LIBV4L_PUBLIC int v4lconvert_vidioc_s_ctrl(struct v4lconvert_data *data,
+ void *arg);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/v4l2-apps/libv4l/libv4l2/Makefile b/v4l2-apps/libv4l/libv4l2/Makefile
index c3af123c8..4356c0975 100644
--- a/v4l2-apps/libv4l/libv4l2/Makefile
+++ b/v4l2-apps/libv4l/libv4l2/Makefile
@@ -3,7 +3,7 @@ override CPPFLAGS += -I../include -I../../../include -fvisibility=hidden
CFLAGS := -g -O1
CFLAGS += -Wall -Wno-unused -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes
-LIBS_libv4l2 = -lpthread
+LIBS_libv4l2 = -lpthread -lrt
V4L2_OBJS = libv4l2.o log.o
V4L2CONVERT = v4l2convert.so
diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2.c b/v4l2-apps/libv4l/libv4l2/libv4l2.c
index b6ddef6e8..91e0193ee 100644
--- a/v4l2-apps/libv4l/libv4l2/libv4l2.c
+++ b/v4l2-apps/libv4l/libv4l2/libv4l2.c
@@ -676,6 +676,9 @@ int v4l2_ioctl (int fd, unsigned long int request, ...)
/* Is this a capture request and do we need to take the stream lock? */
switch (request) {
+ case VIDIOC_QUERYCTRL:
+ case VIDIOC_G_CTRL:
+ case VIDIOC_S_CTRL:
case VIDIOC_QUERYCAP:
is_capture_request = 1;
break;
@@ -739,6 +742,18 @@ int v4l2_ioctl (int fd, unsigned long int request, ...)
&devices[index].src_fmt, &devices[index].dest_fmt);
switch (request) {
+ case VIDIOC_QUERYCTRL:
+ result = v4lconvert_vidioc_queryctrl(devices[index].convert, arg);
+ break;
+
+ case VIDIOC_G_CTRL:
+ result = v4lconvert_vidioc_g_ctrl(devices[index].convert, arg);
+ break;
+
+ case VIDIOC_S_CTRL:
+ result = v4lconvert_vidioc_s_ctrl(devices[index].convert, arg);
+ break;
+
case VIDIOC_QUERYCAP:
{
struct v4l2_capability *cap = arg;
diff --git a/v4l2-apps/libv4l/libv4l2/log.c b/v4l2-apps/libv4l/libv4l2/log.c
index c29086ff4..251b46ecf 100644
--- a/v4l2-apps/libv4l/libv4l2/log.c
+++ b/v4l2-apps/libv4l/libv4l2/log.c
@@ -1,5 +1,7 @@
/*
-# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+# (C) 2008 Elmar Kleijn <elmar_kleijn@hotmail.com>
+# (C) 2008 Sjoerd Piepenbrink <need4weed@gmail.com>
+# (C) 2008 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
diff --git a/v4l2-apps/libv4l/libv4lconvert/Makefile b/v4l2-apps/libv4l/libv4lconvert/Makefile
index 95b9d31d9..64f6690d2 100644
--- a/v4l2-apps/libv4l/libv4lconvert/Makefile
+++ b/v4l2-apps/libv4l/libv4lconvert/Makefile
@@ -12,7 +12,9 @@ endif
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
+ rgbyuv.o spca501.o sq905c.o bayer.o hm12.o \
+ control/libv4lcontrol.o processing/libv4lprocessing.o \
+ processing/rgbprocessing.o processing/bayerprocessing.o
TARGETS = $(CONVERT_LIB) libv4lconvert.pc
INCLUDES = ../include/libv4lconvert.h
@@ -60,7 +62,8 @@ endif
install -m 644 libv4lconvert.pc $(DESTDIR)$(LIBDIR)/pkgconfig
clean::
- rm -f *.a *.so* *.o *.d libv4lconvert.pc log *~ *.orig *.rej
+ rm -f *.a *.so* *.o *.d */*.o */*.d libv4lconvert.pc log *~ */*~
+ rm -f *.orig *.rej */*.orig */*.rej
%.d:: %.c
@set -e; rm -f $@; \
diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h
new file mode 100644
index 000000000..59305a237
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h
@@ -0,0 +1,33 @@
+/*
+# (C) 2008-2009 Elmar Kleijn <elmar_kleijn@hotmail.com>
+# (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com>
+# (C) 2008-2009 Radjnies Bhansingh <radjnies@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 __LIBV4LCONTROL_PRIV_H
+#define __LIBV4LCONTROL_PRIV_H
+
+#define V4LCONTROL_SHM_SIZE 4096
+
+struct v4lcontrol_data {
+ int fd; /* Knowledge of the fd is needed in original syscalls */
+ unsigned int controls; /* Which controls to use for this device */
+ unsigned int *shm_values; /* shared memory control value store */
+};
+
+#endif
diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c
new file mode 100644
index 000000000..cb4e34327
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c
@@ -0,0 +1,210 @@
+/*
+# (C) 2008-2009 Elmar Kleijn <elmar_kleijn@hotmail.com>
+# (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com>
+# (C) 2008-2009 Radjnies Bhansingh <radjnies@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 <sys/types.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <syscall.h>
+#include "libv4lcontrol.h"
+#include "libv4lcontrol-priv.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>
+
+static void v4lcontrol_init(struct v4lcontrol_data *data, int first_time)
+{
+ /* FIXME: Temporary spoof future communication with driver by always enabling
+ the fake controls */
+ data->controls = (1 << V4LCONTROL_WHITEBALANCE) |
+ (1 << V4LCONTROL_NORMALIZE) | (1 << V4LCONTROL_NORM_LOW_BOUND) |
+ (1 << V4LCONTROL_NORM_HIGH_BOUND);
+
+ if (first_time) {
+ /* Initialize the new shm object when created */
+ memset(data->shm_values, 0, sizeof(V4LCONTROL_SHM_SIZE));
+ data->shm_values[V4LCONTROL_WHITEBALANCE] = 1;
+ data->shm_values[V4LCONTROL_NORM_HIGH_BOUND] = 255;
+ }
+}
+
+struct v4lcontrol_data *v4lcontrol_create(int fd)
+{
+ int shm_fd;
+ int init = 0;
+ char shm_name[256];
+ struct v4l2_capability cap;
+
+ struct v4lcontrol_data *data = calloc(1, sizeof(struct v4lcontrol_data));
+
+ if (!data)
+ return NULL;
+
+ syscall(SYS_ioctl, fd, VIDIOC_QUERYCAP, &cap);
+ snprintf(shm_name, 256, "/%s:%s", cap.bus_info, cap.card);
+
+ /* Open the shared memory object identified by shm_name */
+ if ((shm_fd = shm_open(shm_name, (O_CREAT | O_EXCL | O_RDWR),
+ (S_IREAD | S_IWRITE))) >= 0)
+ init = 1;
+ else if ((shm_fd = shm_open(shm_name, O_RDWR, (S_IREAD | S_IWRITE))) < 0)
+ goto error;
+
+ /* Set the shared memory size */
+ ftruncate(shm_fd, V4LCONTROL_SHM_SIZE);
+
+ /* Retreive a pointer to the shm object */
+ data->shm_values = mmap(NULL, V4LCONTROL_SHM_SIZE, (PROT_READ | PROT_WRITE),
+ MAP_SHARED, shm_fd, 0);
+ close(shm_fd);
+
+ if (data->shm_values == MAP_FAILED)
+ goto error;
+
+ v4lcontrol_init(data, init); /* Set the driver defined fake controls */
+
+ data->fd = fd;
+
+ return data;
+
+error:
+ free(data);
+ return NULL;
+}
+
+void v4lcontrol_destroy(struct v4lcontrol_data *data)
+{
+ munmap(data->shm_values, V4LCONTROL_SHM_SIZE);
+ free(data);
+}
+
+/* FIXME get better CID's for normalize */
+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",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ .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
+},
+};
+
+int v4lcontrol_vidioc_queryctrl(struct v4lcontrol_data *data, void *arg)
+{
+ int i;
+ struct v4l2_queryctrl *ctrl = arg;
+
+ for (i = 0; i < V4LCONTROL_COUNT; i++)
+ if ((data->controls & (1 << i)) &&
+ ctrl->id == fake_controls[i].id) {
+ memcpy(ctrl, &fake_controls[i], sizeof(struct v4l2_queryctrl));
+ return 0;
+ }
+
+ return syscall(SYS_ioctl, data->fd, VIDIOC_QUERYCTRL, arg);
+}
+
+int v4lcontrol_vidioc_g_ctrl(struct v4lcontrol_data *data, void *arg)
+{
+ int i;
+ struct v4l2_control *ctrl = arg;
+
+ for (i = 0; i < V4LCONTROL_COUNT; i++)
+ if ((data->controls & (1 << i)) &&
+ ctrl->id == fake_controls[i].id) {
+ ctrl->value = data->shm_values[i];
+ return 0;
+ }
+
+ return syscall(SYS_ioctl, data->fd, VIDIOC_G_CTRL, arg);
+}
+
+int v4lcontrol_vidioc_s_ctrl(struct v4lcontrol_data *data, void *arg)
+{
+ int i;
+ struct v4l2_control *ctrl = arg;
+
+ for (i = 0; i < V4LCONTROL_COUNT; i++)
+ if ((data->controls & (1 << i)) &&
+ ctrl->id == fake_controls[i].id) {
+ if (ctrl->value > fake_controls[i].maximum ||
+ ctrl->value < fake_controls[i].minimum) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ data->shm_values[i] = ctrl->value;
+ return 0;
+ }
+
+ return syscall(SYS_ioctl, data->fd, VIDIOC_S_CTRL, arg);
+}
+
+int v4lcontrol_get_ctrl(struct v4lcontrol_data *data, int ctrl)
+{
+ if (data->controls & (1 << ctrl))
+ return data->shm_values[ctrl];
+
+ return 0;
+}
diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h
new file mode 100644
index 000000000..3611304d6
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h
@@ -0,0 +1,41 @@
+/*
+# (C) 2008-2009 Elmar Kleijn <elmar_kleijn@hotmail.com>
+# (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com>
+# (C) 2008-2009 Radjnies Bhansingh <radjnies@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 __LIBV4LCONTROL_H
+#define __LIBV4LCONTROL_H
+
+enum { V4LCONTROL_WHITEBALANCE, V4LCONTROL_NORMALIZE,
+ V4LCONTROL_NORM_LOW_BOUND, V4LCONTROL_NORM_HIGH_BOUND, V4LCONTROL_COUNT };
+
+struct v4lcontrol_data;
+
+struct v4lcontrol_data* v4lcontrol_create(int fd);
+void v4lcontrol_destroy(struct v4lcontrol_data *data);
+
+/* Functions used by v4lprocessing to get the control state */
+int v4lcontrol_get_ctrl(struct v4lcontrol_data *data, int ctrl);
+
+/* Functions used by v4lconvert to pass vidioc calls from libv4l2 */
+int v4lcontrol_vidioc_queryctrl(struct v4lcontrol_data *data, void *arg);
+int v4lcontrol_vidioc_g_ctrl(struct v4lcontrol_data *data, void *arg);
+int v4lcontrol_vidioc_s_ctrl(struct v4lcontrol_data *data, void *arg);
+
+#endif
diff --git a/v4l2-apps/libv4l/libv4lconvert/flip.c b/v4l2-apps/libv4l/libv4lconvert/flip.c
index f47afde72..9835f045c 100644
--- a/v4l2-apps/libv4l/libv4lconvert/flip.c
+++ b/v4l2-apps/libv4l/libv4lconvert/flip.c
@@ -106,37 +106,46 @@ static void v4lconvert_rotate90_yuv420(const unsigned char *src,
}
}
-void v4lconvert_rotate(unsigned char *src, unsigned char *dest,
- int width, int height, unsigned int pix_fmt, int rotate)
+void v4lconvert_rotate90(unsigned char *src, unsigned char *dest,
+ struct v4l2_format *fmt)
{
- switch (rotate) {
- case 0:
- break;
- case 90:
- switch (pix_fmt) {
- case V4L2_PIX_FMT_RGB24:
- case V4L2_PIX_FMT_BGR24:
- v4lconvert_rotate90_rgbbgr24(src, dest, width, height);
- break;
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_YVU420:
- v4lconvert_rotate90_yuv420(src, dest, width, height);
- break;
- }
- break;
- case 180:
- switch (pix_fmt) {
+ int tmp;
+
+ tmp = fmt->fmt.pix.width;
+ fmt->fmt.pix.width = fmt->fmt.pix.height;
+ fmt->fmt.pix.height = tmp;
+
+ switch (fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_BGR24:
+ v4lconvert_rotate90_rgbbgr24(src, dest, fmt->fmt.pix.width,
+ fmt->fmt.pix.height);
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YVU420:
+ v4lconvert_rotate90_yuv420(src, dest, fmt->fmt.pix.width,
+ fmt->fmt.pix.height);
+ break;
+ }
+}
+
+void v4lconvert_flip(unsigned char *src, unsigned char *dest,
+ struct v4l2_format *fmt, int flags)
+{
+ /* FIXME implement separate vflipping and hflipping, for now we always
+ rotate 180 when vflip is selected! */
+ if (flags & V4LCONVERT_VFLIP) {
+ switch (fmt->fmt.pix.pixelformat) {
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_BGR24:
- v4lconvert_rotate180_rgbbgr24(src, dest, width, height);
+ v4lconvert_rotate180_rgbbgr24(src, dest, fmt->fmt.pix.width,
+ fmt->fmt.pix.height);
break;
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
- v4lconvert_rotate180_yuv420(src, dest, width, height);
+ v4lconvert_rotate180_yuv420(src, dest, fmt->fmt.pix.width,
+ fmt->fmt.pix.height);
break;
}
- break;
- default:
- printf("FIXME add %d degrees rotation\n", rotate);
}
}
diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h
index 4e6130d3c..acf921a31 100644
--- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h
+++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h
@@ -21,8 +21,12 @@
#include <stdio.h>
#include "libv4lconvert.h"
+#include "control/libv4lcontrol.h"
+#include "processing/libv4lprocessing.h"
#include "tinyjpeg.h"
+/* Workaround these potentially missing from videodev2.h */
+
#ifndef V4L2_PIX_FMT_SPCA501
#define V4L2_PIX_FMT_SPCA501 v4l2_fourcc('S','5','0','1') /* YUYV per line */
#endif
@@ -79,6 +83,15 @@
#define V4L2_PIX_FMT_SN9C20X_I420 v4l2_fourcc('S', '9', '2', '0')
#endif
+#ifndef V4L2_IN_ST_HFLIP
+#define V4L2_IN_ST_HFLIP 0x00000010 /* Frames are flipped horizontally */
+#endif
+
+#ifndef V4L2_IN_ST_VFLIP
+#define V4L2_IN_ST_VFLIP 0x00000020 /* Frames are flipped vertically */
+#endif
+
+
#define V4LCONVERT_ERROR_MSG_SIZE 256
#define V4LCONVERT_MAX_FRAMESIZES 16
@@ -87,10 +100,11 @@
"v4l-convert: error " __VA_ARGS__)
/* Card flags */
-#define V4LCONVERT_ROTATE_90 0x01
-#define V4LCONVERT_ROTATE_180 0x02
-#define V4LCONVERT_IS_UVC 0x04
-#define V4LCONVERT_IS_SN9C20X 0x08
+#define V4LCONVERT_HFLIP 0x01
+#define V4LCONVERT_VFLIP 0x02
+#define V4LCONVERT_JPEG_ROTATE_90_HACK 0x04
+#define V4LCONVERT_IS_UVC 0x08
+#define V4LCONVERT_IS_SN9C20X 0x10
/* Pixformat flags */
#define V4LCONVERT_COMPRESSED 0x01
@@ -104,12 +118,18 @@ struct v4lconvert_data {
struct jdec_private *jdec;
struct v4l2_frmsizeenum framesizes[V4LCONVERT_MAX_FRAMESIZES];
unsigned int no_framesizes;
- int convert_buf_size;
- int rotate_buf_size;
+ int convert1_buf_size;
+ int convert2_buf_size;
+ int rotate90_buf_size;
+ int flip_buf_size;
int convert_pixfmt_buf_size;
- unsigned char *convert_buf;
- unsigned char *rotate_buf;
+ unsigned char *convert1_buf;
+ unsigned char *convert2_buf;
+ unsigned char *rotate90_buf;
+ unsigned char *flip_buf;
unsigned char *convert_pixfmt_buf;
+ struct v4lcontrol_data *control;
+ struct v4lprocessing_data *processing;
};
struct v4lconvert_flags_info {
@@ -210,8 +230,11 @@ void v4lconvert_hm12_to_bgr24(const unsigned char *src,
void v4lconvert_hm12_to_yuv420(const unsigned char *src,
unsigned char *dst, int width, int height, int yvu);
-void v4lconvert_rotate(unsigned char *src, unsigned char *dest,
- int width, int height, unsigned int pix_fmt, int rotate);
+void v4lconvert_rotate90(unsigned char *src, unsigned char *dest,
+ struct v4l2_format *fmt);
+
+void v4lconvert_flip(unsigned char *src, unsigned char *dest,
+ struct v4l2_format *fmt, int flags);
void v4lconvert_crop(unsigned char *src, unsigned char *dest,
const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt);
diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c
index f3191f1d9..6fbc1affa 100644
--- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c
+++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c
@@ -29,11 +29,6 @@
#define MIN(a,b) (((a)<(b))?(a):(b))
#define ARRAY_SIZE(x) ((int)sizeof(x)/(int)sizeof((x)[0]))
-/* Workaround this potentially being missing from videodev2.h */
-#ifndef V4L2_IN_ST_VFLIP
-#define V4L2_IN_ST_VFLIP 0x00000020 /* Output is flipped vertically */
-#endif
-
/* Note for proper functioning of v4lconvert_enum_fmt the first entries in
supported_src_pixfmts must match with the entries in supported_dst_pixfmts */
#define SUPPORTED_DST_PIXFMTS \
@@ -77,10 +72,10 @@ static const struct v4lconvert_pixfmt supported_dst_pixfmts[] = {
/* List of cams which need special flags */
static const struct v4lconvert_flags_info v4lconvert_flags[] = {
- { 0x0471, 0x0325, V4LCONVERT_ROTATE_180 }, /* Philips SPC200NC */
- { 0x0471, 0x0326, V4LCONVERT_ROTATE_180 }, /* Philips SPC300NC */
- { 0x0471, 0x032d, V4LCONVERT_ROTATE_180 }, /* Philips SPC210NC */
- { 0x093a, 0x2476, V4LCONVERT_ROTATE_180 }, /* Genius E-M 112 */
+ { 0x0471, 0x0325, V4LCONVERT_HFLIP|V4LCONVERT_VFLIP }, /* Philips SPC200NC */
+ { 0x0471, 0x0326, V4LCONVERT_HFLIP|V4LCONVERT_VFLIP }, /* Philips SPC300NC */
+ { 0x0471, 0x032d, V4LCONVERT_HFLIP|V4LCONVERT_VFLIP }, /* Philips SPC210NC */
+ { 0x093a, 0x2476, V4LCONVERT_HFLIP|V4LCONVERT_VFLIP }, /* Genius E-M 112 */
};
/* List of well known resolutions which we can get by cropping somewhat larger
@@ -214,10 +209,10 @@ struct v4lconvert_data *v4lconvert_create(int fd)
data->flags = v4lconvert_get_flags(data->fd);
if ((syscall(SYS_ioctl, fd, VIDIOC_G_INPUT, &input.index) == 0) &&
(syscall(SYS_ioctl, fd, VIDIOC_ENUMINPUT, &input) == 0)) {
- /* Don't yet support independent HFLIP and VFLIP so getting
- * image the right way up is highest priority. */
+ if (input.status & V4L2_IN_ST_HFLIP)
+ data->flags |= V4LCONVERT_HFLIP;
if (input.status & V4L2_IN_ST_VFLIP)
- data->flags |= V4LCONVERT_ROTATE_180;
+ data->flags |= V4LCONVERT_VFLIP;
}
if (syscall(SYS_ioctl, fd, VIDIOC_QUERYCAP, &cap) == 0) {
if (!strcmp((char *)cap.driver, "uvcvideo"))
@@ -226,18 +221,35 @@ struct v4lconvert_data *v4lconvert_create(int fd)
data->flags |= V4LCONVERT_IS_SN9C20X;
}
+ data->control = v4lcontrol_create(fd);
+ if (!data->control) {
+ free(data);
+ return NULL;
+ }
+
+ data->processing = v4lprocessing_create(data->control);
+ if (!data->processing) {
+ v4lcontrol_destroy(data->control);
+ free(data);
+ return NULL;
+ }
+
return data;
}
void v4lconvert_destroy(struct v4lconvert_data *data)
{
+ v4lprocessing_destroy(data->processing);
+ v4lcontrol_destroy(data->control);
if (data->jdec) {
unsigned char *comps[3] = { NULL, NULL, NULL };
tinyjpeg_set_components(data->jdec, comps, 3);
tinyjpeg_free(data->jdec);
}
- free(data->convert_buf);
- free(data->rotate_buf);
+ free(data->convert1_buf);
+ free(data->convert2_buf);
+ free(data->rotate90_buf);
+ free(data->flip_buf);
free(data->convert_pixfmt_buf);
free(data);
}
@@ -490,7 +502,7 @@ int v4lconvert_needs_conversion(struct v4lconvert_data *data,
src_fmt->fmt.pix.pixelformat != dest_fmt->fmt.pix.pixelformat)
return 1; /* Formats differ */
- if (!(data->flags & (V4LCONVERT_ROTATE_90|V4LCONVERT_ROTATE_180)))
+ if (!(data->flags & (V4LCONVERT_HFLIP|V4LCONVERT_VFLIP)))
return 0; /* Formats identical and we don't need flip */
/* Formats are identical, but we need flip, do we support the dest_fmt? */
@@ -500,6 +512,32 @@ int v4lconvert_needs_conversion(struct v4lconvert_data *data,
return 1; /* Needs flip and thus conversion */
}
+static int v4lconvert_processing_needs_double_conversion(
+ unsigned int src_pix_fmt, unsigned int dest_pix_fmt)
+{
+ switch (src_pix_fmt) {
+ case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_BGR24:
+ case V4L2_PIX_FMT_SPCA561:
+ case V4L2_PIX_FMT_SN9C10X:
+ case V4L2_PIX_FMT_PAC207:
+ case V4L2_PIX_FMT_MR97310A:
+ case V4L2_PIX_FMT_SQ905C:
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SGRBG8:
+ case V4L2_PIX_FMT_SRGGB8:
+ return 0;
+ }
+ switch (dest_pix_fmt) {
+ case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_BGR24:
+ return 0;
+ }
+
+ return 1;
+}
+
static unsigned char *v4lconvert_alloc_buffer(struct v4lconvert_data *data,
int needed, unsigned char **buf, int *buf_size)
{
@@ -519,14 +557,14 @@ static unsigned char *v4lconvert_alloc_buffer(struct v4lconvert_data *data,
static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
unsigned char *src, int src_size, unsigned char *dest,
- const struct v4l2_format *src_fmt, unsigned int dest_pix_fmt)
+ struct v4l2_format *fmt, unsigned int dest_pix_fmt)
{
unsigned int header_width, header_height;
int result = 0, jpeg_flags = TINYJPEG_FLAGS_MJPEG_TABLE;
unsigned char *components[3];
- unsigned int src_pix_fmt = src_fmt->fmt.pix.pixelformat;
- unsigned int width = src_fmt->fmt.pix.width;
- unsigned int height = src_fmt->fmt.pix.height;
+ unsigned int src_pix_fmt = fmt->fmt.pix.pixelformat;
+ unsigned int width = fmt->fmt.pix.width;
+ unsigned int height = fmt->fmt.pix.height;
switch (src_pix_fmt) {
case V4L2_PIX_FMT_PJPG:
@@ -554,12 +592,14 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
if (header_width != width || header_height != height) {
/* Check for (pixart) rotated JPEG */
if (header_width == height && header_height == width) {
- if (!(data->flags & V4LCONVERT_ROTATE_90)) {
+ if (!(data->flags & V4LCONVERT_JPEG_ROTATE_90_HACK)) {
V4LCONVERT_ERR("JPEG needs 90 degree rotation\n");
- data->flags |= V4LCONVERT_ROTATE_90;
+ data->flags |= V4LCONVERT_JPEG_ROTATE_90_HACK;
errno = EAGAIN;
return -1;
}
+ fmt->fmt.pix.width = header_width;
+ fmt->fmt.pix.height = header_height;
} else {
V4LCONVERT_ERR("unexpected width / height in JPEG header"
"expected: %ux%u, header: %ux%u\n", width, height,
@@ -690,6 +730,7 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
case V4L2_PIX_FMT_SQ905C:
{
unsigned char *tmpbuf;
+ struct v4l2_format tmpfmt = *fmt;
tmpbuf = v4lconvert_alloc_buffer(data, width * height,
&data->convert_pixfmt_buf, &data->convert_pixfmt_buf_size);
@@ -699,27 +740,31 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
switch (src_pix_fmt) {
case V4L2_PIX_FMT_SPCA561:
v4lconvert_decode_spca561(src, tmpbuf, width, height);
- src_pix_fmt = V4L2_PIX_FMT_SGBRG8;
+ tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SGBRG8;
break;
case V4L2_PIX_FMT_SN9C10X:
v4lconvert_decode_sn9c10x(src, tmpbuf, width, height);
- src_pix_fmt = V4L2_PIX_FMT_SBGGR8;
+ tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
break;
case V4L2_PIX_FMT_PAC207:
v4lconvert_decode_pac207(src, tmpbuf, width, height);
- src_pix_fmt = V4L2_PIX_FMT_SBGGR8;
+ tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
break;
case V4L2_PIX_FMT_MR97310A:
v4lconvert_decode_mr97310a(src, tmpbuf, width, height);
- src_pix_fmt = V4L2_PIX_FMT_SBGGR8;
+ tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
break;
case V4L2_PIX_FMT_SQ905C:
v4lconvert_decode_sq905c(src, tmpbuf, width, height);
- src_pix_fmt = V4L2_PIX_FMT_SRGGB8;
+ tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SRGGB8;
break;
}
- src = tmpbuf;
+ /* Do processing on the tmp buffer, because doing it on bayer data is
+ cheaper, and bayer == rgb and our dest_fmt may be yuv */
+ v4lprocessing_processing(data->processing, tmpbuf, &tmpfmt);
/* Deliberate fall through to raw bayer fmt code! */
+ src_pix_fmt = tmpfmt.fmt.pix.pixelformat;
+ src = tmpbuf;
}
/* Raw bayer formats */
@@ -749,10 +794,10 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
v4lconvert_swap_rgb(src, dest, width, height);
break;
case V4L2_PIX_FMT_YUV420:
- v4lconvert_rgb24_to_yuv420(src, dest, src_fmt, 0, 0);
+ v4lconvert_rgb24_to_yuv420(src, dest, fmt, 0, 0);
break;
case V4L2_PIX_FMT_YVU420:
- v4lconvert_rgb24_to_yuv420(src, dest, src_fmt, 0, 1);
+ v4lconvert_rgb24_to_yuv420(src, dest, fmt, 0, 1);
break;
}
break;
@@ -763,10 +808,10 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
v4lconvert_swap_rgb(src, dest, width, height);
break;
case V4L2_PIX_FMT_YUV420:
- v4lconvert_rgb24_to_yuv420(src, dest, src_fmt, 1, 0);
+ v4lconvert_rgb24_to_yuv420(src, dest, fmt, 1, 0);
break;
case V4L2_PIX_FMT_YVU420:
- v4lconvert_rgb24_to_yuv420(src, dest, src_fmt, 1, 1);
+ v4lconvert_rgb24_to_yuv420(src, dest, fmt, 1, 1);
break;
}
break;
@@ -782,7 +827,7 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
height, 0);
break;
case V4L2_PIX_FMT_YVU420:
- v4lconvert_swap_uv(src, dest, src_fmt);
+ v4lconvert_swap_uv(src, dest, fmt);
break;
}
break;
@@ -798,7 +843,7 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
height, 1);
break;
case V4L2_PIX_FMT_YUV420:
- v4lconvert_swap_uv(src, dest, src_fmt);
+ v4lconvert_swap_uv(src, dest, fmt);
break;
}
break;
@@ -861,6 +906,10 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
errno = EINVAL;
return -1;
}
+
+ fmt->fmt.pix.pixelformat = dest_pix_fmt;
+ v4lconvert_fixup_fmt(fmt);
+
return 0;
}
@@ -869,8 +918,11 @@ int v4lconvert_convert(struct v4lconvert_data *data,
const struct v4l2_format *dest_fmt, /* in */
unsigned char *src, int src_size, unsigned char *dest, int dest_size)
{
- int res, dest_needed, temp_needed, convert = 0, rotate = 0, crop = 0;
- unsigned char *convert_dest = dest, *rotate_src = src, *rotate_dest = dest;
+ int res, dest_needed, temp_needed, processing, convert = 0, crop = 0;
+ unsigned char *convert1_dest = dest;
+ unsigned char *convert2_src = src, *convert2_dest = dest;
+ unsigned char *rotate90_src = src, *rotate90_dest = dest;
+ unsigned char *flip_src = src, *flip_dest = dest;
unsigned char *crop_src = src;
struct v4l2_format my_src_fmt = *src_fmt;
struct v4l2_format my_dest_fmt = *dest_fmt;
@@ -915,52 +967,98 @@ int v4lconvert_convert(struct v4lconvert_data *data,
return -1;
}
- if (my_dest_fmt.fmt.pix.pixelformat != my_src_fmt.fmt.pix.pixelformat)
- convert = 1;
+ processing = v4lprocessing_pre_processing(data->processing);
- if (data->flags & V4LCONVERT_ROTATE_90)
- rotate += 90;
- if (data->flags & V4LCONVERT_ROTATE_180)
- rotate += 180;
+ /* Sometimes we need foo -> rgb -> bar as video processing (whitebalance,
+ etc.) can only be done on rgb data */
+ if (processing && v4lconvert_processing_needs_double_conversion(
+ my_src_fmt.fmt.pix.pixelformat,
+ my_dest_fmt.fmt.pix.pixelformat))
+ convert = 2;
+ else if (my_dest_fmt.fmt.pix.pixelformat != my_src_fmt.fmt.pix.pixelformat)
+ convert = 1;
if (my_dest_fmt.fmt.pix.width != my_src_fmt.fmt.pix.width ||
my_dest_fmt.fmt.pix.height != my_src_fmt.fmt.pix.height)
crop = 1;
- /* convert_pixfmt -> rotate -> crop, all steps are optional */
- if (convert && (rotate || crop)) {
- convert_dest = v4lconvert_alloc_buffer(data, temp_needed,
- &data->convert_buf, &data->convert_buf_size);
- if (!convert_dest)
+ /* convert_pixfmt (only if convert == 2) -> processing -> convert_pixfmt ->
+ rotate -> flip -> crop, all steps are optional */
+ if (convert == 2) {
+ convert1_dest = v4lconvert_alloc_buffer(data,
+ my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3,
+ &data->convert1_buf, &data->convert1_buf_size);
+ if (!convert1_dest)
return -1;
- rotate_src = crop_src = convert_dest;
+ convert2_src = convert1_dest;
}
- if (rotate && crop) {
- rotate_dest = v4lconvert_alloc_buffer(data, temp_needed,
- &data->rotate_buf, &data->rotate_buf_size);
- if (!rotate_dest)
+ if (convert && (data->flags & (V4LCONVERT_JPEG_ROTATE_90_HACK |
+ V4LCONVERT_VFLIP | V4LCONVERT_HFLIP) || crop)) {
+ convert2_dest = v4lconvert_alloc_buffer(data, temp_needed,
+ &data->convert2_buf, &data->convert2_buf_size);
+ if (!convert2_dest)
return -1;
- crop_src = rotate_dest;
+ rotate90_src = flip_src = crop_src = convert2_dest;
}
- if (convert) {
- res = v4lconvert_convert_pixfmt(data, src, src_size, convert_dest,
+ if ((data->flags & V4LCONVERT_JPEG_ROTATE_90_HACK) &&
+ ((data->flags & (V4LCONVERT_VFLIP | V4LCONVERT_HFLIP)) || crop)) {
+ rotate90_dest = v4lconvert_alloc_buffer(data, temp_needed,
+ &data->rotate90_buf, &data->rotate90_buf_size);
+ if (!rotate90_dest)
+ return -1;
+
+ flip_src = crop_src = rotate90_dest;
+ }
+
+ if ((data->flags & (V4LCONVERT_VFLIP | V4LCONVERT_HFLIP)) && crop) {
+ flip_dest = v4lconvert_alloc_buffer(data, temp_needed, &data->flip_buf,
+ &data->flip_buf_size);
+ if (!flip_dest)
+ return -1;
+
+ crop_src = flip_dest;
+ }
+
+ /* Done setting sources / dest and allocating intermediate buffers,
+ real conversion / processing / ... starts here. */
+ if (convert == 2) {
+ res = v4lconvert_convert_pixfmt(data, src, src_size, convert1_dest,
&my_src_fmt,
+ V4L2_PIX_FMT_RGB24);
+ if (res)
+ return res;
+
+ src_size = my_src_fmt.fmt.pix.sizeimage;
+ }
+
+ if (processing)
+ v4lprocessing_processing(data->processing, convert2_src, &my_src_fmt);
+
+ if (convert) {
+ res = v4lconvert_convert_pixfmt(data, convert2_src, src_size,
+ convert2_dest, &my_src_fmt,
my_dest_fmt.fmt.pix.pixelformat);
if (res)
return res;
- my_src_fmt.fmt.pix.pixelformat = my_dest_fmt.fmt.pix.pixelformat;
- v4lconvert_fixup_fmt(&my_src_fmt);
+ src_size = my_src_fmt.fmt.pix.sizeimage;
}
- if (rotate)
- v4lconvert_rotate(rotate_src, rotate_dest,
- my_src_fmt.fmt.pix.width, my_src_fmt.fmt.pix.height,
- my_src_fmt.fmt.pix.pixelformat, rotate);
+ /* We call processing here again in case the source format was not
+ rgb, but the dest is. v4lprocessing checks it self it only actually
+ does the processing once per frame. */
+ if (processing)
+ v4lprocessing_processing(data->processing, rotate90_src, &my_src_fmt);
+
+ if (data->flags & V4LCONVERT_JPEG_ROTATE_90_HACK)
+ v4lconvert_rotate90(rotate90_src, rotate90_dest, &my_src_fmt);
+
+ if (data->flags & (V4LCONVERT_VFLIP | V4LCONVERT_HFLIP))
+ v4lconvert_flip(flip_src, flip_dest, &my_src_fmt, data->flags);
if (crop)
v4lconvert_crop(crop_src, dest, &my_src_fmt, &my_dest_fmt);
@@ -1135,3 +1233,15 @@ int v4lconvert_enum_frameintervals(struct v4lconvert_data *data,
return res;
}
+
+int v4lconvert_vidioc_queryctrl(struct v4lconvert_data *data, void *arg) {
+ return v4lcontrol_vidioc_queryctrl(data->control, arg);
+}
+
+int v4lconvert_vidioc_g_ctrl(struct v4lconvert_data *data, void *arg) {
+ return v4lcontrol_vidioc_g_ctrl(data->control, arg);
+}
+
+int v4lconvert_vidioc_s_ctrl(struct v4lconvert_data *data, void *arg){
+ return v4lcontrol_vidioc_s_ctrl(data->control, arg);
+}
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);
+ }
+}