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/libv4lcontrol.c | |
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/libv4lcontrol.c')
-rw-r--r-- | v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c | 159 |
1 files changed, 145 insertions, 14 deletions
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)) |