libv4l: add gamma correction to video processing
authorhans@rhel5-devel.localdomain <hans@rhel5-devel.localdomain>
Tue, 26 May 2009 08:07:18 +0000 (10:07 +0200)
committerhans@rhel5-devel.localdomain <hans@rhel5-devel.localdomain>
Tue, 26 May 2009 08:07:18 +0000 (10:07 +0200)
From: Hans de Goede <hdegoede@redhat.com>

add gamma correction to the video processing, and enable it by default
(correct for a display gamma of 1.5) for pac207 based cams.

Priority: normal

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
lib/ChangeLog
lib/TODO
lib/libv4lconvert/Makefile
lib/libv4lconvert/control/libv4lcontrol-priv.h
lib/libv4lconvert/control/libv4lcontrol.c
lib/libv4lconvert/control/libv4lcontrol.h
lib/libv4lconvert/processing/gamma.c [new file with mode: 0644]
lib/libv4lconvert/processing/libv4lprocessing-priv.h
lib/libv4lconvert/processing/libv4lprocessing.c

index db2fa02..5e1e7fd 100644 (file)
@@ -16,6 +16,7 @@ libv4l-0.5.98
 * Add software auto gain / exposure
 * The V4L2_ENABLE_ENUM_FMT_EMULATION v4l2_fd_open flag is obsolete, libv4l2
   now *always* reports emulated formats through the ENUM_FMT ioctl
+* Add software gamma correction
 
 libv4l-0.5.97
 -------------
index e4ea436..8f77443 100644 (file)
--- a/lib/TODO
+++ b/lib/TODO
@@ -12,7 +12,4 @@
 -make updating of parameters happen based on time elapsed rather then
  frames
 
-
--add gamma correction video processing
-
 -get standardized CID for AUTOGAIN_TARGET upstream and switch to that
index f4f529c..7bc4993 100644 (file)
@@ -16,7 +16,8 @@ CONVERT_OBJS  = libv4lconvert.o tinyjpeg.o sn9c10x.o sn9c20x.o pac207.o \
                mr97310a.o flip.o crop.o jidctflt.o spca561-decompress.o \
                rgbyuv.o spca501.o sq905c.o bayer.o hm12.o \
                control/libv4lcontrol.o processing/libv4lprocessing.o \
-               processing/whitebalance.o processing/autogain.o
+               processing/whitebalance.o processing/autogain.o \
+               processing/gamma.o
 TARGETS       = $(CONVERT_LIB) libv4lconvert.pc
 INCLUDES      = ../include/libv4lconvert.h
 
index 14481a9..6211ee2 100644 (file)
@@ -26,6 +26,8 @@
 
 #define V4LCONTROL_SUPPORTS_NEXT_CTRL 0x01
 
+struct v4lcontrol_flags_info;
+
 struct v4lcontrol_data {
   int fd;                   /* Device fd */
   int flags;                /* Flags for this device */
@@ -33,6 +35,7 @@ struct v4lcontrol_data {
   int controls;             /* Which controls to use for this device */
   unsigned int *shm_values; /* shared memory control value store */
   unsigned int old_values[V4LCONTROL_COUNT]; /* for controls_changed() */
+  const struct v4lcontrol_flags_info *flags_info;
 };
 
 struct v4lcontrol_flags_info {
@@ -45,6 +48,7 @@ struct v4lcontrol_flags_info {
   const char *manufacturer;
   const char *product; */
   int flags;
+  int default_gamma;
 };
 
 #endif
index 3f57afb..6bf5b62 100644 (file)
@@ -63,16 +63,16 @@ static const struct v4lcontrol_flags_info v4lcontrol_flags[] = {
   { 0x0471, 0x032d, 0, NULL, NULL, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
   /* Genius E-M 112 (also want whitebalance by default) */
   { 0x093a, 0x2476, 0, NULL, NULL,
-    V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED|V4LCONTROL_WANTS_WB },
+    V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED|V4LCONTROL_WANTS_WB, 1500 },
   /* Asus N50Vn laptop */
   { 0x04f2, 0xb106, 0, "ASUSTeK Computer Inc.        ", "N50Vn      ",
     V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
 /* Second: devices which should use some software processing by default */
   /* Pac207 based devices */
-  { 0x041e, 0x4028, 0,    NULL, NULL, V4LCONTROL_WANTS_WB },
-  { 0x093a, 0x2460, 0x1f, NULL, NULL, V4LCONTROL_WANTS_WB },
-  { 0x145f, 0x013a, 0,    NULL, NULL, V4LCONTROL_WANTS_WB },
-  { 0x2001, 0xf115, 0,    NULL, NULL, V4LCONTROL_WANTS_WB },
+  { 0x041e, 0x4028, 0,    NULL, NULL, V4LCONTROL_WANTS_WB, 1500 },
+  { 0x093a, 0x2460, 0x1f, NULL, NULL, V4LCONTROL_WANTS_WB, 1500 },
+  { 0x145f, 0x013a, 0,    NULL, NULL, V4LCONTROL_WANTS_WB, 1500 },
+  { 0x2001, 0xf115, 0,    NULL, NULL, V4LCONTROL_WANTS_WB, 1500 },
   /* Pac7302 based devices */
   { 0x093a, 0x2620, 0x0f, NULL, NULL,
     V4LCONTROL_ROTATED_90_JPEG|V4LCONTROL_WANTS_WB },
@@ -198,6 +198,7 @@ static void v4lcontrol_init_flags(struct v4lcontrol_data *data)
        (v4lcontrol_flags[i].dmi_board_name == NULL ||
         !strcmp(v4lcontrol_flags[i].dmi_board_name, dmi_board_name))) {
       data->flags |= v4lcontrol_flags[i].flags;
+      data->flags_info = &v4lcontrol_flags[i];
       break;
     }
 }
@@ -283,6 +284,9 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion)
 
     if (data->flags & V4LCONTROL_WANTS_WB)
       data->shm_values[V4LCONTROL_WHITEBALANCE] = 1;
+
+    if (data->flags_info && data->flags_info->default_gamma)
+      data->shm_values[V4LCONTROL_GAMMA] = data->flags_info->default_gamma;
   }
 
   return data;
