summaryrefslogtreecommitdiff
path: root/v4l2-apps/libv4l/libv4lconvert
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2009-09-07 01:17:45 -0300
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-09-07 01:17:45 -0300
commitc8d4bba77d042c9ede4936550f38666cde85a50c (patch)
treeee7aa9817d9af2ca9edfb26a137c6192fa6c2072 /v4l2-apps/libv4l/libv4lconvert
parent38df09ba8b967b4d219c2afe04dcc1ae743e766f (diff)
parentb90712cf41e75451c3b515ed41d2eda714db3de1 (diff)
downloadmediapointer-dvb-s2-c8d4bba77d042c9ede4936550f38666cde85a50c.tar.gz
mediapointer-dvb-s2-c8d4bba77d042c9ede4936550f38666cde85a50c.tar.bz2
merge: http://linuxtv.org/hg/~awalls/v4l-dvb
From: Mauro Carvalho Chehab <mchehab@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'v4l2-apps/libv4l/libv4lconvert')
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/Makefile14
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/bayer.c2
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h10
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c252
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/crop.c2
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/flip.c3
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h26
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c62
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/pac207.c57
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h6
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c9
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c136
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/rgbyuv.c104
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/sn9c2028-decomp.c157
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/spca501.c2
15 files changed, 713 insertions, 129 deletions
diff --git a/v4l2-apps/libv4l/libv4lconvert/Makefile b/v4l2-apps/libv4l/libv4lconvert/Makefile
index 036649e86..cc3941b87 100644
--- a/v4l2-apps/libv4l/libv4lconvert/Makefile
+++ b/v4l2-apps/libv4l/libv4lconvert/Makefile
@@ -14,10 +14,10 @@ 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 helper.o \
+ rgbyuv.o sn9c2028-decomp.o spca501.o sq905c.o bayer.o hm12.o \
control/libv4lcontrol.o processing/libv4lprocessing.o \
processing/whitebalance.o processing/autogain.o \
- processing/gamma.o
+ processing/gamma.o helper.o
TARGETS = $(CONVERT_LIB) libv4lconvert.pc ov511-decomp ov518-decomp
INCLUDES = ../include/libv4lconvert.h
@@ -33,7 +33,11 @@ ifeq ($(LIBDIR),)
LIBDIR = $(PREFIX)/lib
endif
-override CPPFLAGS += -DLIBDIR=\"$(LIBDIR)\"
+ifeq ($(LIBSUBDIR),)
+LIBSUBDIR = libv4l
+endif
+
+override CPPFLAGS += -DLIBDIR=\"$(LIBDIR)\" -DLIBSUBDIR=\"$(LIBSUBDIR)\"
all: $(TARGETS)
@@ -55,7 +59,7 @@ libv4lconvert.pc:
install: all
mkdir -p $(DESTDIR)$(PREFIX)/include
install -p -m 644 $(INCLUDES) $(DESTDIR)$(PREFIX)/include
- mkdir -p $(DESTDIR)$(LIBDIR)/libv4l
+ mkdir -p $(DESTDIR)$(LIBDIR)/$(LIBSUBDIR)
ifeq ($(LINKTYPE),static)
install -m 644 $(CONVERT_LIB) $(DESTDIR)$(LIBDIR)
else
@@ -63,7 +67,7 @@ else
cd $(DESTDIR)$(LIBDIR) && \
ln -f -s $(CONVERT_LIB).$(LIB_RELEASE) $(CONVERT_LIB)
endif
- install -m 755 *-decomp $(DESTDIR)$(LIBDIR)/libv4l
+ install -m 755 *-decomp $(DESTDIR)$(LIBDIR)/$(LIBSUBDIR)
mkdir -p $(DESTDIR)$(LIBDIR)/pkgconfig
install -m 644 libv4lconvert.pc $(DESTDIR)$(LIBDIR)/pkgconfig
diff --git a/v4l2-apps/libv4l/libv4lconvert/bayer.c b/v4l2-apps/libv4l/libv4lconvert/bayer.c
index 033ee2724..d299629a6 100644
--- a/v4l2-apps/libv4l/libv4lconvert/bayer.c
+++ b/v4l2-apps/libv4l/libv4lconvert/bayer.c
@@ -1,6 +1,6 @@
/*
* lib4lconvert, video4linux2 format conversion lib
- * (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+ * (C) 2008 Hans de Goede <hdegoede@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h
index 6211ee22a..632e9338a 100644
--- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h
+++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h
@@ -25,6 +25,7 @@
#define V4LCONTROL_SHM_SIZE 4096
#define V4LCONTROL_SUPPORTS_NEXT_CTRL 0x01
+#define V4LCONTROL_MEMORY_IS_MALLOCED 0x02
struct v4lcontrol_flags_info;
@@ -49,6 +50,15 @@ struct v4lcontrol_flags_info {
const char *product; */
int flags;
int default_gamma;
+/* Some seldom used dmi strings (for notebooks with bogus info in the board
+ entries, but usefull info elsewhere). We keep this at the end as to not
+ polute the initalizers for the normal case. */
+ /* System (product) vendor / name */
+ const char *dmi_system_vendor;
+ const char *dmi_system_name;
+ /* Board and System versions */
+ const char *dmi_board_version;
+ const char *dmi_system_version;
};
#endif
diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c
index 4e600351b..243f35dae 100644
--- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c
+++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c
@@ -3,6 +3,7 @@
# (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>
+# (C) 2009 Paul Sladen <ubuntu@paul.sladen.org>
# 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
@@ -28,6 +29,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
+#include <pwd.h>
#include "libv4lcontrol.h"
#include "libv4lcontrol-priv.h"
#include "../libv4lsyscall-priv.h"
@@ -57,9 +59,111 @@ static const struct v4lcontrol_flags_info v4lcontrol_flags[] = {
/* Genius E-M 112 (also want whitebalance by default) */
{ 0x093a, 0x2476, 0, NULL, NULL,
V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED|V4LCONTROL_WANTS_WB, 1500 },
- /* Asus N50Vn laptop */
+ /* Laptops */
+ { 0x04f2, 0xb012, 0, "ASUSTeK Computer Inc. ", "F7L ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb012, 0, "ASUSTeK Computer Inc. ", "W7Sg ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb012, 0, "ASUSTeK Computer Inc. ", "F7SR ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb012, 0, "ASUSTeK Computer Inc. ", "G50VT ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb012, 0, "ASUSTeK Computer Inc. ", "W7S ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb012, 0, "ASUSTeK Computer Inc. ", "X55SR ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb012, 0, "ASUSTeK Computer Inc. ", "X55SV ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ /* note different white space: http://launchpad.net/bugs/413752 */
+ { 0x04f2, 0xb012, 0, "ASUSTeK Computer Inc. ", "X71SL ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ /* These 3 PACKARD BELL's seem to be Asus notebook in disguise */
+ { 0x04f2, 0xb012, 0, "Packard Bell BV", "T32A ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb012, 0, "PACKARD BELL BV ", "EasyNote_BG45",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb012, 0, "PACKARD BELL BV ", "EasyNote_BG46",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb036, 0, "ASUSTeK Computer Inc. ", "U6S ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb036, 0, "ASUSTeK Computer Inc. ", "U6V ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb071, 0, "ASUSTeK Computer Inc. ", "K40IJ ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb071, 0, "ASUSTeK Computer Inc. ", "K50IJ ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb071, 0, "ASUSTeK Computer Inc. ", "K50IN ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb071, 0, "ASUSTeK Computer Inc. ", "K70AB ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb071, 0, "ASUSTeK Computer Inc. ", "K70IO ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb071, 0, "ASUSTeK Computer Inc. ", "N10J ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb071, 0, "ASUSTeK Computer Inc. ", "N20A ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ /* Note no whitespace padding for these 2 models, this is not a typo */
+ { 0x04f2, 0xb071, 0, "ASUSTeK Computer INC.", "K50AB",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb071, 0, "ASUSTeK Computer INC.", "N5051Tp",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb106, 0, "ASUSTeK Computer Inc. ", "N50Vc ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
{ 0x04f2, 0xb106, 0, "ASUSTeK Computer Inc. ", "N50Vn ",
V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb106, 0, "ASUSTeK Computer Inc. ", "N51Vf ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb106, 0, "ASUSTeK Computer Inc. ", "N51Vg ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb106, 0, "ASUSTeK Computer Inc. ", "N51Vn ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb16b, 0, "ASUSTeK Computer Inc. ", "U80A ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ /* Note no whitespace padding for board vendor, this is not a typo */
+ { 0x064e, 0xa111, 0, "ASUSTeK Computer Inc.", "F5RL ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ /* Another Asus laptop in disguise */
+ { 0x064e, 0xa111, 0, "PEGATRON CORPORATION ", "F5SR ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x064e, 0xa116, 0, "ASUSTeK Computer Inc. ", "N10Jb ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x064e, 0xa116, 0, "ASUSTeK Computer Inc. ", "N10Jc ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x064e, 0xa116, 0, "ASUSTeK Computer Inc. ", "N20A ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x064e, 0xa116, 0, "ASUSTeK Computer Inc. ", "X58LE ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x090c, 0xe370, 0, "ASUSTeK Computer Inc. ", "U6S ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x174f, 0x5a35, 0, "ASUSTeK Computer Inc. ", "F3Ke ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x174f, 0x5a35, 0, "ASUSTeK Computer Inc. ", "F3Q ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x174f, 0x5a35, 0, "ASUSTeK Computer Inc. ", "F3Sa ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x174f, 0x5a35, 0, "ASUSTeK Computer Inc. ", "F3Sg ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x174f, 0x5a35, 0, "ASUSTeK Computer Inc. ", "F3Sr ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x174f, 0x5a35, 0, "ASUSTeK Computer Inc. ", "F5N ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x174f, 0x5a35, 0, "ASUSTeK Computer Inc. ", "F5SL ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x174f, 0x5a35, 0, "ASUSTeK Computer Inc. ", "G1S ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x174f, 0x5a35, 0, "ASUSTeK Computer Inc. ", "G1Sn ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x174f, 0x5a35, 0, "ASUSTeK Computer Inc. ", "G2S ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x174f, 0xa311, 0, "ASUSTeK Computer Inc. ", "A3F ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x5986, 0x0200, 0, "LENOVO", "SPEEDY ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED, 0, NULL, NULL, NULL,
+ "Lenovo IdeaPad Y510" },
+ { 0x5986, 0x0205, 0, "LENOVO", "Base Board Product Name",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED, 0, NULL, NULL, NULL,
+ "Lenovo IdeaPad U330" },
+
/* Second: devices which should use some software processing by default */
/* Pac207 based devices */
{ 0x041e, 0x4028, 0, NULL, NULL, V4LCONTROL_WANTS_WB, 1500 },
@@ -69,6 +173,8 @@ static const struct v4lcontrol_flags_info v4lcontrol_flags[] = {
/* Pac7302 based devices */
{ 0x093a, 0x2620, 0x0f, NULL, NULL,
V4LCONTROL_ROTATED_90_JPEG|V4LCONTROL_WANTS_WB },
+ { 0x06f8, 0x3009, 0, NULL, NULL,
+ V4LCONTROL_ROTATED_90_JPEG|V4LCONTROL_WANTS_WB },
/* Pac7311 based devices */
{ 0x093a, 0x2600, 0x0f, NULL, NULL, V4LCONTROL_WANTS_WB },
/* sq905 devices */
@@ -87,6 +193,33 @@ static const struct v4lcontrol_flags_info v4lcontrol_flags[] = {
static const struct v4l2_queryctrl fake_controls[];
+static void v4lcontrol_get_dmi_string(const char *string, char *buf, int size)
+{
+ FILE *f;
+ char *s, sysfs_name[512];
+
+ snprintf(sysfs_name, sizeof(sysfs_name),
+ "/sys/class/dmi/id/%s", string);
+ f = fopen(sysfs_name, "r");
+ if (!f) {
+ /* Try again with a different sysfs path, not sure if this is needed
+ but we used to look under /sys/devices/virtual/dmi/id in older
+ libv4l versions, but this did not work with some kernels */
+ snprintf(sysfs_name, sizeof(sysfs_name),
+ "/sys/devices/virtual/dmi/id/%s", string);
+ f = fopen(sysfs_name, "r");
+ if (!f) {
+ buf[0] = 0;
+ return;
+ }
+ }
+
+ s = fgets(buf, size, f);
+ if (s)
+ s[strlen(s) - 1] = 0;
+ fclose(f);
+}
+
static void v4lcontrol_init_flags(struct v4lcontrol_data *data)
{
struct stat st;
@@ -94,8 +227,8 @@ static void v4lcontrol_init_flags(struct v4lcontrol_data *data)
char sysfs_name[512];
unsigned short vendor_id = 0;
unsigned short product_id = 0;
- char dmi_board_vendor[512] = "";
- char dmi_board_name[512]= "";
+ char dmi_system_vendor[512], dmi_system_name[512], dmi_system_version[512];
+ char dmi_board_vendor[512], dmi_board_name[512], dmi_board_version[512];
int i, minor;
char c, *s, buf[32];
struct v4l2_input input;
@@ -174,31 +307,39 @@ static void v4lcontrol_init_flags(struct v4lcontrol_data *data)
return; /* Should never happen */
}
- /* Get DMI board vendor and name */
- f = fopen("/sys/devices/virtual/dmi/id/board_vendor", "r");
- if (f) {
- s = fgets(dmi_board_vendor, sizeof(dmi_board_vendor), f);
- if (s)
- s[strlen(s) - 1] = 0;
- fclose(f);
- }
-
- f = fopen("/sys/devices/virtual/dmi/id/board_name", "r");
- if (f) {
- s = fgets(dmi_board_name, sizeof(dmi_board_name), f);
- if (s)
- s[strlen(s) - 1] = 0;
- fclose(f);
- }
+ /* Get DMI board and system strings */
+ v4lcontrol_get_dmi_string("sys_vendor", dmi_system_vendor,
+ sizeof(dmi_system_vendor));
+ v4lcontrol_get_dmi_string("product_name", dmi_system_name,
+ sizeof(dmi_system_name));
+ v4lcontrol_get_dmi_string("product_version", dmi_system_version,
+ sizeof(dmi_system_version));
+
+ v4lcontrol_get_dmi_string("board_vendor", dmi_board_vendor,
+ sizeof(dmi_board_vendor));
+ v4lcontrol_get_dmi_string("board_name", dmi_board_name,
+ sizeof(dmi_board_name));
+ v4lcontrol_get_dmi_string("board_version", dmi_board_version,
+ sizeof(dmi_board_version));
for (i = 0; i < ARRAY_SIZE(v4lcontrol_flags); i++)
if (v4lcontrol_flags[i].vendor_id == vendor_id &&
v4lcontrol_flags[i].product_id ==
(product_id & ~v4lcontrol_flags[i].product_mask) &&
+
+ (v4lcontrol_flags[i].dmi_system_vendor == NULL ||
+ !strcmp(v4lcontrol_flags[i].dmi_system_vendor, dmi_system_vendor)) &&
+ (v4lcontrol_flags[i].dmi_system_name == NULL ||
+ !strcmp(v4lcontrol_flags[i].dmi_system_name, dmi_system_name)) &&
+ (v4lcontrol_flags[i].dmi_system_version == NULL ||
+ !strcmp(v4lcontrol_flags[i].dmi_system_version, dmi_system_version)) &&
+
(v4lcontrol_flags[i].dmi_board_vendor == NULL ||
!strcmp(v4lcontrol_flags[i].dmi_board_vendor, dmi_board_vendor)) &&
(v4lcontrol_flags[i].dmi_board_name == NULL ||
- !strcmp(v4lcontrol_flags[i].dmi_board_name, dmi_board_name))) {
+ !strcmp(v4lcontrol_flags[i].dmi_board_name, dmi_board_name)) &&
+ (v4lcontrol_flags[i].dmi_board_version == NULL ||
+ !strcmp(v4lcontrol_flags[i].dmi_board_version, dmi_board_version))) {
data->flags |= v4lcontrol_flags[i].flags;
data->flags_info = &v4lcontrol_flags[i];
break;
@@ -209,14 +350,17 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion)
{
int shm_fd;
int i, rc, init = 0;
- char *s, shm_name[256];
+ char *s, shm_name[256], pwd_buf[1024];
struct v4l2_capability cap;
struct v4l2_queryctrl ctrl;
+ struct passwd pwd, *pwd_p;
struct v4lcontrol_data *data = calloc(1, sizeof(struct v4lcontrol_data));
- if (!data)
+ if (!data) {
+ fprintf(stderr, "libv4lcontrol: error: out of memory!\n");
return NULL;
+ }
data->fd = fd;
@@ -252,8 +396,19 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion)
if (data->controls == 0)
return data; /* No need to create a shared memory segment */
- SYS_IOCTL(fd, VIDIOC_QUERYCAP, &cap);
- snprintf(shm_name, 256, "/%s:%s", cap.bus_info, cap.card);
+ if (SYS_IOCTL(fd, VIDIOC_QUERYCAP, &cap)) {
+ perror("libv4lcontrol: error querying device capabilities");
+ goto error;
+ }
+
+ if (getpwuid_r(geteuid(), &pwd, pwd_buf, sizeof(pwd_buf), &pwd_p) == 0) {
+ snprintf(shm_name, 256, "/libv4l-%s:%s:%s", pwd.pw_name,
+ cap.bus_info, cap.card);
+ } else {
+ perror("libv4lcontrol: error getting username using uid instead");
+ snprintf(shm_name, 256, "/libv4l-%lu:%s:%s", (unsigned long)geteuid(),
+ cap.bus_info, cap.card);
+ }
/* / is not allowed inside shm names */
for (i = 1; shm_name[i]; i++)
@@ -264,23 +419,41 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion)
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;
+ else
+ shm_fd = shm_open(shm_name, O_RDWR, (S_IREAD | S_IWRITE));
- /* Set the shared memory size */
- ftruncate(shm_fd, V4LCONTROL_SHM_SIZE);
+ if (shm_fd >= 0) {
+ /* 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);
+ /* 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;
+ if (data->shm_values == MAP_FAILED) {
+ perror("libv4lcontrol: error shm mmap failed");
+ data->shm_values = NULL;
+ }
+ } else
+ perror("libv4lcontrol: error creating shm segment failed");
+
+ /* Fall back to malloc */
+ if (data->shm_values == NULL) {
+ fprintf(stderr,
+ "libv4lcontrol: falling back to malloc-ed memory for controls\n");
+ data->shm_values = malloc(V4LCONTROL_SHM_SIZE);
+ if (!data->shm_values) {
+ fprintf(stderr, "libv4lcontrol: error: out of memory!\n");
+ goto error;
+ }
+ init = 1;
+ data->priv_flags |= V4LCONTROL_MEMORY_IS_MALLOCED;
+ }
if (init) {
/* Initialize the new shm object we created */
- memset(data->shm_values, 0, sizeof(V4LCONTROL_SHM_SIZE));
+ memset(data->shm_values, 0, V4LCONTROL_SHM_SIZE);
for (i = 0; i < V4LCONTROL_COUNT; i++)
data->shm_values[i] = fake_controls[i].default_value;
@@ -301,12 +474,15 @@ error:
void v4lcontrol_destroy(struct v4lcontrol_data *data)
{
- if (data->controls)
- munmap(data->shm_values, V4LCONTROL_SHM_SIZE);
+ if (data->controls) {
+ if (data->priv_flags & V4LCONTROL_MEMORY_IS_MALLOCED)
+ free(data->shm_values);
+ else
+ munmap(data->shm_values, V4LCONTROL_SHM_SIZE);
+ }
free(data);
}
-/* FIXME get better CID's for normalize */
static const struct v4l2_queryctrl fake_controls[V4LCONTROL_COUNT] = {
{
.id = V4L2_CID_AUTO_WHITE_BALANCE,
diff --git a/v4l2-apps/libv4l/libv4lconvert/crop.c b/v4l2-apps/libv4l/libv4lconvert/crop.c
index 46c87f0ce..b2d878963 100644
--- a/v4l2-apps/libv4l/libv4lconvert/crop.c
+++ b/v4l2-apps/libv4l/libv4lconvert/crop.c
@@ -2,7 +2,7 @@
# RGB and YUV crop routines
-# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+# (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/flip.c b/v4l2-apps/libv4l/libv4lconvert/flip.c
index 8c4d8233c..dc9b858c9 100644
--- a/v4l2-apps/libv4l/libv4lconvert/flip.c
+++ b/v4l2-apps/libv4l/libv4lconvert/flip.c
@@ -2,7 +2,7 @@
# RGB / YUV flip/rotate routines
-# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+# (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
@@ -219,6 +219,7 @@ void v4lconvert_rotate90(unsigned char *src, unsigned char *dest,
fmt->fmt.pix.height);
break;
}
+ v4lconvert_fixup_fmt(fmt);
}
void v4lconvert_flip(unsigned char *src, unsigned char *dest,
diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h
index 2cf8f6ba4..f16d05d02 100644
--- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h
+++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h
@@ -1,5 +1,5 @@
/*
-# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+# (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
@@ -52,6 +52,10 @@
#define V4L2_PIX_FMT_MR97310A v4l2_fourcc('M','3','1','0')
#endif
+#ifndef V4L2_PIX_FMT_SN9C2028
+#define V4L2_PIX_FMT_SN9C2028 v4l2_fourcc('S', 'O', 'N', 'X')
+#endif
+
#ifndef V4L2_PIX_FMT_SQ905C
#define V4L2_PIX_FMT_SQ905C v4l2_fourcc('9', '0', '5', 'C')
#endif
@@ -92,6 +96,10 @@
#define V4L2_PIX_FMT_OV518 v4l2_fourcc('O', '5', '1', '8') /* ov518 JPEG */
#endif
+#ifndef V4L2_FMT_FLAG_EMULATED
+#define V4L2_FMT_FLAG_EMULATED 0x0002
+#endif
+
#define ARRAY_SIZE(x) ((int)sizeof(x)/(int)sizeof((x)[0]))
#define V4LCONVERT_ERROR_MSG_SIZE 256
@@ -108,6 +116,7 @@
/* Pixformat flags */
#define V4LCONVERT_COMPRESSED 0x01 /* Compressed format */
#define V4LCONVERT_NEEDS_CONVERSION 0x02 /* Apps likely wont know this */
+#define V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION 0x03
struct v4lconvert_data {
int fd;
@@ -184,6 +193,15 @@ void v4lconvert_swap_rgb(const unsigned char *src, unsigned char *dst,
void v4lconvert_swap_uv(const unsigned char *src, unsigned char *dst,
const struct v4l2_format *src_fmt);
+void v4lconvert_rgb565_to_rgb24(const unsigned char *src, unsigned char *dest,
+ int width, int height);
+
+void v4lconvert_rgb565_to_bgr24(const unsigned char *src, unsigned char *dest,
+ int width, int height);
+
+void v4lconvert_rgb565_to_yuv420(const unsigned char *src, unsigned char *dest,
+ const struct v4l2_format *src_fmt, int yvu);
+
void v4lconvert_spca501_to_yuv420(const unsigned char *src, unsigned char *dst,
int width, int height, int yvu);
@@ -202,12 +220,16 @@ void v4lconvert_decode_spca561(const unsigned char *src, unsigned char *dst,
void v4lconvert_decode_sn9c10x(const unsigned char *src, unsigned char *dst,
int width, int height);
-void v4lconvert_decode_pac207(const unsigned char *src, unsigned char *dst,
+int v4lconvert_decode_pac207(struct v4lconvert_data *data,
+ const unsigned char *inp, int src_size, unsigned char *outp,
int width, int height);
void v4lconvert_decode_mr97310a(const unsigned char *src, unsigned char *dst,
int width, int height);
+void v4lconvert_decode_sn9c2028(const unsigned char *src, unsigned char *dst,
+ int width, int height);
+
void v4lconvert_decode_sq905c(const unsigned char *src, unsigned char *dst,
int width, int height);
diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c
index 1389c58bc..32b9a51bb 100644
--- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c
+++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c
@@ -1,5 +1,5 @@
/*
-# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+# (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
@@ -46,6 +46,7 @@ static const struct v4lconvert_pixfmt supported_src_pixfmts[] = {
{ V4L2_PIX_FMT_YUYV, 0 },
{ V4L2_PIX_FMT_YVYU, 0 },
{ V4L2_PIX_FMT_UYVY, 0 },
+ { V4L2_PIX_FMT_RGB565, 0 },
{ V4L2_PIX_FMT_SN9C20X_I420, V4LCONVERT_NEEDS_CONVERSION },
{ V4L2_PIX_FMT_SBGGR8, V4LCONVERT_NEEDS_CONVERSION },
{ V4L2_PIX_FMT_SGBRG8, V4LCONVERT_NEEDS_CONVERSION },
@@ -57,14 +58,15 @@ static const struct v4lconvert_pixfmt supported_src_pixfmts[] = {
{ V4L2_PIX_FMT_HM12, V4LCONVERT_NEEDS_CONVERSION },
{ V4L2_PIX_FMT_MJPEG, V4LCONVERT_COMPRESSED },
{ V4L2_PIX_FMT_JPEG, V4LCONVERT_COMPRESSED },
- { V4L2_PIX_FMT_SPCA561, V4LCONVERT_COMPRESSED },
- { V4L2_PIX_FMT_SN9C10X, V4LCONVERT_COMPRESSED },
- { V4L2_PIX_FMT_PAC207, V4LCONVERT_COMPRESSED },
- { V4L2_PIX_FMT_MR97310A, V4LCONVERT_COMPRESSED },
- { V4L2_PIX_FMT_SQ905C, V4LCONVERT_COMPRESSED },
- { V4L2_PIX_FMT_PJPG, V4LCONVERT_COMPRESSED },
- { V4L2_PIX_FMT_OV511, V4LCONVERT_COMPRESSED },
- { V4L2_PIX_FMT_OV518, V4LCONVERT_COMPRESSED },
+ { V4L2_PIX_FMT_SPCA561, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION },
+ { V4L2_PIX_FMT_SN9C10X, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION },
+ { V4L2_PIX_FMT_SN9C2028, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION },
+ { V4L2_PIX_FMT_PAC207, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION },
+ { V4L2_PIX_FMT_MR97310A, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION },
+ { V4L2_PIX_FMT_SQ905C, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION },
+ { V4L2_PIX_FMT_PJPG, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION },
+ { V4L2_PIX_FMT_OV511, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION },
+ { V4L2_PIX_FMT_OV518, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION },
};
static const struct v4lconvert_pixfmt supported_dst_pixfmts[] = {
@@ -94,8 +96,10 @@ struct v4lconvert_data *v4lconvert_create(int fd)
processing controls without a performance impact. */
int always_needs_conversion = 1;
- if (!data)
+ if (!data) {
+ fprintf(stderr, "libv4lconvert: error: out of memory!\n");
return NULL;
+ }
data->fd = fd;
data->decompress_pid = -1;
@@ -113,7 +117,7 @@ struct v4lconvert_data *v4lconvert_create(int fd)
if (fmt.pixelformat == supported_src_pixfmts[j].fmt) {
data->supported_src_formats |= 1 << j;
v4lconvert_get_framesizes(data, fmt.pixelformat, j);
- if (!supported_src_pixfmts[j].flags)
+ if (!(supported_src_pixfmts[j].flags & V4LCONVERT_NEEDS_CONVERSION))
always_needs_conversion = 0;
break;
}
@@ -215,7 +219,7 @@ int v4lconvert_enum_fmt(struct v4lconvert_data *data, struct v4l2_fmtdesc *fmt)
return -1;
}
- fmt->flags = 0;
+ fmt->flags = V4L2_FMT_FLAG_EMULATED;
fmt->pixelformat = faked_fmts[i];
fmt->description[0] = faked_fmts[i] & 0xff;
fmt->description[1] = (faked_fmts[i] >> 8) & 0xff;
@@ -490,6 +494,7 @@ static int v4lconvert_processing_needs_double_conversion(
case V4L2_PIX_FMT_SN9C10X:
case V4L2_PIX_FMT_PAC207:
case V4L2_PIX_FMT_MR97310A:
+ case V4L2_PIX_FMT_SN9C2028:
case V4L2_PIX_FMT_SQ905C:
case V4L2_PIX_FMT_SBGGR8:
case V4L2_PIX_FMT_SGBRG8:
@@ -671,7 +676,7 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
v4lconvert_sn9c20x_to_yuv420(src, d, width, height, yvu);
break;
case V4L2_PIX_FMT_OV511:
- if (v4lconvert_helper_decompress(data, LIBDIR "/libv4l/ov511-decomp",
+ if (v4lconvert_helper_decompress(data, LIBDIR "/" LIBSUBDIR "/ov511-decomp",
src, src_size, d, d_size, width, height, yvu)) {
/* Corrupt frame, better get another one */
errno = EAGAIN;
@@ -679,7 +684,7 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
}
break;
case V4L2_PIX_FMT_OV518:
- if (v4lconvert_helper_decompress(data, LIBDIR "/libv4l/ov518-decomp",
+ if (v4lconvert_helper_decompress(data, LIBDIR "/" LIBSUBDIR "/ov518-decomp",
src, src_size, d, d_size, width, height, yvu)) {
/* Corrupt frame, better get another one */
errno = EAGAIN;
@@ -724,6 +729,7 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
case V4L2_PIX_FMT_SN9C10X:
case V4L2_PIX_FMT_PAC207:
case V4L2_PIX_FMT_MR97310A:
+ case V4L2_PIX_FMT_SN9C2028:
case V4L2_PIX_FMT_SQ905C:
{
unsigned char *tmpbuf;
@@ -744,13 +750,22 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
break;
case V4L2_PIX_FMT_PAC207:
- v4lconvert_decode_pac207(src, tmpbuf, width, height);
+ if (v4lconvert_decode_pac207(data, src, src_size, tmpbuf,
+ width, height)) {
+ /* Corrupt frame, better get another one */
+ errno = EAGAIN;
+ return -1;
+ }
tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
break;
case V4L2_PIX_FMT_MR97310A:
v4lconvert_decode_mr97310a(src, tmpbuf, width, height);
tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
break;
+ case V4L2_PIX_FMT_SN9C2028:
+ v4lconvert_decode_sn9c2028(src, tmpbuf, width, height);
+ tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
+ break;
case V4L2_PIX_FMT_SQ905C:
v4lconvert_decode_sq905c(src, tmpbuf, width, height);
tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SRGGB8;
@@ -787,6 +802,23 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
}
break;
+ case V4L2_PIX_FMT_RGB565:
+ switch (dest_pix_fmt) {
+ case V4L2_PIX_FMT_RGB24:
+ v4lconvert_rgb565_to_rgb24(src, dest, width, height);
+ break;
+ case V4L2_PIX_FMT_BGR24:
+ v4lconvert_rgb565_to_bgr24(src, dest, width, height);
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ v4lconvert_rgb565_to_yuv420(src, dest, fmt, 0);
+ break;
+ case V4L2_PIX_FMT_YVU420:
+ v4lconvert_rgb565_to_yuv420(src, dest, fmt, 1);
+ break;
+ }
+ break;
+
case V4L2_PIX_FMT_RGB24:
switch (dest_pix_fmt) {
case V4L2_PIX_FMT_BGR24:
diff --git a/v4l2-apps/libv4l/libv4lconvert/pac207.c b/v4l2-apps/libv4l/libv4lconvert/pac207.c
index 97ef4ebc0..a81d5d511 100644
--- a/v4l2-apps/libv4l/libv4lconvert/pac207.c
+++ b/v4l2-apps/libv4l/libv4lconvert/pac207.c
@@ -52,35 +52,35 @@ static void init_pixart_decoder(void)
len = 2;
} else if ((i & 0xC0) == 0x40) {
/* code 01 */
- val = -5;
+ val = -1;
len = 2;
} else if ((i & 0xC0) == 0x80) {
/* code 10 */
- val = +5;
+ val = +1;
len = 2;
} else if ((i & 0xF0) == 0xC0) {
/* code 1100 */
- val = -10;
+ val = -2;
len = 4;
} else if ((i & 0xF0) == 0xD0) {
/* code 1101 */
- val = +10;
+ val = +2;
len = 4;
} else if ((i & 0xF8) == 0xE0) {
/* code 11100 */
- val = -15;
+ val = -3;
len = 5;
} else if ((i & 0xF8) == 0xE8) {
/* code 11101 */
- val = +15;
+ val = +3;
len = 5;
} else if ((i & 0xFC) == 0xF0) {
/* code 111100 */
- val = -20;
+ val = -4;
len = 6;
} else if ((i & 0xFC) == 0xF4) {
/* code 111101 */
- val = +20;
+ val = +4;
len = 6;
} else if ((i & 0xF8) == 0xF8) {
/* code 11111xxxxxx */
@@ -109,7 +109,8 @@ static inline unsigned short getShort(const unsigned char *pt)
}
static int
-pac_decompress_row(const unsigned char *inp, unsigned char *outp, int width)
+pac_decompress_row(const unsigned char *inp, unsigned char *outp, int width,
+ int step_size, int abs_bits)
{
int col;
int val;
@@ -135,11 +136,11 @@ pac_decompress_row(const unsigned char *inp, unsigned char *outp, int width)
if (table[code].is_abs) {
/* absolute value: get 6 more bits */
code = getByte(inp, bitpos);
- bitpos += 6;
- *outp++ = code & 0xFC;
+ bitpos += abs_bits;
+ *outp++ = code & ~(0xff >> abs_bits);
} else {
/* relative to left pixel */
- val = outp[-2] + table[code].val;
+ val = outp[-2] + table[code].val * step_size;
*outp++ = CLIP(val);
}
}
@@ -148,18 +149,24 @@ pac_decompress_row(const unsigned char *inp, unsigned char *outp, int width)
return 2 * ((bitpos + 15) / 16);
}
-void v4lconvert_decode_pac207(const unsigned char *inp, unsigned char *outp,
+int v4lconvert_decode_pac207(struct v4lconvert_data *data,
+ const unsigned char *inp, int src_size, unsigned char *outp,
int width, int height)
{
/* we should received a whole frame with header and EOL marker
in myframe->data and return a GBRG pattern in frame->tmpbuffer
remove the header then copy line by line EOL is set with 0x0f 0xf0 marker
or 0x1e 0xe1 for compressed line*/
+ const unsigned char *end = inp + src_size;
unsigned short word;
int row;
/* iterate over all rows */
for (row = 0; row < height; row++) {
+ if ((inp + 2) > end) {
+ V4LCONVERT_ERR("incomplete pac207 frame\n");
+ return -1;
+ }
word = getShort(inp);
switch (word) {
case 0x0FF0:
@@ -167,21 +174,31 @@ or 0x1e 0xe1 for compressed line*/
inp += (2 + width);
break;
case 0x1EE1:
- inp += pac_decompress_row(inp, outp, width);
+ inp += pac_decompress_row(inp, outp, width, 5, 6);
+ break;
+
+ case 0x2DD2:
+ inp += pac_decompress_row(inp, outp, width, 9, 5);
break;
- case 0x2DD2: /* prefix for "stronger" compressed lines, currently the
- kernel driver programs the cam so that we should not
- get any of these */
+ case 0x3CC3:
+ inp += pac_decompress_row(inp, outp, width, 17, 4);
+ break;
+
+ case 0x4BB4:
+ /* skip or copy line? */
+ memcpy(outp, outp - 2 * width, width);
+ inp += 2;
+ break;
default: /* corrupt frame */
- /* FIXME add error reporting */
- return;
+ V4LCONVERT_ERR("unknown pac207 row header: 0x%04x\n", (int)word);
+ return -1;
}
outp += width;
}
- return;
+ return 0;
}
diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h
index b73c73b53..c314231cd 100644
--- a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h
@@ -30,6 +30,7 @@ struct v4lprocessing_data {
struct v4lcontrol_data *control;
int fd;
int do_process;
+ int controls_changed;
/* True if any of the lookup tables does not contain
linear 0-255 */
int lookup_table_active;
@@ -41,6 +42,11 @@ struct v4lprocessing_data {
unsigned char green[256];
unsigned char comp2[256];
/* Filter private data for filters which need it */
+ /* whitebalance.c data */
+ int green_avg;
+ int comp1_avg;
+ int comp2_avg;
+ /* gamma.c data */
int last_gamma;
unsigned char gamma_table[256];
};
diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c
index cbbcca73c..424173ec5 100644
--- a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c
@@ -38,8 +38,10 @@ struct v4lprocessing_data *v4lprocessing_create(int fd, struct v4lcontrol_data*
struct v4lprocessing_data *data =
calloc(1, sizeof(struct v4lprocessing_data));
- if (!data)
+ if (!data) {
+ fprintf(stderr, "libv4lprocessing: error: out of memory!\n");
return NULL;
+ }
data->fd = fd;
data->control = control;
@@ -62,6 +64,8 @@ int v4lprocessing_pre_processing(struct v4lprocessing_data *data)
data->do_process = 1;
}
+ data->controls_changed |= v4lcontrol_controls_changed(data->control);
+
return data->do_process;
}
@@ -167,9 +171,10 @@ void v4lprocessing_processing(struct v4lprocessing_data *data,
return; /* Non supported pix format */
}
- if (v4lcontrol_controls_changed(data->control) ||
+ if (data->controls_changed ||
data->lookup_table_update_counter == V4L2PROCESSING_UPDATE_RATE) {
v4lprocessing_update_lookup_tables(data, buf, fmt);
+ data->controls_changed = 0;
data->lookup_table_update_counter = 0;
} else
data->lookup_table_update_counter++;
diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c b/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c
index 64d20b3ff..5ee0cfaa8 100644
--- a/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c
@@ -27,10 +27,82 @@
#include "libv4lprocessing-priv.h"
#include "../libv4lconvert-priv.h" /* for PIX_FMT defines */
-#define CLIP(color) (unsigned char)(((color)>0xff)?0xff:(((color)<0)?0:(color)))
+#define CLIP256(color) (((color)>0xff)?0xff:(((color)<0)?0:(color)))
+#define CLIP(color, min, max) (((color)>(max))?(max):(((color)<(min))?(min):(color)))
static int whitebalance_active(struct v4lprocessing_data *data) {
- return v4lcontrol_get_ctrl(data->control, V4LCONTROL_WHITEBALANCE);
+ int wb;
+
+ wb = v4lcontrol_get_ctrl(data->control, V4LCONTROL_WHITEBALANCE);
+ if (!wb) {
+ /* Reset cached color averages */
+ data->green_avg = 0;
+ }
+
+ return wb;
+}
+
+static int whitebalance_calculate_lookup_tables_generic(
+ struct v4lprocessing_data *data, int green_avg, int comp1_avg, int comp2_avg)
+{
+ int i, avg_avg;
+ const int max_step = 64;
+
+ /* Clip averages (restricts maximum white balance correction) */
+ green_avg = CLIP(green_avg, 512, 3072);
+ comp1_avg = CLIP(comp1_avg, 512, 3072);
+ comp2_avg = CLIP(comp2_avg, 512, 3072);
+
+ /* First frame ? */
+ if (data->green_avg == 0) {
+ data->green_avg = green_avg;
+ data->comp1_avg = comp1_avg;
+ data->comp2_avg = comp2_avg;
+ } else {
+ /* Slowly adjust the averages used for the correction, so that we
+ do not get a sudden change in colors */
+ if (abs(data->green_avg - green_avg) > max_step) {
+ if (data->green_avg < green_avg)
+ data->green_avg += max_step;
+ else
+ data->green_avg -= max_step;
+ }
+ else
+ data->green_avg = green_avg;
+
+ if (abs(data->comp1_avg - comp1_avg) > max_step) {
+ if (data->comp1_avg < comp1_avg)
+ data->comp1_avg += max_step;
+ else
+ data->comp1_avg -= max_step;
+ }
+ else
+ data->comp1_avg = comp1_avg;
+
+ if (abs(data->comp2_avg - comp2_avg) > max_step) {
+ if (data->comp2_avg < comp2_avg)
+ data->comp2_avg += max_step;
+ else
+ data->comp2_avg -= max_step;
+ }
+ else
+ data->comp2_avg = comp2_avg;
+ }
+
+ if (abs(data->green_avg - data->comp1_avg) < max_step &&
+ abs(data->green_avg - data->comp2_avg) < max_step &&
+ abs(data->comp1_avg - data->comp2_avg) < max_step)
+ return 0;
+
+ avg_avg = (data->green_avg + data->comp1_avg + data->comp2_avg) / 3;
+
+ for (i = 0; i < 256; i++) {
+ data->comp1[i] = CLIP256(data->comp1[i] * avg_avg / data->comp1_avg);
+ data->green[i] = CLIP256(data->green[i] * avg_avg / data->green_avg);
+ data->comp2[i] = CLIP256(data->comp2[i] * avg_avg / data->comp2_avg);
+ }
+
+ return 1;
}
static int whitebalance_calculate_lookup_tables_bayer(
@@ -38,7 +110,7 @@ static int whitebalance_calculate_lookup_tables_bayer(
const struct v4l2_format *fmt, int starts_with_green)
{
int x, y, a1 = 0, a2 = 0, b1 = 0, b2 = 0;
- int green_avg, comp1_avg, comp2_avg, avg_avg;
+ int green_avg, comp1_avg, comp2_avg;
for (y = 0; y < fmt->fmt.pix.height; y += 2) {
for (x = 0; x < fmt->fmt.pix.width; x += 2) {
@@ -54,37 +126,29 @@ static int whitebalance_calculate_lookup_tables_bayer(
}
if (starts_with_green) {
- green_avg = (a1 + b2) / 512;
- comp1_avg = a2 / 256;
- comp2_avg = b1 / 256;
+ green_avg = a1 / 2 + b2 / 2;
+ comp1_avg = a2;
+ comp2_avg = b1;
} else {
- green_avg = (a2 + b1) / 512;
- comp1_avg = a1 / 256;
- comp2_avg = b2 / 256;
+ green_avg = a2 / 2 + b1 / 2;
+ comp1_avg = a1;
+ comp2_avg = b2;
}
- x = fmt->fmt.pix.width * fmt->fmt.pix.height / 64;
- if (abs(green_avg - comp1_avg) < x &&
- abs(green_avg - comp2_avg) < x &&
- abs(comp1_avg - comp2_avg) < x)
- return 0;
-
- avg_avg = (green_avg + comp1_avg + comp2_avg) / 3;
-
- for (x = 0; x < 256; x++) {
- data->comp1[x] = CLIP(data->comp1[x] * avg_avg / comp1_avg);
- data->green[x] = CLIP(data->green[x] * avg_avg / green_avg);
- data->comp2[x] = CLIP(data->comp2[x] * avg_avg / comp2_avg);
- }
+ /* Norm avg to ~ 0 - 4095 */
+ green_avg /= fmt->fmt.pix.width * fmt->fmt.pix.height / 64;
+ comp1_avg /= fmt->fmt.pix.width * fmt->fmt.pix.height / 64;
+ comp2_avg /= fmt->fmt.pix.width * fmt->fmt.pix.height / 64;
- return 1;
+ return whitebalance_calculate_lookup_tables_generic(data, green_avg,
+ comp1_avg, comp2_avg);
}
static int whitebalance_calculate_lookup_tables_rgb(
struct v4lprocessing_data *data, unsigned char *buf,
const struct v4l2_format *fmt)
{
- int x, y, green_avg = 0, comp1_avg = 0, comp2_avg = 0, avg_avg;
+ int x, y, green_avg = 0, comp1_avg = 0, comp2_avg = 0;
for (y = 0; y < fmt->fmt.pix.height; y++) {
for (x = 0; x < fmt->fmt.pix.width; x++) {
@@ -95,25 +159,13 @@ static int whitebalance_calculate_lookup_tables_rgb(
buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width * 3;
}
- x = fmt->fmt.pix.width * fmt->fmt.pix.height * 4;
- if (abs(green_avg - comp1_avg) < x &&
- abs(green_avg - comp2_avg) < x &&
- abs(comp1_avg - comp2_avg) < x)
- return 0;
-
- /* scale to avoid integer overflows */
- green_avg /= 256;
- comp1_avg /= 256;
- comp2_avg /= 256;
- avg_avg = (green_avg + comp1_avg + comp2_avg) / 3;
+ /* Norm avg to ~ 0 - 4095 */
+ green_avg /= fmt->fmt.pix.width * fmt->fmt.pix.height / 16;
+ comp1_avg /= fmt->fmt.pix.width * fmt->fmt.pix.height / 16;
+ comp2_avg /= fmt->fmt.pix.width * fmt->fmt.pix.height / 16;
- for (x = 0; x < 256; x++) {
- data->comp1[x] = CLIP(data->comp1[x] * avg_avg / comp1_avg);
- data->green[x] = CLIP(data->green[x] * avg_avg / green_avg);
- data->comp2[x] = CLIP(data->comp2[x] * avg_avg / comp2_avg);
- }
-
- return 1;
+ return whitebalance_calculate_lookup_tables_generic(data, green_avg,
+ comp1_avg, comp2_avg);
}
diff --git a/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c b/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c
index 31cbc3c68..5c43ce07f 100644
--- a/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c
+++ b/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c
@@ -1,8 +1,10 @@
/*
# RGB <-> YUV conversion routines
+# (C) 2008 Hans de Goede <hdegoede@redhat.com>
-# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+# RGB565 conversion routines
+# (C) 2009 Mauro Carvalho Chehab <mchehab@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
@@ -472,3 +474,103 @@ void v4lconvert_swap_uv(const unsigned char *src, unsigned char *dest,
src += src_fmt->fmt.pix.bytesperline / 2;
}
}
+
+void v4lconvert_rgb565_to_rgb24(const unsigned char *src, unsigned char *dest,
+ int width, int height)
+{
+ int j;
+ while (--height >= 0) {
+ for (j = 0; j < width; j++) {
+ unsigned short tmp = *(unsigned short *)src;
+
+ /* Original format: rrrrrggg gggbbbbb */
+ *dest++ = 0xf8 & (tmp >> 8);
+ *dest++ = 0xfc & (tmp >> 3);
+ *dest++ = 0xf8 & (tmp << 3);
+
+ src += 2;
+ }
+ }
+}
+
+void v4lconvert_rgb565_to_bgr24(const unsigned char *src, unsigned char *dest,
+ int width, int height)
+{
+ int j;
+ while (--height >= 0) {
+ for (j = 0; j < width; j++) {
+ unsigned short tmp = *(unsigned short *)src;
+
+ /* Original format: rrrrrggg gggbbbbb */
+ *dest++ = 0xf8 & (tmp << 3);
+ *dest++ = 0xfc & (tmp >> 3);
+ *dest++ = 0xf8 & (tmp >> 8);
+
+ src += 2;
+ }
+ }
+}
+
+void v4lconvert_rgb565_to_yuv420(const unsigned char *src, unsigned char *dest,
+ const struct v4l2_format *src_fmt, int yvu)
+{
+ int x, y;
+ unsigned short tmp;
+ unsigned char *udest, *vdest;
+ unsigned r[4], g[4], b[4];
+ int avg_src[3];
+
+ /* Y */
+ for (y = 0; y < src_fmt->fmt.pix.height; y++) {
+ for (x = 0; x < src_fmt->fmt.pix.width; x++) {
+ tmp = *(unsigned short *)src;
+ r[0] = 0xf8 & (tmp << 3);
+ g[0] = 0xfc & (tmp >> 3);
+ b[0] = 0xf8 & (tmp >> 8);
+ RGB2Y(r[0], g[0], b[0], *dest++);
+ src += 2;
+ }
+ src += src_fmt->fmt.pix.bytesperline - 2 * src_fmt->fmt.pix.width;
+ }
+ src -= src_fmt->fmt.pix.height * src_fmt->fmt.pix.bytesperline;
+
+ /* U + V */
+ if (yvu) {
+ vdest = dest;
+ udest = dest + src_fmt->fmt.pix.width * src_fmt->fmt.pix.height / 4;
+ } else {
+ udest = dest;
+ vdest = dest + src_fmt->fmt.pix.width * src_fmt->fmt.pix.height / 4;
+ }
+
+ for (y = 0; y < src_fmt->fmt.pix.height / 2; y++) {
+ for (x = 0; x < src_fmt->fmt.pix.width / 2; x++) {
+ tmp = *(unsigned short *)src;
+ r[0] = 0xf8 & (tmp << 3);
+ g[0] = 0xfc & (tmp >> 3);
+ b[0] = 0xf8 & (tmp >> 8);
+
+ tmp = *(((unsigned short *)src) + 1);
+ r[1] = 0xf8 & (tmp << 3);
+ g[1] = 0xfc & (tmp >> 3);
+ b[1] = 0xf8 & (tmp >> 8);
+
+ tmp = *(((unsigned short *)src) + src_fmt->fmt.pix.bytesperline);
+ r[2] = 0xf8 & (tmp << 3);
+ g[2] = 0xfc & (tmp >> 3);
+ b[2] = 0xf8 & (tmp >> 8);
+
+ tmp = *(((unsigned short *)src) + src_fmt->fmt.pix.bytesperline + 1);
+ r[3] = 0xf8 & (tmp << 3);
+ g[3] = 0xfc & (tmp >> 3);
+ b[3] = 0xf8 & (tmp >> 8);
+
+ avg_src[0] = (r[0] + r[1] + r[2] + r[3]) /4;
+ avg_src[1] = (g[0] + g[1] + g[2] + g[3]) /4;
+ avg_src[2] = (b[0] + b[1] + b[2] + b[3]) /4;
+ RGB2UV(avg_src[0], avg_src[1], avg_src[2], *udest++, *vdest++);
+ src += 4;
+ }
+ src += 2 * src_fmt->fmt.pix.bytesperline - 2 * src_fmt->fmt.pix.width;
+ }
+}
diff --git a/v4l2-apps/libv4l/libv4lconvert/sn9c2028-decomp.c b/v4l2-apps/libv4l/libv4lconvert/sn9c2028-decomp.c
new file mode 100644
index 000000000..c21696752
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/sn9c2028-decomp.c
@@ -0,0 +1,157 @@
+/*
+ * sn9c2028-decomp.c
+ *
+ * Decompression function for the Sonix SN9C2028 dual-mode cameras.
+ *
+ * Code adapted from libgphoto2/camlibs/sonix, original version of which was
+ * Copyright (c) 2005 Theodore Kilgore <kilgota@auburn.edu>
+ *
+ * History:
+ *
+ * This decoding algorithm originates from the work of Bertrik Sikken for the
+ * SN9C102 cameras. This version is an adaptation of work done by Mattias
+ * Krauss for the webcam-osx (macam) project. There, it was further adapted
+ * for use with the Vivitar Vivicam 3350B (an SN9C2028 camera) by
+ * Harald Ruda <hrx@users.sourceforge.net>. Harald brought to my attention the
+ * work done in the macam project and suggested that I use it. One improvement
+ * of my own was to notice that the even and odd columns of the image have been
+ * reversed by the decompression algorithm, and this needs to be corrected
+ * during the decompression.
+ *
+ *
+ * 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 "libv4lconvert-priv.h"
+
+/* Four defines for bitstream operations, used in the decode function */
+
+#define PEEK_BITS(num,to) {\
+ if (bitBufCount < num) {\
+ do {\
+ bitBuf = (bitBuf << 8)|(*(src++));\
+ bitBufCount += 8; \
+ } \
+ while\
+ (bitBufCount < 24);\
+ } \
+ to = bitBuf >> (bitBufCount-num);\
+}
+
+/*
+ * PEEK_BITS puts the next <num> bits into the low bits of <to>.
+ * when the buffer is empty, it is completely refilled.
+ * This strategy tries to reduce memory access. Note that the high bits
+ * are NOT set to zero!
+ */
+
+#define EAT_BITS(num) { bitBufCount -= num; bits_eaten += num; }
+
+/*
+ * EAT_BITS consumes <num> bits (PEEK_BITS does not consume anything,
+ * it just peeks)
+ */
+
+#define PARSE_PIXEL(val) {\
+ PEEK_BITS(10, bits);\
+ if ((bits&0x200) == 0) {\
+ EAT_BITS(1);\
+ } \
+ else if ((bits&0x380) == 0x280) {\
+ EAT_BITS(3);\
+ val += 3;\
+ if (val > 255)\
+ val = 255;\
+ } \
+ else if ((bits&0x380) == 0x300) {\
+ EAT_BITS(3);\
+ val -= 3;\
+ if (val < 0)\
+ val = 0;\
+ } \
+ else if ((bits&0x3c0) == 0x200) {\
+ EAT_BITS(4);\
+ val += 8;\
+ if (val > 255)\
+ val = 255;\
+ } \
+ else if ((bits&0x3c0) == 0x240) {\
+ EAT_BITS(4);\
+ val -= 8;\
+ if (val < 0)\
+ val = 0;\
+ } \
+ else if ((bits&0x3c0) == 0x3c0) {\
+ EAT_BITS(4);\
+ val -= 20;\
+ if (val < 0)\
+ val = 0;\
+ } \
+ else if ((bits&0x3e0) == 0x380) {\
+ EAT_BITS(5);\
+ val += 20;\
+ if (val > 255)\
+ val = 255;\
+ } \
+ else {\
+ EAT_BITS(10);\
+ val = 8*(bits&0x1f)+0;\
+ } \
+}
+
+
+#define PUT_PIXEL_PAIR {\
+ long pp;\
+ pp = (c1val<<8)+c2val;\
+ *((unsigned short *) (dst+dst_index)) = pp;\
+ dst_index += 2;\
+}
+
+/* Now the decode function itself */
+
+void v4lconvert_decode_sn9c2028(const unsigned char *src, unsigned char *dst,
+ int width, int height)
+{
+ long dst_index = 0;
+ int starting_row = 0;
+ unsigned short bits;
+ short c1val, c2val;
+ int x, y;
+ unsigned long bitBuf = 0;
+ unsigned long bitBufCount = 0;
+ unsigned long bits_eaten = 0;
+
+ src += 12; /* Remove the header */
+
+ for (y = starting_row; y < height; y++) {
+ PEEK_BITS(8, bits);
+ EAT_BITS(8);
+ c2val = (bits & 0xff);
+ PEEK_BITS(8, bits);
+ EAT_BITS(8);
+ c1val = (bits & 0xff);
+
+ PUT_PIXEL_PAIR;
+
+ for (x = 2; x < width ; x += 2) {
+ /* The compression reversed the even and odd columns.*/
+ PARSE_PIXEL(c2val);
+ PARSE_PIXEL(c1val);
+ PUT_PIXEL_PAIR;
+ }
+ }
+}
diff --git a/v4l2-apps/libv4l/libv4lconvert/spca501.c b/v4l2-apps/libv4l/libv4lconvert/spca501.c
index f491512e3..f4fbc594a 100644
--- a/v4l2-apps/libv4l/libv4lconvert/spca501.c
+++ b/v4l2-apps/libv4l/libv4lconvert/spca501.c
@@ -1,5 +1,5 @@
/*
-# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+# (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