summaryrefslogtreecommitdiff
path: root/v4l2-apps/libv4l/libv4lconvert/processing
diff options
context:
space:
mode:
authorhans@rhel5-devel.localdomain <hans@rhel5-devel.localdomain>2009-05-25 15:25:15 +0200
committerhans@rhel5-devel.localdomain <hans@rhel5-devel.localdomain>2009-05-25 15:25:15 +0200
commit51949cfaadebd8e341fed1e85eca683dd40195d2 (patch)
treea073bed97a4704eb6f73c2c0e54399f30f35e93d /v4l2-apps/libv4l/libv4lconvert/processing
parentb152107391374bfc61ea21d1731fd349352bedf2 (diff)
downloadmediapointer-dvb-s2-51949cfaadebd8e341fed1e85eca683dd40195d2.tar.gz
mediapointer-dvb-s2-51949cfaadebd8e341fed1e85eca683dd40195d2.tar.bz2
libv4l: add software autogain / exposure
From: Hans de Goede <hdegoede@redhat.com> Add software autogain / exposure, for camera's which have gain and exposure controls but do not contain the ability to calculate the average lumination in hardware (which is needed to do this in the kernel). This patch enables this for the spca561 rev12a, but it should be usefull for other cameras too. 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/autogain.c140
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h2
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c4
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.h2
4 files changed, 146 insertions, 2 deletions
diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/autogain.c b/v4l2-apps/libv4l/libv4lconvert/processing/autogain.c
new file mode 100644
index 000000000..ed4b8224f
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/autogain.c
@@ -0,0 +1,140 @@
+/*
+# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <syscall.h>
+#include <unistd.h>
+
+#include "libv4lprocessing.h"
+#include "libv4lprocessing-priv.h"
+#include "../libv4lconvert-priv.h" /* for PIX_FMT defines */
+
+static int autogain_active(struct v4lprocessing_data *data) {
+ return v4lcontrol_get_ctrl(data->control, V4LCONTROL_AUTOGAIN);
+}
+
+/* auto gain and exposure algorithm based on the knee algorithm described here:
+ http://ytse.tricolour.net/docs/LowLightOptimization.html */
+static int autogain_calculate_lookup_tables(
+ struct v4lprocessing_data *data,
+ unsigned char *buf, const struct v4l2_format *fmt)
+{
+ int x, y, target, steps, avg_lum = 0;
+ int gain, exposure, orig_gain, orig_exposure;
+ struct v4l2_control ctrl;
+ struct v4l2_queryctrl gainctrl, expoctrl;
+ const int deadzone = 8;
+
+ ctrl.id = V4L2_CID_EXPOSURE;
+ expoctrl.id = V4L2_CID_EXPOSURE;
+ if (syscall(SYS_ioctl, data->fd, VIDIOC_QUERYCTRL, &expoctrl) ||
+ syscall(SYS_ioctl, data->fd, VIDIOC_G_CTRL, &ctrl))
+ return 0;
+ exposure = orig_exposure = ctrl.value;
+
+ ctrl.id = V4L2_CID_GAIN;
+ gainctrl.id = V4L2_CID_GAIN;
+ if (syscall(SYS_ioctl, data->fd, VIDIOC_QUERYCTRL, &gainctrl) ||
+ syscall(SYS_ioctl, data->fd, VIDIOC_G_CTRL, &ctrl))
+ return 0;
+ gain = orig_gain = ctrl.value;
+
+ switch (fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SGRBG8:
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SRGGB8:
+ buf += fmt->fmt.pix.height * fmt->fmt.pix.bytesperline / 4 +
+ fmt->fmt.pix.width / 4;
+
+ for (y = 0; y < fmt->fmt.pix.height / 2; y++) {
+ for (x = 0; x < fmt->fmt.pix.width / 2; x++) {
+ avg_lum += *buf++;
+ }
+ buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width / 2;
+ }
+ avg_lum /= fmt->fmt.pix.height * fmt->fmt.pix.width / 4;
+ break;
+
+ case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_BGR24:
+ buf += fmt->fmt.pix.height * fmt->fmt.pix.bytesperline / 4 +
+ fmt->fmt.pix.width * 3 / 4;
+
+ for (y = 0; y < fmt->fmt.pix.height / 2; y++) {
+ for (x = 0; x < fmt->fmt.pix.width / 2; x++) {
+ avg_lum += *buf++;
+ avg_lum += *buf++;
+ avg_lum += *buf++;
+ }
+ buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width * 3 / 2;
+ }
+ avg_lum /= fmt->fmt.pix.height * fmt->fmt.pix.width * 3 / 4;
+ break;
+ }
+
+ /* If we are off a multiple of deadzone, do multiple steps to reach the
+ desired lumination fast (with the risc of a slight overshoot) */
+ target = v4lcontrol_get_ctrl(data->control, V4LCONTROL_AUTOGAIN_TARGET);
+ steps = abs(target - avg_lum) / deadzone;
+
+ for (x = 0; x < steps; x++) {
+ if (avg_lum > target) {
+ if (exposure > expoctrl.default_value)
+ exposure--;
+ else if (gain > gainctrl.default_value)
+ gain--;
+ else if (exposure > expoctrl.minimum)
+ exposure--;
+ else if (gain > gainctrl.minimum)
+ gain--;
+ else
+ break;
+ } else {
+ if (gain < gainctrl.default_value)
+ gain++;
+ else if (exposure < expoctrl.default_value)
+ exposure++;
+ else if (gain < gainctrl.maximum)
+ gain++;
+ else if (exposure < expoctrl.maximum)
+ exposure++;
+ else
+ break;
+ }
+ }
+
+ if (gain != orig_gain) {
+ ctrl.id = V4L2_CID_GAIN;
+ ctrl.value = gain;
+ syscall(SYS_ioctl, data->fd, VIDIOC_S_CTRL, &ctrl);
+ }
+ if (exposure != orig_exposure) {
+ ctrl.id = V4L2_CID_EXPOSURE;
+ ctrl.value = exposure;
+ syscall(SYS_ioctl, data->fd, VIDIOC_S_CTRL, &ctrl);
+ }
+
+ return 0;
+}
+
+struct v4lprocessing_filter autogain_filter = {
+ autogain_active, autogain_calculate_lookup_tables };
diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h
index fb514d7f5..b848317f7 100644
--- a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h
@@ -27,6 +27,7 @@
struct v4lprocessing_data {
struct v4lcontrol_data *control;
+ int fd;
int do_process;
/* True if any of the lookup tables does not contain
linear 0-255 */
@@ -49,5 +50,6 @@ struct v4lprocessing_filter {
};
extern struct v4lprocessing_filter whitebalance_filter;
+extern struct v4lprocessing_filter autogain_filter;
#endif
diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c
index 3a3802aab..01de6c111 100644
--- a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c
@@ -30,9 +30,10 @@
static struct v4lprocessing_filter *filters[] = {
&whitebalance_filter,
+ &autogain_filter,
};
-struct v4lprocessing_data *v4lprocessing_create(struct v4lcontrol_data* control)
+struct v4lprocessing_data *v4lprocessing_create(int fd, struct v4lcontrol_data* control)
{
struct v4lprocessing_data *data =
calloc(1, sizeof(struct v4lprocessing_data));
@@ -40,6 +41,7 @@ struct v4lprocessing_data *v4lprocessing_create(struct v4lcontrol_data* control)
if (!data)
return NULL;
+ data->fd = fd;
data->control = control;
return data;
diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.h b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.h
index 3c50d9fb9..f1892a279 100644
--- a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.h
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.h
@@ -32,7 +32,7 @@
struct v4lprocessing_data;
struct v4lcontrol_data;
-struct v4lprocessing_data *v4lprocessing_create(struct v4lcontrol_data *data);
+struct v4lprocessing_data *v4lprocessing_create(int fd, struct v4lcontrol_data *data);
void v4lprocessing_destroy(struct v4lprocessing_data *data);
/* Prepare to process 1 frame, returns 1 if processing is necesary,