@@ -331,6 +335,16 @@ static const struct v4l2_queryctrl fake_controls[V4LCONTROL_COUNT] = {
   .default_value = 0,
   .flags = 0
 },
+{
+  .id = V4L2_CID_GAMMA,
+  .type = V4L2_CTRL_TYPE_INTEGER,
+  .name =  "Gamma (software)",
+  .minimum = 500,  /* == 0.5 */
+  .maximum = 3000, /* == 3.0 */
+  .step = 1,
+  .default_value = 1000, /* == 1.0 */
+  .flags = 0
+},
 {}, /* Dummy place holder for V4LCONTROL_AUTO_ENABLE_COUNT */
 {
   .id = V4L2_CID_AUTOGAIN,
@@ -363,6 +377,10 @@ static void v4lcontrol_copy_queryctrl(struct v4lcontrol_data *data,
   if (ctrl->id == V4L2_CID_AUTO_WHITE_BALANCE &&
       (data->flags & V4LCONTROL_WANTS_WB))
     ctrl->default_value = 1;
+
+  if (ctrl->id == V4L2_CID_GAMMA && data->flags_info &&
+      data->flags_info->default_gamma)
+    ctrl->default_value = data->flags_info->default_gamma;
 }
 
 int v4lcontrol_vidioc_queryctrl(struct v4lcontrol_data *data, void *arg)
index a364003..e29fde3 100644 (file)
@@ -37,6 +37,7 @@ enum {
   V4LCONTROL_WHITEBALANCE,
   V4LCONTROL_HFLIP,
   V4LCONTROL_VFLIP,
+  V4LCONTROL_GAMMA,
   /* All fake controls above here are auto enabled when not present in hw */
   V4LCONTROL_AUTO_ENABLE_COUNT,
   V4LCONTROL_AUTOGAIN,
diff --git a/lib/libv4lconvert/processing/gamma.c b/lib/libv4lconvert/processing/gamma.c
new file mode 100644 (file)
index 0000000..7695abc
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+#             (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 <math.h>
+#include "libv4lprocessing.h"
+#include "libv4lprocessing-priv.h"
+
+#define CLIP(color) (unsigned char)(((color)>0xff)?0xff:(((color)<0)?0:(color)))
+
+static int gamma_active(struct v4lprocessing_data *data) {
+  return v4lcontrol_get_ctrl(data->control, V4LCONTROL_GAMMA) != 1000;
+}
+
+static int gamma_calculate_lookup_tables(
+  struct v4lprocessing_data *data,
+  unsigned char *buf, const struct v4l2_format *fmt)
+{
+  int i, x, gamma;
+
+  gamma = v4lcontrol_get_ctrl(data->control, V4LCONTROL_GAMMA);
+
+  if (gamma != data->last_gamma) {
+    for (i = 0; i < 256; i++) {
+      x = powf(i / 255.0, 1000.0 / gamma) * 255;
+      data->gamma_table[i] = CLIP(x);
+    }
+    data->last_gamma = gamma;
+  }
+
+  for (i = 0; i < 256; i++) {
+    data->comp1[i] = data->gamma_table[data->comp1[i]];
+    data->green[i] = data->gamma_table[data->green[i]];
+    data->comp2[i] = data->gamma_table[data->comp2[i]];
+  }
+
+  return 1;
+}
+
+struct v4lprocessing_filter gamma_filter = {
+  gamma_active, gamma_calculate_lookup_tables };
index b848317..008d352 100644 (file)
@@ -39,6 +39,9 @@ struct v4lprocessing_data {
   unsigned char comp1[256];
   unsigned char green[256];
   unsigned char comp2[256];
+  /* Filter private data for filters which need it */
+  int last_gamma;
+  unsigned char gamma_table[256];
 };
 
 struct v4lprocessing_filter {
@@ -51,5 +54,6 @@ struct v4lprocessing_filter {
 
 extern struct v4lprocessing_filter whitebalance_filter;
 extern struct v4lprocessing_filter autogain_filter;
+extern struct v4lprocessing_filter gamma_filter;
 
 #endif
index 01de6c1..f050086 100644 (file)
@@ -31,6 +31,7 @@
 static struct v4lprocessing_filter *filters[] = {
   &whitebalance_filter,
   &autogain_filter,
+  &gamma_filter,
 };
 
 struct v4lprocessing_data *v4lprocessing_create(int fd, struct v4lcontrol_data* control)