diff options
author | hans@rhel5-devel.localdomain <hans@rhel5-devel.localdomain> | 2009-04-14 09:51:35 +0200 |
---|---|---|
committer | hans@rhel5-devel.localdomain <hans@rhel5-devel.localdomain> | 2009-04-14 09:51:35 +0200 |
commit | 10a09b9ec6e08fb95c36f26d7f69834b0387386b (patch) | |
tree | f135d19a9f7d69205f17cb2b22efc9623ef01e6e /v4l2-apps/libv4l/libv4lconvert/control | |
parent | b1352a9018aeac6722d2e8d606f9c0ea140e0abd (diff) | |
download | mediapointer-dvb-s2-10a09b9ec6e08fb95c36f26d7f69834b0387386b.tar.gz mediapointer-dvb-s2-10a09b9ec6e08fb95c36f26d7f69834b0387386b.tar.bz2 |
libv4l: Enable whitebalancing algorithm based on USB id's
From: Hans de Goede <hdegoede@redhat.com>
* Determine wether or not to do whitebalance and/or normalize at all
based on USB-ID's.
* Add rotate90 hack to flags based on usb-id.
Priority: normal
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Diffstat (limited to 'v4l2-apps/libv4l/libv4lconvert/control')
3 files changed, 171 insertions, 16 deletions
diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h index 59305a237..0dd675754 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h @@ -24,10 +24,27 @@ #define V4LCONTROL_SHM_SIZE 4096 +#define V4LCONTROL_WANTS_WB (1 << V4LCONTROL_WHITEBALANCE) +#define V4LCONTROL_WANTS_NORM ((1 << V4LCONTROL_NORMALIZE) | \ + (1 << V4LCONTROL_NORM_LOW_BOUND) | \ + (1 << V4LCONTROL_NORM_HIGH_BOUND)) + struct v4lcontrol_data { - int fd; /* Knowledge of the fd is needed in original syscalls */ - unsigned int controls; /* Which controls to use for this device */ + int fd; /* Device fd */ + int flags; /* Special flags for this device */ + int controls; /* Which controls to use for this device */ unsigned int *shm_values; /* shared memory control value store */ }; +struct v4lcontrol_flags_info { + unsigned short vendor_id; + unsigned short product_id; + unsigned short product_mask; +/* We could also use the USB manufacturer and product strings some devices have + const char *manufacturer; + const char *product; */ + int flags; + int controls; +}; + #endif diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c index cb4e34327..de8b608f9 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c @@ -40,27 +40,139 @@ /* end broken header workaround includes */ #include <linux/videodev2.h> -static void v4lcontrol_init(struct v4lcontrol_data *data, int first_time) +#define ARRAY_SIZE(x) ((int)sizeof(x)/(int)sizeof((x)[0])) + +/* Workaround these potentially missing from videodev2.h */ +#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 + + +/* List of cams which need special flags */ +static const struct v4lcontrol_flags_info v4lcontrol_flags[] = { +/* First: Upside down devices */ + /* Philips SPC200NC */ + { 0x0471, 0x0325, 0, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED, 0 }, + /* Philips SPC300NC */ + { 0x0471, 0x0326, 0, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED, 0 }, + /* Philips SPC210NC */ + { 0x0471, 0x032d, 0, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED, 0 }, + /* Genius E-M 112 */ + { 0x093a, 0x2476, 0, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED, 0 }, +/* Second: devices which can benifit from software video processing */ + /* Pac207 based devices */ + { 0x041e, 0x4028, 0, 0, V4LCONTROL_WANTS_WB }, + { 0x093a, 0x2460, 0x1f, 0, V4LCONTROL_WANTS_WB }, + { 0x145f, 0x013a, 0, 0, V4LCONTROL_WANTS_WB }, + { 0x2001, 0xf115, 0, 0, V4LCONTROL_WANTS_WB }, + /* Pac7302 based devices */ + { 0x093a, 0x2620, 0x0f, V4LCONTROL_ROTATED_90_JPEG, V4LCONTROL_WANTS_WB }, +}; + +static void v4lcontrol_init_flags(struct v4lcontrol_data *data) { - /* 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 stat st; + FILE *f; + char sysfs_name[512]; + unsigned short vendor_id = 0; + unsigned short product_id = 0; + int i, minor; + char c, *s, buf[32]; + struct v4l2_input input; + + if ((syscall(SYS_ioctl, data->fd, VIDIOC_G_INPUT, &input.index) == 0) && + (syscall(SYS_ioctl, data->fd, VIDIOC_ENUMINPUT, &input) == 0)) { + if (input.status & V4L2_IN_ST_HFLIP) + data->flags |= V4LCONTROL_HFLIPPED; + if (input.status & V4L2_IN_ST_VFLIP) + data->flags |= V4LCONTROL_VFLIPPED; } + + if (fstat(data->fd, &st) || !S_ISCHR(st.st_mode)) { + return; /* Should never happen */ + } + + /* <Sigh> find ourselve in sysfs */ + for (i = 0; i < 256; i++) { + snprintf(sysfs_name, sizeof(sysfs_name), + "/sys/class/video4linux/video%d/dev", i); + f = fopen(sysfs_name, "r"); + if (!f) + continue; + + s = fgets(buf, sizeof(buf), f); + fclose(f); + + if (s && sscanf(buf, "%*d:%d%c", &minor, &c) == 2 && c == '\n' && + minor == minor(st.st_rdev)) + break; + } + if (i == 256) + return; /* Not found, sysfs not mounted? */ + + /* Get vendor and product ID */ + snprintf(sysfs_name, sizeof(sysfs_name), + "/sys/class/video4linux/video%d/device/modalias", i); + f = fopen(sysfs_name, "r"); + if (f) { + s = fgets(buf, sizeof(buf), f); + fclose(f); + + if (!s || + sscanf(s, "usb:v%4hxp%4hx%c", &vendor_id, &product_id, &c) != 3 || + c != 'd') + return; /* Not an USB device */ + } else { + /* Try again assuming the device link points to the usb + device instead of the usb interface (bug in older versions + of gspca) */ + + /* Get product ID */ + snprintf(sysfs_name, sizeof(sysfs_name), + "/sys/class/video4linux/video%d/device/idVendor", i); + f = fopen(sysfs_name, "r"); + if (!f) + return; /* Not an USB device (or no sysfs) */ + + s = fgets(buf, sizeof(buf), f); + fclose(f); + + if (!s || sscanf(s, "%04hx%c", &vendor_id, &c) != 2 || c != '\n') + return; /* Should never happen */ + + /* Get product ID */ + snprintf(sysfs_name, sizeof(sysfs_name), + "/sys/class/video4linux/video%d/device/idProduct", i); + f = fopen(sysfs_name, "r"); + if (!f) + return; /* Should never happen */ + + s = fgets(buf, sizeof(buf), f); + fclose(f); + + if (!s || sscanf(s, "%04hx%c", &product_id, &c) != 2 || c != '\n') + return; /* Should never happen */ + } + + 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)) { + data->flags |= v4lcontrol_flags[i].flags; + data->controls = v4lcontrol_flags[i].controls; + break; + } } struct v4lcontrol_data *v4lcontrol_create(int fd) { int shm_fd; int init = 0; - char shm_name[256]; + char *s, shm_name[256]; struct v4l2_capability cap; struct v4lcontrol_data *data = calloc(1, sizeof(struct v4lcontrol_data)); @@ -89,10 +201,24 @@ struct v4lcontrol_data *v4lcontrol_create(int fd) if (data->shm_values == MAP_FAILED) goto error; - v4lcontrol_init(data, init); /* Set the driver defined fake controls */ + if (init) { + /* Initialize the new shm object we created */ + memset(data->shm_values, 0, sizeof(V4LCONTROL_SHM_SIZE)); + data->shm_values[V4LCONTROL_WHITEBALANCE] = 1; + data->shm_values[V4LCONTROL_NORM_HIGH_BOUND] = 255; + } data->fd = fd; + v4lcontrol_init_flags(data); + + /* Allow overriding through environment */ + if ((s = getenv("LIBV4LCONTROL_FLAGS"))) + data->flags = strtol(s, NULL, 0); + + if ((s = getenv("LIBV4LCONTROL_CONTROLS"))) + data->controls = strtol(s, NULL, 0); + return data; error: @@ -201,6 +327,11 @@ int v4lcontrol_vidioc_s_ctrl(struct v4lcontrol_data *data, void *arg) return syscall(SYS_ioctl, data->fd, VIDIOC_S_CTRL, arg); } +int v4lcontrol_get_flags(struct v4lcontrol_data *data) +{ + return data->flags; +} + int v4lcontrol_get_ctrl(struct v4lcontrol_data *data, int ctrl) { if (data->controls & (1 << ctrl)) diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h index 3611304d6..344e68055 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h @@ -22,6 +22,12 @@ #ifndef __LIBV4LCONTROL_H #define __LIBV4LCONTROL_H +/* Flags */ +#define V4LCONTROL_HFLIPPED 0x01 +#define V4LCONTROL_VFLIPPED 0x02 +#define V4LCONTROL_ROTATED_90_JPEG 0x04 + +/* Controls */ enum { V4LCONTROL_WHITEBALANCE, V4LCONTROL_NORMALIZE, V4LCONTROL_NORM_LOW_BOUND, V4LCONTROL_NORM_HIGH_BOUND, V4LCONTROL_COUNT }; @@ -31,6 +37,7 @@ 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_flags(struct v4lcontrol_data *data); int v4lcontrol_get_ctrl(struct v4lcontrol_data *data, int ctrl); /* Functions used by v4lconvert to pass vidioc calls from libv4l2 */ |