From 6880d6f23b93031ceab3ce0952359c77d124a89f Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Mon, 16 Mar 2009 11:27:29 +0100 Subject: libv4l: drop bad sn9c20x jpeg frames From: Brian Johnson sn9c20x cams have occasional bad jpeg frames, drop these to avoid the flickering effect they cause, by: Brian Johnson Priority: normal Signed-off-by: Brian Johnson Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 5 +++++ v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h | 1 + v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 5 ++++- 3 files changed, 10 insertions(+), 1 deletion(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index 11f6ca2fd..21d60dabb 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -1,3 +1,8 @@ +libv4l-0.5.10 +------------- +* sn9c20x cams have occasional bad jpeg frames, drop these to avoid the + flickering effect they cause, by: Brian Johnson + libv4l-0.5.9 ------------ * Add support for MR97310A decompression by Kyle Guinn diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h index 5ce7bde3b..4e6130d3c 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h @@ -90,6 +90,7 @@ #define V4LCONVERT_ROTATE_90 0x01 #define V4LCONVERT_ROTATE_180 0x02 #define V4LCONVERT_IS_UVC 0x04 +#define V4LCONVERT_IS_SN9C20X 0x08 /* Pixformat flags */ #define V4LCONVERT_COMPRESSED 0x01 diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index 1204e8ef2..5467c695a 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -166,6 +166,8 @@ struct v4lconvert_data *v4lconvert_create(int fd) if (syscall(SYS_ioctl, fd, VIDIOC_QUERYCAP, &cap) == 0) { if (!strcmp((char *)cap.driver, "uvcvideo")) data->flags |= V4LCONVERT_IS_UVC; + else if (!strcmp((char *)cap.driver, "sn9c20x")) + data->flags |= V4LCONVERT_IS_SN9C20X; } return data; @@ -541,7 +543,8 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, are best thrown away to avoid flashes in the video stream. Tell the upper layer this is an intermediate fault and it should try again with a new buffer by setting errno to EAGAIN */ - if (src_pix_fmt == V4L2_PIX_FMT_PJPG) { + if (src_pix_fmt == V4L2_PIX_FMT_PJPG || + data->flags & V4LCONVERT_IS_SN9C20X) { V4LCONVERT_ERR("decompressing JPEG: %s", tinyjpeg_get_errorstring(data->jdec)); errno = EAGAIN; -- cgit v1.2.3 From 4f4f2f81fd16cc9a8b777452b64b3b2ffb4d819c Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Fri, 27 Mar 2009 10:39:24 +0100 Subject: libv4l: Fix upside down detection with certain usb devices From: Hans de Goede * adjust libv4l's upside down cam detection to also work with devices which have the usb interface as parent instead of the usb device * fix libv4l upside down detection for the new v4l minor numbering scheme Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 3 + v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 77 ++++++++++++++++++++------ 2 files changed, 63 insertions(+), 17 deletions(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index 21d60dabb..9b029d68b 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -2,6 +2,9 @@ libv4l-0.5.10 ------------- * sn9c20x cams have occasional bad jpeg frames, drop these to avoid the flickering effect they cause, by: Brian Johnson +* adjust libv4l's upside down cam detection to also work with devices + which have the usb interface as parent instead of the usb device +* fix libv4l upside down detection for the new v4l minor numbering scheme libv4l-0.5.9 ------------ diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index 5467c695a..f11922f3d 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -98,30 +98,73 @@ static int v4lconvert_get_flags(int fd) char sysfs_name[512]; unsigned short vendor_id = 0; unsigned short product_id = 0; - int i; + int i, minor; + char c, *s, buf[32]; if (fstat(fd, &st) || !S_ISCHR(st.st_mode)) return 0; /* Should never happen */ - /* Get product ID */ - snprintf(sysfs_name, sizeof(sysfs_name), - "/sys/class/video4linux/video%d/device/idVendor", - minor(st.st_rdev)); - f = fopen(sysfs_name, "r"); - if (!f) - return 0; /* Not an USB device (or no sysfs) */ - i = fscanf(f, "%hx", &vendor_id); - fclose(f); + /* 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); - /* Get product ID */ + if (s && sscanf(buf, "%*d:%d%c", &minor, &c) == 2 && c == '\n' && + minor == minor(st.st_rdev)) + break; + } + if (i == 256) + return 0; /* Not found, sysfs not mounted? */ + + /* Get vendor and product ID */ snprintf(sysfs_name, sizeof(sysfs_name), - "/sys/class/video4linux/video%d/device/idProduct", - minor(st.st_rdev)); + "/sys/class/video4linux/video%d/device/modalias", i); f = fopen(sysfs_name, "r"); - if (!f) - return 0; /* Should never happen */ - i = fscanf(f, "%hx", &product_id); - fclose(f); + 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 0; /* 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 0; /* 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 0; /* 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 0; /* Should never happen */ + + s = fgets(buf, sizeof(buf), f); + fclose(f); + + if (!s || sscanf(s, "%04hx%c", &product_id, &c) != 2 || c != '\n') + return 0; /* Should never happen */ + } for (i = 0; i < ARRAY_SIZE(v4lconvert_flags); i++) if (v4lconvert_flags[i].vendor_id == vendor_id && -- cgit v1.2.3 From 8fabb280152af70dddc25fd3c57a346b94326a33 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Fri, 10 Apr 2009 13:29:11 +0200 Subject: libv4l: Adds Makefile pre-requisites to libv4l From: Gilles Gigan This patch update libv4l's Makefiles so they automatically update and include dependency information for each source file. Priority: normal Signed-off-by: Gilles Gigan Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/libv4l1/Makefile | 12 +++++++++--- v4l2-apps/libv4l/libv4l2/Makefile | 13 ++++++++++--- v4l2-apps/libv4l/libv4lconvert/Makefile | 8 +++++++- 3 files changed, 26 insertions(+), 7 deletions(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/libv4l1/Makefile b/v4l2-apps/libv4l/libv4l1/Makefile index 9f30cbb0f..d228cc916 100644 --- a/v4l2-apps/libv4l/libv4l1/Makefile +++ b/v4l2-apps/libv4l/libv4l1/Makefile @@ -13,9 +13,10 @@ INCLUDES = ../include/libv4l1.h ifeq ($(LINKTYPE),static) V4L1_LIB = libv4l1.a +V4L1_DEPS = $(V4L1_OBJS) else V4L1_LIB = libv4l1.so -V4L1_OBJS += ../libv4l2/libv4l2.so +V4L1_DEPS += $(V4L1_OBJS) ../libv4l2/libv4l2.so TARGETS += $(V4L1COMPAT) override CPPFLAGS += -fPIC endif @@ -34,8 +35,9 @@ endif all: $(TARGETS) +include $(V4L1_OBJS:.o=.d) -$(V4L1_LIB): $(V4L1_OBJS) +$(V4L1_LIB): $(V4L1_DEPS) $(V4L1COMPAT): $(V4L1COMPAT_O) $(V4L1_LIB) @@ -71,8 +73,12 @@ endif clean:: rm -f *.a *.so* *.o *.d libv4l1.pc log *~ *.orig *.rej +%.d: %.c + @set -e; rm -f $@; \ + gcc -MM $(CPPFLAGS) $< | sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' > $@ + %.o: %.c - $(CC) -c -MMD $(CPPFLAGS) $(CFLAGS) -o $@ $< + $(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $< %.so: $(CC) -shared $(LDFLAGS) -Wl,-soname,$@.$(LIB_RELEASE) -o $@.$(LIB_RELEASE) $^ $(LIBS_$*) diff --git a/v4l2-apps/libv4l/libv4l2/Makefile b/v4l2-apps/libv4l/libv4l2/Makefile index 614b36cf8..c3af123c8 100644 --- a/v4l2-apps/libv4l/libv4l2/Makefile +++ b/v4l2-apps/libv4l/libv4l2/Makefile @@ -13,9 +13,10 @@ INCLUDES = ../include/libv4l2.h ifeq ($(LINKTYPE),static) V4L2_LIB = libv4l2.a +V4L2_DEPS = $(V4L2_OBJS) else V4L2_LIB = libv4l2.so -V4L2_OBJS += ../libv4lconvert/libv4lconvert.so +V4L2_DEPS += $(V4L2_OBJS) ../libv4lconvert/libv4lconvert.so TARGETS += $(V4L2CONVERT) override CPPFLAGS += -fPIC endif @@ -34,7 +35,9 @@ endif all: $(TARGETS) -$(V4L2_LIB): $(V4L2_OBJS) +include $(V4L2_OBJS:.o=.d) + +$(V4L2_LIB): $(V4L2_DEPS) $(V4L2CONVERT): $(V4L2CONVERT_O) $(V4L2_LIB) @@ -70,8 +73,12 @@ endif clean:: rm -f *.a *.so* *.o *.d libv4l2.pc log *~ *.orig *.rej +%.d: %.c + @set -e; rm -f $@; \ + gcc -MM $(CPPFLAGS) $< | sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' > $@ + %.o: %.c - $(CC) -c -MMD $(CPPFLAGS) $(CFLAGS) -o $@ $< + $(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $< %.so: $(CC) -shared $(LDFLAGS) -Wl,-soname,$@.$(LIB_RELEASE) -o $@.$(LIB_RELEASE) $^ $(LIBS_$*) diff --git a/v4l2-apps/libv4l/libv4lconvert/Makefile b/v4l2-apps/libv4l/libv4lconvert/Makefile index f779011b4..95b9d31d9 100644 --- a/v4l2-apps/libv4l/libv4lconvert/Makefile +++ b/v4l2-apps/libv4l/libv4lconvert/Makefile @@ -30,6 +30,8 @@ endif all: $(TARGETS) +include $(CONVERT_OBJS:.o=.d) + $(CONVERT_LIB): $(CONVERT_OBJS) libv4lconvert.pc: @@ -60,8 +62,12 @@ endif clean:: rm -f *.a *.so* *.o *.d libv4lconvert.pc log *~ *.orig *.rej +%.d:: %.c + @set -e; rm -f $@; \ + $(CC) -MM $(CPPFLAGS) $< | sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' > $@ + %.o: %.c - $(CC) -c -MMD $(CPPFLAGS) $(CFLAGS) -o $@ $< + $(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $< %.so: $(CC) -shared $(LDFLAGS) -Wl,-soname,$@.$(LIB_RELEASE) -o $@.$(LIB_RELEASE) $^ -- cgit v1.2.3 From 47b68b12ace2d6414547991a02fda32a4ae748f7 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Fri, 10 Apr 2009 13:34:07 +0200 Subject: libv4l: Add support to use orientation from VIDIOC_ENUMINPUT From: Adam Baker Add check to libv4l of the sensor orientation as reported by VIDIOC_ENUMINPUT Priority: normal Signed-off-by: Adam Baker Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 6 ++++++ v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 13 +++++++++++++ 2 files changed, 19 insertions(+) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index 9b029d68b..9c9a5a3b2 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -1,3 +1,9 @@ +libv4l-0.5.11 +------------- +* Add dependency generation to libv4l by: Gilles Gigan +* Add support to use orientation from VIDIOC_ENUMINPUT by: + Adam Baker + libv4l-0.5.10 ------------- * sn9c20x cams have occasional bad jpeg frames, drop these to avoid the diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index f11922f3d..f3191f1d9 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -29,6 +29,11 @@ #define MIN(a,b) (((a)<(b))?(a):(b)) #define ARRAY_SIZE(x) ((int)sizeof(x)/(int)sizeof((x)[0])) +/* Workaround this potentially being missing from videodev2.h */ +#ifndef V4L2_IN_ST_VFLIP +#define V4L2_IN_ST_VFLIP 0x00000020 /* Output is flipped vertically */ +#endif + /* Note for proper functioning of v4lconvert_enum_fmt the first entries in supported_src_pixfmts must match with the entries in supported_dst_pixfmts */ #define SUPPORTED_DST_PIXFMTS \ @@ -179,6 +184,7 @@ struct v4lconvert_data *v4lconvert_create(int fd) int i, j; struct v4lconvert_data *data = calloc(1, sizeof(struct v4lconvert_data)); struct v4l2_capability cap; + struct v4l2_input input; if (!data) return NULL; @@ -206,6 +212,13 @@ struct v4lconvert_data *v4lconvert_create(int fd) /* Check if this cam has any special flags */ data->flags = v4lconvert_get_flags(data->fd); + if ((syscall(SYS_ioctl, fd, VIDIOC_G_INPUT, &input.index) == 0) && + (syscall(SYS_ioctl, fd, VIDIOC_ENUMINPUT, &input) == 0)) { + /* Don't yet support independent HFLIP and VFLIP so getting + * image the right way up is highest priority. */ + if (input.status & V4L2_IN_ST_VFLIP) + data->flags |= V4LCONVERT_ROTATE_180; + } if (syscall(SYS_ioctl, fd, VIDIOC_QUERYCAP, &cap) == 0) { if (!strcmp((char *)cap.driver, "uvcvideo")) data->flags |= V4LCONVERT_IS_UVC; -- cgit v1.2.3 From fa59c01eadd849ed2e5b0cf1406347bf632c80ed Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Mon, 13 Apr 2009 20:02:34 +0200 Subject: libv4l: add video processing: whitebalance and normalize From: Hans de Goede As the version number shows this work is the basis for a beta release of the 0.6.x series, the big change here is the addition of video processing to libv4l currently this only does whitebalance and normalizing (which turns out to be useless for most cams) but the basic framework for doing video processing, and being able to control it through fake v4l2 controls using for example v4l2ucp is there. The initial version of this code was written by 3 of my computer science students: Elmar Kleijn, Sjoerd Piepenbrink and Radjnies Bhansingh. This initial hg commit is a cleaned up and somewhat bug fixed version of their code. Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 13 +- v4l2-apps/libv4l/README | 28 ++- v4l2-apps/libv4l/TODO | 3 + v4l2-apps/libv4l/include/libv4lconvert.h | 8 + v4l2-apps/libv4l/libv4l2/Makefile | 2 +- v4l2-apps/libv4l/libv4l2/libv4l2.c | 15 ++ v4l2-apps/libv4l/libv4l2/log.c | 4 +- v4l2-apps/libv4l/libv4lconvert/Makefile | 7 +- .../libv4lconvert/control/libv4lcontrol-priv.h | 33 +++ .../libv4l/libv4lconvert/control/libv4lcontrol.c | 210 ++++++++++++++++++ .../libv4l/libv4lconvert/control/libv4lcontrol.h | 41 ++++ v4l2-apps/libv4l/libv4lconvert/flip.c | 57 +++-- .../libv4l/libv4lconvert/libv4lconvert-priv.h | 43 +++- v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 230 ++++++++++++++----- .../libv4lconvert/processing/bayerprocessing.c | 244 +++++++++++++++++++++ .../processing/libv4lprocessing-priv.h | 89 ++++++++ .../libv4lconvert/processing/libv4lprocessing.c | 179 +++++++++++++++ .../libv4lconvert/processing/libv4lprocessing.h | 48 ++++ .../libv4lconvert/processing/rgbprocessing.c | 156 +++++++++++++ 19 files changed, 1300 insertions(+), 110 deletions(-) create mode 100644 v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h create mode 100644 v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c create mode 100644 v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h create mode 100644 v4l2-apps/libv4l/libv4lconvert/processing/bayerprocessing.c create mode 100644 v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h create mode 100644 v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c create mode 100644 v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.h create mode 100644 v4l2-apps/libv4l/libv4lconvert/processing/rgbprocessing.c (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index 9c9a5a3b2..52b429687 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -1,11 +1,16 @@ -libv4l-0.5.11 +libv4l-0.5.97 ------------- +* As the version number shows this is a beta release of the 0.6.x series, + the big change here is the addition of video processing to libv4l + currently this only does whitebalance and normalizing (which turns out + to be useless for most cams) but the basic framework for doing video + processing, and being able to control it through fake v4l2 controls using + for example v4l2ucp is there. + The initial version of this code was written by 3 of my computer science + students: Elmar Kleijn, Sjoerd Piepenbrink and Radjnies Bhansingh * Add dependency generation to libv4l by: Gilles Gigan * Add support to use orientation from VIDIOC_ENUMINPUT by: Adam Baker - -libv4l-0.5.10 -------------- * sn9c20x cams have occasional bad jpeg frames, drop these to avoid the flickering effect they cause, by: Brian Johnson * adjust libv4l's upside down cam detection to also work with devices diff --git a/v4l2-apps/libv4l/README b/v4l2-apps/libv4l/README index 3a2059224..481d5b92e 100644 --- a/v4l2-apps/libv4l/README +++ b/v4l2-apps/libv4l/README @@ -15,14 +15,26 @@ libv4l consists of 3 different libraries: libv4lconvert ------------- -libv4lconvert offers functions to convert from any (known) pixelformat -to V4l2_PIX_FMT_BGR24 or V4l2_PIX_FMT_YUV420. - -Currently the following source formats are supported: -jpeg, mjpeg, bayer (all 4 variants: bggr, rggb, gbrg, grbg), -spca501 (chip specific yuv 420 with interlaced components), -spca561 (chip specific compressed gbrg bayer) -For more details on the v4lconvert_ functions see libv4lconvert.h . +libv4lconvert started as a library to convert from any (known) pixelformat to +V4l2_PIX_FMT_BGR24, RGB24, YUV420 or YVU420. + +The list of know source formats is large and continually growing, so instead +of keeping an (almost always outdated) list here in the README, I refer you +to the source, see the list of defines at the top of +libv4lconvert/libv4lconvert.c for the full list. +For more details on the v4lconvert_ functions see libv4lconvert.h. + +Later on libv4lconvert was expanded to also be able to do various video +processing functions improve webcam video quality on a software basis. So +the name no longer 100% covers the functionality. The video processing is +split in to 2 parts, libv4lconvert/control and libv4lconvert/processing. + +The control part is used to offer video controls which can be used to control +the video processing functions made available by libv4lconvert/processing. +These controls are stored application wide (untill reboot) by using a +persistent shared memory object. + +libv4lconvert/processing offers the actual video processing functionality. libv4l1 diff --git a/v4l2-apps/libv4l/TODO b/v4l2-apps/libv4l/TODO index debb9c78c..2bd2fc992 100644 --- a/v4l2-apps/libv4l/TODO +++ b/v4l2-apps/libv4l/TODO @@ -8,3 +8,6 @@ necessary to implement CGMBUF in the kernel for each driver. -take the possibility of pitch != width into account everywhere + +-only report faked formats in list formats and only allow setting fake + formats when processing or flipping. diff --git a/v4l2-apps/libv4l/include/libv4lconvert.h b/v4l2-apps/libv4l/include/libv4lconvert.h index 626c43473..fcc31dace 100644 --- a/v4l2-apps/libv4l/include/libv4lconvert.h +++ b/v4l2-apps/libv4l/include/libv4lconvert.h @@ -81,6 +81,14 @@ LIBV4L_PUBLIC int v4lconvert_enum_framesizes(struct v4lconvert_data *data, LIBV4L_PUBLIC int v4lconvert_enum_frameintervals(struct v4lconvert_data *data, struct v4l2_frmivalenum *frmival); +/* Pass calls to query, get and set video controls to the libv4lcontrol class */ +LIBV4L_PUBLIC int v4lconvert_vidioc_queryctrl(struct v4lconvert_data *data, + void *arg); +LIBV4L_PUBLIC int v4lconvert_vidioc_g_ctrl(struct v4lconvert_data *data, + void *arg); +LIBV4L_PUBLIC int v4lconvert_vidioc_s_ctrl(struct v4lconvert_data *data, + void *arg); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/v4l2-apps/libv4l/libv4l2/Makefile b/v4l2-apps/libv4l/libv4l2/Makefile index c3af123c8..4356c0975 100644 --- a/v4l2-apps/libv4l/libv4l2/Makefile +++ b/v4l2-apps/libv4l/libv4l2/Makefile @@ -3,7 +3,7 @@ override CPPFLAGS += -I../include -I../../../include -fvisibility=hidden CFLAGS := -g -O1 CFLAGS += -Wall -Wno-unused -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -LIBS_libv4l2 = -lpthread +LIBS_libv4l2 = -lpthread -lrt V4L2_OBJS = libv4l2.o log.o V4L2CONVERT = v4l2convert.so diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2.c b/v4l2-apps/libv4l/libv4l2/libv4l2.c index b6ddef6e8..91e0193ee 100644 --- a/v4l2-apps/libv4l/libv4l2/libv4l2.c +++ b/v4l2-apps/libv4l/libv4l2/libv4l2.c @@ -676,6 +676,9 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) /* Is this a capture request and do we need to take the stream lock? */ switch (request) { + case VIDIOC_QUERYCTRL: + case VIDIOC_G_CTRL: + case VIDIOC_S_CTRL: case VIDIOC_QUERYCAP: is_capture_request = 1; break; @@ -739,6 +742,18 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) &devices[index].src_fmt, &devices[index].dest_fmt); switch (request) { + case VIDIOC_QUERYCTRL: + result = v4lconvert_vidioc_queryctrl(devices[index].convert, arg); + break; + + case VIDIOC_G_CTRL: + result = v4lconvert_vidioc_g_ctrl(devices[index].convert, arg); + break; + + case VIDIOC_S_CTRL: + result = v4lconvert_vidioc_s_ctrl(devices[index].convert, arg); + break; + case VIDIOC_QUERYCAP: { struct v4l2_capability *cap = arg; diff --git a/v4l2-apps/libv4l/libv4l2/log.c b/v4l2-apps/libv4l/libv4l2/log.c index c29086ff4..251b46ecf 100644 --- a/v4l2-apps/libv4l/libv4l2/log.c +++ b/v4l2-apps/libv4l/libv4l2/log.c @@ -1,5 +1,7 @@ /* -# (C) 2008 Hans de Goede +# (C) 2008 Elmar Kleijn +# (C) 2008 Sjoerd Piepenbrink +# (C) 2008 Hans de Goede # 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/Makefile b/v4l2-apps/libv4l/libv4lconvert/Makefile index 95b9d31d9..64f6690d2 100644 --- a/v4l2-apps/libv4l/libv4lconvert/Makefile +++ b/v4l2-apps/libv4l/libv4lconvert/Makefile @@ -12,7 +12,9 @@ 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 + rgbyuv.o spca501.o sq905c.o bayer.o hm12.o \ + control/libv4lcontrol.o processing/libv4lprocessing.o \ + processing/rgbprocessing.o processing/bayerprocessing.o TARGETS = $(CONVERT_LIB) libv4lconvert.pc INCLUDES = ../include/libv4lconvert.h @@ -60,7 +62,8 @@ endif install -m 644 libv4lconvert.pc $(DESTDIR)$(LIBDIR)/pkgconfig clean:: - rm -f *.a *.so* *.o *.d libv4lconvert.pc log *~ *.orig *.rej + rm -f *.a *.so* *.o *.d */*.o */*.d libv4lconvert.pc log *~ */*~ + rm -f *.orig *.rej */*.orig */*.rej %.d:: %.c @set -e; rm -f $@; \ diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h new file mode 100644 index 000000000..59305a237 --- /dev/null +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h @@ -0,0 +1,33 @@ +/* +# (C) 2008-2009 Elmar Kleijn +# (C) 2008-2009 Sjoerd Piepenbrink +# (C) 2008-2009 Radjnies Bhansingh +# (C) 2008-2009 Hans de Goede + +# 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 +*/ + +#ifndef __LIBV4LCONTROL_PRIV_H +#define __LIBV4LCONTROL_PRIV_H + +#define V4LCONTROL_SHM_SIZE 4096 + +struct v4lcontrol_data { + int fd; /* Knowledge of the fd is needed in original syscalls */ + unsigned int controls; /* Which controls to use for this device */ + unsigned int *shm_values; /* shared memory control value store */ +}; + +#endif diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c new file mode 100644 index 000000000..cb4e34327 --- /dev/null +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c @@ -0,0 +1,210 @@ +/* +# (C) 2008-2009 Elmar Kleijn +# (C) 2008-2009 Sjoerd Piepenbrink +# (C) 2008-2009 Radjnies Bhansingh +# (C) 2008-2009 Hans de Goede + +# 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "libv4lcontrol.h" +#include "libv4lcontrol-priv.h" + +/* These headers are not needed by us, but by linux/videodev2.h, + which is broken on some systems and doesn't include them itself :( */ +#include +#include +#include +/* end broken header workaround includes */ +#include + +static void v4lcontrol_init(struct v4lcontrol_data *data, int first_time) +{ + /* 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 v4lcontrol_data *v4lcontrol_create(int fd) +{ + int shm_fd; + int init = 0; + char shm_name[256]; + struct v4l2_capability cap; + + struct v4lcontrol_data *data = calloc(1, sizeof(struct v4lcontrol_data)); + + if (!data) + return NULL; + + syscall(SYS_ioctl, fd, VIDIOC_QUERYCAP, &cap); + snprintf(shm_name, 256, "/%s:%s", cap.bus_info, cap.card); + + /* Open the shared memory object identified by shm_name */ + 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; + + /* 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); + + if (data->shm_values == MAP_FAILED) + goto error; + + v4lcontrol_init(data, init); /* Set the driver defined fake controls */ + + data->fd = fd; + + return data; + +error: + free(data); + return NULL; +} + +void v4lcontrol_destroy(struct v4lcontrol_data *data) +{ + munmap(data->shm_values, V4LCONTROL_SHM_SIZE); + free(data); +} + +/* FIXME get better CID's for normalize */ +struct v4l2_queryctrl fake_controls[V4LCONTROL_COUNT] = { +{ + .id = V4L2_CID_AUTO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Whitebalance", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + .flags = 0 +}, +{ + .id = V4L2_CID_DO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Normalize", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0 +}, +{ + .id = V4L2_CID_BLACK_LEVEL, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Normalize: low bound", + .minimum = 0, + .maximum = 127, + .step = 1, + .default_value = 0, + .flags = 0 +}, +{ + .id = V4L2_CID_WHITENESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Normalize: high bound", + .minimum = 128, + .maximum = 255, + .step = 1, + .default_value = 255, + .flags = 0 +}, +}; + +int v4lcontrol_vidioc_queryctrl(struct v4lcontrol_data *data, void *arg) +{ + int i; + struct v4l2_queryctrl *ctrl = arg; + + for (i = 0; i < V4LCONTROL_COUNT; i++) + if ((data->controls & (1 << i)) && + ctrl->id == fake_controls[i].id) { + memcpy(ctrl, &fake_controls[i], sizeof(struct v4l2_queryctrl)); + return 0; + } + + return syscall(SYS_ioctl, data->fd, VIDIOC_QUERYCTRL, arg); +} + +int v4lcontrol_vidioc_g_ctrl(struct v4lcontrol_data *data, void *arg) +{ + int i; + struct v4l2_control *ctrl = arg; + + for (i = 0; i < V4LCONTROL_COUNT; i++) + if ((data->controls & (1 << i)) && + ctrl->id == fake_controls[i].id) { + ctrl->value = data->shm_values[i]; + return 0; + } + + return syscall(SYS_ioctl, data->fd, VIDIOC_G_CTRL, arg); +} + +int v4lcontrol_vidioc_s_ctrl(struct v4lcontrol_data *data, void *arg) +{ + int i; + struct v4l2_control *ctrl = arg; + + for (i = 0; i < V4LCONTROL_COUNT; i++) + if ((data->controls & (1 << i)) && + ctrl->id == fake_controls[i].id) { + if (ctrl->value > fake_controls[i].maximum || + ctrl->value < fake_controls[i].minimum) { + errno = EINVAL; + return -1; + } + + data->shm_values[i] = ctrl->value; + return 0; + } + + return syscall(SYS_ioctl, data->fd, VIDIOC_S_CTRL, arg); +} + +int v4lcontrol_get_ctrl(struct v4lcontrol_data *data, int ctrl) +{ + if (data->controls & (1 << ctrl)) + return data->shm_values[ctrl]; + + return 0; +} diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h new file mode 100644 index 000000000..3611304d6 --- /dev/null +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h @@ -0,0 +1,41 @@ +/* +# (C) 2008-2009 Elmar Kleijn +# (C) 2008-2009 Sjoerd Piepenbrink +# (C) 2008-2009 Radjnies Bhansingh +# (C) 2008-2009 Hans de Goede + +# 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 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 +*/ + +#ifndef __LIBV4LCONTROL_H +#define __LIBV4LCONTROL_H + +enum { V4LCONTROL_WHITEBALANCE, V4LCONTROL_NORMALIZE, + V4LCONTROL_NORM_LOW_BOUND, V4LCONTROL_NORM_HIGH_BOUND, V4LCONTROL_COUNT }; + +struct v4lcontrol_data; + +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_ctrl(struct v4lcontrol_data *data, int ctrl); + +/* Functions used by v4lconvert to pass vidioc calls from libv4l2 */ +int v4lcontrol_vidioc_queryctrl(struct v4lcontrol_data *data, void *arg); +int v4lcontrol_vidioc_g_ctrl(struct v4lcontrol_data *data, void *arg); +int v4lcontrol_vidioc_s_ctrl(struct v4lcontrol_data *data, void *arg); + +#endif diff --git a/v4l2-apps/libv4l/libv4lconvert/flip.c b/v4l2-apps/libv4l/libv4lconvert/flip.c index f47afde72..9835f045c 100644 --- a/v4l2-apps/libv4l/libv4lconvert/flip.c +++ b/v4l2-apps/libv4l/libv4lconvert/flip.c @@ -106,37 +106,46 @@ static void v4lconvert_rotate90_yuv420(const unsigned char *src, } } -void v4lconvert_rotate(unsigned char *src, unsigned char *dest, - int width, int height, unsigned int pix_fmt, int rotate) +void v4lconvert_rotate90(unsigned char *src, unsigned char *dest, + struct v4l2_format *fmt) { - switch (rotate) { - case 0: - break; - case 90: - switch (pix_fmt) { - case V4L2_PIX_FMT_RGB24: - case V4L2_PIX_FMT_BGR24: - v4lconvert_rotate90_rgbbgr24(src, dest, width, height); - break; - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_YVU420: - v4lconvert_rotate90_yuv420(src, dest, width, height); - break; - } - break; - case 180: - switch (pix_fmt) { + int tmp; + + tmp = fmt->fmt.pix.width; + fmt->fmt.pix.width = fmt->fmt.pix.height; + fmt->fmt.pix.height = tmp; + + switch (fmt->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + v4lconvert_rotate90_rgbbgr24(src, dest, fmt->fmt.pix.width, + fmt->fmt.pix.height); + break; + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + v4lconvert_rotate90_yuv420(src, dest, fmt->fmt.pix.width, + fmt->fmt.pix.height); + break; + } +} + +void v4lconvert_flip(unsigned char *src, unsigned char *dest, + struct v4l2_format *fmt, int flags) +{ + /* FIXME implement separate vflipping and hflipping, for now we always + rotate 180 when vflip is selected! */ + if (flags & V4LCONVERT_VFLIP) { + switch (fmt->fmt.pix.pixelformat) { case V4L2_PIX_FMT_RGB24: case V4L2_PIX_FMT_BGR24: - v4lconvert_rotate180_rgbbgr24(src, dest, width, height); + v4lconvert_rotate180_rgbbgr24(src, dest, fmt->fmt.pix.width, + fmt->fmt.pix.height); break; case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: - v4lconvert_rotate180_yuv420(src, dest, width, height); + v4lconvert_rotate180_yuv420(src, dest, fmt->fmt.pix.width, + fmt->fmt.pix.height); break; } - break; - default: - printf("FIXME add %d degrees rotation\n", rotate); } } diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h index 4e6130d3c..acf921a31 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h @@ -21,8 +21,12 @@ #include #include "libv4lconvert.h" +#include "control/libv4lcontrol.h" +#include "processing/libv4lprocessing.h" #include "tinyjpeg.h" +/* Workaround these potentially missing from videodev2.h */ + #ifndef V4L2_PIX_FMT_SPCA501 #define V4L2_PIX_FMT_SPCA501 v4l2_fourcc('S','5','0','1') /* YUYV per line */ #endif @@ -79,6 +83,15 @@ #define V4L2_PIX_FMT_SN9C20X_I420 v4l2_fourcc('S', '9', '2', '0') #endif +#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 + + #define V4LCONVERT_ERROR_MSG_SIZE 256 #define V4LCONVERT_MAX_FRAMESIZES 16 @@ -87,10 +100,11 @@ "v4l-convert: error " __VA_ARGS__) /* Card flags */ -#define V4LCONVERT_ROTATE_90 0x01 -#define V4LCONVERT_ROTATE_180 0x02 -#define V4LCONVERT_IS_UVC 0x04 -#define V4LCONVERT_IS_SN9C20X 0x08 +#define V4LCONVERT_HFLIP 0x01 +#define V4LCONVERT_VFLIP 0x02 +#define V4LCONVERT_JPEG_ROTATE_90_HACK 0x04 +#define V4LCONVERT_IS_UVC 0x08 +#define V4LCONVERT_IS_SN9C20X 0x10 /* Pixformat flags */ #define V4LCONVERT_COMPRESSED 0x01 @@ -104,12 +118,18 @@ struct v4lconvert_data { struct jdec_private *jdec; struct v4l2_frmsizeenum framesizes[V4LCONVERT_MAX_FRAMESIZES]; unsigned int no_framesizes; - int convert_buf_size; - int rotate_buf_size; + int convert1_buf_size; + int convert2_buf_size; + int rotate90_buf_size; + int flip_buf_size; int convert_pixfmt_buf_size; - unsigned char *convert_buf; - unsigned char *rotate_buf; + unsigned char *convert1_buf; + unsigned char *convert2_buf; + unsigned char *rotate90_buf; + unsigned char *flip_buf; unsigned char *convert_pixfmt_buf; + struct v4lcontrol_data *control; + struct v4lprocessing_data *processing; }; struct v4lconvert_flags_info { @@ -210,8 +230,11 @@ void v4lconvert_hm12_to_bgr24(const unsigned char *src, void v4lconvert_hm12_to_yuv420(const unsigned char *src, unsigned char *dst, int width, int height, int yvu); -void v4lconvert_rotate(unsigned char *src, unsigned char *dest, - int width, int height, unsigned int pix_fmt, int rotate); +void v4lconvert_rotate90(unsigned char *src, unsigned char *dest, + struct v4l2_format *fmt); + +void v4lconvert_flip(unsigned char *src, unsigned char *dest, + struct v4l2_format *fmt, int flags); void v4lconvert_crop(unsigned char *src, unsigned char *dest, const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt); diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index f3191f1d9..6fbc1affa 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -29,11 +29,6 @@ #define MIN(a,b) (((a)<(b))?(a):(b)) #define ARRAY_SIZE(x) ((int)sizeof(x)/(int)sizeof((x)[0])) -/* Workaround this potentially being missing from videodev2.h */ -#ifndef V4L2_IN_ST_VFLIP -#define V4L2_IN_ST_VFLIP 0x00000020 /* Output is flipped vertically */ -#endif - /* Note for proper functioning of v4lconvert_enum_fmt the first entries in supported_src_pixfmts must match with the entries in supported_dst_pixfmts */ #define SUPPORTED_DST_PIXFMTS \ @@ -77,10 +72,10 @@ static const struct v4lconvert_pixfmt supported_dst_pixfmts[] = { /* List of cams which need special flags */ static const struct v4lconvert_flags_info v4lconvert_flags[] = { - { 0x0471, 0x0325, V4LCONVERT_ROTATE_180 }, /* Philips SPC200NC */ - { 0x0471, 0x0326, V4LCONVERT_ROTATE_180 }, /* Philips SPC300NC */ - { 0x0471, 0x032d, V4LCONVERT_ROTATE_180 }, /* Philips SPC210NC */ - { 0x093a, 0x2476, V4LCONVERT_ROTATE_180 }, /* Genius E-M 112 */ + { 0x0471, 0x0325, V4LCONVERT_HFLIP|V4LCONVERT_VFLIP }, /* Philips SPC200NC */ + { 0x0471, 0x0326, V4LCONVERT_HFLIP|V4LCONVERT_VFLIP }, /* Philips SPC300NC */ + { 0x0471, 0x032d, V4LCONVERT_HFLIP|V4LCONVERT_VFLIP }, /* Philips SPC210NC */ + { 0x093a, 0x2476, V4LCONVERT_HFLIP|V4LCONVERT_VFLIP }, /* Genius E-M 112 */ }; /* List of well known resolutions which we can get by cropping somewhat larger @@ -214,10 +209,10 @@ struct v4lconvert_data *v4lconvert_create(int fd) data->flags = v4lconvert_get_flags(data->fd); if ((syscall(SYS_ioctl, fd, VIDIOC_G_INPUT, &input.index) == 0) && (syscall(SYS_ioctl, fd, VIDIOC_ENUMINPUT, &input) == 0)) { - /* Don't yet support independent HFLIP and VFLIP so getting - * image the right way up is highest priority. */ + if (input.status & V4L2_IN_ST_HFLIP) + data->flags |= V4LCONVERT_HFLIP; if (input.status & V4L2_IN_ST_VFLIP) - data->flags |= V4LCONVERT_ROTATE_180; + data->flags |= V4LCONVERT_VFLIP; } if (syscall(SYS_ioctl, fd, VIDIOC_QUERYCAP, &cap) == 0) { if (!strcmp((char *)cap.driver, "uvcvideo")) @@ -226,18 +221,35 @@ struct v4lconvert_data *v4lconvert_create(int fd) data->flags |= V4LCONVERT_IS_SN9C20X; } + data->control = v4lcontrol_create(fd); + if (!data->control) { + free(data); + return NULL; + } + + data->processing = v4lprocessing_create(data->control); + if (!data->processing) { + v4lcontrol_destroy(data->control); + free(data); + return NULL; + } + return data; } void v4lconvert_destroy(struct v4lconvert_data *data) { + v4lprocessing_destroy(data->processing); + v4lcontrol_destroy(data->control); if (data->jdec) { unsigned char *comps[3] = { NULL, NULL, NULL }; tinyjpeg_set_components(data->jdec, comps, 3); tinyjpeg_free(data->jdec); } - free(data->convert_buf); - free(data->rotate_buf); + free(data->convert1_buf); + free(data->convert2_buf); + free(data->rotate90_buf); + free(data->flip_buf); free(data->convert_pixfmt_buf); free(data); } @@ -490,7 +502,7 @@ int v4lconvert_needs_conversion(struct v4lconvert_data *data, src_fmt->fmt.pix.pixelformat != dest_fmt->fmt.pix.pixelformat) return 1; /* Formats differ */ - if (!(data->flags & (V4LCONVERT_ROTATE_90|V4LCONVERT_ROTATE_180))) + if (!(data->flags & (V4LCONVERT_HFLIP|V4LCONVERT_VFLIP))) return 0; /* Formats identical and we don't need flip */ /* Formats are identical, but we need flip, do we support the dest_fmt? */ @@ -500,6 +512,32 @@ int v4lconvert_needs_conversion(struct v4lconvert_data *data, return 1; /* Needs flip and thus conversion */ } +static int v4lconvert_processing_needs_double_conversion( + unsigned int src_pix_fmt, unsigned int dest_pix_fmt) +{ + switch (src_pix_fmt) { + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + case V4L2_PIX_FMT_SPCA561: + case V4L2_PIX_FMT_SN9C10X: + case V4L2_PIX_FMT_PAC207: + case V4L2_PIX_FMT_MR97310A: + case V4L2_PIX_FMT_SQ905C: + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + return 0; + } + switch (dest_pix_fmt) { + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + return 0; + } + + return 1; +} + static unsigned char *v4lconvert_alloc_buffer(struct v4lconvert_data *data, int needed, unsigned char **buf, int *buf_size) { @@ -519,14 +557,14 @@ static unsigned char *v4lconvert_alloc_buffer(struct v4lconvert_data *data, static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, unsigned char *src, int src_size, unsigned char *dest, - const struct v4l2_format *src_fmt, unsigned int dest_pix_fmt) + struct v4l2_format *fmt, unsigned int dest_pix_fmt) { unsigned int header_width, header_height; int result = 0, jpeg_flags = TINYJPEG_FLAGS_MJPEG_TABLE; unsigned char *components[3]; - unsigned int src_pix_fmt = src_fmt->fmt.pix.pixelformat; - unsigned int width = src_fmt->fmt.pix.width; - unsigned int height = src_fmt->fmt.pix.height; + unsigned int src_pix_fmt = fmt->fmt.pix.pixelformat; + unsigned int width = fmt->fmt.pix.width; + unsigned int height = fmt->fmt.pix.height; switch (src_pix_fmt) { case V4L2_PIX_FMT_PJPG: @@ -554,12 +592,14 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, if (header_width != width || header_height != height) { /* Check for (pixart) rotated JPEG */ if (header_width == height && header_height == width) { - if (!(data->flags & V4LCONVERT_ROTATE_90)) { + if (!(data->flags & V4LCONVERT_JPEG_ROTATE_90_HACK)) { V4LCONVERT_ERR("JPEG needs 90 degree rotation\n"); - data->flags |= V4LCONVERT_ROTATE_90; + data->flags |= V4LCONVERT_JPEG_ROTATE_90_HACK; errno = EAGAIN; return -1; } + fmt->fmt.pix.width = header_width; + fmt->fmt.pix.height = header_height; } else { V4LCONVERT_ERR("unexpected width / height in JPEG header" "expected: %ux%u, header: %ux%u\n", width, height, @@ -690,6 +730,7 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, case V4L2_PIX_FMT_SQ905C: { unsigned char *tmpbuf; + struct v4l2_format tmpfmt = *fmt; tmpbuf = v4lconvert_alloc_buffer(data, width * height, &data->convert_pixfmt_buf, &data->convert_pixfmt_buf_size); @@ -699,27 +740,31 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, switch (src_pix_fmt) { case V4L2_PIX_FMT_SPCA561: v4lconvert_decode_spca561(src, tmpbuf, width, height); - src_pix_fmt = V4L2_PIX_FMT_SGBRG8; + tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SGBRG8; break; case V4L2_PIX_FMT_SN9C10X: v4lconvert_decode_sn9c10x(src, tmpbuf, width, height); - src_pix_fmt = V4L2_PIX_FMT_SBGGR8; + tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8; break; case V4L2_PIX_FMT_PAC207: v4lconvert_decode_pac207(src, tmpbuf, width, height); - src_pix_fmt = V4L2_PIX_FMT_SBGGR8; + tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8; break; case V4L2_PIX_FMT_MR97310A: v4lconvert_decode_mr97310a(src, tmpbuf, width, height); - src_pix_fmt = V4L2_PIX_FMT_SBGGR8; + tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8; break; case V4L2_PIX_FMT_SQ905C: v4lconvert_decode_sq905c(src, tmpbuf, width, height); - src_pix_fmt = V4L2_PIX_FMT_SRGGB8; + tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SRGGB8; break; } - src = tmpbuf; + /* Do processing on the tmp buffer, because doing it on bayer data is + cheaper, and bayer == rgb and our dest_fmt may be yuv */ + v4lprocessing_processing(data->processing, tmpbuf, &tmpfmt); /* Deliberate fall through to raw bayer fmt code! */ + src_pix_fmt = tmpfmt.fmt.pix.pixelformat; + src = tmpbuf; } /* Raw bayer formats */ @@ -749,10 +794,10 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, v4lconvert_swap_rgb(src, dest, width, height); break; case V4L2_PIX_FMT_YUV420: - v4lconvert_rgb24_to_yuv420(src, dest, src_fmt, 0, 0); + v4lconvert_rgb24_to_yuv420(src, dest, fmt, 0, 0); break; case V4L2_PIX_FMT_YVU420: - v4lconvert_rgb24_to_yuv420(src, dest, src_fmt, 0, 1); + v4lconvert_rgb24_to_yuv420(src, dest, fmt, 0, 1); break; } break; @@ -763,10 +808,10 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, v4lconvert_swap_rgb(src, dest, width, height); break; case V4L2_PIX_FMT_YUV420: - v4lconvert_rgb24_to_yuv420(src, dest, src_fmt, 1, 0); + v4lconvert_rgb24_to_yuv420(src, dest, fmt, 1, 0); break; case V4L2_PIX_FMT_YVU420: - v4lconvert_rgb24_to_yuv420(src, dest, src_fmt, 1, 1); + v4lconvert_rgb24_to_yuv420(src, dest, fmt, 1, 1); break; } break; @@ -782,7 +827,7 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, height, 0); break; case V4L2_PIX_FMT_YVU420: - v4lconvert_swap_uv(src, dest, src_fmt); + v4lconvert_swap_uv(src, dest, fmt); break; } break; @@ -798,7 +843,7 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, height, 1); break; case V4L2_PIX_FMT_YUV420: - v4lconvert_swap_uv(src, dest, src_fmt); + v4lconvert_swap_uv(src, dest, fmt); break; } break; @@ -861,6 +906,10 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, errno = EINVAL; return -1; } + + fmt->fmt.pix.pixelformat = dest_pix_fmt; + v4lconvert_fixup_fmt(fmt); + return 0; } @@ -869,8 +918,11 @@ int v4lconvert_convert(struct v4lconvert_data *data, const struct v4l2_format *dest_fmt, /* in */ unsigned char *src, int src_size, unsigned char *dest, int dest_size) { - int res, dest_needed, temp_needed, convert = 0, rotate = 0, crop = 0; - unsigned char *convert_dest = dest, *rotate_src = src, *rotate_dest = dest; + int res, dest_needed, temp_needed, processing, convert = 0, crop = 0; + unsigned char *convert1_dest = dest; + unsigned char *convert2_src = src, *convert2_dest = dest; + unsigned char *rotate90_src = src, *rotate90_dest = dest; + unsigned char *flip_src = src, *flip_dest = dest; unsigned char *crop_src = src; struct v4l2_format my_src_fmt = *src_fmt; struct v4l2_format my_dest_fmt = *dest_fmt; @@ -915,52 +967,98 @@ int v4lconvert_convert(struct v4lconvert_data *data, return -1; } - if (my_dest_fmt.fmt.pix.pixelformat != my_src_fmt.fmt.pix.pixelformat) - convert = 1; + processing = v4lprocessing_pre_processing(data->processing); - if (data->flags & V4LCONVERT_ROTATE_90) - rotate += 90; - if (data->flags & V4LCONVERT_ROTATE_180) - rotate += 180; + /* Sometimes we need foo -> rgb -> bar as video processing (whitebalance, + etc.) can only be done on rgb data */ + if (processing && v4lconvert_processing_needs_double_conversion( + my_src_fmt.fmt.pix.pixelformat, + my_dest_fmt.fmt.pix.pixelformat)) + convert = 2; + else if (my_dest_fmt.fmt.pix.pixelformat != my_src_fmt.fmt.pix.pixelformat) + convert = 1; if (my_dest_fmt.fmt.pix.width != my_src_fmt.fmt.pix.width || my_dest_fmt.fmt.pix.height != my_src_fmt.fmt.pix.height) crop = 1; - /* convert_pixfmt -> rotate -> crop, all steps are optional */ - if (convert && (rotate || crop)) { - convert_dest = v4lconvert_alloc_buffer(data, temp_needed, - &data->convert_buf, &data->convert_buf_size); - if (!convert_dest) + /* convert_pixfmt (only if convert == 2) -> processing -> convert_pixfmt -> + rotate -> flip -> crop, all steps are optional */ + if (convert == 2) { + convert1_dest = v4lconvert_alloc_buffer(data, + my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3, + &data->convert1_buf, &data->convert1_buf_size); + if (!convert1_dest) return -1; - rotate_src = crop_src = convert_dest; + convert2_src = convert1_dest; } - if (rotate && crop) { - rotate_dest = v4lconvert_alloc_buffer(data, temp_needed, - &data->rotate_buf, &data->rotate_buf_size); - if (!rotate_dest) + if (convert && (data->flags & (V4LCONVERT_JPEG_ROTATE_90_HACK | + V4LCONVERT_VFLIP | V4LCONVERT_HFLIP) || crop)) { + convert2_dest = v4lconvert_alloc_buffer(data, temp_needed, + &data->convert2_buf, &data->convert2_buf_size); + if (!convert2_dest) return -1; - crop_src = rotate_dest; + rotate90_src = flip_src = crop_src = convert2_dest; } - if (convert) { - res = v4lconvert_convert_pixfmt(data, src, src_size, convert_dest, + if ((data->flags & V4LCONVERT_JPEG_ROTATE_90_HACK) && + ((data->flags & (V4LCONVERT_VFLIP | V4LCONVERT_HFLIP)) || crop)) { + rotate90_dest = v4lconvert_alloc_buffer(data, temp_needed, + &data->rotate90_buf, &data->rotate90_buf_size); + if (!rotate90_dest) + return -1; + + flip_src = crop_src = rotate90_dest; + } + + if ((data->flags & (V4LCONVERT_VFLIP | V4LCONVERT_HFLIP)) && crop) { + flip_dest = v4lconvert_alloc_buffer(data, temp_needed, &data->flip_buf, + &data->flip_buf_size); + if (!flip_dest) + return -1; + + crop_src = flip_dest; + } + + /* Done setting sources / dest and allocating intermediate buffers, + real conversion / processing / ... starts here. */ + if (convert == 2) { + res = v4lconvert_convert_pixfmt(data, src, src_size, convert1_dest, &my_src_fmt, + V4L2_PIX_FMT_RGB24); + if (res) + return res; + + src_size = my_src_fmt.fmt.pix.sizeimage; + } + + if (processing) + v4lprocessing_processing(data->processing, convert2_src, &my_src_fmt); + + if (convert) { + res = v4lconvert_convert_pixfmt(data, convert2_src, src_size, + convert2_dest, &my_src_fmt, my_dest_fmt.fmt.pix.pixelformat); if (res) return res; - my_src_fmt.fmt.pix.pixelformat = my_dest_fmt.fmt.pix.pixelformat; - v4lconvert_fixup_fmt(&my_src_fmt); + src_size = my_src_fmt.fmt.pix.sizeimage; } - if (rotate) - v4lconvert_rotate(rotate_src, rotate_dest, - my_src_fmt.fmt.pix.width, my_src_fmt.fmt.pix.height, - my_src_fmt.fmt.pix.pixelformat, rotate); + /* We call processing here again in case the source format was not + rgb, but the dest is. v4lprocessing checks it self it only actually + does the processing once per frame. */ + if (processing) + v4lprocessing_processing(data->processing, rotate90_src, &my_src_fmt); + + if (data->flags & V4LCONVERT_JPEG_ROTATE_90_HACK) + v4lconvert_rotate90(rotate90_src, rotate90_dest, &my_src_fmt); + + if (data->flags & (V4LCONVERT_VFLIP | V4LCONVERT_HFLIP)) + v4lconvert_flip(flip_src, flip_dest, &my_src_fmt, data->flags); if (crop) v4lconvert_crop(crop_src, dest, &my_src_fmt, &my_dest_fmt); @@ -1135,3 +1233,15 @@ int v4lconvert_enum_frameintervals(struct v4lconvert_data *data, return res; } + +int v4lconvert_vidioc_queryctrl(struct v4lconvert_data *data, void *arg) { + return v4lcontrol_vidioc_queryctrl(data->control, arg); +} + +int v4lconvert_vidioc_g_ctrl(struct v4lconvert_data *data, void *arg) { + return v4lcontrol_vidioc_g_ctrl(data->control, arg); +} + +int v4lconvert_vidioc_s_ctrl(struct v4lconvert_data *data, void *arg){ + return v4lcontrol_vidioc_s_ctrl(data->control, arg); +} diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/bayerprocessing.c b/v4l2-apps/libv4l/libv4lconvert/processing/bayerprocessing.c new file mode 100644 index 000000000..f4cc9922b --- /dev/null +++ b/v4l2-apps/libv4l/libv4lconvert/processing/bayerprocessing.c @@ -0,0 +1,244 @@ +/* +# (C) 2008-2009 Elmar Kleijn +# (C) 2008-2009 Sjoerd Piepenbrink +# (C) 2008-2009 Hans de Goede + +# 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 "libv4lprocessing-priv.h" +#include "../libv4lconvert-priv.h" /* for PIX_FMT defines */ + +void bayer_normalize_analyse(unsigned char *buf, int width, int height, + struct v4lprocessing_data *data) +{ + int value, max = 0, min = 255; + unsigned char *buf_end = buf + width * height; + + while (buf < buf_end) { + value = *buf++; + if (max < value) + max = value; + if (min > value) + min = value; + } + + data->comp1 = ((data->norm_high_bound - data->norm_low_bound) << 16) / (max - min); + data->offset1 = min; + data->offset2 = data->norm_low_bound; +} + +void bayer_whitebalance_analyse(unsigned char *src_buffer, int width, + int height, unsigned int pix_fmt, struct v4lprocessing_data *data) +{ + int i, j, x1 = 0, x2 = 0, y1 = 0, y2 = 0; + float green_avg, x_avg, y_avg, avg_avg; + unsigned char *buf = src_buffer; + + int start_with_green = pix_fmt == V4L2_PIX_FMT_SGBRG8 || + pix_fmt == V4L2_PIX_FMT_SGRBG8; + + for (i = 0; i < height; i += 2) { + for (j = 0; j < width; j += 2) { + x1 += *buf++; + x2 += *buf++; + } + for (j = 0; j < width; j += 2) { + y1 += *buf++; + y2 += *buf++; + } + } + + if (start_with_green) { + green_avg = (x1 + y2) / 2; + x_avg = x2; + y_avg = y1; + } else { + green_avg = (x2 + y1) / 2; + x_avg = x1; + y_avg = y2; + } + + avg_avg = (green_avg + x_avg + y_avg) / 3; + + data->comp1 = (avg_avg / green_avg) * 65536; + data->comp2 = (avg_avg / x_avg) * 65536; + data->comp3 = (avg_avg / y_avg) * 65536; +} + +void bayer_normalize_whitebalance_analyse(unsigned char *buf, int width, + int height, unsigned int pix_fmt, struct v4lprocessing_data *data) +{ + int i, j, value, max = 0, min = 255, n_fac, x1 = 0, x2 = 0, y1 = 0, y2 = 0; + float green_avg, x_avg, y_avg, avg_avg; + + int start_with_green = pix_fmt == V4L2_PIX_FMT_SGBRG8 || + pix_fmt == V4L2_PIX_FMT_SGRBG8; + + for (i = 0; i < height; i += 2) { + for (j = 0; j < width; j += 2) { + x1 += *buf; + value = *buf++; + if (max < value) + max = value; + if (min > value) + min = value; + x2 += *buf; + value = *buf++; + if (max < value) + max = value; + if (min > value) + min = value; + } + for (j = 0; j < width; j += 2) { + y1 += *buf; + value = *buf++; + if (max < value) + max = value; + if (min > value) + min = value; + y2 += *buf; + value = *buf++; + if (max < value) + max = value; + if (min > value) + min = value; + } + } + + if (start_with_green) { + green_avg = (x1 + y2) / 2; + x_avg = x2; + y_avg = y1; + } else { + green_avg = (x2 + y1) / 2; + x_avg = x1; + y_avg = y2; + } + + n_fac = ((data->norm_high_bound - data->norm_low_bound) << 16) / (max - min); + + avg_avg = (green_avg + x_avg + y_avg) / 3; + + data->comp1 = (avg_avg / green_avg) * n_fac; + data->comp2 = (avg_avg / x_avg) * n_fac; + data->comp3 = (avg_avg / y_avg) * n_fac; + + data->offset1 = min; + data->offset2 = data->norm_low_bound; +} + +#define CLIP(color) (unsigned char)(((color)>0xff)?0xff:(((color)<0)?0:(color))) +#define TOP(color) (unsigned char)(((color)>0xff)?0xff:(color)) + +void bayer_normalize(unsigned char *buf, int width, + int height, struct v4lprocessing_data *data) +{ + int value; + unsigned char *buf_end = buf + width * height; + + while (buf < buf_end) { + value = ((data->comp1 * (*buf - data->offset1)) >> 16) + data->offset2; + *buf++ = CLIP(value); + } +} + +void bayer_whitebalance(unsigned char *src_buffer, int width, + int height, unsigned int pix_fmt, + struct v4lprocessing_data *data) +{ + int i, j, value; + int limit = width * height; + unsigned char *buf = src_buffer; + + int start_with_green = pix_fmt == V4L2_PIX_FMT_SGBRG8 || + pix_fmt == V4L2_PIX_FMT_SGRBG8; + + if (start_with_green) { + for (i = 0; i < height; i += 2) { + for (j = 0; j < width; j += 2) { + value = (*buf * data->comp1) >> 16; + *buf++ = TOP(value); + value = (*buf * data->comp2) >> 16; + *buf++ = TOP(value); + } + for (j = 0; j < width; j += 2) { + value = (*buf * data->comp3) >> 16; + *buf++ = TOP(value); + value = (*buf * data->comp1) >> 16; + *buf++ = TOP(value); + } + } + } else { + for (i = 0; i < height; i += 2) { + for (j = 0; j < width; j += 2) { + value = (*buf * data->comp2) >> 16; + *buf++ = TOP(value); + value = (*buf * data->comp1) >> 16; + *buf++ = TOP(value); + } + for (j = 0; j < width; j += 2) { + value = (*buf * data->comp1) >> 16; + *buf++ = TOP(value); + value = (*buf * data->comp3) >> 16; + *buf++ = TOP(value); + } + } + } +} + +void bayer_normalize_whitebalance(unsigned char *src_buffer, int width, + int height, unsigned int pix_fmt, + struct v4lprocessing_data *data) +{ + int i, j, value; + int limit = width * height; + unsigned char *buf = src_buffer; + + int start_with_green = pix_fmt == V4L2_PIX_FMT_SGBRG8 || + pix_fmt == V4L2_PIX_FMT_SGRBG8; + + if (start_with_green) { + for (i = 0; i < height; i += 2) { + for (j = 0; j < width; j += 2) { + value = ((data->comp1 * (*buf - data->offset1)) >> 16) + data->offset2; + *buf++ = CLIP(value); + value = ((data->comp2 * (*buf - data->offset1)) >> 16) + data->offset2; + *buf++ = CLIP(value); + } + for (j = 0; j < width; j += 2) { + value = ((data->comp3 * (*buf - data->offset1)) >> 16) + data->offset2; + *buf++ = CLIP(value); + value = ((data->comp1 * (*buf - data->offset1)) >> 16) + data->offset2; + *buf++ = CLIP(value); + } + } + } else { + for (i = 0; i < height; i += 2) { + for (j = 0; j < width; j += 2) { + value = ((data->comp2 * (*buf - data->offset1)) >> 16) + data->offset2; + *buf++ = CLIP(value); + value = ((data->comp1 * (*buf - data->offset1)) >> 16) + data->offset2; + *buf++ = CLIP(value); + } + for (j = 0; j < width; j += 2) { + value = ((data->comp1 * (*buf - data->offset1)) >> 16) + data->offset2; + *buf++ = CLIP(value); + value = ((data->comp3 * (*buf - data->offset1)) >> 16) + data->offset2; + *buf++ = CLIP(value); + } + } + } +} diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h new file mode 100644 index 000000000..f2aae373d --- /dev/null +++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h @@ -0,0 +1,89 @@ +/* +# (C) 2008-2009 Elmar Kleijn +# (C) 2008-2009 Sjoerd Piepenbrink +# (C) 2008-2009 Hans de Goede + +# 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 +*/ + +#ifndef __LIBV4LPROCESSING_PRIV_H +#define __LIBV4LPROCESSING_PRIV_H + +#include "../control/libv4lcontrol.h" + +#define V4L2PROCESSING_PROCESS_NONE 0x00 +#define V4L2PROCESSING_PROCESS_NORMALIZE 0x01 +#define V4L2PROCESSING_PROCESS_WHITEBALANCE 0x02 +#define V4L2PROCESSING_PROCESS_NORMALIZE_WHITEBALANCE 0x03 +#define V4L2PROCESSING_PROCESS_RGB_NORMALIZE 0x01 +#define V4L2PROCESSING_PROCESS_RGB_WHITEBALANCE 0x02 +#define V4L2PROCESSING_PROCESS_RGB_NORMALIZE_WHITEBALANCE 0x03 +#define V4L2PROCESSING_PROCESS_BAYER_NORMALIZE 0x11 +#define V4L2PROCESSING_PROCESS_BAYER_WHITEBALANCE 0x12 +#define V4L2PROCESSING_PROCESS_BAYER_NORMALIZE_WHITEBALANCE 0x13 + +#define V4L2PROCESSING_UPDATE_RATE 10 + +struct v4lprocessing_data { + struct v4lcontrol_data *control; + int do_process; + /* Provides the current type of processing */ + int process; + int norm_low_bound; + int norm_high_bound; + /* Counts the number of processed frames until a + V4L2PROCESSING_UPDATE_RATE overflow happens */ + int processing_data_update; + /* Multiplication factors and offsets from the analyse functions */ + int comp1; + int comp2; + int comp3; + int comp4; + int offset1; + int offset2; +}; + +/* Processing Bayer */ +void bayer_normalize_analyse(unsigned char *src_buffer, int width, int height, + struct v4lprocessing_data *data); +void bayer_whitebalance_analyse(unsigned char *src_buffer, int width, + int height, unsigned int pix_fmt, + struct v4lprocessing_data *data); +void bayer_normalize_whitebalance_analyse(unsigned char *src_buffer, + int width, int height, unsigned int pix_fmt, + struct v4lprocessing_data *data); +void bayer_normalize(unsigned char *src_buffer, int width, int height, + struct v4lprocessing_data *data); +void bayer_whitebalance(unsigned char *src_buffer, int width, int height, + unsigned int pix_fmt, struct v4lprocessing_data *data); +void bayer_normalize_whitebalance(unsigned char *src_buffer, int width, + int height, unsigned int pix_fmt, + struct v4lprocessing_data *data); + +/* Processing RGB */ +void rgb_normalize_analyse(unsigned char *src_buffer, int width, int height, + struct v4lprocessing_data *data); +void rgb_whitebalance_analyse(unsigned char *src_buffer, int width, int height, + struct v4lprocessing_data *data); +void rgb_normalize_whitebalance_analyse(unsigned char *src_buffer, + int width, int height, struct v4lprocessing_data *data); +void rgb_normalize(unsigned char *src_buffer, int width, int height, + struct v4lprocessing_data *data); +void rgb_whitebalance(unsigned char *src_buffer, int width, int height, + struct v4lprocessing_data *data); +void rgb_normalize_whitebalance(unsigned char *src_buffer, int width, + int height, struct v4lprocessing_data *data); + +#endif diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c new file mode 100644 index 000000000..d61c29275 --- /dev/null +++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c @@ -0,0 +1,179 @@ +/* +# (C) 2008-2009 Elmar Kleijn +# (C) 2008-2009 Sjoerd Piepenbrink +# (C) 2008-2009 Hans de Goede + +# 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 +#include +#include +#include +#include +#include +#include "libv4lprocessing.h" +#include "libv4lprocessing-priv.h" +#include "../libv4lconvert-priv.h" /* for PIX_FMT defines */ + +struct v4lprocessing_data *v4lprocessing_create(struct v4lcontrol_data* control) +{ + struct v4lprocessing_data *data = + calloc(1, sizeof(struct v4lprocessing_data)); + + if (!data) + return NULL; + + data->control = control; + + return data; +} + +void v4lprocessing_destroy(struct v4lprocessing_data *data) +{ + free(data); +} + +static int v4lprocessing_get_process(struct v4lprocessing_data *data, + unsigned int pix_fmt) +{ + int process = V4L2PROCESSING_PROCESS_NONE; + + switch(pix_fmt) { + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + if (v4lcontrol_get_ctrl(data->control, V4LCONTROL_NORMALIZE)) { + process |= V4L2PROCESSING_PROCESS_BAYER_NORMALIZE; + } + if (v4lcontrol_get_ctrl(data->control, V4LCONTROL_WHITEBALANCE)) { + process |= V4L2PROCESSING_PROCESS_BAYER_WHITEBALANCE; + } + break; + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + if (v4lcontrol_get_ctrl(data->control, V4LCONTROL_NORMALIZE)) { + process |= V4L2PROCESSING_PROCESS_RGB_NORMALIZE; + } + if (v4lcontrol_get_ctrl(data->control, V4LCONTROL_WHITEBALANCE)) { + process |= V4L2PROCESSING_PROCESS_RGB_WHITEBALANCE; + } + break; + } + + return process; +} + +static void v4lprocessing_update_processing_data( + struct v4lprocessing_data *data, + unsigned int pix_fmt, unsigned char *buf, unsigned int width, + unsigned int height) +{ + switch (data->process) { + case V4L2PROCESSING_PROCESS_BAYER_NORMALIZE: + bayer_normalize_analyse(buf, width, height, data); + break; + + case V4L2PROCESSING_PROCESS_BAYER_WHITEBALANCE: + bayer_whitebalance_analyse(buf, width, height, pix_fmt, data); + break; + + case V4L2PROCESSING_PROCESS_BAYER_NORMALIZE_WHITEBALANCE: + bayer_normalize_whitebalance_analyse(buf, width, height, pix_fmt, data); + break; + + case V4L2PROCESSING_PROCESS_RGB_NORMALIZE: + rgb_normalize_analyse(buf, width, height, data); + break; + + case V4L2PROCESSING_PROCESS_RGB_WHITEBALANCE: + rgb_whitebalance_analyse(buf, width, height, data); + break; + + case V4L2PROCESSING_PROCESS_RGB_NORMALIZE_WHITEBALANCE: + rgb_normalize_whitebalance_analyse(buf, width, height, data); + break; + } +} + +int v4lprocessing_pre_processing(struct v4lprocessing_data *data) +{ + data->do_process = + v4lcontrol_get_ctrl(data->control, V4LCONTROL_WHITEBALANCE) || + v4lcontrol_get_ctrl(data->control, V4LCONTROL_NORMALIZE); + + return data->do_process; +} + +void v4lprocessing_processing(struct v4lprocessing_data *data, + unsigned char *buf, const struct v4l2_format *fmt) +{ + int low_bound, high_bound, process; + + if (!data->do_process) + return; + + process = v4lprocessing_get_process(data, fmt->fmt.pix.pixelformat); + if (process == V4L2PROCESSING_PROCESS_NONE) { + data->process = process; + return; + } + + low_bound = v4lcontrol_get_ctrl(data->control, V4LCONTROL_NORM_LOW_BOUND); + high_bound = v4lcontrol_get_ctrl(data->control, V4LCONTROL_NORM_HIGH_BOUND); + + if (process != data->process || low_bound != data->norm_low_bound || + high_bound != data->norm_high_bound) { + data->process = process; + data->norm_low_bound = low_bound; + data->norm_high_bound = high_bound; + data->processing_data_update = V4L2PROCESSING_UPDATE_RATE; + } + + if (data->processing_data_update == V4L2PROCESSING_UPDATE_RATE) { + data->processing_data_update = 0; + v4lprocessing_update_processing_data(data, fmt->fmt.pix.pixelformat, buf, fmt->fmt.pix.width, fmt->fmt.pix.height); + } else + data->processing_data_update++; + + switch (data->process) { + case V4L2PROCESSING_PROCESS_BAYER_NORMALIZE: + bayer_normalize(buf, fmt->fmt.pix.width, fmt->fmt.pix.height, data); + break; + + case V4L2PROCESSING_PROCESS_BAYER_WHITEBALANCE: + bayer_whitebalance(buf, fmt->fmt.pix.width, fmt->fmt.pix.height, fmt->fmt.pix.pixelformat, data); + break; + + case V4L2PROCESSING_PROCESS_BAYER_NORMALIZE_WHITEBALANCE: + bayer_normalize_whitebalance(buf, fmt->fmt.pix.width, fmt->fmt.pix.height, fmt->fmt.pix.pixelformat, + data); + break; + + case V4L2PROCESSING_PROCESS_RGB_NORMALIZE: + rgb_normalize(buf, fmt->fmt.pix.width, fmt->fmt.pix.height, data); + break; + + case V4L2PROCESSING_PROCESS_RGB_WHITEBALANCE: + rgb_whitebalance(buf, fmt->fmt.pix.width, fmt->fmt.pix.height, data); + break; + + case V4L2PROCESSING_PROCESS_RGB_NORMALIZE_WHITEBALANCE: + rgb_normalize_whitebalance(buf, fmt->fmt.pix.width, fmt->fmt.pix.height, data); + break; + } + data->do_process = 0; +} diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.h b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.h new file mode 100644 index 000000000..3c50d9fb9 --- /dev/null +++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.h @@ -0,0 +1,48 @@ +/* +# (C) 2008-2009 Elmar Kleijn +# (C) 2008-2009 Sjoerd Piepenbrink +# (C) 2008-2009 Hans de Goede + +# 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 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 +*/ + +#ifndef __LIBV4LPROCESSING_H +#define __LIBV4LPROCESSING_H + +/* These headers are not needed by us, but by linux/videodev2.h, + which is broken on some systems and doesn't include them itself :( */ +#include +#include +#include +/* end broken header workaround includes */ +#include + +struct v4lprocessing_data; +struct v4lcontrol_data; + +struct v4lprocessing_data *v4lprocessing_create(struct v4lcontrol_data *data); +void v4lprocessing_destroy(struct v4lprocessing_data *data); + +/* Prepare to process 1 frame, returns 1 if processing is necesary, + return 0 if no processing will be done */ +int v4lprocessing_pre_processing(struct v4lprocessing_data *data); + +/* Do the actual processing, this is a nop if v4lprocessing_pre_processing() + returned 0, or if called more then 1 time after a single + v4lprocessing_pre_processing() call. */ +void v4lprocessing_processing(struct v4lprocessing_data *data, + unsigned char *buf, const struct v4l2_format *fmt); + +#endif diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/rgbprocessing.c b/v4l2-apps/libv4l/libv4lconvert/processing/rgbprocessing.c new file mode 100644 index 000000000..4e0fc3f4a --- /dev/null +++ b/v4l2-apps/libv4l/libv4lconvert/processing/rgbprocessing.c @@ -0,0 +1,156 @@ +/* +# (C) 2008-2009 Elmar Kleijn +# (C) 2008-2009 Sjoerd Piepenbrink +# (C) 2008-2009 Hans de Goede + +# 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 "libv4lprocessing-priv.h" + +void rgb_normalize_analyse(unsigned char *buf, int width, int height, + struct v4lprocessing_data *data) +{ + int value, max = 0, min = 255; + unsigned char *buf_end = buf + width * height * 3; + + while (buf < buf_end) { + value = *buf++; + if (max < value) + max = value; + if (min > value) + min = value; + } + + data->comp1 = ((data->norm_high_bound - data->norm_low_bound) << 16) / (max - min); + data->offset1 = min; + data->offset2 = data->norm_low_bound; +} + +void rgb_whitebalance_analyse(unsigned char *buf, int width, int height, + struct v4lprocessing_data *data) +{ + int value, x = 0, y = 0, z = 0; + float x_avg, y_avg, z_avg, avg_avg; + unsigned char *buf_end = buf + width * height * 3; + + while (buf < buf_end) { + x += *buf++; + y += *buf++; + z += *buf++; + } + + x_avg = x; + y_avg = y; + z_avg = z; + avg_avg = (x_avg + y_avg + z_avg) / 3; + + data->comp1 = (avg_avg / x_avg) * 65536; + data->comp2 = (avg_avg / y_avg) * 65536; + data->comp3 = (avg_avg / z_avg) * 65536; +} + +void rgb_normalize_whitebalance_analyse(unsigned char *buf, + int width, int height, struct v4lprocessing_data *data) +{ + int value, max = 0, min = 255; + int n_fac, wb_max, x = 0, y = 0, z = 0; + float x_avg, y_avg, z_avg, avg_avg; + unsigned char *buf_end = buf + width * height * 3; + + while (buf < buf_end) { + x += *buf; + value = *buf++; + if (max < value) + max = value; + if (min > value) + min = value; + y += *buf; + value = *buf++; + if (max < value) + max = value; + if (min > value) + min = value; + z += *buf; + value = *buf++; + if (max < value) + max = value; + if (min > value) + min = value; + } + + x_avg = x; + y_avg = y; + z_avg = z; + avg_avg = (x_avg + y_avg + z_avg) / 3; + + n_fac = ((data->norm_high_bound - data->norm_low_bound) << 16) / (max - min); + + data->comp1 = (avg_avg / x_avg) * n_fac; + data->comp2 = (avg_avg / y_avg) * n_fac; + data->comp3 = (avg_avg / z_avg) * n_fac; + + data->offset1 = min; + data->offset2 = data->norm_low_bound; +} + +#define CLIP(color) (unsigned char)(((color)>0xff)?0xff:(((color)<0)?0:(color))) +#define TOP(color) (unsigned char)(((color)>0xff)?0xff:(color)) + +void rgb_normalize(unsigned char *buf, int width, int height, + struct v4lprocessing_data *data) +{ + int value; + unsigned char *buf_end = buf + width * height * 3; + + while (buf < buf_end) { + value = ((data->comp1 * (*buf - data->offset1)) >> 16) + + data->offset2; + *buf++ = CLIP(value); + } +} + +void rgb_whitebalance(unsigned char *buf, int width, int height, + struct v4lprocessing_data *data) +{ + int value; + unsigned char *buf_end = buf + width * height * 3; + + while (buf < buf_end) { + value = (*buf * data->comp1) >> 16; + *buf++ = TOP(value); + value = (*buf * data->comp2) >> 16; + *buf++ = TOP(value); + value = (*buf * data->comp3) >> 16; + *buf++ = TOP(value); + } +} + +void rgb_normalize_whitebalance(unsigned char *buf, int width, int height, + struct v4lprocessing_data *data) +{ + int i, value; + int limit = width * height * 3; + unsigned char *buf_end = buf + width * height * 3; + + while (buf < buf_end) { + value = ((data->comp1 * (*buf - data->offset1)) >> 16) + data->offset2; + *buf++ = CLIP(value); + value = ((data->comp2 * (*buf - data->offset1)) >> 16) + data->offset2; + *buf++ = CLIP(value); + value = ((data->comp3 * (*buf - data->offset1)) >> 16) + data->offset2; + *buf++ = CLIP(value); + } +} -- cgit v1.2.3 From b1352a9018aeac6722d2e8d606f9c0ea140e0abd Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Mon, 13 Apr 2009 21:56:28 +0200 Subject: libv4l: Fix video processing parameter updating From: Hans de Goede Unless the source format of a conversion was a format supported to do processing on we would update the processing parameters each frame instead of every 10 frames Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c index d61c29275..f986da02d 100644 --- a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c +++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c @@ -115,6 +115,9 @@ int v4lprocessing_pre_processing(struct v4lprocessing_data *data) v4lcontrol_get_ctrl(data->control, V4LCONTROL_WHITEBALANCE) || v4lcontrol_get_ctrl(data->control, V4LCONTROL_NORMALIZE); + if (!data->do_process) + data->process = V4L2PROCESSING_PROCESS_NONE; + return data->do_process; } @@ -128,7 +131,6 @@ void v4lprocessing_processing(struct v4lprocessing_data *data, process = v4lprocessing_get_process(data, fmt->fmt.pix.pixelformat); if (process == V4L2PROCESSING_PROCESS_NONE) { - data->process = process; return; } -- cgit v1.2.3 From 10a09b9ec6e08fb95c36f26d7f69834b0387386b Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Tue, 14 Apr 2009 09:51:35 +0200 Subject: libv4l: Enable whitebalancing algorithm based on USB id's From: Hans de Goede * 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 --- v4l2-apps/libv4l/TODO | 7 + .../libv4lconvert/control/libv4lcontrol-priv.h | 21 ++- .../libv4l/libv4lconvert/control/libv4lcontrol.c | 159 +++++++++++++++++++-- .../libv4l/libv4lconvert/control/libv4lcontrol.h | 7 + v4l2-apps/libv4l/libv4lconvert/flip.c | 5 +- .../libv4l/libv4lconvert/libv4lconvert-priv.h | 25 +--- v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 128 +++-------------- 7 files changed, 202 insertions(+), 150 deletions(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/TODO b/v4l2-apps/libv4l/TODO index 2bd2fc992..f1aac5a95 100644 --- a/v4l2-apps/libv4l/TODO +++ b/v4l2-apps/libv4l/TODO @@ -9,5 +9,12 @@ -take the possibility of pitch != width into account everywhere + -only report faked formats in list formats and only allow setting fake formats when processing or flipping. + +-make updating of parameters happen based on time elapsed rather then + frames + +-add fake flip controls on devices where we are already limiting the + formats which can be set 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 -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 */ + } + + /* 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 */ diff --git a/v4l2-apps/libv4l/libv4lconvert/flip.c b/v4l2-apps/libv4l/libv4lconvert/flip.c index 9835f045c..cc9526493 100644 --- a/v4l2-apps/libv4l/libv4lconvert/flip.c +++ b/v4l2-apps/libv4l/libv4lconvert/flip.c @@ -20,6 +20,7 @@ */ +#include #include "libv4lconvert-priv.h" static void v4lconvert_rotate180_rgbbgr24(const unsigned char *src, @@ -134,7 +135,7 @@ void v4lconvert_flip(unsigned char *src, unsigned char *dest, { /* FIXME implement separate vflipping and hflipping, for now we always rotate 180 when vflip is selected! */ - if (flags & V4LCONVERT_VFLIP) { + if (flags & V4LCONTROL_VFLIPPED) { switch (fmt->fmt.pix.pixelformat) { case V4L2_PIX_FMT_RGB24: case V4L2_PIX_FMT_BGR24: @@ -148,4 +149,6 @@ void v4lconvert_flip(unsigned char *src, unsigned char *dest, break; } } + else /* FIXME and do nothing when only HFLIP is selected */ + memcpy(dest, src, fmt->fmt.pix.sizeimage); } diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h index acf921a31..4a333d9a9 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h @@ -83,14 +83,6 @@ #define V4L2_PIX_FMT_SN9C20X_I420 v4l2_fourcc('S', '9', '2', '0') #endif -#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 - #define V4LCONVERT_ERROR_MSG_SIZE 256 #define V4LCONVERT_MAX_FRAMESIZES 16 @@ -100,11 +92,8 @@ "v4l-convert: error " __VA_ARGS__) /* Card flags */ -#define V4LCONVERT_HFLIP 0x01 -#define V4LCONVERT_VFLIP 0x02 -#define V4LCONVERT_JPEG_ROTATE_90_HACK 0x04 -#define V4LCONVERT_IS_UVC 0x08 -#define V4LCONVERT_IS_SN9C20X 0x10 +#define V4LCONVERT_IS_UVC 0x01 +#define V4LCONVERT_IS_SN9C20X 0x02 /* Pixformat flags */ #define V4LCONVERT_COMPRESSED 0x01 @@ -112,6 +101,7 @@ struct v4lconvert_data { int fd; int flags; /* bitfield */ + int control_flags; /* bitfield */ int supported_src_formats; /* bitfield */ unsigned int no_formats; char error_msg[V4LCONVERT_ERROR_MSG_SIZE]; @@ -132,15 +122,6 @@ struct v4lconvert_data { struct v4lprocessing_data *processing; }; -struct v4lconvert_flags_info { - unsigned short vendor_id; - unsigned short product_id; -/* We could also use the USB manufacturer and product strings some devices have - const char *manufacturer; - const char *product; */ - int flags; -}; - struct v4lconvert_pixfmt { unsigned int fmt; int flags; diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index 6fbc1affa..5ec85324e 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -70,14 +70,6 @@ static const struct v4lconvert_pixfmt supported_dst_pixfmts[] = { SUPPORTED_DST_PIXFMTS }; -/* List of cams which need special flags */ -static const struct v4lconvert_flags_info v4lconvert_flags[] = { - { 0x0471, 0x0325, V4LCONVERT_HFLIP|V4LCONVERT_VFLIP }, /* Philips SPC200NC */ - { 0x0471, 0x0326, V4LCONVERT_HFLIP|V4LCONVERT_VFLIP }, /* Philips SPC300NC */ - { 0x0471, 0x032d, V4LCONVERT_HFLIP|V4LCONVERT_VFLIP }, /* Philips SPC210NC */ - { 0x093a, 0x2476, V4LCONVERT_HFLIP|V4LCONVERT_VFLIP }, /* Genius E-M 112 */ -}; - /* List of well known resolutions which we can get by cropping somewhat larger resolutions */ static const int v4lconvert_crop_res[][2] = { @@ -91,95 +83,11 @@ static const int v4lconvert_crop_res[][2] = { { 176, 144 }, }; -static int v4lconvert_get_flags(int fd) -{ - 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]; - - if (fstat(fd, &st) || !S_ISCHR(st.st_mode)) - return 0; /* Should never happen */ - - /* 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 0; /* 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 0; /* 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 0; /* 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 0; /* 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 0; /* Should never happen */ - - s = fgets(buf, sizeof(buf), f); - fclose(f); - - if (!s || sscanf(s, "%04hx%c", &product_id, &c) != 2 || c != '\n') - return 0; /* Should never happen */ - } - - for (i = 0; i < ARRAY_SIZE(v4lconvert_flags); i++) - if (v4lconvert_flags[i].vendor_id == vendor_id && - v4lconvert_flags[i].product_id == product_id) - return v4lconvert_flags[i].flags; - - return 0; -} - struct v4lconvert_data *v4lconvert_create(int fd) { int i, j; struct v4lconvert_data *data = calloc(1, sizeof(struct v4lconvert_data)); struct v4l2_capability cap; - struct v4l2_input input; if (!data) return NULL; @@ -206,14 +114,6 @@ struct v4lconvert_data *v4lconvert_create(int fd) data->no_formats = i; /* Check if this cam has any special flags */ - data->flags = v4lconvert_get_flags(data->fd); - if ((syscall(SYS_ioctl, fd, VIDIOC_G_INPUT, &input.index) == 0) && - (syscall(SYS_ioctl, fd, VIDIOC_ENUMINPUT, &input) == 0)) { - if (input.status & V4L2_IN_ST_HFLIP) - data->flags |= V4LCONVERT_HFLIP; - if (input.status & V4L2_IN_ST_VFLIP) - data->flags |= V4LCONVERT_VFLIP; - } if (syscall(SYS_ioctl, fd, VIDIOC_QUERYCAP, &cap) == 0) { if (!strcmp((char *)cap.driver, "uvcvideo")) data->flags |= V4LCONVERT_IS_UVC; @@ -226,6 +126,7 @@ struct v4lconvert_data *v4lconvert_create(int fd) free(data); return NULL; } + data->control_flags = v4lcontrol_get_flags(data->control); data->processing = v4lprocessing_create(data->control); if (!data->processing) { @@ -502,7 +403,7 @@ int v4lconvert_needs_conversion(struct v4lconvert_data *data, src_fmt->fmt.pix.pixelformat != dest_fmt->fmt.pix.pixelformat) return 1; /* Formats differ */ - if (!(data->flags & (V4LCONVERT_HFLIP|V4LCONVERT_VFLIP))) + if (!(data->control_flags & (V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED))) return 0; /* Formats identical and we don't need flip */ /* Formats are identical, but we need flip, do we support the dest_fmt? */ @@ -592,9 +493,12 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, if (header_width != width || header_height != height) { /* Check for (pixart) rotated JPEG */ if (header_width == height && header_height == width) { - if (!(data->flags & V4LCONVERT_JPEG_ROTATE_90_HACK)) { + if (!(data->control_flags & V4LCONTROL_ROTATED_90_JPEG)) { + fprintf(stderr, + "libv4lconvert: Unknown cam with 90° rotated JPEG, " + "please report this to \n"); V4LCONVERT_ERR("JPEG needs 90 degree rotation\n"); - data->flags |= V4LCONVERT_JPEG_ROTATE_90_HACK; + data->control_flags |= V4LCONTROL_ROTATED_90_JPEG; errno = EAGAIN; return -1; } @@ -994,8 +898,8 @@ int v4lconvert_convert(struct v4lconvert_data *data, convert2_src = convert1_dest; } - if (convert && (data->flags & (V4LCONVERT_JPEG_ROTATE_90_HACK | - V4LCONVERT_VFLIP | V4LCONVERT_HFLIP) || crop)) { + if (convert && ((data->control_flags & (V4LCONTROL_ROTATED_90_JPEG | + V4LCONTROL_VFLIPPED | V4LCONTROL_HFLIPPED)) || crop)) { convert2_dest = v4lconvert_alloc_buffer(data, temp_needed, &data->convert2_buf, &data->convert2_buf_size); if (!convert2_dest) @@ -1004,8 +908,9 @@ int v4lconvert_convert(struct v4lconvert_data *data, rotate90_src = flip_src = crop_src = convert2_dest; } - if ((data->flags & V4LCONVERT_JPEG_ROTATE_90_HACK) && - ((data->flags & (V4LCONVERT_VFLIP | V4LCONVERT_HFLIP)) || crop)) { + if ((data->control_flags & V4LCONTROL_ROTATED_90_JPEG) && + ((data->control_flags & (V4LCONTROL_VFLIPPED | V4LCONTROL_HFLIPPED)) || + crop)) { rotate90_dest = v4lconvert_alloc_buffer(data, temp_needed, &data->rotate90_buf, &data->rotate90_buf_size); if (!rotate90_dest) @@ -1014,7 +919,8 @@ int v4lconvert_convert(struct v4lconvert_data *data, flip_src = crop_src = rotate90_dest; } - if ((data->flags & (V4LCONVERT_VFLIP | V4LCONVERT_HFLIP)) && crop) { + if ((data->control_flags & (V4LCONTROL_VFLIPPED | V4LCONTROL_HFLIPPED)) && + crop) { flip_dest = v4lconvert_alloc_buffer(data, temp_needed, &data->flip_buf, &data->flip_buf_size); if (!flip_dest) @@ -1054,11 +960,11 @@ int v4lconvert_convert(struct v4lconvert_data *data, if (processing) v4lprocessing_processing(data->processing, rotate90_src, &my_src_fmt); - if (data->flags & V4LCONVERT_JPEG_ROTATE_90_HACK) + if (data->control_flags & V4LCONTROL_ROTATED_90_JPEG) v4lconvert_rotate90(rotate90_src, rotate90_dest, &my_src_fmt); - if (data->flags & (V4LCONVERT_VFLIP | V4LCONVERT_HFLIP)) - v4lconvert_flip(flip_src, flip_dest, &my_src_fmt, data->flags); + if (data->control_flags & (V4LCONTROL_VFLIPPED | V4LCONTROL_HFLIPPED)) + v4lconvert_flip(flip_src, flip_dest, &my_src_fmt, data->control_flags); if (crop) v4lconvert_crop(crop_src, dest, &my_src_fmt, &my_dest_fmt); -- cgit v1.2.3 From 58d3334b54c207b8e04e7035969e0c2acfa1ce73 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Tue, 14 Apr 2009 15:03:07 +0200 Subject: libv4l: Only allow supported destination formats when doing processing From: Hans de Goede Only report / allow supported destination formats in enum_fmt / try_fmt / g_fmt / s_fmt when processing, rotating or flipping. Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 8 ++ v4l2-apps/libv4l/TODO | 14 +++- v4l2-apps/libv4l/include/libv4lconvert.h | 21 ++++- v4l2-apps/libv4l/libv4l1/libv4l1.c | 17 ++-- v4l2-apps/libv4l/libv4l2/libv4l2.c | 8 ++ .../libv4l/libv4lconvert/control/libv4lcontrol.c | 5 ++ .../libv4l/libv4lconvert/control/libv4lcontrol.h | 5 ++ v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 91 +++++++++++++++------- 8 files changed, 127 insertions(+), 42 deletions(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index 52b429687..3a7d3f3a8 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -8,6 +8,14 @@ libv4l-0.5.97 for example v4l2ucp is there. The initial version of this code was written by 3 of my computer science students: Elmar Kleijn, Sjoerd Piepenbrink and Radjnies Bhansingh +* Currently whitebalancing gets enabled based on USB-ID's and it only gets + enabled for Pixart webcam's. You can force it being enabled with other + webcams by setting the environment variable LIBV4LCONTROL_CONTROLS, this + sets a bitmask enabling certain v4l2 controls which control the video + processing set it to 15 to enable both whitebalancing and normalize. You + can then change the settings using a v4l2 control panel like v4l2ucp +* Only report / allow supported destination formats in enum_fmt / try_fmt / + g_fmt / s_fmt when processing, rotating or flipping. * Add dependency generation to libv4l by: Gilles Gigan * Add support to use orientation from VIDIOC_ENUMINPUT by: Adam Baker diff --git a/v4l2-apps/libv4l/TODO b/v4l2-apps/libv4l/TODO index f1aac5a95..94c40b84e 100644 --- a/v4l2-apps/libv4l/TODO +++ b/v4l2-apps/libv4l/TODO @@ -10,11 +10,19 @@ -take the possibility of pitch != width into account everywhere --only report faked formats in list formats and only allow setting fake - formats when processing or flipping. - -make updating of parameters happen based on time elapsed rather then frames -add fake flip controls on devices where we are already limiting the formats which can be set + +-add reverse cropping (adding black borders) to get from 320x232 -> + 320x240, for zc3xx webcams with a broken (last row of jpeg blocks missing) + 320x240 mode + +-add software auto exposure (for spca561 cams) + +-change video processing to use a per component lookup table for easy combining of + of different effects in 1 pass + +-add gamma correction video processing diff --git a/v4l2-apps/libv4l/include/libv4lconvert.h b/v4l2-apps/libv4l/include/libv4lconvert.h index fcc31dace..7901b35dc 100644 --- a/v4l2-apps/libv4l/include/libv4lconvert.h +++ b/v4l2-apps/libv4l/include/libv4lconvert.h @@ -42,18 +42,30 @@ struct v4lconvert_data; LIBV4L_PUBLIC struct v4lconvert_data *v4lconvert_create(int fd); LIBV4L_PUBLIC void v4lconvert_destroy(struct v4lconvert_data *data); +/* When doing flipping / rotating / video-processing, only supported + destination formats can be used (as flipping / rotating / video-processing + is not supported on other formats). This function can be used to query + if that is the case. */ +LIBV4L_PUBLIC int v4lconvert_supported_dst_fmt_only( + struct v4lconvert_data *data); + /* With regards to dest_fmt just like VIDIOC_TRY_FMT, except that the try format will succeed and return the requested V4L2_PIX_FMT_foo in dest_fmt if the cam has a format from which v4lconvert can convert to dest_fmt. The real format to which the cam should be set is returned through src_fmt - when not NULL. */ + when not NULL. + Note that just like the real VIDIOC_TRY_FMT this function will change the + dest_fmt when not supported. This includes changing it to a supported + destination format when trying a native format of the camera and + v4lconvert_supported_dst_fmt_only() returns true. */ LIBV4L_PUBLIC int v4lconvert_try_format(struct v4lconvert_data *data, struct v4l2_format *dest_fmt, /* in / out */ struct v4l2_format *src_fmt /* out */ ); -/* Just like VIDIOC_ENUM_FMT, except that the emulated formats are added at - the end of the list */ +/* Like VIDIOC_ENUM_FMT, but the emulated formats are added at the end of the + list, except if flipping / processing is active for the device, then only + supported destination formats are listed */ LIBV4L_PUBLIC int v4lconvert_enum_fmt(struct v4lconvert_data *data, struct v4l2_fmtdesc *fmt); /* Is conversion necessary or can the app use the data directly? */ @@ -89,6 +101,9 @@ LIBV4L_PUBLIC int v4lconvert_vidioc_g_ctrl(struct v4lconvert_data *data, LIBV4L_PUBLIC int v4lconvert_vidioc_s_ctrl(struct v4lconvert_data *data, void *arg); +/* Is the passed in pixelformat supported as destination format ? */ +LIBV4L_PUBLIC int v4lconvert_supported_dst_format(unsigned int pixelformat); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/v4l2-apps/libv4l/libv4l1/libv4l1.c b/v4l2-apps/libv4l/libv4l1/libv4l1.c index 797c8768a..a7de0af8e 100644 --- a/v4l2-apps/libv4l/libv4l1/libv4l1.c +++ b/v4l2-apps/libv4l/libv4l1/libv4l1.c @@ -155,8 +155,10 @@ static int v4l1_set_format(int index, unsigned int width, /* Do we need to change the resolution / format ? */ if (width == devices[index].width && height == devices[index].height && - v4l2_pixfmt == devices[index].v4l2_pixfmt) + v4l2_pixfmt == devices[index].v4l2_pixfmt) { + devices[index].v4l1_pal = v4l1_pal; return 0; + } /* Get current settings, apply our changes and try the new setting */ if ((result = v4l2_ioctl(devices[index].fd, VIDIOC_G_FMT, &fmt2))) { @@ -308,19 +310,18 @@ int v4l1_open (const char *file, int oflag, ...) if (!v4l2_log_file) v4l2_log_file = v4l1_log_file; - /* Get initial width, height and pixelformat */ - fmt2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (syscall(SYS_ioctl, fd, VIDIOC_G_FMT, &fmt2)) { + /* Register with libv4l2, as we use that todo format conversion and read() + emulation for us */ + if (v4l2_fd_open(fd, V4L2_ENABLE_ENUM_FMT_EMULATION) == -1) { int saved_err = errno; - V4L1_LOG_ERR("getting pixformat: %s\n", strerror(errno)); syscall(SYS_close, fd); errno = saved_err; return -1; } - /* Register with libv4l2, as we use that todo format conversion and read() - emulation for us */ - if (v4l2_fd_open(fd, V4L2_ENABLE_ENUM_FMT_EMULATION) == -1) { + /* Get initial width, height and pixelformat */ + fmt2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (v4l2_ioctl(fd, VIDIOC_G_FMT, &fmt2)) { int saved_err = errno; syscall(SYS_close, fd); errno = saved_err; diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2.c b/v4l2-apps/libv4l/libv4l2/libv4l2.c index 91e0193ee..8d01b034c 100644 --- a/v4l2-apps/libv4l/libv4l2/libv4l2.c +++ b/v4l2-apps/libv4l/libv4l2/libv4l2.c @@ -516,6 +516,14 @@ int v4l2_fd_open(int fd, int v4l2_flags) V4L2_LOG("open: %d\n", fd); + if (v4lconvert_supported_dst_fmt_only(convert) && + !v4lconvert_supported_dst_format(fmt.fmt.pix.pixelformat)) { + V4L2_LOG("open %d: setting pixelformat to RGB24\n", fd); + fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24; + v4l2_ioctl(fd, VIDIOC_S_FMT, &fmt); + V4L2_LOG("open %d: done setting pixelformat\n", fd); + } + return fd; } diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c index de8b608f9..b09ffc582 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c @@ -339,3 +339,8 @@ int v4lcontrol_get_ctrl(struct v4lcontrol_data *data, int ctrl) return 0; } + +/* See the comment about this in libv4lconvert.h */ +int v4lcontrol_needs_conversion(struct v4lcontrol_data *data) { + return data->flags || data->controls; +} diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h index 344e68055..28308bc55 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h @@ -39,6 +39,11 @@ 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); +/* Check if we must go through the conversion path (and thus alloc conversion + buffers, etc. in libv4l2). Note this always return 1 if we *may* need + rotate90 / flipping / processing, as if we actually need this may change + on the fly while the stream is active. */ +int v4lcontrol_needs_conversion(struct v4lcontrol_data *data); /* Functions used by v4lconvert to pass vidioc calls from libv4l2 */ int v4lcontrol_vidioc_queryctrl(struct v4lcontrol_data *data, void *arg); diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index 5ec85324e..2e029a81c 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -155,7 +155,7 @@ void v4lconvert_destroy(struct v4lconvert_data *data) free(data); } -static int v4lconvert_supported_dst_format(unsigned int pixelformat) +int v4lconvert_supported_dst_format(unsigned int pixelformat) { int i; @@ -166,6 +166,12 @@ static int v4lconvert_supported_dst_format(unsigned int pixelformat) return i != ARRAY_SIZE(supported_dst_pixfmts); } +int v4lconvert_supported_dst_fmt_only(struct v4lconvert_data *data) +{ + return v4lcontrol_needs_conversion(data->control) && + data->supported_src_formats; +} + /* See libv4lconvert.h for description of in / out parameters */ int v4lconvert_enum_fmt(struct v4lconvert_data *data, struct v4l2_fmtdesc *fmt) { @@ -173,17 +179,22 @@ int v4lconvert_enum_fmt(struct v4lconvert_data *data, struct v4l2_fmtdesc *fmt) unsigned int faked_fmts[ARRAY_SIZE(supported_dst_pixfmts)]; if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - fmt->index < data->no_formats || - !data->supported_src_formats) + (!v4lconvert_supported_dst_fmt_only(data) && + fmt->index < data->no_formats)) return syscall(SYS_ioctl, data->fd, VIDIOC_ENUM_FMT, fmt); for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) - if (!(data->supported_src_formats & (1 << i))) { + if (v4lconvert_supported_dst_fmt_only(data) || + !(data->supported_src_formats & (1 << i))) { faked_fmts[no_faked_fmts] = supported_dst_pixfmts[i].fmt; no_faked_fmts++; } - i = fmt->index - data->no_formats; + if (!v4lconvert_supported_dst_fmt_only(data)) + i = fmt->index - data->no_formats; + else + i = fmt->index; + if (i >= no_faked_fmts) { errno = EINVAL; return -1; @@ -333,7 +344,14 @@ int v4lconvert_try_format(struct v4lconvert_data *data, int i, result; unsigned int desired_width = dest_fmt->fmt.pix.width; unsigned int desired_height = dest_fmt->fmt.pix.height; - struct v4l2_format try_src, try_dest = *dest_fmt; + struct v4l2_format try_src, try_dest; + + if (dest_fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && + v4lconvert_supported_dst_fmt_only(data) && + !v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat)) + dest_fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24; + + try_dest = *dest_fmt; /* Can we do conversion to the requested format & type? */ if (!v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat) || @@ -398,19 +416,14 @@ int v4lconvert_needs_conversion(struct v4lconvert_data *data, const struct v4l2_format *src_fmt, /* in */ const struct v4l2_format *dest_fmt) /* in */ { - if(src_fmt->fmt.pix.width != dest_fmt->fmt.pix.width || - src_fmt->fmt.pix.height != dest_fmt->fmt.pix.height || - src_fmt->fmt.pix.pixelformat != dest_fmt->fmt.pix.pixelformat) - return 1; /* Formats differ */ - - if (!(data->control_flags & (V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED))) - return 0; /* Formats identical and we don't need flip */ + if (src_fmt->fmt.pix.width != dest_fmt->fmt.pix.width || + src_fmt->fmt.pix.height != dest_fmt->fmt.pix.height || + src_fmt->fmt.pix.pixelformat != dest_fmt->fmt.pix.pixelformat || + (v4lcontrol_needs_conversion(data->control) && + v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat))) + return 1; - /* Formats are identical, but we need flip, do we support the dest_fmt? */ - if (!v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat)) - return 0; /* Needs flip but we cannot do it :( */ - else - return 1; /* Needs flip and thus conversion */ + return 0; } static int v4lconvert_processing_needs_double_conversion( @@ -494,12 +507,9 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, /* Check for (pixart) rotated JPEG */ if (header_width == height && header_height == width) { if (!(data->control_flags & V4LCONTROL_ROTATED_90_JPEG)) { - fprintf(stderr, - "libv4lconvert: Unknown cam with 90° rotated JPEG, " - "please report this to \n"); - V4LCONVERT_ERR("JPEG needs 90 degree rotation\n"); - data->control_flags |= V4LCONTROL_ROTATED_90_JPEG; - errno = EAGAIN; + V4LCONVERT_ERR("JPEG needs 90° rotation, please report " + "this to \n"); + errno = EIO; return -1; } fmt->fmt.pix.width = header_width; @@ -511,6 +521,13 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, errno = EIO; return -1; } + } else if ((data->control_flags & V4LCONTROL_ROTATED_90_JPEG)) { + fprintf(stderr, "libv4lconvert: expected 90° rotated JPEG, but got " + "normal JPEG, please report this to \n"); + V4LCONVERT_ERR("expected 90° rotated JPEG, but got normal JPEG\n"); + errno = EAGAIN; + data->control_flags &= ~V4LCONTROL_ROTATED_90_JPEG; + return -1; } components[0] = dest; @@ -831,8 +848,18 @@ int v4lconvert_convert(struct v4lconvert_data *data, struct v4l2_format my_src_fmt = *src_fmt; struct v4l2_format my_dest_fmt = *dest_fmt; - /* Special case when no conversion is needed */ - if (!v4lconvert_needs_conversion(data, src_fmt, dest_fmt)) { + processing = v4lprocessing_pre_processing(data->processing); + + if (/* If no conversion/processing is needed */ + (src_fmt->fmt.pix.width == dest_fmt->fmt.pix.width && + src_fmt->fmt.pix.height == dest_fmt->fmt.pix.height && + src_fmt->fmt.pix.pixelformat == dest_fmt->fmt.pix.pixelformat && + !processing && + !(data->control_flags & (V4LCONTROL_ROTATED_90_JPEG | + V4LCONTROL_VFLIPPED | V4LCONTROL_HFLIPPED))) || + /* or if we should do processing/rotating/flipping but the app tries to + use the native cam format, we just return an unprocessed frame copy */ + !v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat)) { int to_copy = MIN(dest_size, src_size); memcpy(dest, src, to_copy); return to_copy; @@ -871,7 +898,6 @@ int v4lconvert_convert(struct v4lconvert_data *data, return -1; } - processing = v4lprocessing_pre_processing(data->processing); /* Sometimes we need foo -> rgb -> bar as video processing (whitebalance, etc.) can only be done on rgb data */ @@ -1040,8 +1066,13 @@ static void v4lconvert_get_framesizes(struct v4lconvert_data *data, int v4lconvert_enum_framesizes(struct v4lconvert_data *data, struct v4l2_frmsizeenum *frmsize) { - if (!v4lconvert_supported_dst_format(frmsize->pixel_format)) + if (!v4lconvert_supported_dst_format(frmsize->pixel_format)) { + if (v4lconvert_supported_dst_fmt_only(data)) { + errno = EINVAL; + return -1; + } return syscall(SYS_ioctl, data->fd, VIDIOC_ENUM_FRAMESIZES, frmsize); + } if (frmsize->index >= data->no_framesizes) { errno = EINVAL; @@ -1069,6 +1100,10 @@ int v4lconvert_enum_frameintervals(struct v4lconvert_data *data, struct v4l2_format src_fmt, dest_fmt; if (!v4lconvert_supported_dst_format(frmival->pixel_format)) { + if (v4lconvert_supported_dst_fmt_only(data)) { + errno = EINVAL; + return -1; + } res = syscall(SYS_ioctl, data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival); if (res) V4LCONVERT_ERR("%s\n", strerror(errno)); -- cgit v1.2.3 From 67f9c69681d56764910ae950b367bc99dfc51d4f Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Tue, 14 Apr 2009 16:49:43 +0200 Subject: libv4l: fix reading wrong memory when doing yuv420->rgb conversion From: Hans de Goede Fix reading outside of the source memory when doing yuv420->rgb conversion. Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 1 + v4l2-apps/libv4l/libv4l2/log.c | 12 ++++++------ v4l2-apps/libv4l/libv4lconvert/rgbyuv.c | 4 ++-- 3 files changed, 9 insertions(+), 8 deletions(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index 3a7d3f3a8..b1f4c3a22 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -24,6 +24,7 @@ libv4l-0.5.97 * adjust libv4l's upside down cam detection to also work with devices which have the usb interface as parent instead of the usb device * fix libv4l upside down detection for the new v4l minor numbering scheme +* fix reading outside of the source memory when doing yuv420->rgb conversion libv4l-0.5.9 ------------ diff --git a/v4l2-apps/libv4l/libv4l2/log.c b/v4l2-apps/libv4l/libv4l2/log.c index 251b46ecf..a08ae3554 100644 --- a/v4l2-apps/libv4l/libv4l2/log.c +++ b/v4l2-apps/libv4l/libv4l2/log.c @@ -163,7 +163,7 @@ void v4l2_log_ioctl(unsigned long int request, void *arg, int result) struct v4l2_frmsizeenum *frmsize = arg; int pixfmt = frmsize->pixel_format; - fprintf(v4l2_log_file, " index: %u pixelformat: %c%c%c%c", + fprintf(v4l2_log_file, " index: %u pixelformat: %c%c%c%c\n", frmsize->index, pixfmt & 0xff, (pixfmt >> 8) & 0xff, @@ -171,12 +171,12 @@ void v4l2_log_ioctl(unsigned long int request, void *arg, int result) pixfmt >> 24); switch (frmsize->type) { case V4L2_FRMSIZE_TYPE_DISCRETE: - fprintf(v4l2_log_file, " %ux%u\n", frmsize->discrete.width, + fprintf(v4l2_log_file, " %ux%u\n", frmsize->discrete.width, frmsize->discrete.height); break; case V4L2_FRMSIZE_TYPE_CONTINUOUS: case V4L2_FRMSIZE_TYPE_STEPWISE: - fprintf(v4l2_log_file, " %ux%u -> %ux%u\n", + fprintf(v4l2_log_file, " %ux%u -> %ux%u\n", frmsize->stepwise.min_width, frmsize->stepwise.min_height, frmsize->stepwise.max_width, frmsize->stepwise.max_height); break; @@ -188,7 +188,7 @@ void v4l2_log_ioctl(unsigned long int request, void *arg, int result) struct v4l2_frmivalenum *frmival = arg; int pixfmt = frmival->pixel_format; - fprintf(v4l2_log_file, " index: %u pixelformat: %c%c%c%c %ux%u: ", + fprintf(v4l2_log_file, " index: %u pixelformat: %c%c%c%c %ux%u:\n", frmival->index, pixfmt & 0xff, (pixfmt >> 8) & 0xff, @@ -198,12 +198,12 @@ void v4l2_log_ioctl(unsigned long int request, void *arg, int result) frmival->height); switch (frmival->type) { case V4L2_FRMIVAL_TYPE_DISCRETE: - fprintf(v4l2_log_file, "%u/%u\n", frmival->discrete.numerator, + fprintf(v4l2_log_file, " %u/%u\n", frmival->discrete.numerator, frmival->discrete.denominator); break; case V4L2_FRMIVAL_TYPE_CONTINUOUS: case V4L2_FRMIVAL_TYPE_STEPWISE: - fprintf(v4l2_log_file, "%u/%u -> %u/%u\n", + fprintf(v4l2_log_file, " %u/%u -> %u/%u\n", frmival->stepwise.min.numerator, frmival->stepwise.min.denominator, frmival->stepwise.max.numerator, diff --git a/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c b/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c index 00706be9d..3fbff8e85 100644 --- a/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c +++ b/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c @@ -135,7 +135,7 @@ void v4lconvert_yuv420_to_bgr24(const unsigned char *src, unsigned char *dest, vsrc++; } /* Rewind u and v for next line */ - if (i&1) { + if (!(i&1)) { usrc -= width / 2; vsrc -= width / 2; } @@ -189,7 +189,7 @@ void v4lconvert_yuv420_to_rgb24(const unsigned char *src, unsigned char *dest, vsrc++; } /* Rewind u and v for next line */ - if (i&1) { + if (!(i&1)) { usrc -= width / 2; vsrc -= width / 2; } -- cgit v1.2.3 From 18d8f58054d630d7f1c80f5586aaa7331d4f46e7 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Tue, 14 Apr 2009 23:11:39 +0200 Subject: libv4l: crop widths to the nearest multiple of 8 when converting to YUV420 From: Hans de Goede Some applications / libs (*cough* gstreamer *cough*) will not work correctly with planar YUV formats when the width is not a multiple of 8, so crop widths which are not a multiple of 8 to the nearest multiple of 8 when converting to planar YUV Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 4 ++++ v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index b1f4c3a22..e60ccdbb2 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -16,6 +16,10 @@ libv4l-0.5.97 can then change the settings using a v4l2 control panel like v4l2ucp * Only report / allow supported destination formats in enum_fmt / try_fmt / g_fmt / s_fmt when processing, rotating or flipping. +* Some applications / libs (*cough* gstreamer *cough*) will not work + correctly with planar YUV formats when the width is not a multiple of 8, + so crop widths which are not a multiple of 8 to the nearest multiple of 8 + when converting to planar YUV * Add dependency generation to libv4l by: Gilles Gigan * Add support to use orientation from VIDIOC_ENUMINPUT by: Adam Baker diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index 2e029a81c..39e9d8669 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -398,6 +398,21 @@ int v4lconvert_try_format(struct v4lconvert_data *data, } } + /* Some applications / libs (*cough* gstreamer *cough*) will not work + correctly with planar YUV formats when the width is not a multiple of 8 + or the height is not a multiple of 2 */ + if (try_dest.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420 || + try_dest.fmt.pix.pixelformat == V4L2_PIX_FMT_YVU420) { + try_dest.fmt.pix.width &= ~7; + try_dest.fmt.pix.height &= ~1; + } + + /* Likewise the width needs to be a multiple of 4 for RGB formats + (although I've never seen a device with a width not a multiple of 4) */ + if (try_dest.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24 || + try_dest.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24) + try_dest.fmt.pix.width &= ~3; + /* Are we converting? */ if(try_src.fmt.pix.width != try_dest.fmt.pix.width || try_src.fmt.pix.height != try_dest.fmt.pix.height || @@ -1083,6 +1098,13 @@ int v4lconvert_enum_framesizes(struct v4lconvert_data *data, switch(frmsize->type) { case V4L2_FRMSIZE_TYPE_DISCRETE: frmsize->discrete = data->framesizes[frmsize->index].discrete; + /* Apply the same rounding algorithm as v4lconvert_try_format */ + if (frmsize->pixel_format == V4L2_PIX_FMT_YUV420 || + frmsize->pixel_format == V4L2_PIX_FMT_YVU420) { + frmsize->discrete.width &= ~7; + frmsize->discrete.height &= ~1; + } else + frmsize->discrete.width &= ~3; break; case V4L2_FRMSIZE_TYPE_CONTINUOUS: case V4L2_FRMSIZE_TYPE_STEPWISE: -- cgit v1.2.3 From 3c523ed18793284d90b8b2940f85e747dd24ac47 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 15 Apr 2009 14:03:32 +0200 Subject: libv4l: Don't add "fake" controls when not doing conversion From: Hans de Goede Since all things fake controls enable (such as whitebalancing) depend upon libv4lconvert_convert being called, do not fake controls when conversion is disabled. Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/libv4l2/libv4l2.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2.c b/v4l2-apps/libv4l/libv4l2/libv4l2.c index 8d01b034c..fc5e63eaa 100644 --- a/v4l2-apps/libv4l/libv4l2/libv4l2.c +++ b/v4l2-apps/libv4l/libv4l2/libv4l2.c @@ -687,6 +687,9 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) case VIDIOC_QUERYCTRL: case VIDIOC_G_CTRL: case VIDIOC_S_CTRL: + if (!(devices[index].flags & V4L2_DISABLE_CONVERSION)) + is_capture_request = 1; + break; case VIDIOC_QUERYCAP: is_capture_request = 1; break; -- cgit v1.2.3 From 2a12d063ebe4fd3ce43d3ed2eabd70741056771b Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 15 Apr 2009 14:05:19 +0200 Subject: libv4l: 0.9.97 release From: Hans de Goede libv4l: 0.9.97 release Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/Makefile b/v4l2-apps/libv4l/Makefile index 703f3298f..4d57b42cc 100644 --- a/v4l2-apps/libv4l/Makefile +++ b/v4l2-apps/libv4l/Makefile @@ -1,5 +1,5 @@ LIB_RELEASE=0 -V4L2_LIB_VERSION=$(LIB_RELEASE).5.9 +V4L2_LIB_VERSION=$(LIB_RELEASE).5.97 all install: $(MAKE) -C libv4lconvert V4L2_LIB_VERSION=$(V4L2_LIB_VERSION) $@ -- cgit v1.2.3 From 279a5b30fa2545d54a582d9a8e4dd3e4beceac40 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Thu, 16 Apr 2009 09:52:50 +0200 Subject: libv4l: genius messenger 112 needs both upside down and whitebalance flags. From: Hans de Goede libv4l: genius messenger 112 needs both upside down and whitebalance flags. Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c index b09ffc582..ff9b3b5c1 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c @@ -61,9 +61,10 @@ static const struct v4lcontrol_flags_info v4lcontrol_flags[] = { { 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 */ + /* Genius E-M 112 (also needs processing) */ + { 0x093a, 0x2476, 0, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED, + V4LCONTROL_WANTS_WB }, +/* Second: devices which can benefit from software video processing */ /* Pac207 based devices */ { 0x041e, 0x4028, 0, 0, V4LCONTROL_WANTS_WB }, { 0x093a, 0x2460, 0x1f, 0, V4LCONTROL_WANTS_WB }, -- cgit v1.2.3 From 419bda948df875f0c02e25d005d8d20b58fc0931 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Thu, 16 Apr 2009 10:49:08 +0200 Subject: libv4l: link libv4lcontrol against rt, not libv4l2 From: Hans de Goede libv4l: link libv4lcontrol against rt, not libv4l2 Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 4 ++++ v4l2-apps/libv4l/libv4l2/Makefile | 3 +-- v4l2-apps/libv4l/libv4lconvert/Makefile | 4 +++- 3 files changed, 8 insertions(+), 3 deletions(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index e60ccdbb2..6081e26cf 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -1,3 +1,7 @@ +libv4l-0.5.98 +------------- +* Genius E-M 112 needs both upside down and whitebalance flags + libv4l-0.5.97 ------------- * As the version number shows this is a beta release of the 0.6.x series, diff --git a/v4l2-apps/libv4l/libv4l2/Makefile b/v4l2-apps/libv4l/libv4l2/Makefile index 4356c0975..463e4e833 100644 --- a/v4l2-apps/libv4l/libv4l2/Makefile +++ b/v4l2-apps/libv4l/libv4l2/Makefile @@ -3,7 +3,7 @@ override CPPFLAGS += -I../include -I../../../include -fvisibility=hidden CFLAGS := -g -O1 CFLAGS += -Wall -Wno-unused -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -LIBS_libv4l2 = -lpthread -lrt +LIBS_libv4l2 = -lpthread V4L2_OBJS = libv4l2.o log.o V4L2CONVERT = v4l2convert.so @@ -86,4 +86,3 @@ clean:: %.a: $(AR) cqs $@ $^ - diff --git a/v4l2-apps/libv4l/libv4lconvert/Makefile b/v4l2-apps/libv4l/libv4lconvert/Makefile index 64f6690d2..0e1d5e84e 100644 --- a/v4l2-apps/libv4l/libv4lconvert/Makefile +++ b/v4l2-apps/libv4l/libv4lconvert/Makefile @@ -3,6 +3,8 @@ override CPPFLAGS += -I../include -I../../../include -fvisibility=hidden CFLAGS := -g -O1 CFLAGS += -Wall -Wno-unused -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes +LIBS_libv4lconvert = -lrt + ifeq ($(LINKTYPE),static) CONVERT_LIB = libv4lconvert.a else @@ -73,7 +75,7 @@ clean:: $(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $< %.so: - $(CC) -shared $(LDFLAGS) -Wl,-soname,$@.$(LIB_RELEASE) -o $@.$(LIB_RELEASE) $^ + $(CC) -shared $(LDFLAGS) -Wl,-soname,$@.$(LIB_RELEASE) -o $@.$(LIB_RELEASE) $^ $(LIBS_$*) ln -f -s $@.$(LIB_RELEASE) $@ %.a: -- cgit v1.2.3 From 9fdc384d90d5bfd705bd5d619d2a7fbdd93aeaf0 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Thu, 16 Apr 2009 10:52:39 +0200 Subject: libv4l: Makefiles: better dependency generation From: Gregor Jasny libv4l: Makefiles: better dependency generation Priority: normal Signed-off-by: Gregor Jasny Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/libv4l1/Makefile | 8 ++------ v4l2-apps/libv4l/libv4l2/Makefile | 8 ++------ v4l2-apps/libv4l/libv4lconvert/Makefile | 8 ++------ 3 files changed, 6 insertions(+), 18 deletions(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/libv4l1/Makefile b/v4l2-apps/libv4l/libv4l1/Makefile index d228cc916..bd6687e1a 100644 --- a/v4l2-apps/libv4l/libv4l1/Makefile +++ b/v4l2-apps/libv4l/libv4l1/Makefile @@ -35,7 +35,7 @@ endif all: $(TARGETS) -include $(V4L1_OBJS:.o=.d) +-include $(V4L1_OBJS:.o=.d) $(V4L1_LIB): $(V4L1_DEPS) @@ -73,12 +73,8 @@ endif clean:: rm -f *.a *.so* *.o *.d libv4l1.pc log *~ *.orig *.rej -%.d: %.c - @set -e; rm -f $@; \ - gcc -MM $(CPPFLAGS) $< | sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' > $@ - %.o: %.c - $(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $< + $(CC) -Wp,-MMD,"$*.d",-MQ,"$@",-MP -c $(CPPFLAGS) $(CFLAGS) -o $@ $< %.so: $(CC) -shared $(LDFLAGS) -Wl,-soname,$@.$(LIB_RELEASE) -o $@.$(LIB_RELEASE) $^ $(LIBS_$*) diff --git a/v4l2-apps/libv4l/libv4l2/Makefile b/v4l2-apps/libv4l/libv4l2/Makefile index 463e4e833..6a2271572 100644 --- a/v4l2-apps/libv4l/libv4l2/Makefile +++ b/v4l2-apps/libv4l/libv4l2/Makefile @@ -35,7 +35,7 @@ endif all: $(TARGETS) -include $(V4L2_OBJS:.o=.d) +-include $(V4L2_OBJS:.o=.d) $(V4L2_LIB): $(V4L2_DEPS) @@ -73,12 +73,8 @@ endif clean:: rm -f *.a *.so* *.o *.d libv4l2.pc log *~ *.orig *.rej -%.d: %.c - @set -e; rm -f $@; \ - gcc -MM $(CPPFLAGS) $< | sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' > $@ - %.o: %.c - $(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $< + $(CC) -Wp,-MMD,"$*.d",-MQ,"$@",-MP -c $(CPPFLAGS) $(CFLAGS) -o $@ $< %.so: $(CC) -shared $(LDFLAGS) -Wl,-soname,$@.$(LIB_RELEASE) -o $@.$(LIB_RELEASE) $^ $(LIBS_$*) diff --git a/v4l2-apps/libv4l/libv4lconvert/Makefile b/v4l2-apps/libv4l/libv4lconvert/Makefile index 0e1d5e84e..1ffabcbb9 100644 --- a/v4l2-apps/libv4l/libv4lconvert/Makefile +++ b/v4l2-apps/libv4l/libv4lconvert/Makefile @@ -34,7 +34,7 @@ endif all: $(TARGETS) -include $(CONVERT_OBJS:.o=.d) +-include $(CONVERT_OBJS:.o=.d) $(CONVERT_LIB): $(CONVERT_OBJS) @@ -67,12 +67,8 @@ clean:: rm -f *.a *.so* *.o *.d */*.o */*.d libv4lconvert.pc log *~ */*~ rm -f *.orig *.rej */*.orig */*.rej -%.d:: %.c - @set -e; rm -f $@; \ - $(CC) -MM $(CPPFLAGS) $< | sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' > $@ - %.o: %.c - $(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $< + $(CC) -Wp,-MMD,"$*.d",-MQ,"$@",-MP -c $(CPPFLAGS) $(CFLAGS) -o $@ $< %.so: $(CC) -shared $(LDFLAGS) -Wl,-soname,$@.$(LIB_RELEASE) -o $@.$(LIB_RELEASE) $^ $(LIBS_$*) -- cgit v1.2.3 From 53edb5d92907f9dd3f0dff06eff83cc864345e00 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Thu, 16 Apr 2009 11:26:54 +0200 Subject: libv4l: if the card name contains a / replace it with a - in the shm name From: Hans de Goede / is not allowed inside shm names, so if the card name contains a / replace it with a - Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 2 ++ v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index 6081e26cf..ebe34fb7f 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -1,6 +1,8 @@ libv4l-0.5.98 ------------- * Genius E-M 112 needs both upside down and whitebalance flags +* Some makefile improvements by Gregor Jasny +* If the card name contains a / replace it with a - in the shm name libv4l-0.5.97 ------------- diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c index ff9b3b5c1..4834c786a 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c @@ -172,7 +172,7 @@ static void v4lcontrol_init_flags(struct v4lcontrol_data *data) struct v4lcontrol_data *v4lcontrol_create(int fd) { int shm_fd; - int init = 0; + int i, init = 0; char *s, shm_name[256]; struct v4l2_capability cap; @@ -184,6 +184,11 @@ struct v4lcontrol_data *v4lcontrol_create(int fd) syscall(SYS_ioctl, fd, VIDIOC_QUERYCAP, &cap); snprintf(shm_name, 256, "/%s:%s", cap.bus_info, cap.card); + /* / is not allowed inside shm names */ + for (i = 1; shm_name[i]; i++) + if (shm_name[i] == '/') + shm_name[i] = '-'; + /* Open the shared memory object identified by shm_name */ if ((shm_fd = shm_open(shm_name, (O_CREAT | O_EXCL | O_RDWR), (S_IREAD | S_IWRITE))) >= 0) -- cgit v1.2.3 From b2a1a64aa8c773f2648b5526bf414277d3106854 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Thu, 16 Apr 2009 11:31:21 +0200 Subject: libv4l: Only created shared memory segment when we have fake v4l2 controls From: Hans de Goede libv4l: Only created shared memory segment when we have fake v4l2 controls Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 1 + .../libv4l/libv4lconvert/control/libv4lcontrol.c | 28 ++++++++++++---------- 2 files changed, 17 insertions(+), 12 deletions(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index ebe34fb7f..b57ceca57 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -3,6 +3,7 @@ libv4l-0.5.98 * Genius E-M 112 needs both upside down and whitebalance flags * Some makefile improvements by Gregor Jasny * If the card name contains a / replace it with a - in the shm name +* Only created shared memory segment when we have fake v4l2 controls libv4l-0.5.97 ------------- diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c index 4834c786a..2aa2d8b38 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c @@ -181,6 +181,20 @@ struct v4lcontrol_data *v4lcontrol_create(int fd) if (!data) return NULL; + 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); + + if (data->controls == 0) + return data; /* No need to create a shared memory segment */ + syscall(SYS_ioctl, fd, VIDIOC_QUERYCAP, &cap); snprintf(shm_name, 256, "/%s:%s", cap.bus_info, cap.card); @@ -214,17 +228,6 @@ struct v4lcontrol_data *v4lcontrol_create(int fd) 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: @@ -234,7 +237,8 @@ error: void v4lcontrol_destroy(struct v4lcontrol_data *data) { - munmap(data->shm_values, V4LCONTROL_SHM_SIZE); + if (data->controls) + munmap(data->shm_values, V4LCONTROL_SHM_SIZE); free(data); } -- cgit v1.2.3 From 719bc62fd5ec60a01544dbcd3ce01b8356151f56 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Fri, 17 Apr 2009 10:49:25 +0200 Subject: libv4l: add missing Libs.private to v4lconvert.pc From: Hans de Goede libv4l: add missing Libs.private to v4lconvert.pc Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/libv4lconvert/Makefile | 1 + 1 file changed, 1 insertion(+) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/libv4lconvert/Makefile b/v4l2-apps/libv4l/libv4lconvert/Makefile index 1ffabcbb9..ffc2e337d 100644 --- a/v4l2-apps/libv4l/libv4lconvert/Makefile +++ b/v4l2-apps/libv4l/libv4lconvert/Makefile @@ -46,6 +46,7 @@ libv4lconvert.pc: @echo 'Description: v4l format conversion library' >> libv4lconvert.pc @echo 'Version: '$(V4L2_LIB_VERSION) >> libv4lconvert.pc @echo 'Libs: -L$${libdir} -lv4lconvert' >> libv4lconvert.pc + @echo 'Libs.private: -lrt' >> libv4lconvert.pc @echo 'Cflags: -I$${prefix}/include' >> libv4lconvert.pc install: all -- cgit v1.2.3 From 53d7375e8b366a0639000eb0377a93fc20ee563b Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Fri, 17 Apr 2009 11:12:08 +0200 Subject: libv4l: Add sq905 to the list of devices which benefit from whitebalancing From: Hans de Goede libv4l: Add sq905 to the list of devices which benefit from whitebalancing Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 1 + v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c | 2 ++ 2 files changed, 3 insertions(+) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index b57ceca57..2da0139d4 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -4,6 +4,7 @@ libv4l-0.5.98 * Some makefile improvements by Gregor Jasny * If the card name contains a / replace it with a - in the shm name * Only created shared memory segment when we have fake v4l2 controls +* Add sq905 to the list of devices which benefit from whitebalancing libv4l-0.5.97 ------------- diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c index 2aa2d8b38..93c08c0c2 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c @@ -72,6 +72,8 @@ static const struct v4lcontrol_flags_info v4lcontrol_flags[] = { { 0x2001, 0xf115, 0, 0, V4LCONTROL_WANTS_WB }, /* Pac7302 based devices */ { 0x093a, 0x2620, 0x0f, V4LCONTROL_ROTATED_90_JPEG, V4LCONTROL_WANTS_WB }, + /* sq905 devices */ + { 0x2770, 0x9120, 0, 0, V4LCONTROL_WANTS_WB }, }; static void v4lcontrol_init_flags(struct v4lcontrol_data *data) -- cgit v1.2.3 From 89b93efcabe5cc48d405d26843b53d288286752b Mon Sep 17 00:00:00 2001 From: "hans@localhost.localdomain" Date: Sat, 16 May 2009 12:57:18 +0200 Subject: libv4l: Support V4L2_CTRL_FLAG_NEXT_CTRL for fake controls From: Adam Baker The "fake" controls added by libv4l to provide whitebalance on some cameras do not respect the V4L2_CTRL_FLAG_NEXT_CTRL and hence don't appear on control programs that try to use that flag if there are any driver controls that do support the flag. Add support for V4L2_CTRL_FLAG_NEXT_CTRL Priority: normal Signed-off-by: Adam Baker Signed-off-by: Hans de Goede --- .../libv4l/libv4lconvert/control/libv4lcontrol.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c index 93c08c0c2..63de07bf1 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c @@ -292,7 +292,10 @@ int v4lcontrol_vidioc_queryctrl(struct v4lcontrol_data *data, void *arg) { int i; struct v4l2_queryctrl *ctrl = arg; + int retval; + __u32 orig_id=ctrl->id; + /* if we have an exact match return it */ for (i = 0; i < V4LCONTROL_COUNT; i++) if ((data->controls & (1 << i)) && ctrl->id == fake_controls[i].id) { @@ -300,7 +303,21 @@ int v4lcontrol_vidioc_queryctrl(struct v4lcontrol_data *data, void *arg) return 0; } - return syscall(SYS_ioctl, data->fd, VIDIOC_QUERYCTRL, arg); + /* find out what the kernel driver would respond. */ + retval = syscall(SYS_ioctl, data->fd, VIDIOC_QUERYCTRL, arg); + + /* if any of our controls have an id > orig_id but less than + ctrl->id then return that control instead. */ + if (orig_id & V4L2_CTRL_FLAG_NEXT_CTRL) + for (i = 0; i < V4LCONTROL_COUNT; i++) + if ((data->controls & (1 << i)) && + (fake_controls[i].id > (orig_id & ~V4L2_CTRL_FLAG_NEXT_CTRL)) && + (fake_controls[i].id <= ctrl->id)) { + memcpy(ctrl, &fake_controls[i], sizeof(struct v4l2_queryctrl)); + retval = 0; + } + + return retval; } int v4lcontrol_vidioc_g_ctrl(struct v4lcontrol_data *data, void *arg) -- cgit v1.2.3 From 719bdce1fa2e052cbd9c4cc21362dd21b662f989 Mon Sep 17 00:00:00 2001 From: "hans@localhost.localdomain" Date: Sat, 16 May 2009 22:04:27 +0200 Subject: libv4l: add ability to determine flags based on DMI info From: Hans de Goede It is possible for the same laptop webcam module (so same usb id) to be mounted upside down in some models and the right way up in other laptop models. This patch adds the ability to only apply flags to a webcam based on the combination of usb id and dmi info to identify the laptop model. It also adds the webcam in the Asus N50Vn as the first upside down cam identified this way. Priority: normal Signed-off-by: Hans de Goede --- .../libv4lconvert/control/libv4lcontrol-priv.h | 2 + .../libv4l/libv4lconvert/control/libv4lcontrol.c | 49 +++++++++++++++++----- 2 files changed, 40 insertions(+), 11 deletions(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h index 0dd675754..0157af280 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h @@ -40,6 +40,8 @@ struct v4lcontrol_flags_info { unsigned short vendor_id; unsigned short product_id; unsigned short product_mask; + const char *dmi_board_vendor; + const char *dmi_board_name; /* We could also use the USB manufacturer and product strings some devices have const char *manufacturer; const char *product; */ diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c index 63de07bf1..1ffd05cc4 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c @@ -56,24 +56,28 @@ static const struct v4lcontrol_flags_info v4lcontrol_flags[] = { /* First: Upside down devices */ /* Philips SPC200NC */ - { 0x0471, 0x0325, 0, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED, 0 }, + { 0x0471, 0x0325, 0, NULL, NULL, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED, 0 }, /* Philips SPC300NC */ - { 0x0471, 0x0326, 0, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED, 0 }, + { 0x0471, 0x0326, 0, NULL, NULL, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED, 0 }, /* Philips SPC210NC */ - { 0x0471, 0x032d, 0, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED, 0 }, + { 0x0471, 0x032d, 0, NULL, NULL, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED, 0 }, /* Genius E-M 112 (also needs processing) */ - { 0x093a, 0x2476, 0, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED, + { 0x093a, 0x2476, 0, NULL, NULL, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED, V4LCONTROL_WANTS_WB }, + /* Asus N50Vn laptop */ + { 0x04f2, 0xb106, 0, "ASUSTeK Computer Inc. ", "N50Vn ", + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED, 0 }, /* Second: devices which can benefit 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 }, + { 0x041e, 0x4028, 0, NULL, NULL, 0, V4LCONTROL_WANTS_WB }, + { 0x093a, 0x2460, 0x1f, NULL, NULL, 0, V4LCONTROL_WANTS_WB }, + { 0x145f, 0x013a, 0, NULL, NULL, 0, V4LCONTROL_WANTS_WB }, + { 0x2001, 0xf115, 0, NULL, NULL, 0, V4LCONTROL_WANTS_WB }, /* Pac7302 based devices */ - { 0x093a, 0x2620, 0x0f, V4LCONTROL_ROTATED_90_JPEG, V4LCONTROL_WANTS_WB }, + { 0x093a, 0x2620, 0x0f, NULL, NULL, V4LCONTROL_ROTATED_90_JPEG, + V4LCONTROL_WANTS_WB }, /* sq905 devices */ - { 0x2770, 0x9120, 0, 0, V4LCONTROL_WANTS_WB }, + { 0x2770, 0x9120, 0, NULL, NULL, 0, V4LCONTROL_WANTS_WB }, }; static void v4lcontrol_init_flags(struct v4lcontrol_data *data) @@ -83,6 +87,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]= ""; int i, minor; char c, *s, buf[32]; struct v4l2_input input; @@ -161,10 +167,31 @@ 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); + } + 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)) { + (product_id & ~v4lcontrol_flags[i].product_mask) && + (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))) { data->flags |= v4lcontrol_flags[i].flags; data->controls = v4lcontrol_flags[i].controls; break; -- cgit v1.2.3 From 9919241faa605f4024a77e4e01c5cc4f6676bfe7 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Sun, 17 May 2009 15:18:29 +0200 Subject: libv4l: fix v4lconvert_uyvy_to_yuv420() From: Hans de Goede v4lconvert_uyvy_to_yuv420() had a bug causing the result to be all messed up, also see: http://bugzilla.gnome.org/show_bug.cgi?id=571772 Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/libv4lconvert/rgbyuv.c | 1 - 1 file changed, 1 deletion(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c b/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c index 3fbff8e85..31cbc3c68 100644 --- a/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c +++ b/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c @@ -409,7 +409,6 @@ void v4lconvert_uyvy_to_yuv420(const unsigned char *src, unsigned char *dest, } /* copy the U and V values */ - src++; /* point to V */ src1 = src + width * 2; /* next line */ if (yvu) { vdest = dest; -- cgit v1.2.3 From e760f2575db92f9bdfe64e24d817409d4e7518d8 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Sun, 17 May 2009 15:21:00 +0200 Subject: libv4l: add Changelog entry for last 3 commits From: Hans de Goede libv4l: add Changelog entry for last 3 commits (I should really learn to do this before comitting) Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 3 +++ 1 file changed, 3 insertions(+) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index 2da0139d4..82402f1bf 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -5,6 +5,9 @@ libv4l-0.5.98 * If the card name contains a / replace it with a - in the shm name * Only created shared memory segment when we have fake v4l2 controls * Add sq905 to the list of devices which benefit from whitebalancing +* Support V4L2_CTRL_FLAG_NEXT_CTRL for fake controls by Adam Baker +* Add ability to determine upside down cams based on DMI info +* Fix a bug in v4lconvert_uyvy_to_yuv420() libv4l-0.5.97 ------------- -- cgit v1.2.3 From a077e421fe63a7102f6bbaa7057df7690e239cf6 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Tue, 19 May 2009 14:25:22 +0200 Subject: libv4l: support separate vfliping and hfliping From: Hans de Goede Before this patch libv4l only support 180 degree rotation, which is hflip and vflip combined, this patch adds support for separate hflipping and vflipping. Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 1 + v4l2-apps/libv4l/libv4lconvert/flip.c | 129 ++++++++++++++++++++- .../libv4l/libv4lconvert/libv4lconvert-priv.h | 2 + v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 2 +- 4 files changed, 128 insertions(+), 6 deletions(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index 82402f1bf..aa0a3ea3c 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -8,6 +8,7 @@ libv4l-0.5.98 * Support V4L2_CTRL_FLAG_NEXT_CTRL for fake controls by Adam Baker * Add ability to determine upside down cams based on DMI info * Fix a bug in v4lconvert_uyvy_to_yuv420() +* Add support for separate vflipping and hflipping libv4l-0.5.97 ------------- diff --git a/v4l2-apps/libv4l/libv4lconvert/flip.c b/v4l2-apps/libv4l/libv4lconvert/flip.c index cc9526493..5d881844a 100644 --- a/v4l2-apps/libv4l/libv4lconvert/flip.c +++ b/v4l2-apps/libv4l/libv4lconvert/flip.c @@ -23,6 +23,97 @@ #include #include "libv4lconvert-priv.h" +static void v4lconvert_vflip_rgbbgr24(unsigned char *src, unsigned char *dest, + struct v4l2_format *fmt) +{ + int y; + + src += fmt->fmt.pix.height * fmt->fmt.pix.bytesperline; + for (y = 0; y < fmt->fmt.pix.height; y++) { + src -= fmt->fmt.pix.bytesperline; + memcpy(dest, src, fmt->fmt.pix.width * 3); + dest += fmt->fmt.pix.width * 3; + } +} + +static void v4lconvert_vflip_yuv420(unsigned char *src, unsigned char *dest, + struct v4l2_format *fmt) +{ + int y; + + /* First flip the Y plane */ + src += fmt->fmt.pix.height * fmt->fmt.pix.bytesperline; + for (y = 0; y < fmt->fmt.pix.height; y++) { + src -= fmt->fmt.pix.bytesperline; + memcpy(dest, src, fmt->fmt.pix.width); + dest += fmt->fmt.pix.width; + } + + /* Now flip the U plane */ + src += fmt->fmt.pix.height * fmt->fmt.pix.bytesperline * 5 / 4; + for (y = 0; y < fmt->fmt.pix.height / 2; y++) { + src -= fmt->fmt.pix.bytesperline / 2; + memcpy(dest, src, fmt->fmt.pix.width / 2); + dest += fmt->fmt.pix.width / 2; + } + + /* Last flip the V plane */ + src += fmt->fmt.pix.height * fmt->fmt.pix.bytesperline / 2; + for (y = 0; y < fmt->fmt.pix.height / 2; y++) { + src -= fmt->fmt.pix.bytesperline / 2; + memcpy(dest, src, fmt->fmt.pix.width / 2); + dest += fmt->fmt.pix.width / 2; + } +} + +static void v4lconvert_hflip_rgbbgr24(unsigned char *src, unsigned char *dest, + struct v4l2_format *fmt) +{ + int x, y; + + for (y = 0; y < fmt->fmt.pix.height; y++) { + src += fmt->fmt.pix.width * 3; + for (x = 0; x < fmt->fmt.pix.width; x++) { + src -= 3; + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest += 3; + } + src += fmt->fmt.pix.bytesperline; + } +} + +static void v4lconvert_hflip_yuv420(unsigned char *src, unsigned char *dest, + struct v4l2_format *fmt) +{ + int x, y; + + /* First flip the Y plane */ + for (y = 0; y < fmt->fmt.pix.height; y++) { + src += fmt->fmt.pix.width; + for (x = 0; x < fmt->fmt.pix.width; x++) + *dest++ = *--src; + src += fmt->fmt.pix.bytesperline; + } + + /* Now flip the U plane */ + for (y = 0; y < fmt->fmt.pix.height / 2; y++) { + src += fmt->fmt.pix.width / 2; + for (x = 0; x < fmt->fmt.pix.width / 2; x++) + *dest++ = *--src; + src += fmt->fmt.pix.bytesperline / 2; + } + + /* Last flip the V plane */ + for (y = 0; y < fmt->fmt.pix.height / 2; y++) { + src += fmt->fmt.pix.width / 2; + for (x = 0; x < fmt->fmt.pix.width / 2; x++) + *dest++ = *--src; + src += fmt->fmt.pix.bytesperline / 2; + } +} + static void v4lconvert_rotate180_rgbbgr24(const unsigned char *src, unsigned char *dst, int width, int height) { @@ -133,9 +224,35 @@ void v4lconvert_rotate90(unsigned char *src, unsigned char *dest, void v4lconvert_flip(unsigned char *src, unsigned char *dest, struct v4l2_format *fmt, int flags) { - /* FIXME implement separate vflipping and hflipping, for now we always - rotate 180 when vflip is selected! */ - if (flags & V4LCONTROL_VFLIPPED) { + switch (flags & (V4LCONTROL_VFLIPPED|V4LCONTROL_HFLIPPED)) { + + case V4LCONTROL_VFLIPPED: + switch (fmt->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + v4lconvert_vflip_rgbbgr24(src, dest, fmt); + break; + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + v4lconvert_vflip_yuv420(src, dest, fmt); + break; + } + break; + + case V4LCONTROL_HFLIPPED: + switch (fmt->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + v4lconvert_hflip_rgbbgr24(src, dest, fmt); + break; + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + v4lconvert_hflip_yuv420(src, dest, fmt); + break; + } + break; + + case (V4LCONTROL_VFLIPPED|V4LCONTROL_HFLIPPED): switch (fmt->fmt.pix.pixelformat) { case V4L2_PIX_FMT_RGB24: case V4L2_PIX_FMT_BGR24: @@ -148,7 +265,9 @@ void v4lconvert_flip(unsigned char *src, unsigned char *dest, fmt->fmt.pix.height); break; } + break; } - else /* FIXME and do nothing when only HFLIP is selected */ - memcpy(dest, src, fmt->fmt.pix.sizeimage); + + /* Our newly written data has no padding */ + v4lconvert_fixup_fmt(fmt); } diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h index 4a333d9a9..2d34bd6a4 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h @@ -127,6 +127,8 @@ struct v4lconvert_pixfmt { int flags; }; +void v4lconvert_fixup_fmt(struct v4l2_format *fmt); + void v4lconvert_rgb24_to_yuv420(const unsigned char *src, unsigned char *dest, const struct v4l2_format *src_fmt, int bgr, int yvu); diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index 39e9d8669..a175973ef 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -321,7 +321,7 @@ static int v4lconvert_do_try_format(struct v4lconvert_data *data, return 0; } -static void v4lconvert_fixup_fmt(struct v4l2_format *fmt) +void v4lconvert_fixup_fmt(struct v4l2_format *fmt) { switch (fmt->fmt.pix.pixelformat) { case V4L2_PIX_FMT_RGB24: -- cgit v1.2.3 From 34a210b573f9c8ff8f07077f239be95d9d9248c5 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 20 May 2009 07:23:00 +0200 Subject: libv4l: add fake controls controlling the software h- and v-flipping From: Hans de Goede When we need to go through the fake mmap buffer anyways, we can add fake controls at no cost. So in the case of webcams which only support non standard pixformats, export fake flipping controls, as this can be done at no (performace) cost (until the user activates them). Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 1 + v4l2-apps/libv4l/TODO | 3 - .../libv4l/libv4lconvert/control/libv4lcontrol.c | 42 +++++++++++++- .../libv4l/libv4lconvert/control/libv4lcontrol.h | 12 +++- v4l2-apps/libv4l/libv4lconvert/flip.c | 27 ++++----- .../libv4l/libv4lconvert/libv4lconvert-priv.h | 5 +- v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 65 +++++++++++----------- 7 files changed, 97 insertions(+), 58 deletions(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index aa0a3ea3c..9bfecab85 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -9,6 +9,7 @@ libv4l-0.5.98 * Add ability to determine upside down cams based on DMI info * Fix a bug in v4lconvert_uyvy_to_yuv420() * Add support for separate vflipping and hflipping +* Add fake controls controlling the software h- and v-flipping libv4l-0.5.97 ------------- diff --git a/v4l2-apps/libv4l/TODO b/v4l2-apps/libv4l/TODO index 94c40b84e..b676bfeb5 100644 --- a/v4l2-apps/libv4l/TODO +++ b/v4l2-apps/libv4l/TODO @@ -13,9 +13,6 @@ -make updating of parameters happen based on time elapsed rather then frames --add fake flip controls on devices where we are already limiting the - formats which can be set - -add reverse cropping (adding black borders) to get from 320x232 -> 320x240, for zc3xx webcams with a broken (last row of jpeg blocks missing) 320x240 mode diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c index 1ffd05cc4..b120aa2fc 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c @@ -198,12 +198,13 @@ static void v4lcontrol_init_flags(struct v4lcontrol_data *data) } } -struct v4lcontrol_data *v4lcontrol_create(int fd) +struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) { int shm_fd; int i, init = 0; char *s, shm_name[256]; struct v4l2_capability cap; + struct v4l2_queryctrl ctrl; struct v4lcontrol_data *data = calloc(1, sizeof(struct v4lcontrol_data)); @@ -214,6 +215,17 @@ struct v4lcontrol_data *v4lcontrol_create(int fd) v4lcontrol_init_flags(data); + /* If the device always needs conversion, we can add fake controls at no cost + (no cost when not activated by the user that is) */ + if (always_needs_conversion || v4lcontrol_needs_conversion(data)) { + ctrl.id = V4L2_CID_HFLIP; + if (syscall(SYS_ioctl, data->fd, VIDIOC_QUERYCTRL, &ctrl) == -1) + data->controls |= 1 << V4LCONTROL_HFLIP; + ctrl.id = V4L2_CID_VFLIP; + if (syscall(SYS_ioctl, data->fd, VIDIOC_QUERYCTRL, &ctrl) == -1) + data->controls |= 1 << V4LCONTROL_VFLIP; + } + /* Allow overriding through environment */ if ((s = getenv("LIBV4LCONTROL_FLAGS"))) data->flags = strtol(s, NULL, 0); @@ -313,6 +325,26 @@ struct v4l2_queryctrl fake_controls[V4LCONTROL_COUNT] = { .default_value = 255, .flags = 0 }, +{ + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Horizontal flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0 +}, +{ + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Vertical flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0 +}, }; int v4lcontrol_vidioc_queryctrl(struct v4lcontrol_data *data, void *arg) @@ -390,8 +422,14 @@ int v4lcontrol_get_flags(struct v4lcontrol_data *data) int v4lcontrol_get_ctrl(struct v4lcontrol_data *data, int ctrl) { - if (data->controls & (1 << ctrl)) + if (data->controls & (1 << ctrl)) { + /* Special case for devices with flipped input */ + if ((ctrl == V4LCONTROL_HFLIP && (data->flags & V4LCONTROL_HFLIPPED)) || + (ctrl == V4LCONTROL_VFLIP && (data->flags & V4LCONTROL_VFLIPPED))) + return !data->shm_values[ctrl]; + return data->shm_values[ctrl]; + } return 0; } diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h index 28308bc55..43ef7c49f 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h @@ -28,12 +28,18 @@ #define V4LCONTROL_ROTATED_90_JPEG 0x04 /* Controls */ -enum { V4LCONTROL_WHITEBALANCE, V4LCONTROL_NORMALIZE, - V4LCONTROL_NORM_LOW_BOUND, V4LCONTROL_NORM_HIGH_BOUND, V4LCONTROL_COUNT }; +enum { + V4LCONTROL_WHITEBALANCE, + V4LCONTROL_NORMALIZE, + V4LCONTROL_NORM_LOW_BOUND, + V4LCONTROL_NORM_HIGH_BOUND, + V4LCONTROL_HFLIP, + V4LCONTROL_VFLIP, + V4LCONTROL_COUNT }; struct v4lcontrol_data; -struct v4lcontrol_data* v4lcontrol_create(int fd); +struct v4lcontrol_data* v4lcontrol_create(int fd, int always_needs_conversion); void v4lcontrol_destroy(struct v4lcontrol_data *data); /* Functions used by v4lprocessing to get the control state */ diff --git a/v4l2-apps/libv4l/libv4lconvert/flip.c b/v4l2-apps/libv4l/libv4lconvert/flip.c index 5d881844a..8c4d8233c 100644 --- a/v4l2-apps/libv4l/libv4lconvert/flip.c +++ b/v4l2-apps/libv4l/libv4lconvert/flip.c @@ -222,24 +222,22 @@ void v4lconvert_rotate90(unsigned char *src, unsigned char *dest, } void v4lconvert_flip(unsigned char *src, unsigned char *dest, - struct v4l2_format *fmt, int flags) + struct v4l2_format *fmt, int hflip, int vflip) { - switch (flags & (V4LCONTROL_VFLIPPED|V4LCONTROL_HFLIPPED)) { - - case V4LCONTROL_VFLIPPED: + if (vflip && hflip) { switch (fmt->fmt.pix.pixelformat) { case V4L2_PIX_FMT_RGB24: case V4L2_PIX_FMT_BGR24: - v4lconvert_vflip_rgbbgr24(src, dest, fmt); + v4lconvert_rotate180_rgbbgr24(src, dest, fmt->fmt.pix.width, + fmt->fmt.pix.height); break; case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: - v4lconvert_vflip_yuv420(src, dest, fmt); + v4lconvert_rotate180_yuv420(src, dest, fmt->fmt.pix.width, + fmt->fmt.pix.height); break; } - break; - - case V4LCONTROL_HFLIPPED: + } else if (hflip) { switch (fmt->fmt.pix.pixelformat) { case V4L2_PIX_FMT_RGB24: case V4L2_PIX_FMT_BGR24: @@ -250,22 +248,17 @@ void v4lconvert_flip(unsigned char *src, unsigned char *dest, v4lconvert_hflip_yuv420(src, dest, fmt); break; } - break; - - case (V4LCONTROL_VFLIPPED|V4LCONTROL_HFLIPPED): + } else if (vflip) { switch (fmt->fmt.pix.pixelformat) { case V4L2_PIX_FMT_RGB24: case V4L2_PIX_FMT_BGR24: - v4lconvert_rotate180_rgbbgr24(src, dest, fmt->fmt.pix.width, - fmt->fmt.pix.height); + v4lconvert_vflip_rgbbgr24(src, dest, fmt); break; case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: - v4lconvert_rotate180_yuv420(src, dest, fmt->fmt.pix.width, - fmt->fmt.pix.height); + v4lconvert_vflip_yuv420(src, dest, fmt); break; } - break; } /* Our newly written data has no padding */ diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h index 2d34bd6a4..60e62af97 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h @@ -96,7 +96,8 @@ #define V4LCONVERT_IS_SN9C20X 0x02 /* Pixformat flags */ -#define V4LCONVERT_COMPRESSED 0x01 +#define V4LCONVERT_COMPRESSED 0x01 /* Compressed format */ +#define V4LCONVERT_NEEDS_CONVERSION 0x02 /* Apps likely wont know this */ struct v4lconvert_data { int fd; @@ -217,7 +218,7 @@ void v4lconvert_rotate90(unsigned char *src, unsigned char *dest, struct v4l2_format *fmt); void v4lconvert_flip(unsigned char *src, unsigned char *dest, - struct v4l2_format *fmt, int flags); + struct v4l2_format *fmt, int hflip, int vflip); void v4lconvert_crop(unsigned char *src, unsigned char *dest, const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt); diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index a175973ef..94539e376 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -47,15 +47,15 @@ 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_SN9C20X_I420, 0 }, - { V4L2_PIX_FMT_SBGGR8, 0 }, - { V4L2_PIX_FMT_SGBRG8, 0 }, - { V4L2_PIX_FMT_SGRBG8, 0 }, - { V4L2_PIX_FMT_SRGGB8, 0 }, - { V4L2_PIX_FMT_SPCA501, 0 }, - { V4L2_PIX_FMT_SPCA505, 0 }, - { V4L2_PIX_FMT_SPCA508, 0 }, - { V4L2_PIX_FMT_HM12, 0 }, + { V4L2_PIX_FMT_SN9C20X_I420, V4LCONVERT_NEEDS_CONVERSION }, + { V4L2_PIX_FMT_SBGGR8, V4LCONVERT_NEEDS_CONVERSION }, + { V4L2_PIX_FMT_SGBRG8, V4LCONVERT_NEEDS_CONVERSION }, + { V4L2_PIX_FMT_SGRBG8, V4LCONVERT_NEEDS_CONVERSION }, + { V4L2_PIX_FMT_SRGGB8, V4LCONVERT_NEEDS_CONVERSION }, + { V4L2_PIX_FMT_SPCA501, V4LCONVERT_NEEDS_CONVERSION }, + { V4L2_PIX_FMT_SPCA505, V4LCONVERT_NEEDS_CONVERSION }, + { V4L2_PIX_FMT_SPCA508, V4LCONVERT_NEEDS_CONVERSION }, + { 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 }, @@ -88,6 +88,10 @@ struct v4lconvert_data *v4lconvert_create(int fd) int i, j; struct v4lconvert_data *data = calloc(1, sizeof(struct v4lconvert_data)); struct v4l2_capability cap; + /* This keeps tracks of devices which have only formats for which apps + most likely will need conversion and we can thus safely add software + processing controls without a performance impact. */ + int always_needs_conversion = 1; if (!data) return NULL; @@ -107,8 +111,13 @@ 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) + always_needs_conversion = 0; break; } + + if (j == ARRAY_SIZE(supported_src_pixfmts)) + always_needs_conversion = 0; } data->no_formats = i; @@ -121,7 +130,7 @@ struct v4lconvert_data *v4lconvert_create(int fd) data->flags |= V4LCONVERT_IS_SN9C20X; } - data->control = v4lcontrol_create(fd); + data->control = v4lcontrol_create(fd, always_needs_conversion); if (!data->control) { free(data); return NULL; @@ -854,7 +863,8 @@ int v4lconvert_convert(struct v4lconvert_data *data, const struct v4l2_format *dest_fmt, /* in */ unsigned char *src, int src_size, unsigned char *dest, int dest_size) { - int res, dest_needed, temp_needed, processing, convert = 0, crop = 0; + int res, dest_needed, temp_needed, processing, convert = 0; + int rotate90, vflip, hflip, crop; unsigned char *convert1_dest = dest; unsigned char *convert2_src = src, *convert2_dest = dest; unsigned char *rotate90_src = src, *rotate90_dest = dest; @@ -864,14 +874,15 @@ int v4lconvert_convert(struct v4lconvert_data *data, struct v4l2_format my_dest_fmt = *dest_fmt; processing = v4lprocessing_pre_processing(data->processing); + rotate90 = data->control_flags & V4LCONTROL_ROTATED_90_JPEG; + hflip = v4lcontrol_get_ctrl(data->control, V4LCONTROL_HFLIP); + vflip = v4lcontrol_get_ctrl(data->control, V4LCONTROL_VFLIP); + crop = my_dest_fmt.fmt.pix.width != my_src_fmt.fmt.pix.width || + my_dest_fmt.fmt.pix.height != my_src_fmt.fmt.pix.height; if (/* If no conversion/processing is needed */ - (src_fmt->fmt.pix.width == dest_fmt->fmt.pix.width && - src_fmt->fmt.pix.height == dest_fmt->fmt.pix.height && - src_fmt->fmt.pix.pixelformat == dest_fmt->fmt.pix.pixelformat && - !processing && - !(data->control_flags & (V4LCONTROL_ROTATED_90_JPEG | - V4LCONTROL_VFLIPPED | V4LCONTROL_HFLIPPED))) || + (src_fmt->fmt.pix.pixelformat == dest_fmt->fmt.pix.pixelformat && + !processing && !rotate90 && !hflip && !vflip && !crop) || /* or if we should do processing/rotating/flipping but the app tries to use the native cam format, we just return an unprocessed frame copy */ !v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat)) { @@ -923,10 +934,6 @@ int v4lconvert_convert(struct v4lconvert_data *data, else if (my_dest_fmt.fmt.pix.pixelformat != my_src_fmt.fmt.pix.pixelformat) convert = 1; - if (my_dest_fmt.fmt.pix.width != my_src_fmt.fmt.pix.width || - my_dest_fmt.fmt.pix.height != my_src_fmt.fmt.pix.height) - crop = 1; - /* convert_pixfmt (only if convert == 2) -> processing -> convert_pixfmt -> rotate -> flip -> crop, all steps are optional */ if (convert == 2) { @@ -939,8 +946,7 @@ int v4lconvert_convert(struct v4lconvert_data *data, convert2_src = convert1_dest; } - if (convert && ((data->control_flags & (V4LCONTROL_ROTATED_90_JPEG | - V4LCONTROL_VFLIPPED | V4LCONTROL_HFLIPPED)) || crop)) { + if (convert && (rotate90 || hflip || vflip || crop)) { convert2_dest = v4lconvert_alloc_buffer(data, temp_needed, &data->convert2_buf, &data->convert2_buf_size); if (!convert2_dest) @@ -949,9 +955,7 @@ int v4lconvert_convert(struct v4lconvert_data *data, rotate90_src = flip_src = crop_src = convert2_dest; } - if ((data->control_flags & V4LCONTROL_ROTATED_90_JPEG) && - ((data->control_flags & (V4LCONTROL_VFLIPPED | V4LCONTROL_HFLIPPED)) || - crop)) { + if (rotate90 && (hflip || vflip || crop)) { rotate90_dest = v4lconvert_alloc_buffer(data, temp_needed, &data->rotate90_buf, &data->rotate90_buf_size); if (!rotate90_dest) @@ -960,8 +964,7 @@ int v4lconvert_convert(struct v4lconvert_data *data, flip_src = crop_src = rotate90_dest; } - if ((data->control_flags & (V4LCONTROL_VFLIPPED | V4LCONTROL_HFLIPPED)) && - crop) { + if ((vflip || hflip) && crop) { flip_dest = v4lconvert_alloc_buffer(data, temp_needed, &data->flip_buf, &data->flip_buf_size); if (!flip_dest) @@ -1001,11 +1004,11 @@ int v4lconvert_convert(struct v4lconvert_data *data, if (processing) v4lprocessing_processing(data->processing, rotate90_src, &my_src_fmt); - if (data->control_flags & V4LCONTROL_ROTATED_90_JPEG) + if (rotate90) v4lconvert_rotate90(rotate90_src, rotate90_dest, &my_src_fmt); - if (data->control_flags & (V4LCONTROL_VFLIPPED | V4LCONTROL_HFLIPPED)) - v4lconvert_flip(flip_src, flip_dest, &my_src_fmt, data->control_flags); + if (hflip || vflip) + v4lconvert_flip(flip_src, flip_dest, &my_src_fmt, hflip, vflip); if (crop) v4lconvert_crop(crop_src, dest, &my_src_fmt, &my_dest_fmt); -- cgit v1.2.3 From 62805a6b176a0bbd17ab8fa421791765186fb77d Mon Sep 17 00:00:00 2001 From: "hans@localhost.localdomain" Date: Thu, 21 May 2009 13:08:29 +0200 Subject: libv4l: rewrite video processing code From: Hans de Goede Rewrite video processing code to make it easier to add more video filters (and with little extra processing cost). As part of this the normalize filter has been removed as it wasn't functioning satisfactory anyways Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 3 + v4l2-apps/libv4l/TODO | 3 - v4l2-apps/libv4l/libv4lconvert/Makefile | 2 +- .../libv4lconvert/control/libv4lcontrol-priv.h | 7 +- .../libv4l/libv4lconvert/control/libv4lcontrol.c | 107 ++++----- .../libv4l/libv4lconvert/control/libv4lcontrol.h | 7 +- .../libv4l/libv4lconvert/libv4lconvert-priv.h | 1 + v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 3 +- .../libv4lconvert/processing/bayerprocessing.c | 244 --------------------- .../processing/libv4lprocessing-priv.h | 68 ++---- .../libv4lconvert/processing/libv4lprocessing.c | 202 +++++++++-------- .../libv4lconvert/processing/rgbprocessing.c | 156 ------------- .../libv4l/libv4lconvert/processing/whitebalance.c | 143 ++++++++++++ 13 files changed, 319 insertions(+), 627 deletions(-) delete mode 100644 v4l2-apps/libv4l/libv4lconvert/processing/bayerprocessing.c delete mode 100644 v4l2-apps/libv4l/libv4lconvert/processing/rgbprocessing.c create mode 100644 v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index 9bfecab85..73b237a93 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -10,6 +10,9 @@ libv4l-0.5.98 * Fix a bug in v4lconvert_uyvy_to_yuv420() * Add support for separate vflipping and hflipping * Add fake controls controlling the software h- and v-flipping +* Rewrite video processing code to make it easier to add more video filters + (and with little extra processing cost). As part of this the normalize + filter has been removed as it wasn't functioning satisfactory anyways libv4l-0.5.97 ------------- diff --git a/v4l2-apps/libv4l/TODO b/v4l2-apps/libv4l/TODO index b676bfeb5..959adc574 100644 --- a/v4l2-apps/libv4l/TODO +++ b/v4l2-apps/libv4l/TODO @@ -19,7 +19,4 @@ -add software auto exposure (for spca561 cams) --change video processing to use a per component lookup table for easy combining of - of different effects in 1 pass - -add gamma correction video processing diff --git a/v4l2-apps/libv4l/libv4lconvert/Makefile b/v4l2-apps/libv4l/libv4lconvert/Makefile index ffc2e337d..49d508694 100644 --- a/v4l2-apps/libv4l/libv4lconvert/Makefile +++ b/v4l2-apps/libv4l/libv4lconvert/Makefile @@ -16,7 +16,7 @@ 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/rgbprocessing.o processing/bayerprocessing.o + processing/whitebalance.o TARGETS = $(CONVERT_LIB) libv4lconvert.pc INCLUDES = ../include/libv4lconvert.h diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h index 0157af280..14e4fe838 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h @@ -24,16 +24,12 @@ #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; /* 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 */ + unsigned int old_values[V4LCONTROL_COUNT]; /* for controls_changed() */ }; struct v4lcontrol_flags_info { @@ -46,7 +42,6 @@ struct v4lcontrol_flags_info { 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 b120aa2fc..4d227c366 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c @@ -56,30 +56,32 @@ static const struct v4lcontrol_flags_info v4lcontrol_flags[] = { /* First: Upside down devices */ /* Philips SPC200NC */ - { 0x0471, 0x0325, 0, NULL, NULL, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED, 0 }, + { 0x0471, 0x0325, 0, NULL, NULL, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, /* Philips SPC300NC */ - { 0x0471, 0x0326, 0, NULL, NULL, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED, 0 }, + { 0x0471, 0x0326, 0, NULL, NULL, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, /* Philips SPC210NC */ - { 0x0471, 0x032d, 0, NULL, NULL, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED, 0 }, - /* Genius E-M 112 (also needs processing) */ - { 0x093a, 0x2476, 0, NULL, NULL, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED, - V4LCONTROL_WANTS_WB }, + { 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 }, /* Asus N50Vn laptop */ { 0x04f2, 0xb106, 0, "ASUSTeK Computer Inc. ", "N50Vn ", - V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED, 0 }, -/* Second: devices which can benefit from software video processing */ + V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, +/* Second: devices which should use sw whitebalance by default */ /* Pac207 based devices */ - { 0x041e, 0x4028, 0, NULL, NULL, 0, V4LCONTROL_WANTS_WB }, - { 0x093a, 0x2460, 0x1f, NULL, NULL, 0, V4LCONTROL_WANTS_WB }, - { 0x145f, 0x013a, 0, NULL, NULL, 0, V4LCONTROL_WANTS_WB }, - { 0x2001, 0xf115, 0, NULL, NULL, 0, V4LCONTROL_WANTS_WB }, + { 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 }, /* Pac7302 based devices */ - { 0x093a, 0x2620, 0x0f, NULL, NULL, V4LCONTROL_ROTATED_90_JPEG, - V4LCONTROL_WANTS_WB }, + { 0x093a, 0x2620, 0x0f, NULL, NULL, + V4LCONTROL_ROTATED_90_JPEG|V4LCONTROL_WANTS_WB }, /* sq905 devices */ - { 0x2770, 0x9120, 0, NULL, NULL, 0, V4LCONTROL_WANTS_WB }, + { 0x2770, 0x9120, 0, NULL, NULL, V4LCONTROL_WANTS_WB }, }; +static const struct v4l2_queryctrl fake_controls[]; + static void v4lcontrol_init_flags(struct v4lcontrol_data *data) { struct stat st; @@ -193,7 +195,6 @@ 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->controls = v4lcontrol_flags[i].controls; break; } } @@ -215,21 +216,21 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) v4lcontrol_init_flags(data); + /* Allow overriding through environment */ + if ((s = getenv("LIBV4LCONTROL_FLAGS"))) + data->flags = strtol(s, NULL, 0); + /* If the device always needs conversion, we can add fake controls at no cost (no cost when not activated by the user that is) */ if (always_needs_conversion || v4lcontrol_needs_conversion(data)) { - ctrl.id = V4L2_CID_HFLIP; - if (syscall(SYS_ioctl, data->fd, VIDIOC_QUERYCTRL, &ctrl) == -1) - data->controls |= 1 << V4LCONTROL_HFLIP; - ctrl.id = V4L2_CID_VFLIP; - if (syscall(SYS_ioctl, data->fd, VIDIOC_QUERYCTRL, &ctrl) == -1) - data->controls |= 1 << V4LCONTROL_VFLIP; + for (i = 0; i < V4LCONTROL_COUNT; i++) { + ctrl.id = fake_controls[i].id; + if (syscall(SYS_ioctl, data->fd, VIDIOC_QUERYCTRL, &ctrl) == -1) + data->controls |= 1 << i; + } } /* 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); @@ -265,8 +266,8 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) 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; + if (data->flags & V4LCONTROL_WANTS_WB) + data->shm_values[V4LCONTROL_WHITEBALANCE] = 1; } return data; @@ -284,47 +285,17 @@ void v4lcontrol_destroy(struct v4lcontrol_data *data) } /* FIXME get better CID's for normalize */ -struct v4l2_queryctrl fake_controls[V4LCONTROL_COUNT] = { +static const struct v4l2_queryctrl fake_controls[V4LCONTROL_COUNT] = { { .id = V4L2_CID_AUTO_WHITE_BALANCE, .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Whitebalance", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - .flags = 0 -}, -{ - .id = V4L2_CID_DO_WHITE_BALANCE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Normalize", + .name = "Whitebalance (software)", .minimum = 0, .maximum = 1, .step = 1, .default_value = 0, .flags = 0 }, -{ - .id = V4L2_CID_BLACK_LEVEL, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Normalize: low bound", - .minimum = 0, - .maximum = 127, - .step = 1, - .default_value = 0, - .flags = 0 -}, -{ - .id = V4L2_CID_WHITENESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Normalize: high bound", - .minimum = 128, - .maximum = 255, - .step = 1, - .default_value = 255, - .flags = 0 -}, { .id = V4L2_CID_HFLIP, .type = V4L2_CTRL_TYPE_BOOLEAN, @@ -359,6 +330,11 @@ int v4lcontrol_vidioc_queryctrl(struct v4lcontrol_data *data, void *arg) if ((data->controls & (1 << i)) && ctrl->id == fake_controls[i].id) { memcpy(ctrl, &fake_controls[i], sizeof(struct v4l2_queryctrl)); + /* Hmm, not pretty */ + if (ctrl->id == V4L2_CID_AUTO_WHITE_BALANCE && + (data->flags & V4LCONTROL_WANTS_WB)) + ctrl->default_value = 1; + return 0; } @@ -434,6 +410,19 @@ int v4lcontrol_get_ctrl(struct v4lcontrol_data *data, int ctrl) return 0; } +int v4lcontrol_controls_changed(struct v4lcontrol_data *data) +{ + int res; + + res = memcmp(data->shm_values, data->old_values, + V4LCONTROL_COUNT * sizeof(unsigned int)); + + memcpy(data->old_values, data->shm_values, + V4LCONTROL_COUNT * sizeof(unsigned int)); + + return res; +} + /* See the comment about this in libv4lconvert.h */ int v4lcontrol_needs_conversion(struct v4lcontrol_data *data) { return data->flags || data->controls; diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h index 43ef7c49f..85129ee4c 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h @@ -26,13 +26,11 @@ #define V4LCONTROL_HFLIPPED 0x01 #define V4LCONTROL_VFLIPPED 0x02 #define V4LCONTROL_ROTATED_90_JPEG 0x04 +#define V4LCONTROL_WANTS_WB 0x08 /* Controls */ enum { V4LCONTROL_WHITEBALANCE, - V4LCONTROL_NORMALIZE, - V4LCONTROL_NORM_LOW_BOUND, - V4LCONTROL_NORM_HIGH_BOUND, V4LCONTROL_HFLIP, V4LCONTROL_VFLIP, V4LCONTROL_COUNT }; @@ -45,6 +43,9 @@ 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); +/* Check if the controls have changed since the last time this function + was called */ +int v4lcontrol_controls_changed(struct v4lcontrol_data *data); /* Check if we must go through the conversion path (and thus alloc conversion buffers, etc. in libv4l2). Note this always return 1 if we *may* need rotate90 / flipping / processing, as if we actually need this may change diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h index 60e62af97..407be3435 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h @@ -83,6 +83,7 @@ #define V4L2_PIX_FMT_SN9C20X_I420 v4l2_fourcc('S', '9', '2', '0') #endif +#define ARRAY_SIZE(x) ((int)sizeof(x)/(int)sizeof((x)[0])) #define V4LCONVERT_ERROR_MSG_SIZE 256 #define V4LCONVERT_MAX_FRAMESIZES 16 diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index 94539e376..1a94b53ba 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -27,7 +27,6 @@ #include "libv4lconvert-priv.h" #define MIN(a,b) (((a)<(b))?(a):(b)) -#define ARRAY_SIZE(x) ((int)sizeof(x)/(int)sizeof((x)[0])) /* Note for proper functioning of v4lconvert_enum_fmt the first entries in supported_src_pixfmts must match with the entries in supported_dst_pixfmts */ @@ -706,6 +705,8 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, } /* Do processing on the tmp buffer, because doing it on bayer data is cheaper, and bayer == rgb and our dest_fmt may be yuv */ + tmpfmt.fmt.pix.bytesperline = width; + tmpfmt.fmt.pix.sizeimage = width * height; v4lprocessing_processing(data->processing, tmpbuf, &tmpfmt); /* Deliberate fall through to raw bayer fmt code! */ src_pix_fmt = tmpfmt.fmt.pix.pixelformat; diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/bayerprocessing.c b/v4l2-apps/libv4l/libv4lconvert/processing/bayerprocessing.c deleted file mode 100644 index f4cc9922b..000000000 --- a/v4l2-apps/libv4l/libv4lconvert/processing/bayerprocessing.c +++ /dev/null @@ -1,244 +0,0 @@ -/* -# (C) 2008-2009 Elmar Kleijn -# (C) 2008-2009 Sjoerd Piepenbrink -# (C) 2008-2009 Hans de Goede - -# 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 "libv4lprocessing-priv.h" -#include "../libv4lconvert-priv.h" /* for PIX_FMT defines */ - -void bayer_normalize_analyse(unsigned char *buf, int width, int height, - struct v4lprocessing_data *data) -{ - int value, max = 0, min = 255; - unsigned char *buf_end = buf + width * height; - - while (buf < buf_end) { - value = *buf++; - if (max < value) - max = value; - if (min > value) - min = value; - } - - data->comp1 = ((data->norm_high_bound - data->norm_low_bound) << 16) / (max - min); - data->offset1 = min; - data->offset2 = data->norm_low_bound; -} - -void bayer_whitebalance_analyse(unsigned char *src_buffer, int width, - int height, unsigned int pix_fmt, struct v4lprocessing_data *data) -{ - int i, j, x1 = 0, x2 = 0, y1 = 0, y2 = 0; - float green_avg, x_avg, y_avg, avg_avg; - unsigned char *buf = src_buffer; - - int start_with_green = pix_fmt == V4L2_PIX_FMT_SGBRG8 || - pix_fmt == V4L2_PIX_FMT_SGRBG8; - - for (i = 0; i < height; i += 2) { - for (j = 0; j < width; j += 2) { - x1 += *buf++; - x2 += *buf++; - } - for (j = 0; j < width; j += 2) { - y1 += *buf++; - y2 += *buf++; - } - } - - if (start_with_green) { - green_avg = (x1 + y2) / 2; - x_avg = x2; - y_avg = y1; - } else { - green_avg = (x2 + y1) / 2; - x_avg = x1; - y_avg = y2; - } - - avg_avg = (green_avg + x_avg + y_avg) / 3; - - data->comp1 = (avg_avg / green_avg) * 65536; - data->comp2 = (avg_avg / x_avg) * 65536; - data->comp3 = (avg_avg / y_avg) * 65536; -} - -void bayer_normalize_whitebalance_analyse(unsigned char *buf, int width, - int height, unsigned int pix_fmt, struct v4lprocessing_data *data) -{ - int i, j, value, max = 0, min = 255, n_fac, x1 = 0, x2 = 0, y1 = 0, y2 = 0; - float green_avg, x_avg, y_avg, avg_avg; - - int start_with_green = pix_fmt == V4L2_PIX_FMT_SGBRG8 || - pix_fmt == V4L2_PIX_FMT_SGRBG8; - - for (i = 0; i < height; i += 2) { - for (j = 0; j < width; j += 2) { - x1 += *buf; - value = *buf++; - if (max < value) - max = value; - if (min > value) - min = value; - x2 += *buf; - value = *buf++; - if (max < value) - max = value; - if (min > value) - min = value; - } - for (j = 0; j < width; j += 2) { - y1 += *buf; - value = *buf++; - if (max < value) - max = value; - if (min > value) - min = value; - y2 += *buf; - value = *buf++; - if (max < value) - max = value; - if (min > value) - min = value; - } - } - - if (start_with_green) { - green_avg = (x1 + y2) / 2; - x_avg = x2; - y_avg = y1; - } else { - green_avg = (x2 + y1) / 2; - x_avg = x1; - y_avg = y2; - } - - n_fac = ((data->norm_high_bound - data->norm_low_bound) << 16) / (max - min); - - avg_avg = (green_avg + x_avg + y_avg) / 3; - - data->comp1 = (avg_avg / green_avg) * n_fac; - data->comp2 = (avg_avg / x_avg) * n_fac; - data->comp3 = (avg_avg / y_avg) * n_fac; - - data->offset1 = min; - data->offset2 = data->norm_low_bound; -} - -#define CLIP(color) (unsigned char)(((color)>0xff)?0xff:(((color)<0)?0:(color))) -#define TOP(color) (unsigned char)(((color)>0xff)?0xff:(color)) - -void bayer_normalize(unsigned char *buf, int width, - int height, struct v4lprocessing_data *data) -{ - int value; - unsigned char *buf_end = buf + width * height; - - while (buf < buf_end) { - value = ((data->comp1 * (*buf - data->offset1)) >> 16) + data->offset2; - *buf++ = CLIP(value); - } -} - -void bayer_whitebalance(unsigned char *src_buffer, int width, - int height, unsigned int pix_fmt, - struct v4lprocessing_data *data) -{ - int i, j, value; - int limit = width * height; - unsigned char *buf = src_buffer; - - int start_with_green = pix_fmt == V4L2_PIX_FMT_SGBRG8 || - pix_fmt == V4L2_PIX_FMT_SGRBG8; - - if (start_with_green) { - for (i = 0; i < height; i += 2) { - for (j = 0; j < width; j += 2) { - value = (*buf * data->comp1) >> 16; - *buf++ = TOP(value); - value = (*buf * data->comp2) >> 16; - *buf++ = TOP(value); - } - for (j = 0; j < width; j += 2) { - value = (*buf * data->comp3) >> 16; - *buf++ = TOP(value); - value = (*buf * data->comp1) >> 16; - *buf++ = TOP(value); - } - } - } else { - for (i = 0; i < height; i += 2) { - for (j = 0; j < width; j += 2) { - value = (*buf * data->comp2) >> 16; - *buf++ = TOP(value); - value = (*buf * data->comp1) >> 16; - *buf++ = TOP(value); - } - for (j = 0; j < width; j += 2) { - value = (*buf * data->comp1) >> 16; - *buf++ = TOP(value); - value = (*buf * data->comp3) >> 16; - *buf++ = TOP(value); - } - } - } -} - -void bayer_normalize_whitebalance(unsigned char *src_buffer, int width, - int height, unsigned int pix_fmt, - struct v4lprocessing_data *data) -{ - int i, j, value; - int limit = width * height; - unsigned char *buf = src_buffer; - - int start_with_green = pix_fmt == V4L2_PIX_FMT_SGBRG8 || - pix_fmt == V4L2_PIX_FMT_SGRBG8; - - if (start_with_green) { - for (i = 0; i < height; i += 2) { - for (j = 0; j < width; j += 2) { - value = ((data->comp1 * (*buf - data->offset1)) >> 16) + data->offset2; - *buf++ = CLIP(value); - value = ((data->comp2 * (*buf - data->offset1)) >> 16) + data->offset2; - *buf++ = CLIP(value); - } - for (j = 0; j < width; j += 2) { - value = ((data->comp3 * (*buf - data->offset1)) >> 16) + data->offset2; - *buf++ = CLIP(value); - value = ((data->comp1 * (*buf - data->offset1)) >> 16) + data->offset2; - *buf++ = CLIP(value); - } - } - } else { - for (i = 0; i < height; i += 2) { - for (j = 0; j < width; j += 2) { - value = ((data->comp2 * (*buf - data->offset1)) >> 16) + data->offset2; - *buf++ = CLIP(value); - value = ((data->comp1 * (*buf - data->offset1)) >> 16) + data->offset2; - *buf++ = CLIP(value); - } - for (j = 0; j < width; j += 2) { - value = ((data->comp1 * (*buf - data->offset1)) >> 16) + data->offset2; - *buf++ = CLIP(value); - value = ((data->comp3 * (*buf - data->offset1)) >> 16) + data->offset2; - *buf++ = CLIP(value); - } - } - } -} diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h index f2aae373d..fb514d7f5 100644 --- a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h +++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h @@ -23,67 +23,31 @@ #include "../control/libv4lcontrol.h" -#define V4L2PROCESSING_PROCESS_NONE 0x00 -#define V4L2PROCESSING_PROCESS_NORMALIZE 0x01 -#define V4L2PROCESSING_PROCESS_WHITEBALANCE 0x02 -#define V4L2PROCESSING_PROCESS_NORMALIZE_WHITEBALANCE 0x03 -#define V4L2PROCESSING_PROCESS_RGB_NORMALIZE 0x01 -#define V4L2PROCESSING_PROCESS_RGB_WHITEBALANCE 0x02 -#define V4L2PROCESSING_PROCESS_RGB_NORMALIZE_WHITEBALANCE 0x03 -#define V4L2PROCESSING_PROCESS_BAYER_NORMALIZE 0x11 -#define V4L2PROCESSING_PROCESS_BAYER_WHITEBALANCE 0x12 -#define V4L2PROCESSING_PROCESS_BAYER_NORMALIZE_WHITEBALANCE 0x13 - #define V4L2PROCESSING_UPDATE_RATE 10 struct v4lprocessing_data { struct v4lcontrol_data *control; int do_process; - /* Provides the current type of processing */ - int process; - int norm_low_bound; - int norm_high_bound; + /* True if any of the lookup tables does not contain + linear 0-255 */ + int lookup_table_active; /* Counts the number of processed frames until a V4L2PROCESSING_UPDATE_RATE overflow happens */ - int processing_data_update; - /* Multiplication factors and offsets from the analyse functions */ - int comp1; - int comp2; - int comp3; - int comp4; - int offset1; - int offset2; + int lookup_table_update_counter; + /* RGB/BGR lookup tables */ + unsigned char comp1[256]; + unsigned char green[256]; + unsigned char comp2[256]; }; -/* Processing Bayer */ -void bayer_normalize_analyse(unsigned char *src_buffer, int width, int height, - struct v4lprocessing_data *data); -void bayer_whitebalance_analyse(unsigned char *src_buffer, int width, - int height, unsigned int pix_fmt, - struct v4lprocessing_data *data); -void bayer_normalize_whitebalance_analyse(unsigned char *src_buffer, - int width, int height, unsigned int pix_fmt, - struct v4lprocessing_data *data); -void bayer_normalize(unsigned char *src_buffer, int width, int height, - struct v4lprocessing_data *data); -void bayer_whitebalance(unsigned char *src_buffer, int width, int height, - unsigned int pix_fmt, struct v4lprocessing_data *data); -void bayer_normalize_whitebalance(unsigned char *src_buffer, int width, - int height, unsigned int pix_fmt, - struct v4lprocessing_data *data); +struct v4lprocessing_filter { + /* Returns 1 if the filter is active */ + int (*active)(struct v4lprocessing_data *data); + /* Returns 1 if any of the lookup tables was changed */ + int (*calculate_lookup_tables)(struct v4lprocessing_data *data, + unsigned char *buf, const struct v4l2_format *fmt); +}; -/* Processing RGB */ -void rgb_normalize_analyse(unsigned char *src_buffer, int width, int height, - struct v4lprocessing_data *data); -void rgb_whitebalance_analyse(unsigned char *src_buffer, int width, int height, - struct v4lprocessing_data *data); -void rgb_normalize_whitebalance_analyse(unsigned char *src_buffer, - int width, int height, struct v4lprocessing_data *data); -void rgb_normalize(unsigned char *src_buffer, int width, int height, - struct v4lprocessing_data *data); -void rgb_whitebalance(unsigned char *src_buffer, int width, int height, - struct v4lprocessing_data *data); -void rgb_normalize_whitebalance(unsigned char *src_buffer, int width, - int height, struct v4lprocessing_data *data); +extern struct v4lprocessing_filter whitebalance_filter; #endif diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c index f986da02d..3a3802aab 100644 --- a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c +++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c @@ -28,6 +28,10 @@ #include "libv4lprocessing-priv.h" #include "../libv4lconvert-priv.h" /* for PIX_FMT defines */ +static struct v4lprocessing_filter *filters[] = { + &whitebalance_filter, +}; + struct v4lprocessing_data *v4lprocessing_create(struct v4lcontrol_data* control) { struct v4lprocessing_data *data = @@ -46,136 +50,130 @@ void v4lprocessing_destroy(struct v4lprocessing_data *data) free(data); } -static int v4lprocessing_get_process(struct v4lprocessing_data *data, - unsigned int pix_fmt) +int v4lprocessing_pre_processing(struct v4lprocessing_data *data) { - int process = V4L2PROCESSING_PROCESS_NONE; + int i; - switch(pix_fmt) { - case V4L2_PIX_FMT_SBGGR8: - case V4L2_PIX_FMT_SGBRG8: - case V4L2_PIX_FMT_SGRBG8: - case V4L2_PIX_FMT_SRGGB8: - if (v4lcontrol_get_ctrl(data->control, V4LCONTROL_NORMALIZE)) { - process |= V4L2PROCESSING_PROCESS_BAYER_NORMALIZE; - } - if (v4lcontrol_get_ctrl(data->control, V4LCONTROL_WHITEBALANCE)) { - process |= V4L2PROCESSING_PROCESS_BAYER_WHITEBALANCE; - } - break; - case V4L2_PIX_FMT_RGB24: - case V4L2_PIX_FMT_BGR24: - if (v4lcontrol_get_ctrl(data->control, V4LCONTROL_NORMALIZE)) { - process |= V4L2PROCESSING_PROCESS_RGB_NORMALIZE; - } - if (v4lcontrol_get_ctrl(data->control, V4LCONTROL_WHITEBALANCE)) { - process |= V4L2PROCESSING_PROCESS_RGB_WHITEBALANCE; - } - break; + data->do_process = 0; + for (i = 0; i < ARRAY_SIZE(filters); i++) { + if (filters[i]->active(data)) + data->do_process = 1; } - return process; + return data->do_process; } -static void v4lprocessing_update_processing_data( - struct v4lprocessing_data *data, - unsigned int pix_fmt, unsigned char *buf, unsigned int width, - unsigned int height) +static void v4lprocessing_update_lookup_tables(struct v4lprocessing_data *data, + unsigned char *buf, const struct v4l2_format *fmt) { - switch (data->process) { - case V4L2PROCESSING_PROCESS_BAYER_NORMALIZE: - bayer_normalize_analyse(buf, width, height, data); - break; + int i; - case V4L2PROCESSING_PROCESS_BAYER_WHITEBALANCE: - bayer_whitebalance_analyse(buf, width, height, pix_fmt, data); - break; + for (i = 0; i < 256; i++) { + data->comp1[i] = i; + data->green[i] = i; + data->comp2[i] = i; + } - case V4L2PROCESSING_PROCESS_BAYER_NORMALIZE_WHITEBALANCE: - bayer_normalize_whitebalance_analyse(buf, width, height, pix_fmt, data); - break; + data->lookup_table_active = 0; + for (i = 0; i < ARRAY_SIZE(filters); i++) { + if (filters[i]->active(data)) { + if (filters[i]->calculate_lookup_tables(data, buf, fmt)) + data->lookup_table_active = 1; + } + } +} + +static void v4lprocessing_do_processing(struct v4lprocessing_data *data, + unsigned char *buf, const struct v4l2_format *fmt) +{ + int x, y; - case V4L2PROCESSING_PROCESS_RGB_NORMALIZE: - rgb_normalize_analyse(buf, width, height, data); + switch (fmt->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: /* Bayer patterns starting with green */ + for (y = 0; y < fmt->fmt.pix.height / 2; y++) { + for (x = 0; x < fmt->fmt.pix.width / 2; x++) { + *buf = data->green[*buf]; + buf++; + *buf = data->comp1[*buf]; + buf++; + } + buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width; + for (x = 0; x < fmt->fmt.pix.width / 2; x++) { + *buf = data->comp2[*buf]; + buf++; + *buf = data->green[*buf]; + buf++; + } + buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width; + } break; - case V4L2PROCESSING_PROCESS_RGB_WHITEBALANCE: - rgb_whitebalance_analyse(buf, width, height, data); + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SRGGB8: /* Bayer patterns *NOT* starting with green */ + for (y = 0; y < fmt->fmt.pix.height / 2; y++) { + for (x = 0; x < fmt->fmt.pix.width / 2; x++) { + *buf = data->comp1[*buf]; + buf++; + *buf = data->green[*buf]; + buf++; + } + buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width; + for (x = 0; x < fmt->fmt.pix.width / 2; x++) { + *buf = data->green[*buf]; + buf++; + *buf = data->comp2[*buf]; + buf++; + } + buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width; + } break; - case V4L2PROCESSING_PROCESS_RGB_NORMALIZE_WHITEBALANCE: - rgb_normalize_whitebalance_analyse(buf, width, height, data); + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + for (y = 0; y < fmt->fmt.pix.height; y++) { + for (x = 0; x < fmt->fmt.pix.width; x++) { + *buf = data->comp1[*buf]; + buf++; + *buf = data->green[*buf]; + buf++; + *buf = data->comp2[*buf]; + buf++; + } + buf += fmt->fmt.pix.bytesperline - 3 * fmt->fmt.pix.width; + } break; } } -int v4lprocessing_pre_processing(struct v4lprocessing_data *data) -{ - data->do_process = - v4lcontrol_get_ctrl(data->control, V4LCONTROL_WHITEBALANCE) || - v4lcontrol_get_ctrl(data->control, V4LCONTROL_NORMALIZE); - - if (!data->do_process) - data->process = V4L2PROCESSING_PROCESS_NONE; - - return data->do_process; -} - void v4lprocessing_processing(struct v4lprocessing_data *data, unsigned char *buf, const struct v4l2_format *fmt) { - int low_bound, high_bound, process; - if (!data->do_process) return; - process = v4lprocessing_get_process(data, fmt->fmt.pix.pixelformat); - if (process == V4L2PROCESSING_PROCESS_NONE) { - return; - } - - low_bound = v4lcontrol_get_ctrl(data->control, V4LCONTROL_NORM_LOW_BOUND); - high_bound = v4lcontrol_get_ctrl(data->control, V4LCONTROL_NORM_HIGH_BOUND); - - if (process != data->process || low_bound != data->norm_low_bound || - high_bound != data->norm_high_bound) { - data->process = process; - data->norm_low_bound = low_bound; - data->norm_high_bound = high_bound; - data->processing_data_update = V4L2PROCESSING_UPDATE_RATE; + /* Do we support the current pixformat? */ + 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: + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + break; + default: + return; /* Non supported pix format */ } - if (data->processing_data_update == V4L2PROCESSING_UPDATE_RATE) { - data->processing_data_update = 0; - v4lprocessing_update_processing_data(data, fmt->fmt.pix.pixelformat, buf, fmt->fmt.pix.width, fmt->fmt.pix.height); + if (v4lcontrol_controls_changed(data->control) || + data->lookup_table_update_counter == V4L2PROCESSING_UPDATE_RATE) { + v4lprocessing_update_lookup_tables(data, buf, fmt); + data->lookup_table_update_counter = 0; } else - data->processing_data_update++; - - switch (data->process) { - case V4L2PROCESSING_PROCESS_BAYER_NORMALIZE: - bayer_normalize(buf, fmt->fmt.pix.width, fmt->fmt.pix.height, data); - break; - - case V4L2PROCESSING_PROCESS_BAYER_WHITEBALANCE: - bayer_whitebalance(buf, fmt->fmt.pix.width, fmt->fmt.pix.height, fmt->fmt.pix.pixelformat, data); - break; - - case V4L2PROCESSING_PROCESS_BAYER_NORMALIZE_WHITEBALANCE: - bayer_normalize_whitebalance(buf, fmt->fmt.pix.width, fmt->fmt.pix.height, fmt->fmt.pix.pixelformat, - data); - break; - - case V4L2PROCESSING_PROCESS_RGB_NORMALIZE: - rgb_normalize(buf, fmt->fmt.pix.width, fmt->fmt.pix.height, data); - break; + data->lookup_table_update_counter++; - case V4L2PROCESSING_PROCESS_RGB_WHITEBALANCE: - rgb_whitebalance(buf, fmt->fmt.pix.width, fmt->fmt.pix.height, data); - break; + if (data->lookup_table_active) + v4lprocessing_do_processing(data, buf, fmt); - case V4L2PROCESSING_PROCESS_RGB_NORMALIZE_WHITEBALANCE: - rgb_normalize_whitebalance(buf, fmt->fmt.pix.width, fmt->fmt.pix.height, data); - break; - } data->do_process = 0; } diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/rgbprocessing.c b/v4l2-apps/libv4l/libv4lconvert/processing/rgbprocessing.c deleted file mode 100644 index 4e0fc3f4a..000000000 --- a/v4l2-apps/libv4l/libv4lconvert/processing/rgbprocessing.c +++ /dev/null @@ -1,156 +0,0 @@ -/* -# (C) 2008-2009 Elmar Kleijn -# (C) 2008-2009 Sjoerd Piepenbrink -# (C) 2008-2009 Hans de Goede - -# 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 "libv4lprocessing-priv.h" - -void rgb_normalize_analyse(unsigned char *buf, int width, int height, - struct v4lprocessing_data *data) -{ - int value, max = 0, min = 255; - unsigned char *buf_end = buf + width * height * 3; - - while (buf < buf_end) { - value = *buf++; - if (max < value) - max = value; - if (min > value) - min = value; - } - - data->comp1 = ((data->norm_high_bound - data->norm_low_bound) << 16) / (max - min); - data->offset1 = min; - data->offset2 = data->norm_low_bound; -} - -void rgb_whitebalance_analyse(unsigned char *buf, int width, int height, - struct v4lprocessing_data *data) -{ - int value, x = 0, y = 0, z = 0; - float x_avg, y_avg, z_avg, avg_avg; - unsigned char *buf_end = buf + width * height * 3; - - while (buf < buf_end) { - x += *buf++; - y += *buf++; - z += *buf++; - } - - x_avg = x; - y_avg = y; - z_avg = z; - avg_avg = (x_avg + y_avg + z_avg) / 3; - - data->comp1 = (avg_avg / x_avg) * 65536; - data->comp2 = (avg_avg / y_avg) * 65536; - data->comp3 = (avg_avg / z_avg) * 65536; -} - -void rgb_normalize_whitebalance_analyse(unsigned char *buf, - int width, int height, struct v4lprocessing_data *data) -{ - int value, max = 0, min = 255; - int n_fac, wb_max, x = 0, y = 0, z = 0; - float x_avg, y_avg, z_avg, avg_avg; - unsigned char *buf_end = buf + width * height * 3; - - while (buf < buf_end) { - x += *buf; - value = *buf++; - if (max < value) - max = value; - if (min > value) - min = value; - y += *buf; - value = *buf++; - if (max < value) - max = value; - if (min > value) - min = value; - z += *buf; - value = *buf++; - if (max < value) - max = value; - if (min > value) - min = value; - } - - x_avg = x; - y_avg = y; - z_avg = z; - avg_avg = (x_avg + y_avg + z_avg) / 3; - - n_fac = ((data->norm_high_bound - data->norm_low_bound) << 16) / (max - min); - - data->comp1 = (avg_avg / x_avg) * n_fac; - data->comp2 = (avg_avg / y_avg) * n_fac; - data->comp3 = (avg_avg / z_avg) * n_fac; - - data->offset1 = min; - data->offset2 = data->norm_low_bound; -} - -#define CLIP(color) (unsigned char)(((color)>0xff)?0xff:(((color)<0)?0:(color))) -#define TOP(color) (unsigned char)(((color)>0xff)?0xff:(color)) - -void rgb_normalize(unsigned char *buf, int width, int height, - struct v4lprocessing_data *data) -{ - int value; - unsigned char *buf_end = buf + width * height * 3; - - while (buf < buf_end) { - value = ((data->comp1 * (*buf - data->offset1)) >> 16) + - data->offset2; - *buf++ = CLIP(value); - } -} - -void rgb_whitebalance(unsigned char *buf, int width, int height, - struct v4lprocessing_data *data) -{ - int value; - unsigned char *buf_end = buf + width * height * 3; - - while (buf < buf_end) { - value = (*buf * data->comp1) >> 16; - *buf++ = TOP(value); - value = (*buf * data->comp2) >> 16; - *buf++ = TOP(value); - value = (*buf * data->comp3) >> 16; - *buf++ = TOP(value); - } -} - -void rgb_normalize_whitebalance(unsigned char *buf, int width, int height, - struct v4lprocessing_data *data) -{ - int i, value; - int limit = width * height * 3; - unsigned char *buf_end = buf + width * height * 3; - - while (buf < buf_end) { - value = ((data->comp1 * (*buf - data->offset1)) >> 16) + data->offset2; - *buf++ = CLIP(value); - value = ((data->comp2 * (*buf - data->offset1)) >> 16) + data->offset2; - *buf++ = CLIP(value); - value = ((data->comp3 * (*buf - data->offset1)) >> 16) + data->offset2; - *buf++ = CLIP(value); - } -} diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c b/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c new file mode 100644 index 000000000..f5bfd961c --- /dev/null +++ b/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c @@ -0,0 +1,143 @@ +/* +# (C) 2008-2009 Elmar Kleijn +# (C) 2008-2009 Sjoerd Piepenbrink +# (C) 2008-2009 Hans de Goede + +# 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 +#include +#include +#include +#include +#include +#include "libv4lprocessing.h" +#include "libv4lprocessing-priv.h" +#include "../libv4lconvert-priv.h" /* for PIX_FMT defines */ + +#define CLIP(color) (unsigned char)(((color)>0xff)?0xff:(((color)<0)?0:(color))) + +static int whitebalance_active(struct v4lprocessing_data *data) { + return v4lcontrol_get_ctrl(data->control, V4LCONTROL_WHITEBALANCE); +} + +static int whitebalance_calculate_lookup_tables_bayer( + struct v4lprocessing_data *data, unsigned char *buf, + 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; + + for (y = 0; y < fmt->fmt.pix.height; y += 2) { + for (x = 0; x < fmt->fmt.pix.width; x += 2) { + a1 += *buf++; + a2 += *buf++; + } + buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width; + for (x = 0; x < fmt->fmt.pix.width; x += 2) { + b1 += *buf++; + b2 += *buf++; + } + buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width; + } + + if (starts_with_green) { + green_avg = (a1 + b2) / 512; + comp1_avg = a2 / 256; + comp2_avg = b1 / 256; + } else { + green_avg = (a2 + b1) / 512; + comp1_avg = a1 / 256; + comp2_avg = b2 / 256; + } + + 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); + } + + return 1; +} + +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; + + for (y = 0; y < fmt->fmt.pix.height; y++) { + for (x = 0; x < fmt->fmt.pix.width; x++) { + comp1_avg += *buf++; + green_avg += *buf++; + comp2_avg += *buf++; + } + 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; + + 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; +} + + +static int whitebalance_calculate_lookup_tables( + struct v4lprocessing_data *data, + unsigned char *buf, const struct v4l2_format *fmt) +{ + switch (fmt->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: /* Bayer patterns starting with green */ + return whitebalance_calculate_lookup_tables_bayer(data, buf, fmt, 1); + + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SRGGB8: /* Bayer patterns *NOT* starting with green */ + return whitebalance_calculate_lookup_tables_bayer(data, buf, fmt, 0); + + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + return whitebalance_calculate_lookup_tables_rgb(data, buf, fmt); + } + + return 0; /* Should never happen */ +} + +struct v4lprocessing_filter whitebalance_filter = { + whitebalance_active, whitebalance_calculate_lookup_tables }; -- cgit v1.2.3 From fbb8b6b6db6a69404ec9735bff66ca628dd6c2f5 Mon Sep 17 00:00:00 2001 From: "hans@localhost.localdomain" Date: Thu, 21 May 2009 16:20:32 +0200 Subject: libv4l: Do not set format for control applications From: Hans de Goede When we must do conversion (as we want todo flipping / processing) and the cam does not default to a supported dest format, we set the emulated format to rgb24, wait with doing this till the app actually does something format related, otherwise control applications like v4l2ucp used to become the stream owner locking out other apps. Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/libv4l2/libv4l2.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2.c b/v4l2-apps/libv4l/libv4l2/libv4l2.c index fc5e63eaa..4f88ffd73 100644 --- a/v4l2-apps/libv4l/libv4l2/libv4l2.c +++ b/v4l2-apps/libv4l/libv4l2/libv4l2.c @@ -77,6 +77,7 @@ #define V4L2_STREAM_CONTROLLED_BY_READ 0x0400 #define V4L2_SUPPORTS_READ 0x0800 #define V4L2_IS_UVC 0x1000 +#define V4L2_STREAM_TOUCHED 0x2000 #define V4L2_MMAP_OFFSET_MAGIC 0xABCDEF00u @@ -516,14 +517,6 @@ int v4l2_fd_open(int fd, int v4l2_flags) V4L2_LOG("open: %d\n", fd); - if (v4lconvert_supported_dst_fmt_only(convert) && - !v4lconvert_supported_dst_format(fmt.fmt.pix.pixelformat)) { - V4L2_LOG("open %d: setting pixelformat to RGB24\n", fd); - fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24; - v4l2_ioctl(fd, VIDIOC_S_FMT, &fmt); - V4L2_LOG("open %d: done setting pixelformat\n", fd); - } - return fd; } @@ -746,8 +739,27 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) } - if (stream_needs_locking) + if (stream_needs_locking) { + /* If this is the first stream related ioctl, and we should only allow + libv4lconvert supported destination formats (so that it can do flipping, + processing, etc.) and the current destination format is not supported, + try setting the format to RGB24 (which is a supported dest. format). */ + if (!(devices[index].flags & V4L2_STREAM_TOUCHED) && + !(devices[index].flags & V4L2_DISABLE_CONVERSION) && + v4lconvert_supported_dst_fmt_only(devices[index].convert) && + !v4lconvert_supported_dst_format( + devices[index].dest_fmt.fmt.pix.pixelformat)) { + struct v4l2_format fmt = devices[index].dest_fmt; + + V4L2_LOG("Setting pixelformat to RGB24 (supported_dst_fmt_only)"); + devices[index].flags |= V4L2_STREAM_TOUCHED; + fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24; + v4l2_ioctl(fd, VIDIOC_S_FMT, &fmt); + V4L2_LOG("Done setting pixelformat (supported_dst_fmt_only)"); + } pthread_mutex_lock(&devices[index].stream_lock); + devices[index].flags |= V4L2_STREAM_TOUCHED; + } converting = v4lconvert_needs_conversion(devices[index].convert, &devices[index].src_fmt, &devices[index].dest_fmt); -- cgit v1.2.3 From e021d3a000c760f4af4aa098b1d5a2dd24a86129 Mon Sep 17 00:00:00 2001 From: "hans@localhost.localdomain" Date: Thu, 21 May 2009 16:49:03 +0200 Subject: libv4l: fix detection of conversion mode in v4l2_buffers_mapped() From: Hans de Goede libv4l: fix detection of conversion mode in v4l2_buffers_mapped() Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 4 +--- v4l2-apps/libv4l/libv4l2/libv4l2.c | 6 +++--- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index 73b237a93..673eee4c0 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -1,18 +1,16 @@ libv4l-0.5.98 ------------- -* Genius E-M 112 needs both upside down and whitebalance flags * Some makefile improvements by Gregor Jasny * If the card name contains a / replace it with a - in the shm name -* Only created shared memory segment when we have fake v4l2 controls * Add sq905 to the list of devices which benefit from whitebalancing * Support V4L2_CTRL_FLAG_NEXT_CTRL for fake controls by Adam Baker * Add ability to determine upside down cams based on DMI info -* Fix a bug in v4lconvert_uyvy_to_yuv420() * Add support for separate vflipping and hflipping * Add fake controls controlling the software h- and v-flipping * Rewrite video processing code to make it easier to add more video filters (and with little extra processing cost). As part of this the normalize filter has been removed as it wasn't functioning satisfactory anyways +* Various small bugfixes and tweaks libv4l-0.5.97 ------------- diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2.c b/v4l2-apps/libv4l/libv4l2/libv4l2.c index 4f88ffd73..2562987b4 100644 --- a/v4l2-apps/libv4l/libv4l2/libv4l2.c +++ b/v4l2-apps/libv4l/libv4l2/libv4l2.c @@ -369,8 +369,8 @@ static int v4l2_buffers_mapped(int index) { unsigned int i; - if (devices[index].src_fmt.fmt.pix.pixelformat == - devices[index].dest_fmt.fmt.pix.pixelformat) { + if (!v4lconvert_needs_conversion(devices[index].convert, + &devices[index].src_fmt, &devices[index].dest_fmt)) { /* Normal (no conversion) mode */ struct v4l2_buffer buf; @@ -559,7 +559,6 @@ int v4l2_close(int fd) /* Free resources */ v4l2_unmap_buffers(index); - v4lconvert_destroy(devices[index].convert); if (devices[index].convert_mmap_buf != MAP_FAILED) { if (v4l2_buffers_mapped(index)) V4L2_LOG_WARN("v4l2 mmap buffers still mapped on close()\n"); @@ -568,6 +567,7 @@ int v4l2_close(int fd) devices[index].no_frames * V4L2_FRAME_BUF_SIZE); devices[index].convert_mmap_buf = MAP_FAILED; } + v4lconvert_destroy(devices[index].convert); /* Remove the fd from our list of managed fds before closing it, because as soon as we've done the actual close the fd maybe returned by an open in -- cgit v1.2.3 From 5a77f99540d308be03bced1c0dea4f480cd50894 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Thu, 21 May 2009 22:34:25 +0200 Subject: libv4l: better handling of the V4L2_DISABLE_CONVERSION flag From: Hans de Goede libv4l: better handling of the V4L2_DISABLE_CONVERSION flag Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/libv4l2/libv4l2.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2.c b/v4l2-apps/libv4l/libv4l2/libv4l2.c index 2562987b4..053e6e28b 100644 --- a/v4l2-apps/libv4l/libv4l2/libv4l2.c +++ b/v4l2-apps/libv4l/libv4l2/libv4l2.c @@ -365,12 +365,20 @@ static int v4l2_deactivate_read_stream(int index) return 0; } +static int v4l2_needs_conversion(int index) +{ + if (!(devices[index].flags & V4L2_DISABLE_CONVERSION)) + return v4lconvert_needs_conversion(devices[index].convert, + &devices[index].src_fmt, &devices[index].dest_fmt); + + return 0; +} + static int v4l2_buffers_mapped(int index) { unsigned int i; - if (!v4lconvert_needs_conversion(devices[index].convert, - &devices[index].src_fmt, &devices[index].dest_fmt)) { + if (!v4l2_needs_conversion(index)) { /* Normal (no conversion) mode */ struct v4l2_buffer buf; @@ -660,7 +668,7 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) { void *arg; va_list ap; - int result, converting, index, saved_err; + int result, index, saved_err; int is_capture_request = 0, stream_needs_locking = 0; va_start (ap, request); @@ -697,7 +705,8 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) is_capture_request = 1; break; case VIDIOC_TRY_FMT: - if (((struct v4l2_format *)arg)->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (((struct v4l2_format *)arg)->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && + !(devices[index].flags & V4L2_DISABLE_CONVERSION)) is_capture_request = 1; break; case VIDIOC_S_FMT: @@ -761,9 +770,6 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) devices[index].flags |= V4L2_STREAM_TOUCHED; } - converting = v4lconvert_needs_conversion(devices[index].convert, - &devices[index].src_fmt, &devices[index].dest_fmt); - switch (request) { case VIDIOC_QUERYCTRL: result = v4lconvert_vidioc_queryctrl(devices[index].convert, arg); @@ -943,7 +949,7 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) /* Do a real query even when converting to let the driver fill in things like buf->field */ result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_QUERYBUF, buf); - if (result || !converting) + if (result || !v4l2_needs_conversion(index)) break; buf->m.offset = V4L2_MMAP_OFFSET_MAGIC | buf->index; @@ -961,7 +967,7 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) break; /* With some drivers the buffers must be mapped before queuing */ - if (converting) + if (v4l2_needs_conversion(index)) if ((result = v4l2_map_buffers(index))) break; @@ -976,7 +982,7 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) if ((result = v4l2_deactivate_read_stream(index))) break; - if (!converting) { + if (!v4l2_needs_conversion(index)) { result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_DQBUF, buf); if (result) { int saved_err = errno; @@ -1063,8 +1069,7 @@ ssize_t v4l2_read (int fd, void* dest, size_t n) /* When not converting and the device supports read let the kernel handle it */ if ((devices[index].flags & V4L2_SUPPORTS_READ) && - !v4lconvert_needs_conversion(devices[index].convert, - &devices[index].src_fmt, &devices[index].dest_fmt)) { + !v4l2_needs_conversion(index)) { result = syscall(SYS_read, fd, dest, n); goto leave; } @@ -1123,8 +1128,7 @@ void *v4l2_mmap(void *start, size_t length, int prot, int flags, int fd, buffer_index = offset & 0xff; if (buffer_index >= devices[index].no_frames || /* Got magic offset and not converting ?? */ - !v4lconvert_needs_conversion(devices[index].convert, - &devices[index].src_fmt, &devices[index].dest_fmt)) { + !v4l2_needs_conversion(index)) { errno = EINVAL; result = MAP_FAILED; goto leave; -- cgit v1.2.3 From b152107391374bfc61ea21d1731fd349352bedf2 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Fri, 22 May 2009 11:40:31 +0200 Subject: libv4l: add support for adding black borders (reverse cropping) From: Hans de Goede Add the capability to provide 320x240 to apps if the cam can only do 320x232 (some zc3xx cams) by adding black borders. And more in general the capability to make certain standard resolutions available by adding black borders to slightly smaller resolutions, in case we encounter more cams which have a hardware limitation which makes them do a resolution slightly smaller then the standard ones. Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 2 + v4l2-apps/libv4l/TODO | 4 - v4l2-apps/libv4l/libv4lconvert/crop.c | 130 ++++++++++++++++++++++++- v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 14 ++- 4 files changed, 138 insertions(+), 12 deletions(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index 673eee4c0..532421ed0 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -11,6 +11,8 @@ libv4l-0.5.98 (and with little extra processing cost). As part of this the normalize filter has been removed as it wasn't functioning satisfactory anyways * Various small bugfixes and tweaks +* Add the capability to provide 320x240 to apps if the cam can only + do 320x232 (some zc3xx cams) by adding black borders libv4l-0.5.97 ------------- diff --git a/v4l2-apps/libv4l/TODO b/v4l2-apps/libv4l/TODO index 959adc574..f4abad05d 100644 --- a/v4l2-apps/libv4l/TODO +++ b/v4l2-apps/libv4l/TODO @@ -9,13 +9,9 @@ -take the possibility of pitch != width into account everywhere - -make updating of parameters happen based on time elapsed rather then frames --add reverse cropping (adding black borders) to get from 320x232 -> - 320x240, for zc3xx webcams with a broken (last row of jpeg blocks missing) - 320x240 mode -add software auto exposure (for spca561 cams) diff --git a/v4l2-apps/libv4l/libv4lconvert/crop.c b/v4l2-apps/libv4l/libv4lconvert/crop.c index 4294fbeaf..f01772c07 100644 --- a/v4l2-apps/libv4l/libv4lconvert/crop.c +++ b/v4l2-apps/libv4l/libv4lconvert/crop.c @@ -143,26 +143,146 @@ static void v4lconvert_crop_yuv420(unsigned char *src, unsigned char *dest, } } +/* Ok, so this is not really cropping, but more the reverse, whatever */ +static void v4lconvert_add_border_rgbbgr24( + unsigned char *src, unsigned char *dest, + const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt) +{ + int y; + int borderx = (dest_fmt->fmt.pix.width - src_fmt->fmt.pix.width) / 2; + int bordery = (dest_fmt->fmt.pix.height - src_fmt->fmt.pix.height) / 2; + + for (y = 0; y < bordery; y++) { + memset(dest, 0, dest_fmt->fmt.pix.width * 3); + dest += dest_fmt->fmt.pix.bytesperline; + } + + for (y = 0; y < src_fmt->fmt.pix.height; y++) { + memset(dest, 0, borderx * 3); + dest += borderx * 3; + + memcpy(dest, src, src_fmt->fmt.pix.width * 3); + src += src_fmt->fmt.pix.bytesperline; + dest += src_fmt->fmt.pix.width * 3; + + memset(dest, 0, borderx * 3); + dest += dest_fmt->fmt.pix.bytesperline - + (borderx + src_fmt->fmt.pix.width) * 3; + } + + for (y = 0; y < bordery; y++) { + memset(dest, 0, dest_fmt->fmt.pix.width * 3); + dest += dest_fmt->fmt.pix.bytesperline; + } +} + +static void v4lconvert_add_border_yuv420( + unsigned char *src, unsigned char *dest, + const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt) +{ + int y; + int borderx = (dest_fmt->fmt.pix.width - src_fmt->fmt.pix.width) / 2; + int bordery = (dest_fmt->fmt.pix.height - src_fmt->fmt.pix.height) / 2; + + /* Y */ + for (y = 0; y < bordery; y++) { + memset(dest, 16, dest_fmt->fmt.pix.width); + dest += dest_fmt->fmt.pix.bytesperline; + } + + for (y = 0; y < src_fmt->fmt.pix.height; y++) { + memset(dest, 16, borderx); + dest += borderx; + + memcpy(dest, src, src_fmt->fmt.pix.width); + src += src_fmt->fmt.pix.bytesperline; + dest += src_fmt->fmt.pix.width; + + memset(dest, 16, borderx); + dest += dest_fmt->fmt.pix.bytesperline - + (borderx + src_fmt->fmt.pix.width); + } + + for (y = 0; y < bordery; y++) { + memset(dest, 16, dest_fmt->fmt.pix.width); + dest += dest_fmt->fmt.pix.bytesperline; + } + + /* U */ + for (y = 0; y < bordery / 2; y++) { + memset(dest, 128, dest_fmt->fmt.pix.width / 2); + dest += dest_fmt->fmt.pix.bytesperline / 2; + } + + for (y = 0; y < src_fmt->fmt.pix.height / 2; y++) { + memset(dest, 128, borderx / 2); + dest += borderx / 2; + + memcpy(dest, src, src_fmt->fmt.pix.width / 2); + src += src_fmt->fmt.pix.bytesperline / 2; + dest += src_fmt->fmt.pix.width / 2; + + memset(dest, 128, borderx / 2); + dest += (dest_fmt->fmt.pix.bytesperline - + (borderx + src_fmt->fmt.pix.width)) / 2; + } + + for (y = 0; y < bordery / 2; y++) { + memset(dest, 128, dest_fmt->fmt.pix.width / 2); + dest += dest_fmt->fmt.pix.bytesperline / 2; + } + + /* V */ + for (y = 0; y < bordery / 2; y++) { + memset(dest, 128, dest_fmt->fmt.pix.width / 2); + dest += dest_fmt->fmt.pix.bytesperline / 2; + } + + for (y = 0; y < src_fmt->fmt.pix.height / 2; y++) { + memset(dest, 128, borderx / 2); + dest += borderx / 2; + + memcpy(dest, src, src_fmt->fmt.pix.width / 2); + src += src_fmt->fmt.pix.bytesperline / 2; + dest += src_fmt->fmt.pix.width / 2; + + memset(dest, 128, borderx / 2); + dest += (dest_fmt->fmt.pix.bytesperline - + (borderx + src_fmt->fmt.pix.width)) / 2; + } + + for (y = 0; y < bordery / 2; y++) { + memset(dest, 128, dest_fmt->fmt.pix.width / 2); + dest += dest_fmt->fmt.pix.bytesperline / 2; + } +} + void v4lconvert_crop(unsigned char *src, unsigned char *dest, const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt) { switch (dest_fmt->fmt.pix.pixelformat) { case V4L2_PIX_FMT_RGB24: case V4L2_PIX_FMT_BGR24: - if (src_fmt->fmt.pix.width >= 2 * dest_fmt->fmt.pix.width && - src_fmt->fmt.pix.height >= 2 * dest_fmt->fmt.pix.height) + if (src_fmt->fmt.pix.width <= dest_fmt->fmt.pix.width && + src_fmt->fmt.pix.height <= dest_fmt->fmt.pix.height) + v4lconvert_add_border_rgbbgr24(src, dest, src_fmt, dest_fmt); + else if (src_fmt->fmt.pix.width >= 2 * dest_fmt->fmt.pix.width && + src_fmt->fmt.pix.height >= 2 * dest_fmt->fmt.pix.height) v4lconvert_reduceandcrop_rgbbgr24(src, dest, src_fmt, dest_fmt); else v4lconvert_crop_rgbbgr24(src, dest, src_fmt, dest_fmt); break; + case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: - if (src_fmt->fmt.pix.width >= 2 * dest_fmt->fmt.pix.width && - src_fmt->fmt.pix.height >= 2 * dest_fmt->fmt.pix.height) + if (src_fmt->fmt.pix.width <= dest_fmt->fmt.pix.width && + src_fmt->fmt.pix.height <= dest_fmt->fmt.pix.height) + v4lconvert_add_border_yuv420(src, dest, src_fmt, dest_fmt); + else if (src_fmt->fmt.pix.width >= 2 * dest_fmt->fmt.pix.width && + src_fmt->fmt.pix.height >= 2 * dest_fmt->fmt.pix.height) v4lconvert_reduceandcrop_yuv420(src, dest, src_fmt, dest_fmt); else v4lconvert_crop_yuv420(src, dest, src_fmt, dest_fmt); - break; } } diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index 1a94b53ba..afb0c854c 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -373,7 +373,8 @@ int v4lconvert_try_format(struct v4lconvert_data *data, /* In case of a non exact resolution match, see if this is a well known resolution some apps are hardcoded too and try to give the app what it - asked for by cropping a slightly larger resolution */ + asked for by cropping a slightly larger resolution or adding a small + black border to a slightly smaller resolution */ if (try_dest.fmt.pix.width != desired_width || try_dest.fmt.pix.height != desired_height) { for (i = 0; i < ARRAY_SIZE(v4lconvert_crop_res); i++) { @@ -387,13 +388,20 @@ int v4lconvert_try_format(struct v4lconvert_data *data, try2_dest.fmt.pix.height = desired_height * 124 / 100; result = v4lconvert_do_try_format(data, &try2_dest, &try2_src); if (result == 0 && - ((try2_dest.fmt.pix.width >= desired_width && + (/* Add a small black border of max 16 pixels */ + (try2_dest.fmt.pix.width >= desired_width - 16 && + try2_dest.fmt.pix.width <= desired_width && + try2_dest.fmt.pix.height >= desired_height - 16 && + try2_dest.fmt.pix.height <= desired_height) || + /* Standard cropping to max 80% of actual width / height */ + (try2_dest.fmt.pix.width >= desired_width && try2_dest.fmt.pix.width <= desired_width * 5 / 4 && try2_dest.fmt.pix.height >= desired_height && try2_dest.fmt.pix.height <= desired_height * 5 / 4) || + /* Downscale 2x + cropping to max 80% of actual width / height */ (try2_dest.fmt.pix.width >= desired_width * 2 && try2_dest.fmt.pix.width <= desired_width * 5 / 2 && - try2_dest.fmt.pix.height >= desired_height && + try2_dest.fmt.pix.height >= desired_height * 2 && try2_dest.fmt.pix.height <= desired_height * 5 / 2))) { /* Success! */ try2_dest.fmt.pix.width = desired_width; -- cgit v1.2.3 From 51949cfaadebd8e341fed1e85eca683dd40195d2 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Mon, 25 May 2009 15:25:15 +0200 Subject: libv4l: add software autogain / exposure From: Hans de Goede 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 --- v4l2-apps/libv4l/ChangeLog | 1 + v4l2-apps/libv4l/TODO | 4 +- v4l2-apps/libv4l/libv4lconvert/Makefile | 2 +- .../libv4l/libv4lconvert/control/libv4lcontrol.c | 36 +++++- .../libv4l/libv4lconvert/control/libv4lcontrol.h | 13 +- v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 5 +- .../libv4l/libv4lconvert/processing/autogain.c | 140 +++++++++++++++++++++ .../processing/libv4lprocessing-priv.h | 2 + .../libv4lconvert/processing/libv4lprocessing.c | 4 +- .../libv4lconvert/processing/libv4lprocessing.h | 2 +- 10 files changed, 199 insertions(+), 10 deletions(-) create mode 100644 v4l2-apps/libv4l/libv4lconvert/processing/autogain.c (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index 532421ed0..efdcda093 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -13,6 +13,7 @@ libv4l-0.5.98 * Various small bugfixes and tweaks * Add the capability to provide 320x240 to apps if the cam can only do 320x232 (some zc3xx cams) by adding black borders +* Add software auto gain / exposure libv4l-0.5.97 ------------- diff --git a/v4l2-apps/libv4l/TODO b/v4l2-apps/libv4l/TODO index f4abad05d..e4ea436a3 100644 --- a/v4l2-apps/libv4l/TODO +++ b/v4l2-apps/libv4l/TODO @@ -13,6 +13,6 @@ frames --add software auto exposure (for spca561 cams) - -add gamma correction video processing + +-get standardized CID for AUTOGAIN_TARGET upstream and switch to that diff --git a/v4l2-apps/libv4l/libv4lconvert/Makefile b/v4l2-apps/libv4l/libv4lconvert/Makefile index 49d508694..f4f529c0d 100644 --- a/v4l2-apps/libv4l/libv4lconvert/Makefile +++ b/v4l2-apps/libv4l/libv4lconvert/Makefile @@ -16,7 +16,7 @@ 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/whitebalance.o processing/autogain.o TARGETS = $(CONVERT_LIB) libv4lconvert.pc INCLUDES = ../include/libv4lconvert.h diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c index 4d227c366..edf86483d 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c @@ -67,7 +67,7 @@ static const struct v4lcontrol_flags_info v4lcontrol_flags[] = { /* Asus N50Vn laptop */ { 0x04f2, 0xb106, 0, "ASUSTeK Computer Inc. ", "N50Vn ", V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED }, -/* Second: devices which should use sw whitebalance by default */ +/* 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 }, @@ -78,6 +78,9 @@ static const struct v4lcontrol_flags_info v4lcontrol_flags[] = { V4LCONTROL_ROTATED_90_JPEG|V4LCONTROL_WANTS_WB }, /* sq905 devices */ { 0x2770, 0x9120, 0, NULL, NULL, V4LCONTROL_WANTS_WB }, + /* spca561 revison 12a devices */ + { 0x041e, 0x403b, 0, NULL, NULL, V4LCONTROL_WANTS_WB_AUTOGAIN }, + { 0x046d, 0x0928, 7, NULL, NULL, V4LCONTROL_WANTS_WB_AUTOGAIN }, }; static const struct v4l2_queryctrl fake_controls[]; @@ -223,13 +226,17 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) /* If the device always needs conversion, we can add fake controls at no cost (no cost when not activated by the user that is) */ if (always_needs_conversion || v4lcontrol_needs_conversion(data)) { - for (i = 0; i < V4LCONTROL_COUNT; i++) { + for (i = 0; i < V4LCONTROL_AUTO_ENABLE_COUNT; i++) { ctrl.id = fake_controls[i].id; if (syscall(SYS_ioctl, data->fd, VIDIOC_QUERYCTRL, &ctrl) == -1) data->controls |= 1 << i; } } + if (data->flags & V4LCONTROL_WANTS_AUTOGAIN) + data->controls |= 1 << V4LCONTROL_AUTOGAIN | + 1 << V4LCONTROL_AUTOGAIN_TARGET; + /* Allow overriding through environment */ if ((s = getenv("LIBV4LCONTROL_CONTROLS"))) data->controls = strtol(s, NULL, 0); @@ -266,6 +273,10 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) if (init) { /* Initialize the new shm object we created */ memset(data->shm_values, 0, sizeof(V4LCONTROL_SHM_SIZE)); + + for (i = 0; i < V4LCONTROL_COUNT; i++) + data->shm_values[i] = fake_controls[i].default_value; + if (data->flags & V4LCONTROL_WANTS_WB) data->shm_values[V4LCONTROL_WHITEBALANCE] = 1; } @@ -316,6 +327,27 @@ static const struct v4l2_queryctrl fake_controls[V4LCONTROL_COUNT] = { .default_value = 0, .flags = 0 }, +{}, /* Dummy place holder for V4LCONTROL_AUTO_ENABLE_COUNT */ +{ + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Gain (software)", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + .flags = 0 +}, +{ + .id = V4L2_CTRL_CLASS_USER + 0x2000, /* FIXME */ + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Auto Gain target", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 100, + .flags = 0 +}, }; int v4lcontrol_vidioc_queryctrl(struct v4lcontrol_data *data, void *arg) diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h index 85129ee4c..a3640038b 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h @@ -12,7 +12,7 @@ # 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 General Public License for more details. +# 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 @@ -27,13 +27,22 @@ #define V4LCONTROL_VFLIPPED 0x02 #define V4LCONTROL_ROTATED_90_JPEG 0x04 #define V4LCONTROL_WANTS_WB 0x08 +#define V4LCONTROL_WANTS_AUTOGAIN 0x10 + +/* Masks */ +#define V4LCONTROL_WANTS_WB_AUTOGAIN (V4LCONTROL_WANTS_WB | V4LCONTROL_WANTS_AUTOGAIN) /* Controls */ enum { V4LCONTROL_WHITEBALANCE, V4LCONTROL_HFLIP, V4LCONTROL_VFLIP, - V4LCONTROL_COUNT }; + /* All fake controls above here are auto enabled when not present in hw */ + V4LCONTROL_AUTO_ENABLE_COUNT, + V4LCONTROL_AUTOGAIN, + V4LCONTROL_AUTOGAIN_TARGET, + V4LCONTROL_COUNT + }; struct v4lcontrol_data; diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index afb0c854c..58d77e5ef 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -127,6 +127,9 @@ struct v4lconvert_data *v4lconvert_create(int fd) data->flags |= V4LCONVERT_IS_UVC; else if (!strcmp((char *)cap.driver, "sn9c20x")) data->flags |= V4LCONVERT_IS_SN9C20X; + + if ((cap.capabilities & 0xff) & ~V4L2_CAP_VIDEO_CAPTURE) + always_needs_conversion = 0; } data->control = v4lcontrol_create(fd, always_needs_conversion); @@ -136,7 +139,7 @@ struct v4lconvert_data *v4lconvert_create(int fd) } data->control_flags = v4lcontrol_get_flags(data->control); - data->processing = v4lprocessing_create(data->control); + data->processing = v4lprocessing_create(fd, data->control); if (!data->processing) { v4lcontrol_destroy(data->control); free(data); 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 + +# 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 +#include +#include +#include +#include +#include + +#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, -- cgit v1.2.3 From 2ffc360be1c38ab86399d6d574ee7cc0671c03d6 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Mon, 25 May 2009 15:35:21 +0200 Subject: libv4l: Obsolete the V4L2_ENABLE_ENUM_FMT_EMULATION v4l2_fd_open flag From: Hans de Goede The V4L2_ENABLE_ENUM_FMT_EMULATION v4l2_fd_open flag is obsolete, libv4l2 now *always* reports emulated formats through the ENUM_FMT ioctl Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 2 ++ v4l2-apps/libv4l/include/libv4l2.h | 21 +++++++++------------ v4l2-apps/libv4l/libv4l2/libv4l2.c | 4 ++-- v4l2-apps/libv4l/libv4l2/v4l2convert.c | 2 +- 4 files changed, 14 insertions(+), 15 deletions(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index efdcda093..db2fa02b0 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -14,6 +14,8 @@ libv4l-0.5.98 * Add the capability to provide 320x240 to apps if the cam can only do 320x232 (some zc3xx cams) by adding black borders * 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 libv4l-0.5.97 ------------- diff --git a/v4l2-apps/libv4l/include/libv4l2.h b/v4l2-apps/libv4l/include/libv4l2.h index b05b57cb6..b2451dced 100644 --- a/v4l2-apps/libv4l/include/libv4l2.h +++ b/v4l2-apps/libv4l/include/libv4l2.h @@ -41,18 +41,12 @@ LIBV4L_PUBLIC extern FILE *v4l2_log_file; format which is not supported by the cam, but is supported by libv4lconvert, then the try_fmt / set_fmt will succeed as if the cam supports the format and on dqbuf / read the data will be converted for you and returned in - the request format. + the request format. enum_fmt will also report support for the formats to + which conversion is possible. Another difference is that you can make v4l2_read() calls even on devices which do not support the regular read() method. - Note that libv4l2 normally does not interfere with enum_fmt, so enum_fmt - will still return the actual formats the hardware supports, and not any - formats which may be emulated on top of that. If you pass the - V4L2_ENABLE_ENUM_FMT_EMULATION flag to v4l2_fd_open (as the v4l2convert.so - wrapper does) then enum_fmt will also report support for the formats to - which conversion is possible. - Note the device name passed to v4l2_open must be of a video4linux2 device, if it is anything else (including a video4linux1 device), v4l2_open will fail. @@ -89,11 +83,14 @@ LIBV4L_PUBLIC int v4l2_get_control(int fd, int cid); /* Flags for v4l2_fd_open's v4l2_flags argument */ -/* Disable all format conversion done by libv4l2 (reduces libv4l2 functionality - to offering v4l2_read() even on devices which don't implement read()) */ +/* Disable all format conversion done by libv4l2, this includes the software + whitebalance, gamma correction, flipping, etc. libv4lconvert does. Use this + if you want raw frame data, but still want the additional error checks and + the read() emulation libv4l2 offers. */ #define V4L2_DISABLE_CONVERSION 0x01 -/* Report not only real but also emulated formats with the ENUM_FMT ioctl */ -#define V4L2_ENABLE_ENUM_FMT_EMULATION 02 +/* This flag is *OBSOLETE*, since version 0.5.98 libv4l *always* reports + emulated formats to ENUM_FMT, except when conversion is disabled. */ +#define V4L2_ENABLE_ENUM_FMT_EMULATION 0x02 /* v4l2_fd_open: open an already opened fd for further use through v4l2lib and possibly modify libv4l2's default behavior through the diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2.c b/v4l2-apps/libv4l/libv4l2/libv4l2.c index 053e6e28b..382dc405b 100644 --- a/v4l2-apps/libv4l/libv4l2/libv4l2.c +++ b/v4l2-apps/libv4l/libv4l2/libv4l2.c @@ -696,12 +696,12 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) break; case VIDIOC_ENUM_FMT: if (((struct v4l2_fmtdesc *)arg)->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && - (devices[index].flags & V4L2_ENABLE_ENUM_FMT_EMULATION)) + !(devices[index].flags & V4L2_DISABLE_CONVERSION)) is_capture_request = 1; break; case VIDIOC_ENUM_FRAMESIZES: case VIDIOC_ENUM_FRAMEINTERVALS: - if (devices[index].flags & V4L2_ENABLE_ENUM_FMT_EMULATION) + if (!(devices[index].flags & V4L2_DISABLE_CONVERSION)) is_capture_request = 1; break; case VIDIOC_TRY_FMT: diff --git a/v4l2-apps/libv4l/libv4l2/v4l2convert.c b/v4l2-apps/libv4l/libv4l2/v4l2convert.c index 307a03ce5..b1354772d 100644 --- a/v4l2-apps/libv4l/libv4l2/v4l2convert.c +++ b/v4l2-apps/libv4l/libv4l2/v4l2convert.c @@ -92,7 +92,7 @@ LIBV4L_PUBLIC int open (const char *file, int oflag, ...) /* Try to Register with libv4l2 (in case of failure pass the fd to the application as is) */ - v4l2_fd_open(fd, V4L2_ENABLE_ENUM_FMT_EMULATION); + v4l2_fd_open(fd, 0); return fd; } -- cgit v1.2.3 From 7b1960c67fb907d4885734c31a41898a9fe6dfa7 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Mon, 25 May 2009 20:59:10 +0200 Subject: libv4l: Fix a few small issues with V4L2_CTRL_FLAG_NEXT_CTRL handling From: Hans de Goede libv4l: Fix a few small issues with V4L2_CTRL_FLAG_NEXT_CTRL handling Priority: normal Signed-off-by: Hans de Goede --- .../libv4lconvert/control/libv4lcontrol-priv.h | 5 ++- .../libv4l/libv4lconvert/control/libv4lcontrol.c | 39 ++++++++++++++++------ 2 files changed, 33 insertions(+), 11 deletions(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h index 14e4fe838..14481a9a2 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h @@ -24,9 +24,12 @@ #define V4LCONTROL_SHM_SIZE 4096 +#define V4LCONTROL_SUPPORTS_NEXT_CTRL 0x01 + struct v4lcontrol_data { int fd; /* Device fd */ - int flags; /* Special flags for this device */ + int flags; /* Flags for this device */ + int priv_flags; /* Internal use only flags */ 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() */ diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c index edf86483d..3f57afb72 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c @@ -223,6 +223,10 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) if ((s = getenv("LIBV4LCONTROL_FLAGS"))) data->flags = strtol(s, NULL, 0); + ctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL; + if (syscall(SYS_ioctl, data->fd, VIDIOC_QUERYCTRL, &ctrl) == 0) + data->priv_flags |= V4LCONTROL_SUPPORTS_NEXT_CTRL; + /* If the device always needs conversion, we can add fake controls at no cost (no cost when not activated by the user that is) */ if (always_needs_conversion || v4lcontrol_needs_conversion(data)) { @@ -350,6 +354,17 @@ static const struct v4l2_queryctrl fake_controls[V4LCONTROL_COUNT] = { }, }; +static void v4lcontrol_copy_queryctrl(struct v4lcontrol_data *data, + struct v4l2_queryctrl *ctrl, int i) +{ + memcpy(ctrl, &fake_controls[i], sizeof(struct v4l2_queryctrl)); + + /* Hmm, not pretty */ + if (ctrl->id == V4L2_CID_AUTO_WHITE_BALANCE && + (data->flags & V4LCONTROL_WANTS_WB)) + ctrl->default_value = 1; +} + int v4lcontrol_vidioc_queryctrl(struct v4lcontrol_data *data, void *arg) { int i; @@ -361,28 +376,32 @@ int v4lcontrol_vidioc_queryctrl(struct v4lcontrol_data *data, void *arg) for (i = 0; i < V4LCONTROL_COUNT; i++) if ((data->controls & (1 << i)) && ctrl->id == fake_controls[i].id) { - memcpy(ctrl, &fake_controls[i], sizeof(struct v4l2_queryctrl)); - /* Hmm, not pretty */ - if (ctrl->id == V4L2_CID_AUTO_WHITE_BALANCE && - (data->flags & V4LCONTROL_WANTS_WB)) - ctrl->default_value = 1; - + v4lcontrol_copy_queryctrl(data, ctrl, i); return 0; } /* find out what the kernel driver would respond. */ retval = syscall(SYS_ioctl, data->fd, VIDIOC_QUERYCTRL, arg); - /* if any of our controls have an id > orig_id but less than - ctrl->id then return that control instead. */ - if (orig_id & V4L2_CTRL_FLAG_NEXT_CTRL) + if ((data->priv_flags & V4LCONTROL_SUPPORTS_NEXT_CTRL) && + (orig_id & V4L2_CTRL_FLAG_NEXT_CTRL)) { + /* If the hardware has no more controls check if we still have any + fake controls with a higher id then the hardware's highest */ + if (retval) + ctrl->id = V4L2_CTRL_FLAG_NEXT_CTRL; + + /* If any of our controls have an id > orig_id but less than + ctrl->id then return that control instead. Note we do not + break when we have a match, but keep iterating, so that + we end up with the fake ctrl with the lowest CID > orig_id. */ for (i = 0; i < V4LCONTROL_COUNT; i++) if ((data->controls & (1 << i)) && (fake_controls[i].id > (orig_id & ~V4L2_CTRL_FLAG_NEXT_CTRL)) && (fake_controls[i].id <= ctrl->id)) { - memcpy(ctrl, &fake_controls[i], sizeof(struct v4l2_queryctrl)); + v4lcontrol_copy_queryctrl(data, ctrl, i); retval = 0; } + } return retval; } -- cgit v1.2.3 From 08f4c9bb91fbc3e348322f140e1a0c1f662b7478 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Tue, 26 May 2009 10:07:18 +0200 Subject: libv4l: add gamma correction to video processing From: Hans de Goede 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 --- v4l2-apps/libv4l/ChangeLog | 1 + v4l2-apps/libv4l/TODO | 3 -- v4l2-apps/libv4l/libv4lconvert/Makefile | 3 +- .../libv4lconvert/control/libv4lcontrol-priv.h | 4 ++ .../libv4l/libv4lconvert/control/libv4lcontrol.c | 28 +++++++++-- .../libv4l/libv4lconvert/control/libv4lcontrol.h | 1 + v4l2-apps/libv4l/libv4lconvert/processing/gamma.c | 55 ++++++++++++++++++++++ .../processing/libv4lprocessing-priv.h | 4 ++ .../libv4lconvert/processing/libv4lprocessing.c | 1 + 9 files changed, 91 insertions(+), 9 deletions(-) create mode 100644 v4l2-apps/libv4l/libv4lconvert/processing/gamma.c (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index db2fa02b0..5e1e7fd4a 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -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 ------------- diff --git a/v4l2-apps/libv4l/TODO b/v4l2-apps/libv4l/TODO index e4ea436a3..8f7744337 100644 --- a/v4l2-apps/libv4l/TODO +++ b/v4l2-apps/libv4l/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 diff --git a/v4l2-apps/libv4l/libv4lconvert/Makefile b/v4l2-apps/libv4l/libv4lconvert/Makefile index f4f529c0d..7bc4993d6 100644 --- a/v4l2-apps/libv4l/libv4lconvert/Makefile +++ b/v4l2-apps/libv4l/libv4lconvert/Makefile @@ -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 diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h index 14481a9a2..6211ee22a 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h @@ -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 diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c index 3f57afb72..6bf5b6229 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c @@ -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) diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h index a3640038b..e29fde3d4 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h @@ -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/v4l2-apps/libv4l/libv4lconvert/processing/gamma.c b/v4l2-apps/libv4l/libv4lconvert/processing/gamma.c new file mode 100644 index 000000000..7695abcb7 --- /dev/null +++ b/v4l2-apps/libv4l/libv4lconvert/processing/gamma.c @@ -0,0 +1,55 @@ +/* +# (C) 2008-2009 Hans de Goede + +# 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 +#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 }; diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h index b848317f7..008d352ff 100644 --- a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h +++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h @@ -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 diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c index 01de6c111..f050086e3 100644 --- a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c +++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c @@ -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) -- cgit v1.2.3 From f0caf21e8eff58357cc92d4b151b05c7447e8438 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Tue, 26 May 2009 10:11:14 +0200 Subject: libv4l: activate software whitebalance by default on some cams From: Hans de Goede libv4l: activate software whitebalance by default on some cams Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c index 6bf5b6229..ec3750408 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c @@ -76,11 +76,15 @@ static const struct v4lcontrol_flags_info v4lcontrol_flags[] = { /* Pac7302 based devices */ { 0x093a, 0x2620, 0x0f, NULL, NULL, V4LCONTROL_ROTATED_90_JPEG|V4LCONTROL_WANTS_WB }, + /* Pac7311 based devices */ + { 0x093a, 0x2600, 0x0f, NULL, NULL, V4LCONTROL_WANTS_WB }, /* sq905 devices */ { 0x2770, 0x9120, 0, NULL, NULL, V4LCONTROL_WANTS_WB }, /* spca561 revison 12a devices */ { 0x041e, 0x403b, 0, NULL, NULL, V4LCONTROL_WANTS_WB_AUTOGAIN }, { 0x046d, 0x0928, 7, NULL, NULL, V4LCONTROL_WANTS_WB_AUTOGAIN }, + /* logitech quickcam express stv06xx + pb0100 */ + { 0x046d, 0x0840, 0, NULL, NULL, V4LCONTROL_WANTS_WB }, }; static const struct v4l2_queryctrl fake_controls[]; -- cgit v1.2.3 From d181de4cbd594ec4c283438f4fb3d2563106ae12 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Tue, 26 May 2009 10:15:15 +0200 Subject: libv4l: fix a crash when doing processing on non rgb / bayer data From: Hans de Goede We were calling processing on the rotate90_src, but when doing single conversion and not doing rotate90 that was not pointing the buffer we should do the processing on (the converted data), but instead it was pointing to the original src buffer. Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index 58d77e5ef..1b95d0657 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -1008,13 +1008,13 @@ int v4lconvert_convert(struct v4lconvert_data *data, return res; src_size = my_src_fmt.fmt.pix.sizeimage; - } - /* We call processing here again in case the source format was not - rgb, but the dest is. v4lprocessing checks it self it only actually - does the processing once per frame. */ - if (processing) - v4lprocessing_processing(data->processing, rotate90_src, &my_src_fmt); + /* We call processing here again in case the source format was not + rgb, but the dest is. v4lprocessing checks it self it only actually + does the processing once per frame. */ + if (processing) + v4lprocessing_processing(data->processing, convert2_dest, &my_src_fmt); + } if (rotate90) v4lconvert_rotate90(rotate90_src, rotate90_dest, &my_src_fmt); -- cgit v1.2.3 From 34c9ff27162488d95480bc8a7ea9b45de5f146ae Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Tue, 26 May 2009 10:26:55 +0200 Subject: libv4l: 0.5.98 release From: Hans de Goede libv4l: 0.5.98 release Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 16 +++++++--------- v4l2-apps/libv4l/Makefile | 2 +- 2 files changed, 8 insertions(+), 10 deletions(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index 5e1e7fd4a..fb324f088 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -1,22 +1,20 @@ libv4l-0.5.98 ------------- -* Some makefile improvements by Gregor Jasny -* If the card name contains a / replace it with a - in the shm name -* Add sq905 to the list of devices which benefit from whitebalancing -* Support V4L2_CTRL_FLAG_NEXT_CTRL for fake controls by Adam Baker -* Add ability to determine upside down cams based on DMI info +* Add software gamma correction +* Add software auto gain / exposure * Add support for separate vflipping and hflipping * Add fake controls controlling the software h- and v-flipping +* Add ability to determine upside down cams based on DMI info +* Add the capability to provide 320x240 to apps if the cam can only + do 320x232 (some zc3xx cams) by adding black borders * Rewrite video processing code to make it easier to add more video filters (and with little extra processing cost). As part of this the normalize filter has been removed as it wasn't functioning satisfactory anyways +* Support V4L2_CTRL_FLAG_NEXT_CTRL for fake controls by Adam Baker +* Some makefile improvements by Gregor Jasny * Various small bugfixes and tweaks -* Add the capability to provide 320x240 to apps if the cam can only - do 320x232 (some zc3xx cams) by adding black borders -* 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 ------------- diff --git a/v4l2-apps/libv4l/Makefile b/v4l2-apps/libv4l/Makefile index 4d57b42cc..ef86fd130 100644 --- a/v4l2-apps/libv4l/Makefile +++ b/v4l2-apps/libv4l/Makefile @@ -1,5 +1,5 @@ LIB_RELEASE=0 -V4L2_LIB_VERSION=$(LIB_RELEASE).5.97 +V4L2_LIB_VERSION=$(LIB_RELEASE).5.98 all install: $(MAKE) -C libv4lconvert V4L2_LIB_VERSION=$(V4L2_LIB_VERSION) $@ -- cgit v1.2.3 From 3034758e42abc467926892a9c2d1c794e28cef1f Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 27 May 2009 09:28:13 +0200 Subject: libv4l: Link libv4lconvert with -lm for powf From: Gregor Jasny libv4l: Link libv4lconvert with -lm for powf Priority: normal Signed-off-by: Gregor Jasny Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 4 ++++ v4l2-apps/libv4l/libv4lconvert/Makefile | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index fb324f088..83fa29a70 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -1,3 +1,7 @@ +libv4l-0.6 +---------- +* Link libv4lconvert with -lm for powf by Gregor Jasny + libv4l-0.5.98 ------------- * Add software gamma correction diff --git a/v4l2-apps/libv4l/libv4lconvert/Makefile b/v4l2-apps/libv4l/libv4lconvert/Makefile index 7bc4993d6..a2726e0d0 100644 --- a/v4l2-apps/libv4l/libv4lconvert/Makefile +++ b/v4l2-apps/libv4l/libv4lconvert/Makefile @@ -3,7 +3,7 @@ override CPPFLAGS += -I../include -I../../../include -fvisibility=hidden CFLAGS := -g -O1 CFLAGS += -Wall -Wno-unused -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -LIBS_libv4lconvert = -lrt +LIBS_libv4lconvert = -lrt -lm ifeq ($(LINKTYPE),static) CONVERT_LIB = libv4lconvert.a @@ -47,7 +47,7 @@ libv4lconvert.pc: @echo 'Description: v4l format conversion library' >> libv4lconvert.pc @echo 'Version: '$(V4L2_LIB_VERSION) >> libv4lconvert.pc @echo 'Libs: -L$${libdir} -lv4lconvert' >> libv4lconvert.pc - @echo 'Libs.private: -lrt' >> libv4lconvert.pc + @echo 'Libs.private: -lrt -lm' >> libv4lconvert.pc @echo 'Cflags: -I$${prefix}/include' >> libv4lconvert.pc install: all -- cgit v1.2.3 From 3976f3799b7993639ae213780b20448c01f58dd9 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 27 May 2009 20:05:11 +0200 Subject: libv4l: Fix black screen on devices with hardware gamma control From: Hans de Goede libv4l: Fix black screen on devices with hardware gamma control Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 1 + v4l2-apps/libv4l/libv4lconvert/processing/gamma.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index 83fa29a70..3f709a632 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -1,6 +1,7 @@ libv4l-0.6 ---------- * Link libv4lconvert with -lm for powf by Gregor Jasny +* Fix black screen on devices with hardware gamma control libv4l-0.5.98 ------------- diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/gamma.c b/v4l2-apps/libv4l/libv4lconvert/processing/gamma.c index 7695abcb7..fcb5bb0cf 100644 --- a/v4l2-apps/libv4l/libv4lconvert/processing/gamma.c +++ b/v4l2-apps/libv4l/libv4lconvert/processing/gamma.c @@ -23,7 +23,9 @@ #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; + int gamma = v4lcontrol_get_ctrl(data->control, V4LCONTROL_GAMMA); + + return gamma && gamma != 1000; } static int gamma_calculate_lookup_tables( -- cgit v1.2.3 From 2e6d2fb93c7435890fd4789e4c01456f4150ff7e Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Fri, 29 May 2009 11:42:59 +0200 Subject: libv4l: Fix a crash in v4lcontrol_controls_changed() From: Hans de Goede Don't crash when v4lcontrol_controls_changed() gets called and we have no fake controls (null pointer dereference). Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c index ec3750408..da2fbcdce 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c @@ -487,6 +487,9 @@ int v4lcontrol_controls_changed(struct v4lcontrol_data *data) { int res; + if (!data->controls) + return 0; + res = memcmp(data->shm_values, data->old_values, V4LCONTROL_COUNT * sizeof(unsigned int)); -- cgit v1.2.3 From 5999b7d164dbf3118a3a75ee3f6f0b48cb8845c1 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Tue, 2 Jun 2009 15:34:34 +0200 Subject: libv4l: initial support for compiling on FreeBSD From: Hans Petter Selasky Add a patch by Hans Petter Selasky , which should lead to allowing use of libv4l (and the Linux webcam drivers ported to userspace usb drivers) on FreeBSd, this is a work in progress Priority: normal Signed-off-by: Hans Petter Selasky Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 6 +- v4l2-apps/libv4l/Makefile | 2 +- v4l2-apps/libv4l/include/libv4l1.h | 2 +- v4l2-apps/libv4l/include/libv4l2.h | 2 +- v4l2-apps/libv4l/include/libv4lconvert.h | 11 ++ v4l2-apps/libv4l/libv4l1/libv4l1-priv.h | 9 +- v4l2-apps/libv4l/libv4l1/libv4l1.c | 46 ++++----- v4l2-apps/libv4l/libv4l1/log.c | 7 +- v4l2-apps/libv4l/libv4l1/v4l1compat.c | 5 + v4l2-apps/libv4l/libv4l2/libv4l2-priv.h | 9 +- v4l2-apps/libv4l/libv4l2/libv4l2.c | 84 ++++++++-------- v4l2-apps/libv4l/libv4l2/log.c | 7 +- v4l2-apps/libv4l/libv4l2/v4l2convert.c | 18 ++-- .../libv4l/libv4lconvert/control/libv4lcontrol.c | 25 ++--- v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 20 ++-- .../libv4l/libv4lconvert/libv4lsyscall-priv.h | 112 +++++++++++++++++++++ .../libv4l/libv4lconvert/processing/autogain.c | 14 +-- .../processing/libv4lprocessing-priv.h | 1 + .../libv4lconvert/processing/libv4lprocessing.c | 1 - .../libv4lconvert/processing/libv4lprocessing.h | 7 +- .../libv4l/libv4lconvert/processing/whitebalance.c | 1 - 21 files changed, 237 insertions(+), 152 deletions(-) create mode 100644 v4l2-apps/libv4l/libv4lconvert/libv4lsyscall-priv.h (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index 3f709a632..08b221c2a 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -1,7 +1,11 @@ -libv4l-0.6 +libv4l-0.5.99 ---------- * Link libv4lconvert with -lm for powf by Gregor Jasny * Fix black screen on devices with hardware gamma control +* Fix crash with devices on which we do not emulate fake controls +* Add a patch by Hans Petter Selasky , which should + lead to allowing use of libv4l (and the Linux webcam drivers ported + to userspace usb drivers) on FreeBSd, this is a work in progress libv4l-0.5.98 ------------- diff --git a/v4l2-apps/libv4l/Makefile b/v4l2-apps/libv4l/Makefile index ef86fd130..374cfab7b 100644 --- a/v4l2-apps/libv4l/Makefile +++ b/v4l2-apps/libv4l/Makefile @@ -1,5 +1,5 @@ LIB_RELEASE=0 -V4L2_LIB_VERSION=$(LIB_RELEASE).5.98 +V4L2_LIB_VERSION=$(LIB_RELEASE).5.99 all install: $(MAKE) -C libv4lconvert V4L2_LIB_VERSION=$(V4L2_LIB_VERSION) $@ diff --git a/v4l2-apps/libv4l/include/libv4l1.h b/v4l2-apps/libv4l/include/libv4l1.h index c878cc198..4ddf8efdb 100644 --- a/v4l2-apps/libv4l/include/libv4l1.h +++ b/v4l2-apps/libv4l/include/libv4l1.h @@ -63,7 +63,7 @@ LIBV4L_PUBLIC int v4l1_dup(int fd); LIBV4L_PUBLIC int v4l1_ioctl (int fd, unsigned long int request, ...); LIBV4L_PUBLIC ssize_t v4l1_read (int fd, void* buffer, size_t n); LIBV4L_PUBLIC void *v4l1_mmap(void *start, size_t length, int prot, int flags, int fd, - __off64_t offset); + int64_t offset); LIBV4L_PUBLIC int v4l1_munmap(void *_start, size_t length); #ifdef __cplusplus diff --git a/v4l2-apps/libv4l/include/libv4l2.h b/v4l2-apps/libv4l/include/libv4l2.h index b2451dced..0403a29dd 100644 --- a/v4l2-apps/libv4l/include/libv4l2.h +++ b/v4l2-apps/libv4l/include/libv4l2.h @@ -58,7 +58,7 @@ LIBV4L_PUBLIC int v4l2_dup(int fd); LIBV4L_PUBLIC int v4l2_ioctl (int fd, unsigned long int request, ...); LIBV4L_PUBLIC ssize_t v4l2_read (int fd, void* buffer, size_t n); LIBV4L_PUBLIC void *v4l2_mmap(void *start, size_t length, int prot, int flags, int fd, - __off64_t offset); + int64_t offset); LIBV4L_PUBLIC int v4l2_munmap(void *_start, size_t length); diff --git a/v4l2-apps/libv4l/include/libv4lconvert.h b/v4l2-apps/libv4l/include/libv4lconvert.h index 7901b35dc..b274c938b 100644 --- a/v4l2-apps/libv4l/include/libv4lconvert.h +++ b/v4l2-apps/libv4l/include/libv4lconvert.h @@ -21,10 +21,21 @@ /* These headers are not needed by us, but by linux/videodev2.h, which is broken on some systems and doesn't include them itself :( */ + +#ifdef linux #include #include #include +#endif + +#ifdef __FreeBSD__ +#include +#include +#include +#endif + /* end broken header workaround includes */ + #include #ifdef __cplusplus diff --git a/v4l2-apps/libv4l/libv4l1/libv4l1-priv.h b/v4l2-apps/libv4l/libv4l1/libv4l1-priv.h index 651599255..370686b3a 100644 --- a/v4l2-apps/libv4l/libv4l1/libv4l1-priv.h +++ b/v4l2-apps/libv4l/libv4l1/libv4l1-priv.h @@ -22,14 +22,7 @@ #include #include -/* On 32 bits archs we always use mmap2, on 64 bits archs there is no mmap2 */ -#ifdef __NR_mmap2 -#define SYS_mmap2 __NR_mmap2 -#define MMAP2_PAGE_SHIFT 12 -#else -#define SYS_mmap2 SYS_mmap -#define MMAP2_PAGE_SHIFT 0 -#endif +#include "../libv4lconvert/libv4lsyscall-priv.h" #define V4L1_MAX_DEVICES 16 #define V4L1_NO_FRAMES 4 diff --git a/v4l2-apps/libv4l/libv4l1/libv4l1.c b/v4l2-apps/libv4l/libv4l1/libv4l1.c index a7de0af8e..b676d69ed 100644 --- a/v4l2-apps/libv4l/libv4l1/libv4l1.c +++ b/v4l2-apps/libv4l/libv4l1/libv4l1.c @@ -44,18 +44,12 @@ #include #include #include -#include #include #include #include #include #include -/* These headers are not needed by us, but by linux/videodev2.h, - which is broken on some systems and doesn't include them itself :( */ -#include -#include -#include -/* end broken header workaround includes */ +#include "../libv4lconvert/libv4lsyscall-priv.h" #include #include #include @@ -225,14 +219,14 @@ static void v4l1_find_min_and_max_size(int index, struct v4l2_format *fmt2) for (i = 0; ; i++) { fmtdesc2.index = i; - if (syscall(SYS_ioctl, devices[index].fd, VIDIOC_ENUM_FMT, &fmtdesc2)) + if (SYS_IOCTL(devices[index].fd, VIDIOC_ENUM_FMT, &fmtdesc2)) break; fmt2->fmt.pix.pixelformat = fmtdesc2.pixelformat; fmt2->fmt.pix.width = 48; fmt2->fmt.pix.height = 32; - if (syscall(SYS_ioctl, devices[index].fd, VIDIOC_TRY_FMT, fmt2) == 0) { + if (SYS_IOCTL(devices[index].fd, VIDIOC_TRY_FMT, fmt2) == 0) { if (fmt2->fmt.pix.width < devices[index].min_width) devices[index].min_width = fmt2->fmt.pix.width; if (fmt2->fmt.pix.height < devices[index].min_height) @@ -243,7 +237,7 @@ static void v4l1_find_min_and_max_size(int index, struct v4l2_format *fmt2) fmt2->fmt.pix.width = 100000; fmt2->fmt.pix.height = 100000; - if (syscall(SYS_ioctl, devices[index].fd, VIDIOC_TRY_FMT, fmt2) == 0) { + if (SYS_IOCTL(devices[index].fd, VIDIOC_TRY_FMT, fmt2) == 0) { if (fmt2->fmt.pix.width > devices[index].max_width) devices[index].max_width = fmt2->fmt.pix.width; if (fmt2->fmt.pix.height > devices[index].max_height) @@ -280,11 +274,12 @@ int v4l1_open (const char *file, int oflag, ...) va_start (ap, oflag); mode = va_arg (ap, mode_t); - fd = syscall(SYS_open, file, oflag, mode); + fd = SYS_OPEN(file, oflag, mode); va_end(ap); } else - fd = syscall(SYS_open, file, oflag); + fd = SYS_OPEN(file, oflag, 0); + /* end of original open code */ if (fd == -1 || !v4l_device) @@ -292,7 +287,7 @@ int v4l1_open (const char *file, int oflag, ...) /* check that this is an v4l2 device, no need to emulate v4l1 on a v4l1 device */ - if (syscall(SYS_ioctl, fd, VIDIOC_QUERYCAP, &cap2)) + if (SYS_IOCTL(fd, VIDIOC_QUERYCAP, &cap2)) return fd; /* IMPROVEME */ @@ -314,7 +309,7 @@ int v4l1_open (const char *file, int oflag, ...) emulation for us */ if (v4l2_fd_open(fd, V4L2_ENABLE_ENUM_FMT_EMULATION) == -1) { int saved_err = errno; - syscall(SYS_close, fd); + SYS_CLOSE(fd); errno = saved_err; return -1; } @@ -323,7 +318,7 @@ int v4l1_open (const char *file, int oflag, ...) fmt2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (v4l2_ioctl(fd, VIDIOC_G_FMT, &fmt2)) { int saved_err = errno; - syscall(SYS_close, fd); + SYS_CLOSE(fd); errno = saved_err; return -1; } @@ -400,7 +395,7 @@ int v4l1_close(int fd) { int index, result; if ((index = v4l1_get_index(fd)) == -1) - return syscall(SYS_close, fd); + return SYS_CLOSE(fd); /* Abuse stream_lock to stop 2 closes from racing and trying to free the resources twice */ @@ -418,7 +413,7 @@ int v4l1_close(int fd) { V4L1_LOG("v4l1 capture buffer still mapped: %d times on close()\n", devices[index].v4l1_frame_buf_map_count); else - syscall(SYS_munmap, devices[index].v4l1_frame_pointer, + SYS_MUNMAP(devices[index].v4l1_frame_pointer, V4L1_NO_FRAMES * V4L1_FRAME_BUF_SIZE); devices[index].v4l1_frame_pointer = MAP_FAILED; } @@ -447,7 +442,6 @@ int v4l1_dup(int fd) return v4l2_dup(fd); } - int v4l1_ioctl (int fd, unsigned long int request, ...) { void *arg; @@ -459,7 +453,7 @@ int v4l1_ioctl (int fd, unsigned long int request, ...) va_end (ap); if ((index = v4l1_get_index(fd)) == -1) - return syscall(SYS_ioctl, fd, request, arg); + return SYS_IOCTL(fd, request, arg); /* Appearantly the kernel and / or glibc ignore the 32 most significant bits when long = 64 bits, and some applications pass an int holding the req to @@ -486,7 +480,7 @@ int v4l1_ioctl (int fd, unsigned long int request, ...) { struct video_capability *cap = arg; - result = syscall(SYS_ioctl, fd, request, arg); + result = SYS_IOCTL(fd, request, arg); /* override kernel v4l1 compat min / max size with our own more accurate values */ @@ -563,7 +557,7 @@ int v4l1_ioctl (int fd, unsigned long int request, ...) case VIDIOCGWIN: devices[index].flags |= V4L1_PIX_SIZE_TOUCHED; - result = syscall(SYS_ioctl, fd, request, arg); + result = SYS_IOCTL(fd, request, arg); break; case VIDIOCGCHAN: @@ -573,7 +567,7 @@ int v4l1_ioctl (int fd, unsigned long int request, ...) if ((devices[index].flags & V4L1_SUPPORTS_ENUMINPUT) && (devices[index].flags & V4L1_SUPPORTS_ENUMSTD)) { - result = syscall(SYS_ioctl, fd, request, arg); + result = SYS_IOCTL(fd, request, arg); break; } @@ -615,7 +609,7 @@ int v4l1_ioctl (int fd, unsigned long int request, ...) struct video_channel *chan = arg; if ((devices[index].flags & V4L1_SUPPORTS_ENUMINPUT) && (devices[index].flags & V4L1_SUPPORTS_ENUMSTD)) { - result = syscall(SYS_ioctl, fd, request, arg); + result = SYS_IOCTL(fd, request, arg); break; } /* In case of no ENUMSTD support, ignore the norm member of the @@ -651,7 +645,7 @@ int v4l1_ioctl (int fd, unsigned long int request, ...) } if (devices[index].v4l1_frame_pointer == MAP_FAILED) { - devices[index].v4l1_frame_pointer = (void *)syscall(SYS_mmap2, NULL, + devices[index].v4l1_frame_pointer = (void *)SYS_MMAP(NULL, (size_t)mbuf->size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); @@ -748,7 +742,7 @@ ssize_t v4l1_read(int fd, void* buffer, size_t n) ssize_t result; if ((index = v4l1_get_index(fd)) == -1) - return syscall(SYS_read, fd, buffer, n); + return SYS_READ(fd, buffer, n); pthread_mutex_lock(&devices[index].stream_lock); result = v4l2_read(fd, buffer, n); @@ -759,7 +753,7 @@ ssize_t v4l1_read(int fd, void* buffer, size_t n) void *v4l1_mmap(void *start, size_t length, int prot, int flags, int fd, - __off64_t offset) + int64_t offset) { int index; void *result; diff --git a/v4l2-apps/libv4l/libv4l1/log.c b/v4l2-apps/libv4l/libv4l1/log.c index 9ff0cea46..fd095817f 100644 --- a/v4l2-apps/libv4l/libv4l1/log.c +++ b/v4l2-apps/libv4l/libv4l1/log.c @@ -18,12 +18,7 @@ #include #include -#include -/* These headers are not needed by us, but by linux/videodev2.h, - which is broken on some systems and doesn't include them itself :( */ -#include -#include -/* end broken header workaround includes */ +#include "../libv4lconvert/libv4lsyscall-priv.h" #include #include "libv4l1-priv.h" diff --git a/v4l2-apps/libv4l/libv4l1/v4l1compat.c b/v4l2-apps/libv4l/libv4l1/v4l1compat.c index e4293d2f9..704ec22dd 100644 --- a/v4l2-apps/libv4l/libv4l1/v4l1compat.c +++ b/v4l2-apps/libv4l/libv4l1/v4l1compat.c @@ -25,6 +25,7 @@ #include #include #include +#include "../libv4lconvert/libv4lsyscall-priv.h" /* for __off_t */ #include #include @@ -61,6 +62,7 @@ LIBV4L_PUBLIC int open (const char *file, int oflag, ...) return fd; } +#ifdef linux LIBV4L_PUBLIC int open64 (const char *file, int oflag, ...) { int fd; @@ -81,6 +83,7 @@ LIBV4L_PUBLIC int open64 (const char *file, int oflag, ...) return fd; } +#endif LIBV4L_PUBLIC int close(int fd) { return v4l1_close(fd); @@ -114,11 +117,13 @@ LIBV4L_PUBLIC void *mmap(void *start, size_t length, int prot, int flags, int fd return v4l1_mmap(start, length, prot, flags, fd, offset); } +#ifdef linux LIBV4L_PUBLIC void *mmap64(void *start, size_t length, int prot, int flags, int fd, __off64_t offset) { return v4l1_mmap(start, length, prot, flags, fd, offset); } +#endif LIBV4L_PUBLIC int munmap(void *start, size_t length) { diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2-priv.h b/v4l2-apps/libv4l/libv4l2/libv4l2-priv.h index 8724832e1..0bfd53e2a 100644 --- a/v4l2-apps/libv4l/libv4l2/libv4l2-priv.h +++ b/v4l2-apps/libv4l/libv4l2/libv4l2-priv.h @@ -23,14 +23,7 @@ #include #include /* includes videodev2.h for us */ -/* On 32 bits archs we always use mmap2, on 64 bits archs there is no mmap2 */ -#ifdef __NR_mmap2 -#define SYS_mmap2 __NR_mmap2 -#define MMAP2_PAGE_SHIFT 12 -#else -#define SYS_mmap2 SYS_mmap -#define MMAP2_PAGE_SHIFT 0 -#endif +#include "../libv4lconvert/libv4lsyscall-priv.h" #define V4L2_MAX_DEVICES 16 /* Warning when making this larger the frame_queued and frame_mapped members of diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2.c b/v4l2-apps/libv4l/libv4l2/libv4l2.c index 382dc405b..a12b41c2c 100644 --- a/v4l2-apps/libv4l/libv4l2/libv4l2.c +++ b/v4l2-apps/libv4l/libv4l2/libv4l2.c @@ -59,7 +59,6 @@ #include #include #include -#include #include #include #include @@ -100,7 +99,7 @@ static int v4l2_request_read_buffers(int index) devices[index].nreadbuffers; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; - if ((result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_REQBUFS, &req)) < 0){ + if ((result = SYS_IOCTL(devices[index].fd, VIDIOC_REQBUFS, &req)) < 0){ int saved_err = errno; V4L2_LOG_ERR("requesting %u buffers: %s\n", req.count, strerror(errno)); errno = saved_err; @@ -127,7 +126,7 @@ static void v4l2_unrequest_read_buffers(int index) req.count = 0; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; - if(syscall(SYS_ioctl, devices[index].fd, VIDIOC_REQBUFS, &req) < 0) + if(SYS_IOCTL(devices[index].fd, VIDIOC_REQBUFS, &req) < 0) return; devices[index].no_frames = MIN(req.count, V4L2_MAX_NO_FRAMES); @@ -148,7 +147,7 @@ static int v4l2_map_buffers(int index) buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = i; - result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_QUERYBUF, &buf); + result = SYS_IOCTL(devices[index].fd, VIDIOC_QUERYBUF, &buf); if (result) { int saved_err = errno; V4L2_LOG_ERR("querying buffer %u: %s\n", i, strerror(errno)); @@ -156,9 +155,9 @@ static int v4l2_map_buffers(int index) break; } - devices[index].frame_pointers[i] = (void *)syscall(SYS_mmap2, NULL, + devices[index].frame_pointers[i] = (void *)SYS_MMAP(NULL, (size_t)buf.length, PROT_READ|PROT_WRITE, MAP_SHARED, devices[index].fd, - (__off_t)(buf.m.offset >> MMAP2_PAGE_SHIFT)); + buf.m.offset); if (devices[index].frame_pointers[i] == MAP_FAILED) { int saved_err = errno; V4L2_LOG_ERR("mmapping buffer %u: %s\n", i, strerror(errno)); @@ -182,7 +181,7 @@ static void v4l2_unmap_buffers(int index) /* unmap the buffers */ for (i = 0; i < devices[index].no_frames; i++) { if (devices[index].frame_pointers[i] != MAP_FAILED) { - syscall(SYS_munmap, devices[index].frame_pointers[i], + SYS_MUNMAP(devices[index].frame_pointers[i], devices[index].frame_sizes[i]); devices[index].frame_pointers[i] = MAP_FAILED; V4L2_LOG("unmapped buffer %u\n", i); @@ -196,7 +195,7 @@ static int v4l2_streamon(int index) enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (!(devices[index].flags & V4L2_STREAMON)) { - if ((result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_STREAMON, + if ((result = SYS_IOCTL(devices[index].fd, VIDIOC_STREAMON, &type))) { int saved_err = errno; V4L2_LOG_ERR("turning on stream: %s\n", strerror(errno)); @@ -215,7 +214,7 @@ static int v4l2_streamoff(int index) enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (devices[index].flags & V4L2_STREAMON) { - if ((result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_STREAMOFF, + if ((result = SYS_IOCTL(devices[index].fd, VIDIOC_STREAMOFF, &type))) { int saved_err = errno; V4L2_LOG_ERR("turning off stream: %s\n", strerror(errno)); @@ -243,7 +242,7 @@ static int v4l2_queue_read_buffer(int index, int buffer_index) buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = buffer_index; - if ((result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_QBUF, &buf))) { + if ((result = SYS_IOCTL(devices[index].fd, VIDIOC_QBUF, &buf))) { int saved_err = errno; V4L2_LOG_ERR("queuing buf %d: %s\n", buffer_index, strerror(errno)); errno = saved_err; @@ -265,7 +264,7 @@ static int v4l2_dequeue_and_convert(int index, struct v4l2_buffer *buf, return result; do { - if ((result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_DQBUF, buf))) { + if ((result = SYS_IOCTL(devices[index].fd, VIDIOC_DQBUF, buf))) { if (errno != EAGAIN) { int saved_err = errno; V4L2_LOG_ERR("dequeuing buf: %s\n", strerror(errno)); @@ -386,7 +385,7 @@ static int v4l2_buffers_mapped(int index) buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = i; - if (syscall(SYS_ioctl, devices[index].fd, VIDIOC_QUERYBUF, &buf)) { + if (SYS_IOCTL(devices[index].fd, VIDIOC_QUERYBUF, &buf)) { int saved_err = errno; V4L2_LOG_ERR("querying buffer %u: %s\n", i, strerror(errno)); errno = saved_err; @@ -422,12 +421,12 @@ int v4l2_open (const char *file, int oflag, ...) va_start (ap, oflag); mode = va_arg (ap, mode_t); - fd = syscall(SYS_open, file, oflag, mode); + fd = SYS_OPEN(file, oflag, mode); va_end(ap); } else - fd = syscall(SYS_open, file, oflag); + fd = SYS_OPEN(file, oflag, 0); /* end of original open code */ if (fd == -1) @@ -435,7 +434,7 @@ int v4l2_open (const char *file, int oflag, ...) if (v4l2_fd_open(fd, 0) == -1) { int saved_err = errno; - syscall(SYS_close, fd); + SYS_CLOSE(fd); errno = saved_err; return -1; } @@ -457,7 +456,7 @@ int v4l2_fd_open(int fd, int v4l2_flags) v4l2_log_file = fopen(lfname, "w"); /* check that this is an v4l2 device */ - if (syscall(SYS_ioctl, fd, VIDIOC_QUERYCAP, &cap)) { + if (SYS_IOCTL(fd, VIDIOC_QUERYCAP, &cap)) { int saved_err = errno; V4L2_LOG_ERR("getting capabilities: %s\n", strerror(errno)); errno = saved_err; @@ -472,7 +471,7 @@ int v4l2_fd_open(int fd, int v4l2_flags) /* Get current cam format */ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (syscall(SYS_ioctl, fd, VIDIOC_G_FMT, &fmt)) { + if (SYS_IOCTL(fd, VIDIOC_G_FMT, &fmt)) { int saved_err = errno; V4L2_LOG_ERR("getting pixformat: %s\n", strerror(errno)); errno = saved_err; @@ -553,7 +552,7 @@ int v4l2_close(int fd) int index, result; if ((index = v4l2_get_index(fd)) == -1) - return syscall(SYS_close, fd); + return SYS_CLOSE(fd); /* Abuse stream_lock to stop 2 closes from racing and trying to free the resources twice */ @@ -571,7 +570,7 @@ int v4l2_close(int fd) if (v4l2_buffers_mapped(index)) V4L2_LOG_WARN("v4l2 mmap buffers still mapped on close()\n"); else - syscall(SYS_munmap, devices[index].convert_mmap_buf, + SYS_MUNMAP(devices[index].convert_mmap_buf, devices[index].no_frames * V4L2_FRAME_BUF_SIZE); devices[index].convert_mmap_buf = MAP_FAILED; } @@ -585,7 +584,7 @@ int v4l2_close(int fd) /* Since we've marked the fd as no longer used, and freed the resources, redo the close in case it was interrupted */ do { - result = syscall(SYS_close, fd); + result = SYS_CLOSE(fd); } while (result == -1 && errno == EINTR); V4L2_LOG("close: %d\n", fd); @@ -622,7 +621,7 @@ static int v4l2_check_buffer_change_ok(int index) /* We may change from convert to non conversion mode and v4l2_unrequest_read_buffers may change the no_frames, so free the convert mmap buffer */ - syscall(SYS_munmap, devices[index].convert_mmap_buf, + SYS_MUNMAP(devices[index].convert_mmap_buf, devices[index].no_frames * V4L2_FRAME_BUF_SIZE); devices[index].convert_mmap_buf = MAP_FAILED; @@ -676,7 +675,7 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) va_end (ap); if ((index = v4l2_get_index(fd)) == -1) - return syscall(SYS_ioctl, fd, request, arg); + return SYS_IOCTL(fd, request, arg); /* Appearantly the kernel and / or glibc ignore the 32 most significant bits when long = 64 bits, and some applications pass an int holding the req to @@ -740,7 +739,7 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) } if (!is_capture_request) { - result = syscall(SYS_ioctl, fd, request, arg); + result = SYS_IOCTL(fd, request, arg); saved_err = errno; v4l2_log_ioctl(request, arg, result); errno = saved_err; @@ -787,7 +786,7 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) { struct v4l2_capability *cap = arg; - result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_QUERYCAP, cap); + result = SYS_IOCTL(devices[index].fd, VIDIOC_QUERYCAP, cap); if (result == 0) /* We always support read() as we fake it using mmap mode */ cap->capabilities |= V4L2_CAP_READWRITE; @@ -838,7 +837,7 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) } if (devices[index].flags & V4L2_DISABLE_CONVERSION) { - result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_TRY_FMT, + result = SYS_IOCTL(devices[index].fd, VIDIOC_TRY_FMT, dest_fmt); src_fmt = *dest_fmt; } else { @@ -878,7 +877,7 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) break; req_pix_fmt = src_fmt.fmt.pix; - result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_S_FMT, &src_fmt); + result = SYS_IOCTL(devices[index].fd, VIDIOC_S_FMT, &src_fmt); if (result) { saved_err = errno; V4L2_LOG_ERR("setting pixformat: %s\n", strerror(errno)); @@ -928,7 +927,7 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) if (req->count > V4L2_MAX_NO_FRAMES) req->count = V4L2_MAX_NO_FRAMES; - result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_REQBUFS, req); + result = SYS_IOCTL(devices[index].fd, VIDIOC_REQBUFS, req); if (result < 0) break; result = 0; /* some drivers return the number of buffers on success */ @@ -948,7 +947,7 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) /* Do a real query even when converting to let the driver fill in things like buf->field */ - result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_QUERYBUF, buf); + result = SYS_IOCTL(devices[index].fd, VIDIOC_QUERYBUF, buf); if (result || !v4l2_needs_conversion(index)) break; @@ -971,7 +970,7 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) if ((result = v4l2_map_buffers(index))) break; - result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_QBUF, arg); + result = SYS_IOCTL(devices[index].fd, VIDIOC_QBUF, arg); break; case VIDIOC_DQBUF: @@ -983,7 +982,7 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) break; if (!v4l2_needs_conversion(index)) { - result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_DQBUF, buf); + result = SYS_IOCTL(devices[index].fd, VIDIOC_DQBUF, buf); if (result) { int saved_err = errno; V4L2_LOG_ERR("dequeuing buf: %s\n", strerror(errno)); @@ -996,7 +995,7 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) but we need the buffer _now_ to write our converted data to it! */ if (devices[index].convert_mmap_buf == MAP_FAILED) { - devices[index].convert_mmap_buf = (void *)syscall(SYS_mmap2, NULL, + devices[index].convert_mmap_buf = (void *)SYS_MMAP(NULL, (size_t)( devices[index].no_frames * V4L2_FRAME_BUF_SIZE), @@ -1041,7 +1040,7 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) break; default: - result = syscall(SYS_ioctl, fd, request, arg); + result = SYS_IOCTL(fd, request, arg); } if (stream_needs_locking) @@ -1062,7 +1061,7 @@ ssize_t v4l2_read (int fd, void* dest, size_t n) struct v4l2_buffer buf; if ((index = v4l2_get_index(fd)) == -1) - return syscall(SYS_read, fd, dest, n); + return SYS_READ(fd, dest, n); pthread_mutex_lock(&devices[index].stream_lock); @@ -1070,7 +1069,7 @@ ssize_t v4l2_read (int fd, void* dest, size_t n) it */ if ((devices[index].flags & V4L2_SUPPORTS_READ) && !v4l2_needs_conversion(index)) { - result = syscall(SYS_read, fd, dest, n); + result = SYS_READ(fd, dest, n); goto leave; } @@ -1099,7 +1098,7 @@ leave: } void *v4l2_mmap(void *start, size_t length, int prot, int flags, int fd, - __off64_t offset) + int64_t offset) { int index; unsigned int buffer_index; @@ -1119,8 +1118,7 @@ void *v4l2_mmap(void *start, size_t length, int prot, int flags, int fd, return MAP_FAILED; } - return (void *)syscall(SYS_mmap2, start, length, prot, flags, fd, - (__off_t)(offset >> MMAP2_PAGE_SHIFT)); + return (void *)SYS_MMAP(start, length, prot, flags, fd, offset); } pthread_mutex_lock(&devices[index].stream_lock); @@ -1135,7 +1133,7 @@ void *v4l2_mmap(void *start, size_t length, int prot, int flags, int fd, } if (devices[index].convert_mmap_buf == MAP_FAILED) { - devices[index].convert_mmap_buf = (void *)syscall(SYS_mmap2, NULL, + devices[index].convert_mmap_buf = (void *)SYS_MMAP(NULL, (size_t)( devices[index].no_frames * V4L2_FRAME_BUF_SIZE), @@ -1208,7 +1206,7 @@ int v4l2_munmap(void *_start, size_t length) V4L2_LOG("v4l2 unknown munmap %p, %d\n", start, (int)length); - return syscall(SYS_munmap, _start, length); + return SYS_MUNMAP(_start, length); } /* Misc utility functions */ @@ -1218,7 +1216,7 @@ int v4l2_set_control(int fd, int cid, int value) struct v4l2_control ctrl = { .id = cid }; int result; - if ((result = syscall(SYS_ioctl, fd, VIDIOC_QUERYCTRL, &qctrl))) + if ((result = SYS_IOCTL(fd, VIDIOC_QUERYCTRL, &qctrl))) return result; if (!(qctrl.flags & V4L2_CTRL_FLAG_DISABLED) && @@ -1229,7 +1227,7 @@ int v4l2_set_control(int fd, int cid, int value) ctrl.value = (value * (qctrl.maximum - qctrl.minimum) + 32767) / 65535 + qctrl.minimum; - result = syscall(SYS_ioctl, fd, VIDIOC_S_CTRL, &ctrl); + result = SYS_IOCTL(fd, VIDIOC_S_CTRL, &ctrl); } return result; @@ -1240,13 +1238,13 @@ int v4l2_get_control(int fd, int cid) struct v4l2_queryctrl qctrl = { .id = cid }; struct v4l2_control ctrl = { .id = cid }; - if (syscall(SYS_ioctl, fd, VIDIOC_QUERYCTRL, &qctrl)) + if (SYS_IOCTL(fd, VIDIOC_QUERYCTRL, &qctrl)) return 0; if (qctrl.flags & V4L2_CTRL_FLAG_DISABLED) return 0; - if (syscall(SYS_ioctl, fd, VIDIOC_G_CTRL, &ctrl)) + if (SYS_IOCTL(fd, VIDIOC_G_CTRL, &ctrl)) return 0; return ((ctrl.value - qctrl.minimum) * 65535 + diff --git a/v4l2-apps/libv4l/libv4l2/log.c b/v4l2-apps/libv4l/libv4l2/log.c index a08ae3554..86d71b64e 100644 --- a/v4l2-apps/libv4l/libv4l2/log.c +++ b/v4l2-apps/libv4l/libv4l2/log.c @@ -22,12 +22,7 @@ #include #include #include -#include -/* These headers are not needed by us, but by linux/videodev2.h, - which is broken on some systems and doesn't include them itself :( */ -#include -#include -/* end broken header workaround includes */ +#include "../libv4lconvert/libv4lsyscall-priv.h" #include #include "libv4l2.h" #include "libv4l2-priv.h" diff --git a/v4l2-apps/libv4l/libv4l2/v4l2convert.c b/v4l2-apps/libv4l/libv4l2/v4l2convert.c index b1354772d..4b75a5ebf 100644 --- a/v4l2-apps/libv4l/libv4l2/v4l2convert.c +++ b/v4l2-apps/libv4l/libv4l2/v4l2convert.c @@ -24,17 +24,11 @@ #include #include -#include #include #include #include #include -/* These headers are not needed by us, but by linux/videodev2.h, - which is broken on some systems and doesn't include them itself :( */ -#include -#include -#include -/* end broken header workaround includes */ +#include "../libv4lconvert/libv4lsyscall-priv.h" #include #include @@ -72,18 +66,18 @@ LIBV4L_PUBLIC int open (const char *file, int oflag, ...) va_start (ap, oflag); mode = va_arg (ap, mode_t); - fd = syscall(SYS_open, file, oflag, mode); + fd = SYS_OPEN(file, oflag, mode); va_end(ap); } else - fd = syscall(SYS_open, file, oflag); + fd = SYS_OPEN(file, oflag, 0); /* end of original open code */ if (fd == -1 || !v4l_device) return fd; /* check that this is an v4l2 device, libv4l2 only supports v4l2 devices */ - if (syscall(SYS_ioctl, fd, VIDIOC_QUERYCAP, &cap)) + if (SYS_IOCTL(fd, VIDIOC_QUERYCAP, &cap)) return fd; /* libv4l2 only adds functionality to capture capable devices */ @@ -97,6 +91,7 @@ LIBV4L_PUBLIC int open (const char *file, int oflag, ...) return fd; } +#ifdef linux LIBV4L_PUBLIC int open64(const char *file, int oflag, ...) { int fd; @@ -119,6 +114,7 @@ LIBV4L_PUBLIC int open64(const char *file, int oflag, ...) return fd; } +#endif LIBV4L_PUBLIC int close(int fd) { @@ -153,11 +149,13 @@ LIBV4L_PUBLIC void *mmap(void *start, size_t length, int prot, int flags, int fd return v4l2_mmap(start, length, prot, flags, fd, offset); } +#ifdef linux LIBV4L_PUBLIC void *mmap64(void *start, size_t length, int prot, int flags, int fd, __off64_t offset) { return v4l2_mmap(start, length, prot, flags, fd, offset); } +#endif LIBV4L_PUBLIC int munmap(void *start, size_t length) { diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c index da2fbcdce..2f459c396 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c @@ -28,16 +28,9 @@ #include #include #include -#include #include "libv4lcontrol.h" #include "libv4lcontrol-priv.h" - -/* These headers are not needed by us, but by linux/videodev2.h, - which is broken on some systems and doesn't include them itself :( */ -#include -#include -#include -/* end broken header workaround includes */ +#include "../libv4lsyscall-priv.h" #include #define ARRAY_SIZE(x) ((int)sizeof(x)/(int)sizeof((x)[0])) @@ -102,8 +95,8 @@ static void v4lcontrol_init_flags(struct v4lcontrol_data *data) 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 ((SYS_IOCTL(data->fd, VIDIOC_G_INPUT, &input.index) == 0) && + (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) @@ -229,7 +222,7 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) data->flags = strtol(s, NULL, 0); ctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL; - if (syscall(SYS_ioctl, data->fd, VIDIOC_QUERYCTRL, &ctrl) == 0) + if (SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL, &ctrl) == 0) data->priv_flags |= V4LCONTROL_SUPPORTS_NEXT_CTRL; /* If the device always needs conversion, we can add fake controls at no cost @@ -237,7 +230,7 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) if (always_needs_conversion || v4lcontrol_needs_conversion(data)) { for (i = 0; i < V4LCONTROL_AUTO_ENABLE_COUNT; i++) { ctrl.id = fake_controls[i].id; - if (syscall(SYS_ioctl, data->fd, VIDIOC_QUERYCTRL, &ctrl) == -1) + if (SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL, &ctrl) == -1) data->controls |= 1 << i; } } @@ -253,7 +246,7 @@ 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 */ - syscall(SYS_ioctl, fd, VIDIOC_QUERYCAP, &cap); + SYS_IOCTL(fd, VIDIOC_QUERYCAP, &cap); snprintf(shm_name, 256, "/%s:%s", cap.bus_info, cap.card); /* / is not allowed inside shm names */ @@ -403,7 +396,7 @@ int v4lcontrol_vidioc_queryctrl(struct v4lcontrol_data *data, void *arg) } /* find out what the kernel driver would respond. */ - retval = syscall(SYS_ioctl, data->fd, VIDIOC_QUERYCTRL, arg); + retval = SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL, arg); if ((data->priv_flags & V4LCONTROL_SUPPORTS_NEXT_CTRL) && (orig_id & V4L2_CTRL_FLAG_NEXT_CTRL)) { @@ -440,7 +433,7 @@ int v4lcontrol_vidioc_g_ctrl(struct v4lcontrol_data *data, void *arg) return 0; } - return syscall(SYS_ioctl, data->fd, VIDIOC_G_CTRL, arg); + return SYS_IOCTL(data->fd, VIDIOC_G_CTRL, arg); } int v4lcontrol_vidioc_s_ctrl(struct v4lcontrol_data *data, void *arg) @@ -461,7 +454,7 @@ int v4lcontrol_vidioc_s_ctrl(struct v4lcontrol_data *data, void *arg) return 0; } - return syscall(SYS_ioctl, data->fd, VIDIOC_S_CTRL, arg); + return SYS_IOCTL(data->fd, VIDIOC_S_CTRL, arg); } int v4lcontrol_get_flags(struct v4lcontrol_data *data) diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index 1b95d0657..ef23be362 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -19,12 +19,12 @@ #include #include #include -#include #include #include #include #include "libv4lconvert.h" #include "libv4lconvert-priv.h" +#include "libv4lsyscall-priv.h" #define MIN(a,b) (((a)<(b))?(a):(b)) @@ -103,7 +103,7 @@ struct v4lconvert_data *v4lconvert_create(int fd) fmt.index = i; - if (syscall(SYS_ioctl, fd, VIDIOC_ENUM_FMT, &fmt)) + if (SYS_IOCTL(data->fd, VIDIOC_ENUM_FMT, &fmt)) break; for (j = 0; j < ARRAY_SIZE(supported_src_pixfmts); j++) @@ -122,7 +122,7 @@ struct v4lconvert_data *v4lconvert_create(int fd) data->no_formats = i; /* Check if this cam has any special flags */ - if (syscall(SYS_ioctl, fd, VIDIOC_QUERYCAP, &cap) == 0) { + if (SYS_IOCTL(data->fd, VIDIOC_QUERYCAP, &cap) == 0) { if (!strcmp((char *)cap.driver, "uvcvideo")) data->flags |= V4LCONVERT_IS_UVC; else if (!strcmp((char *)cap.driver, "sn9c20x")) @@ -192,7 +192,7 @@ int v4lconvert_enum_fmt(struct v4lconvert_data *data, struct v4l2_fmtdesc *fmt) if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || (!v4lconvert_supported_dst_fmt_only(data) && fmt->index < data->no_formats)) - return syscall(SYS_ioctl, data->fd, VIDIOC_ENUM_FMT, fmt); + return SYS_IOCTL(data->fd, VIDIOC_ENUM_FMT, fmt); for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) if (v4lconvert_supported_dst_fmt_only(data) || @@ -300,7 +300,7 @@ static int v4lconvert_do_try_format(struct v4lconvert_data *data, try_fmt = *dest_fmt; try_fmt.fmt.pix.pixelformat = supported_src_pixfmts[i].fmt; - if (!syscall(SYS_ioctl, data->fd, VIDIOC_TRY_FMT, &try_fmt)) + if (!SYS_IOCTL(data->fd, VIDIOC_TRY_FMT, &try_fmt)) { if (try_fmt.fmt.pix.pixelformat == supported_src_pixfmts[i].fmt) { int size_x_diff = abs((int)try_fmt.fmt.pix.width - @@ -368,7 +368,7 @@ int v4lconvert_try_format(struct v4lconvert_data *data, if (!v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat) || dest_fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || v4lconvert_do_try_format(data, &try_dest, &try_src)) { - result = syscall(SYS_ioctl, data->fd, VIDIOC_TRY_FMT, dest_fmt); + result = SYS_IOCTL(data->fd, VIDIOC_TRY_FMT, dest_fmt); if (src_fmt) *src_fmt = *dest_fmt; return result; @@ -1041,7 +1041,7 @@ static void v4lconvert_get_framesizes(struct v4lconvert_data *data, for (i = 0; ; i++) { frmsize.index = i; - if (syscall(SYS_ioctl, data->fd, VIDIOC_ENUM_FRAMESIZES, &frmsize)) + if (SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMESIZES, &frmsize)) break; /* We got a framesize, check we don't have the same one already */ @@ -1101,7 +1101,7 @@ int v4lconvert_enum_framesizes(struct v4lconvert_data *data, errno = EINVAL; return -1; } - return syscall(SYS_ioctl, data->fd, VIDIOC_ENUM_FRAMESIZES, frmsize); + return SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMESIZES, frmsize); } if (frmsize->index >= data->no_framesizes) { @@ -1141,7 +1141,7 @@ int v4lconvert_enum_frameintervals(struct v4lconvert_data *data, errno = EINVAL; return -1; } - res = syscall(SYS_ioctl, data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival); + res = SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival); if (res) V4LCONVERT_ERR("%s\n", strerror(errno)); return res; @@ -1185,7 +1185,7 @@ int v4lconvert_enum_frameintervals(struct v4lconvert_data *data, frmival->pixel_format = src_fmt.fmt.pix.pixelformat; frmival->width = src_fmt.fmt.pix.width; frmival->height = src_fmt.fmt.pix.height; - res = syscall(SYS_ioctl, data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival); + res = SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival); if (res) { int dest_pixfmt = dest_fmt.fmt.pix.pixelformat; int src_pixfmt = src_fmt.fmt.pix.pixelformat; diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lsyscall-priv.h b/v4l2-apps/libv4l/libv4lconvert/libv4lsyscall-priv.h new file mode 100644 index 000000000..a456ceea3 --- /dev/null +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lsyscall-priv.h @@ -0,0 +1,112 @@ +/*- + * Copyright (c) 2009 Hans Petter Selasky. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * The following file allows for having the complete V4L stack and + * hardware drivers in userland. + */ + +#ifndef _LIBV4LSYSCALL_PRIV_H_ +#define _LIBV4LSYSCALL_PRIV_H_ + +/* Some of these headers are not needed by us, but by linux/videodev2.h, + which is broken on some systems and doesn't include them itself :( */ + +#ifdef linux +#include +#include +#include +#include +/* On 32 bits archs we always use mmap2, on 64 bits archs there is no mmap2 */ +#ifdef __NR_mmap2 +#define SYS_mmap2 __NR_mmap2 +#define MMAP2_PAGE_SHIFT 12 +#else +#define SYS_mmap2 SYS_mmap +#define MMAP2_PAGE_SHIFT 0 +#endif +#endif + +#ifdef __FreeBSD__ +#include +#include +#include +#include +#define _IOC_NR(cmd) ((cmd) & 0xFF) +#define _IOC_TYPE(cmd) IOCGROUP(cmd) +#define _IOC_SIZE(cmd) IOCPARM_LEN(cmd) +#define MAP_ANONYMOUS MAP_ANON +#define SYS_mmap2 SYS_mmap +#define MMAP2_PAGE_SHIFT 0 +typedef off_t __off_t; +#endif + +#undef SYS_OPEN +#undef SYS_CLOSE +#undef SYS_IOCTL +#undef SYS_READ +#undef SYS_WRITE +#undef SYS_MMAP +#undef SYS_MUNMAP + +#ifndef CONFIG_SYS_WRAPPER + +#define SYS_OPEN(file, oflag, mode) \ + syscall(SYS_open, (const char *)(file), (int)(oflag), (mode_t)(mode)) +#define SYS_CLOSE(fd) \ + syscall(SYS_close, (int)(fd)) +#define SYS_IOCTL(fd, cmd, arg) \ + syscall(SYS_ioctl, (int)(fd), (unsigned long)(cmd), (void *)(arg)) +#define SYS_READ(fd, buf, len) \ + syscall(SYS_read, (int)(fd), (void *)(buf), (size_t)(len)); +#define SYS_WRITE(fd, buf, len) \ + syscall(SYS_write, (int)(fd), (void *)(buf), (size_t)(len)); +#define SYS_MMAP(addr, len, prot, flags, fd, off) \ + syscall(SYS_mmap2, (void *)(addr), (size_t)(len), \ + (int)(prot), (int)(flags), (int)(fd), (__off_t)((off) >> MMAP2_PAGE_SHIFT)) +#define SYS_MUNMAP(addr, len) \ + syscall(SYS_munmap, (void *)(addr), (size_t)(len)) + +#else + +int v4lx_open_wrapper(const char *, int, int); +int v4lx_close_wrapper(int); +int v4lx_ioctl_wrapper(int, unsigned long, void *); +int v4lx_read_wrapper(int, void *, size_t); +int v4lx_write_wrapper(int, void *, size_t); +void *v4lx_mmap_wrapper(void *, size_t, int, int, int, off_t); +int v4lx_munmap_wrapper(void *, size_t); + +#define SYS_OPEN(...) v4lx_open_wrapper(__VA_ARGS__) +#define SYS_CLOSE(...) v4lx_close_wrapper(__VA_ARGS__) +#define SYS_IOCTL(...) v4lx_ioctl_wrapper(__VA_ARGS__) +#define SYS_READ(...) v4lx_read_wrapper(__VA_ARGS__) +#define SYS_WRITE(...) v4lx_write_wrapper(__VA_ARGS__) +#define SYS_MMAP(...) v4lx_mmap_wrapper(__VA_ARGS__) +#define SYS_MUNMAP(...) v4lx_munmap_wrapper(__VA_ARGS__) + +#endif + +#endif /* _LIBV4LSYSCALL_PRIV_H_ */ diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/autogain.c b/v4l2-apps/libv4l/libv4lconvert/processing/autogain.c index ed4b8224f..358264c68 100644 --- a/v4l2-apps/libv4l/libv4lconvert/processing/autogain.c +++ b/v4l2-apps/libv4l/libv4lconvert/processing/autogain.c @@ -20,12 +20,12 @@ #include #include #include -#include #include #include "libv4lprocessing.h" #include "libv4lprocessing-priv.h" #include "../libv4lconvert-priv.h" /* for PIX_FMT defines */ +#include "../libv4lsyscall-priv.h" static int autogain_active(struct v4lprocessing_data *data) { return v4lcontrol_get_ctrl(data->control, V4LCONTROL_AUTOGAIN); @@ -45,15 +45,15 @@ static int autogain_calculate_lookup_tables( 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)) + if (SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL, &expoctrl) || + 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)) + if (SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL, &gainctrl) || + SYS_IOCTL(data->fd, VIDIOC_G_CTRL, &ctrl)) return 0; gain = orig_gain = ctrl.value; @@ -125,12 +125,12 @@ static int autogain_calculate_lookup_tables( if (gain != orig_gain) { ctrl.id = V4L2_CID_GAIN; ctrl.value = gain; - syscall(SYS_ioctl, data->fd, VIDIOC_S_CTRL, &ctrl); + 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); + SYS_IOCTL(data->fd, VIDIOC_S_CTRL, &ctrl); } return 0; diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h index 008d352ff..b73c73b53 100644 --- a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h +++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h @@ -22,6 +22,7 @@ #define __LIBV4LPROCESSING_PRIV_H #include "../control/libv4lcontrol.h" +#include "../libv4lsyscall-priv.h" #define V4L2PROCESSING_UPDATE_RATE 10 diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c index f050086e3..cbbcca73c 100644 --- a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c +++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include "libv4lprocessing.h" #include "libv4lprocessing-priv.h" diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.h b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.h index f1892a279..69d8865b2 100644 --- a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.h +++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.h @@ -21,12 +21,7 @@ #ifndef __LIBV4LPROCESSING_H #define __LIBV4LPROCESSING_H -/* These headers are not needed by us, but by linux/videodev2.h, - which is broken on some systems and doesn't include them itself :( */ -#include -#include -#include -/* end broken header workaround includes */ +#include "../libv4lsyscall-priv.h" #include struct v4lprocessing_data; diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c b/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c index f5bfd961c..64d20b3ff 100644 --- a/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c +++ b/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include "libv4lprocessing.h" #include "libv4lprocessing-priv.h" -- cgit v1.2.3 From 5fefedb3c3a7a0ceaa161e4a3c1e180ba22cd364 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Fri, 5 Jun 2009 16:02:40 +0200 Subject: libv4l: recognize when controls are disabled From: Hans de Goede libv4l: recognize when controls are disabled Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 9 +++++++-- v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c | 5 +++-- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index 08b221c2a..3d0733a2d 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -1,11 +1,16 @@ +libv4l-0.6.0 +------------ +* Recognize disabled controls and replace with fake equivalents where + available + libv4l-0.5.99 ----------- +------------- * Link libv4lconvert with -lm for powf by Gregor Jasny * Fix black screen on devices with hardware gamma control * Fix crash with devices on which we do not emulate fake controls * Add a patch by Hans Petter Selasky , which should lead to allowing use of libv4l (and the Linux webcam drivers ported - to userspace usb drivers) on FreeBSd, this is a work in progress + to userspace usb drivers) on FreeBSD, this is a work in progress libv4l-0.5.98 ------------- diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c index 2f459c396..b50b686df 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c @@ -203,7 +203,7 @@ static void v4lcontrol_init_flags(struct v4lcontrol_data *data) struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) { int shm_fd; - int i, init = 0; + int i, rc, init = 0; char *s, shm_name[256]; struct v4l2_capability cap; struct v4l2_queryctrl ctrl; @@ -230,7 +230,8 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) if (always_needs_conversion || v4lcontrol_needs_conversion(data)) { for (i = 0; i < V4LCONTROL_AUTO_ENABLE_COUNT; i++) { ctrl.id = fake_controls[i].id; - if (SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL, &ctrl) == -1) + rc = SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL, &ctrl); + if (rc == -1 || (rc == 0 && (ctrl.flags & V4L2_CTRL_FLAG_DISABLED))) data->controls |= 1 << i; } } -- cgit v1.2.3 From 8589234d1984a6acce63c0debf804c59c8414588 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Fri, 5 Jun 2009 16:30:33 +0200 Subject: libv4l: add support for decompressing ov518 JPEG From: Hans de Goede Add support for decompressing ov518 "JPEG", note this code is not LGPL yet, I'm waiting for a license change permission. If I do not get one this will be moved to an external helper and the data will be piped through this, to keep libv4l2.so LGPL Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 4 + v4l2-apps/libv4l/libv4lconvert/Makefile | 2 +- .../libv4l/libv4lconvert/libv4lconvert-priv.h | 8 + v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 5 + v4l2-apps/libv4l/libv4lconvert/ov518-decomp.c | 1423 ++++++++++++++++++++ 5 files changed, 1441 insertions(+), 1 deletion(-) create mode 100644 v4l2-apps/libv4l/libv4lconvert/ov518-decomp.c (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index 3d0733a2d..ce0ea821d 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -2,6 +2,10 @@ libv4l-0.6.0 ------------ * Recognize disabled controls and replace with fake equivalents where available +* Add support for decompressing ov518 "JPEG", note this code is not + LGPL yet, I'm waiting for a license change permission. If I do not + get one this will be moved to an external helper and the data + will be piped through this, to keep libv4l2.so LGPL libv4l-0.5.99 ------------- diff --git a/v4l2-apps/libv4l/libv4lconvert/Makefile b/v4l2-apps/libv4l/libv4lconvert/Makefile index a2726e0d0..997bd6bff 100644 --- a/v4l2-apps/libv4l/libv4lconvert/Makefile +++ b/v4l2-apps/libv4l/libv4lconvert/Makefile @@ -14,7 +14,7 @@ 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 \ + rgbyuv.o spca501.o sq905c.o bayer.o hm12.o ov518-decomp.o \ control/libv4lcontrol.o processing/libv4lprocessing.o \ processing/whitebalance.o processing/autogain.o \ processing/gamma.o diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h index 407be3435..a2242e91a 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h @@ -83,6 +83,10 @@ #define V4L2_PIX_FMT_SN9C20X_I420 v4l2_fourcc('S', '9', '2', '0') #endif +#ifndef V4L2_PIX_FMT_OV518 +#define V4L2_PIX_FMT_OV518 v4l2_fourcc('O', '5', '1', '8') /* ov518 JPEG */ +#endif + #define ARRAY_SIZE(x) ((int)sizeof(x)/(int)sizeof((x)[0])) #define V4LCONVERT_ERROR_MSG_SIZE 256 @@ -182,6 +186,10 @@ void v4lconvert_spca508_to_yuv420(const unsigned char *src, unsigned char *dst, void v4lconvert_sn9c20x_to_yuv420(const unsigned char *src, unsigned char *dst, int width, int height, int yvu); +/* Warning this one modifies its input buffer! */ +void v4lconvert_ov518_to_yuv420(unsigned char *src, unsigned char *dst, + int width, int height, int yvu, int src_size); + void v4lconvert_decode_spca561(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 ef23be362..47eb2272e 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -63,6 +63,7 @@ static const struct v4lconvert_pixfmt supported_src_pixfmts[] = { { V4L2_PIX_FMT_MR97310A, V4LCONVERT_COMPRESSED }, { V4L2_PIX_FMT_SQ905C, V4LCONVERT_COMPRESSED }, { V4L2_PIX_FMT_PJPG, V4LCONVERT_COMPRESSED }, + { V4L2_PIX_FMT_OV518, V4LCONVERT_COMPRESSED }, }; static const struct v4lconvert_pixfmt supported_dst_pixfmts[] = { @@ -615,6 +616,7 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, case V4L2_PIX_FMT_SPCA505: case V4L2_PIX_FMT_SPCA508: case V4L2_PIX_FMT_SN9C20X_I420: + case V4L2_PIX_FMT_OV518: { unsigned char *d; int yvu = 0; @@ -644,6 +646,9 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, case V4L2_PIX_FMT_SN9C20X_I420: v4lconvert_sn9c20x_to_yuv420(src, d, width, height, yvu); break; + case V4L2_PIX_FMT_OV518: + v4lconvert_ov518_to_yuv420(src, d, width, height, yvu, src_size); + break; } switch (dest_pix_fmt) { diff --git a/v4l2-apps/libv4l/libv4lconvert/ov518-decomp.c b/v4l2-apps/libv4l/libv4lconvert/ov518-decomp.c new file mode 100644 index 000000000..6944719bc --- /dev/null +++ b/v4l2-apps/libv4l/libv4lconvert/ov518-decomp.c @@ -0,0 +1,1423 @@ +/* FIXME FIXME FIXME: get permission to relicense this to LGPL !! */ + +/* OV518 Decompression Support Module (No-MMX version) + * + * Copyright (c) 2002-2003 Mark W. McClelland. All rights reserved. + * http://alpha.dyndns.org/ov511/ + * + * Fast integer iDCT by Yuri van Oers + * Original OV511 decompression code Copyright 1998-2000 OmniVision Technologies + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2 of the License. + */ + +#include +#include "libv4lconvert-priv.h" + +/****************************************************************************** + * Compile-time Options + ******************************************************************************/ + +/* Defining APPROXIMATE_MUL_BY_SHIFT increases performance by approximation + * the multiplications by shifts. I think there's no change in the + * calculated picture, but I'm not sure, so the choice is still in here. */ +#undef APPROXIMATE_MUL_BY_SHIFT + +/****************************************************************************** + * Local Data Types + ******************************************************************************/ + +/* Make sure this remains naturally aligned and 2^n bytes in size */ +struct tree_node { + short left; /* Pointer to left child node */ + short right; /* Pointer to right child node */ + signed char depth; /* Depth (starting at 1) if leaf, else -1 */ + signed char coeffbits; /* Size of coefficient data, or zero if none */ + signed char skip; /* Number of zero coefficients. Unused w/ DC */ + char padding; /* Pad out to 8 bytes */ +}; + +struct comp_info { + int bytes; /* Number of processed input bytes */ + int bits; /* Number of unprocessed input bits */ + int rawLen; /* Total number of bytes in input buffer */ + unsigned char *qt; /* Current quantization table */ +}; + +/****************************************************************************** + * Constant Data Definitions + ******************************************************************************/ + +/* Zig-Zag Table */ +static const unsigned char ZigZag518[] = { + 0x00, 0x02, 0x03, 0x09, + 0x01, 0x04, 0x08, 0x0a, + 0x05, 0x07, 0x0b, 0x11, + 0x06, 0x0c, 0x10, 0x12, + 0x0d, 0x0f, 0x13, 0x19, + 0x0e, 0x14, 0x18, 0x1a, + 0x15, 0x17, 0x1b, 0x1e, + 0x16, 0x1c, 0x1d, 0x1f +}; + +/* Huffman trees */ + +static const struct tree_node treeYAC[] = { + { 1, 4, -1, 0, -1}, { 2, 3, -1, 0, -1}, + { -1, -1, 2, 1, 0}, { -1, -1, 2, 2, 0}, + { 5, 9, -1, 0, -1}, { 6, 7, -1, 0, -1}, + { -1, -1, 3, 3, 0}, {323, 8, -1, 0, -1}, + { -1, -1, 4, 4, 0}, { 10, 13, -1, 0, -1}, + { 38, 11, -1, 0, -1}, { 12, 39, -1, 0, -1}, + { -1, -1, 5, 5, 0}, { 59, 14, -1, 0, -1}, + { 15, 18, -1, 0, -1}, { 16, 113, -1, 0, -1}, + { 17, 40, -1, 0, -1}, { -1, -1, 7, 6, 0}, + { 19, 22, -1, 0, -1}, { 20, 41, -1, 0, -1}, + { 21, 61, -1, 0, -1}, { -1, -1, 8, 7, 0}, + { 23, 27, -1, 0, -1}, {169, 24, -1, 0, -1}, + {208, 25, -1, 0, -1}, { 26, 62, -1, 0, -1}, + { -1, -1, 10, 8, 0}, { 44, 28, -1, 0, -1}, + { 63, 29, -1, 0, -1}, { 30, 191, -1, 0, -1}, + { 31, 119, -1, 0, -1}, { 32, 82, -1, 0, -1}, + { 33, 55, -1, 0, -1}, { 34, 48, -1, 0, -1}, + {171, 35, -1, 0, -1}, { 36, 37, -1, 0, -1}, + { -1, -1, 16, 9, 0}, { -1, -1, 16, 10, 0}, + { -1, -1, 4, 1, 1}, { -1, -1, 5, 2, 1}, + { -1, -1, 7, 3, 1}, {151, 42, -1, 0, -1}, + { 43, 79, -1, 0, -1}, { -1, -1, 9, 4, 1}, + { 96, 45, -1, 0, -1}, {246, 46, -1, 0, -1}, + { 47, 115, -1, 0, -1}, { -1, -1, 11, 5, 1}, + { 49, 52, -1, 0, -1}, { 50, 51, -1, 0, -1}, + { -1, -1, 16, 6, 1}, { -1, -1, 16, 7, 1}, + { 53, 54, -1, 0, -1}, { -1, -1, 16, 8, 1}, + { -1, -1, 16, 9, 1}, { 56, 71, -1, 0, -1}, + { 57, 68, -1, 0, -1}, { 58, 67, -1, 0, -1}, + { -1, -1, 16, 10, 1}, { 60, 77, -1, 0, -1}, + { -1, -1, 5, 1, 2}, { -1, -1, 8, 2, 2}, + { -1, -1, 10, 3, 2}, {265, 64, -1, 0, -1}, + { 65, 134, -1, 0, -1}, { 66, 80, -1, 0, -1}, + { -1, -1, 12, 4, 2}, { -1, -1, 16, 5, 2}, + { 69, 70, -1, 0, -1}, { -1, -1, 16, 6, 2}, + { -1, -1, 16, 7, 2}, { 72, 75, -1, 0, -1}, + { 73, 74, -1, 0, -1}, { -1, -1, 16, 8, 2}, + { -1, -1, 16, 9, 2}, { 76, 81, -1, 0, -1}, + { -1, -1, 16, 10, 2}, { 78, 95, -1, 0, -1}, + { -1, -1, 6, 1, 3}, { -1, -1, 9, 2, 3}, + { -1, -1, 12, 3, 3}, { -1, -1, 16, 4, 3}, + { 83, 101, -1, 0, -1}, { 84, 91, -1, 0, -1}, + { 85, 88, -1, 0, -1}, { 86, 87, -1, 0, -1}, + { -1, -1, 16, 5, 3}, { -1, -1, 16, 6, 3}, + { 89, 90, -1, 0, -1}, { -1, -1, 16, 7, 3}, + { -1, -1, 16, 8, 3}, { 92, 98, -1, 0, -1}, + { 93, 94, -1, 0, -1}, { -1, -1, 16, 9, 3}, + { -1, -1, 16, 10, 3}, { -1, -1, 6, 1, 4}, + { 97, 225, -1, 0, -1}, { -1, -1, 10, 2, 4}, + { 99, 100, -1, 0, -1}, { -1, -1, 16, 3, 4}, + { -1, -1, 16, 4, 4}, {102, 109, -1, 0, -1}, + {103, 106, -1, 0, -1}, {104, 105, -1, 0, -1}, + { -1, -1, 16, 5, 4}, { -1, -1, 16, 6, 4}, + {107, 108, -1, 0, -1}, { -1, -1, 16, 7, 4}, + { -1, -1, 16, 8, 4}, {110, 116, -1, 0, -1}, + {111, 112, -1, 0, -1}, { -1, -1, 16, 9, 4}, + { -1, -1, 16, 10, 4}, {114, 133, -1, 0, -1}, + { -1, -1, 7, 1, 5}, { -1, -1, 11, 2, 5}, + {117, 118, -1, 0, -1}, { -1, -1, 16, 3, 5}, + { -1, -1, 16, 4, 5}, {120, 156, -1, 0, -1}, + {121, 139, -1, 0, -1}, {122, 129, -1, 0, -1}, + {123, 126, -1, 0, -1}, {124, 125, -1, 0, -1}, + { -1, -1, 16, 5, 5}, { -1, -1, 16, 6, 5}, + {127, 128, -1, 0, -1}, { -1, -1, 16, 7, 5}, + { -1, -1, 16, 8, 5}, {130, 136, -1, 0, -1}, + {131, 132, -1, 0, -1}, { -1, -1, 16, 9, 5}, + { -1, -1, 16, 10, 5}, { -1, -1, 7, 1, 6}, + {135, 152, -1, 0, -1}, { -1, -1, 12, 2, 6}, + {137, 138, -1, 0, -1}, { -1, -1, 16, 3, 6}, + { -1, -1, 16, 4, 6}, {140, 147, -1, 0, -1}, + {141, 144, -1, 0, -1}, {142, 143, -1, 0, -1}, + { -1, -1, 16, 5, 6}, { -1, -1, 16, 6, 6}, + {145, 146, -1, 0, -1}, { -1, -1, 16, 7, 6}, + { -1, -1, 16, 8, 6}, {148, 153, -1, 0, -1}, + {149, 150, -1, 0, -1}, { -1, -1, 16, 9, 6}, + { -1, -1, 16, 10, 6}, { -1, -1, 8, 1, 7}, + { -1, -1, 12, 2, 7}, {154, 155, -1, 0, -1}, + { -1, -1, 16, 3, 7}, { -1, -1, 16, 4, 7}, + {157, 175, -1, 0, -1}, {158, 165, -1, 0, -1}, + {159, 162, -1, 0, -1}, {160, 161, -1, 0, -1}, + { -1, -1, 16, 5, 7}, { -1, -1, 16, 6, 7}, + {163, 164, -1, 0, -1}, { -1, -1, 16, 7, 7}, + { -1, -1, 16, 8, 7}, {166, 172, -1, 0, -1}, + {167, 168, -1, 0, -1}, { -1, -1, 16, 9, 7}, + { -1, -1, 16, 10, 7}, {170, 187, -1, 0, -1}, + { -1, -1, 9, 1, 8}, { -1, -1, 15, 2, 8}, + {173, 174, -1, 0, -1}, { -1, -1, 16, 3, 8}, + { -1, -1, 16, 4, 8}, {176, 183, -1, 0, -1}, + {177, 180, -1, 0, -1}, {178, 179, -1, 0, -1}, + { -1, -1, 16, 5, 8}, { -1, -1, 16, 6, 8}, + {181, 182, -1, 0, -1}, { -1, -1, 16, 7, 8}, + { -1, -1, 16, 8, 8}, {184, 188, -1, 0, -1}, + {185, 186, -1, 0, -1}, { -1, -1, 16, 9, 8}, + { -1, -1, 16, 10, 8}, { -1, -1, 9, 1, 9}, + {189, 190, -1, 0, -1}, { -1, -1, 16, 2, 9}, + { -1, -1, 16, 3, 9}, {192, 258, -1, 0, -1}, + {193, 226, -1, 0, -1}, {194, 210, -1, 0, -1}, + {195, 202, -1, 0, -1}, {196, 199, -1, 0, -1}, + {197, 198, -1, 0, -1}, { -1, -1, 16, 4, 9}, + { -1, -1, 16, 5, 9}, {200, 201, -1, 0, -1}, + { -1, -1, 16, 6, 9}, { -1, -1, 16, 7, 9}, + {203, 206, -1, 0, -1}, {204, 205, -1, 0, -1}, + { -1, -1, 16, 8, 9}, { -1, -1, 16, 9, 9}, + {207, 209, -1, 0, -1}, { -1, -1, 16, 10, 9}, + { -1, -1, 9, 1, 10}, { -1, -1, 16, 2, 10}, + {211, 218, -1, 0, -1}, {212, 215, -1, 0, -1}, + {213, 214, -1, 0, -1}, { -1, -1, 16, 3, 10}, + { -1, -1, 16, 4, 10}, {216, 217, -1, 0, -1}, + { -1, -1, 16, 5, 10}, { -1, -1, 16, 6, 10}, + {219, 222, -1, 0, -1}, {220, 221, -1, 0, -1}, + { -1, -1, 16, 7, 10}, { -1, -1, 16, 8, 10}, + {223, 224, -1, 0, -1}, { -1, -1, 16, 9, 10}, + { -1, -1, 16, 10, 10}, { -1, -1, 10, 1, 11}, + {227, 242, -1, 0, -1}, {228, 235, -1, 0, -1}, + {229, 232, -1, 0, -1}, {230, 231, -1, 0, -1}, + { -1, -1, 16, 2, 11}, { -1, -1, 16, 3, 11}, + {233, 234, -1, 0, -1}, { -1, -1, 16, 4, 11}, + { -1, -1, 16, 5, 11}, {236, 239, -1, 0, -1}, + {237, 238, -1, 0, -1}, { -1, -1, 16, 6, 11}, + { -1, -1, 16, 7, 11}, {240, 241, -1, 0, -1}, + { -1, -1, 16, 8, 11}, { -1, -1, 16, 9, 11}, + {243, 251, -1, 0, -1}, {244, 248, -1, 0, -1}, + {245, 247, -1, 0, -1}, { -1, -1, 16, 10, 11}, + { -1, -1, 10, 1, 12}, { -1, -1, 16, 2, 12}, + {249, 250, -1, 0, -1}, { -1, -1, 16, 3, 12}, + { -1, -1, 16, 4, 12}, {252, 255, -1, 0, -1}, + {253, 254, -1, 0, -1}, { -1, -1, 16, 5, 12}, + { -1, -1, 16, 6, 12}, {256, 257, -1, 0, -1}, + { -1, -1, 16, 7, 12}, { -1, -1, 16, 8, 12}, + {259, 292, -1, 0, -1}, {260, 277, -1, 0, -1}, + {261, 270, -1, 0, -1}, {262, 267, -1, 0, -1}, + {263, 264, -1, 0, -1}, { -1, -1, 16, 9, 12}, + { -1, -1, 16, 10, 12}, {266, 322, -1, 0, -1}, + { -1, -1, 11, 1, 13}, {268, 269, -1, 0, -1}, + { -1, -1, 16, 2, 13}, { -1, -1, 16, 3, 13}, + {271, 274, -1, 0, -1}, {272, 273, -1, 0, -1}, + { -1, -1, 16, 4, 13}, { -1, -1, 16, 5, 13}, + {275, 276, -1, 0, -1}, { -1, -1, 16, 6, 13}, + { -1, -1, 16, 7, 13}, {278, 285, -1, 0, -1}, + {279, 282, -1, 0, -1}, {280, 281, -1, 0, -1}, + { -1, -1, 16, 8, 13}, { -1, -1, 16, 9, 13}, + {283, 284, -1, 0, -1}, { -1, -1, 16, 10, 13}, + { -1, -1, 16, 1, 14}, {286, 289, -1, 0, -1}, + {287, 288, -1, 0, -1}, { -1, -1, 16, 2, 14}, + { -1, -1, 16, 3, 14}, {290, 291, -1, 0, -1}, + { -1, -1, 16, 4, 14}, { -1, -1, 16, 5, 14}, + {293, 308, -1, 0, -1}, {294, 301, -1, 0, -1}, + {295, 298, -1, 0, -1}, {296, 297, -1, 0, -1}, + { -1, -1, 16, 6, 14}, { -1, -1, 16, 7, 14}, + {299, 300, -1, 0, -1}, { -1, -1, 16, 8, 14}, + { -1, -1, 16, 9, 14}, {302, 305, -1, 0, -1}, + {303, 304, -1, 0, -1}, { -1, -1, 16, 10, 14}, + { -1, -1, 16, 1, 15}, {306, 307, -1, 0, -1}, + { -1, -1, 16, 2, 15}, { -1, -1, 16, 3, 15}, + {309, 316, -1, 0, -1}, {310, 313, -1, 0, -1}, + {311, 312, -1, 0, -1}, { -1, -1, 16, 4, 15}, + { -1, -1, 16, 5, 15}, {314, 315, -1, 0, -1}, + { -1, -1, 16, 6, 15}, { -1, -1, 16, 7, 15}, + {317, 320, -1, 0, -1}, {318, 319, -1, 0, -1}, + { -1, -1, 16, 8, 15}, { -1, -1, 16, 9, 15}, + {321, -1, -1, 0, -1}, { -1, -1, 16, 10, 15}, + { -1, -1, 11, 0, 16}, { -1, -1, 4, 0, -1}, +}; + +static const struct tree_node treeUVAC[] = { + { 1, 3, -1, 0, -1}, {323, 2, -1, 0, -1}, + { -1, -1, 2, 1, 0}, { 4, 8, -1, 0, -1}, + { 5, 6, -1, 0, -1}, { -1, -1, 3, 2, 0}, + { 7, 37, -1, 0, -1}, { -1, -1, 4, 3, 0}, + { 9, 13, -1, 0, -1}, { 10, 60, -1, 0, -1}, + { 11, 12, -1, 0, -1}, { -1, -1, 5, 4, 0}, + { -1, -1, 5, 5, 0}, { 14, 17, -1, 0, -1}, + { 15, 97, -1, 0, -1}, { 16, 38, -1, 0, -1}, + { -1, -1, 6, 6, 0}, { 18, 21, -1, 0, -1}, + { 19, 39, -1, 0, -1}, { 20, 135, -1, 0, -1}, + { -1, -1, 7, 7, 0}, { 22, 26, -1, 0, -1}, + { 82, 23, -1, 0, -1}, { 24, 99, -1, 0, -1}, + { 25, 42, -1, 0, -1}, { -1, -1, 9, 8, 0}, + { 27, 31, -1, 0, -1}, {211, 28, -1, 0, -1}, + {248, 29, -1, 0, -1}, { 30, 63, -1, 0, -1}, + { -1, -1, 10, 9, 0}, { 43, 32, -1, 0, -1}, + { 33, 48, -1, 0, -1}, {153, 34, -1, 0, -1}, + { 35, 64, -1, 0, -1}, { 36, 47, -1, 0, -1}, + { -1, -1, 12, 10, 0}, { -1, -1, 4, 1, 1}, + { -1, -1, 6, 2, 1}, {152, 40, -1, 0, -1}, + { 41, 62, -1, 0, -1}, { -1, -1, 8, 3, 1}, + { -1, -1, 9, 4, 1}, { 84, 44, -1, 0, -1}, + {322, 45, -1, 0, -1}, { 46, 136, -1, 0, -1}, + { -1, -1, 11, 5, 1}, { -1, -1, 12, 6, 1}, + { 49, 189, -1, 0, -1}, { 50, 119, -1, 0, -1}, + { 51, 76, -1, 0, -1}, { 66, 52, -1, 0, -1}, + { 53, 69, -1, 0, -1}, { 54, 57, -1, 0, -1}, + { 55, 56, -1, 0, -1}, { -1, -1, 16, 7, 1}, + { -1, -1, 16, 8, 1}, { 58, 59, -1, 0, -1}, + { -1, -1, 16, 9, 1}, { -1, -1, 16, 10, 1}, + { 61, 81, -1, 0, -1}, { -1, -1, 5, 1, 2}, + { -1, -1, 8, 2, 2}, { -1, -1, 10, 3, 2}, + { 65, 86, -1, 0, -1}, { -1, -1, 12, 4, 2}, + {286, 67, -1, 0, -1}, { 68, 304, -1, 0, -1}, + { -1, -1, 15, 5, 2}, { 70, 73, -1, 0, -1}, + { 71, 72, -1, 0, -1}, { -1, -1, 16, 6, 2}, + { -1, -1, 16, 7, 2}, { 74, 75, -1, 0, -1}, + { -1, -1, 16, 8, 2}, { -1, -1, 16, 9, 2}, + { 77, 102, -1, 0, -1}, { 78, 91, -1, 0, -1}, + { 79, 88, -1, 0, -1}, { 80, 87, -1, 0, -1}, + { -1, -1, 16, 10, 2}, { -1, -1, 5, 1, 3}, + { 83, 171, -1, 0, -1}, { -1, -1, 8, 2, 3}, + { 85, 117, -1, 0, -1}, { -1, -1, 10, 3, 3}, + { -1, -1, 12, 4, 3}, { -1, -1, 16, 5, 3}, + { 89, 90, -1, 0, -1}, { -1, -1, 16, 6, 3}, + { -1, -1, 16, 7, 3}, { 92, 95, -1, 0, -1}, + { 93, 94, -1, 0, -1}, { -1, -1, 16, 8, 3}, + { -1, -1, 16, 9, 3}, { 96, 101, -1, 0, -1}, + { -1, -1, 16, 10, 3}, { 98, 116, -1, 0, -1}, + { -1, -1, 6, 1, 4}, {100, 188, -1, 0, -1}, + { -1, -1, 9, 2, 4}, { -1, -1, 16, 3, 4}, + {103, 110, -1, 0, -1}, {104, 107, -1, 0, -1}, + {105, 106, -1, 0, -1}, { -1, -1, 16, 4, 4}, + { -1, -1, 16, 5, 4}, {108, 109, -1, 0, -1}, + { -1, -1, 16, 6, 4}, { -1, -1, 16, 7, 4}, + {111, 114, -1, 0, -1}, {112, 113, -1, 0, -1}, + { -1, -1, 16, 8, 4}, { -1, -1, 16, 9, 4}, + {115, 118, -1, 0, -1}, { -1, -1, 16, 10, 4}, + { -1, -1, 6, 1, 5}, { -1, -1, 10, 2, 5}, + { -1, -1, 16, 3, 5}, {120, 156, -1, 0, -1}, + {121, 138, -1, 0, -1}, {122, 129, -1, 0, -1}, + {123, 126, -1, 0, -1}, {124, 125, -1, 0, -1}, + { -1, -1, 16, 4, 5}, { -1, -1, 16, 5, 5}, + {127, 128, -1, 0, -1}, { -1, -1, 16, 6, 5}, + { -1, -1, 16, 7, 5}, {130, 133, -1, 0, -1}, + {131, 132, -1, 0, -1}, { -1, -1, 16, 8, 5}, + { -1, -1, 16, 9, 5}, {134, 137, -1, 0, -1}, + { -1, -1, 16, 10, 5}, { -1, -1, 7, 1, 6}, + { -1, -1, 11, 2, 6}, { -1, -1, 16, 3, 6}, + {139, 146, -1, 0, -1}, {140, 143, -1, 0, -1}, + {141, 142, -1, 0, -1}, { -1, -1, 16, 4, 6}, + { -1, -1, 16, 5, 6}, {144, 145, -1, 0, -1}, + { -1, -1, 16, 6, 6}, { -1, -1, 16, 7, 6}, + {147, 150, -1, 0, -1}, {148, 149, -1, 0, -1}, + { -1, -1, 16, 8, 6}, { -1, -1, 16, 9, 6}, + {151, 155, -1, 0, -1}, { -1, -1, 16, 10, 6}, + { -1, -1, 7, 1, 7}, {154, 267, -1, 0, -1}, + { -1, -1, 11, 2, 7}, { -1, -1, 16, 3, 7}, + {157, 173, -1, 0, -1}, {158, 165, -1, 0, -1}, + {159, 162, -1, 0, -1}, {160, 161, -1, 0, -1}, + { -1, -1, 16, 4, 7}, { -1, -1, 16, 5, 7}, + {163, 164, -1, 0, -1}, { -1, -1, 16, 6, 7}, + { -1, -1, 16, 7, 7}, {166, 169, -1, 0, -1}, + {167, 168, -1, 0, -1}, { -1, -1, 16, 8, 7}, + { -1, -1, 16, 9, 7}, {170, 172, -1, 0, -1}, + { -1, -1, 16, 10, 7}, { -1, -1, 8, 1, 8}, + { -1, -1, 16, 2, 8}, {174, 181, -1, 0, -1}, + {175, 178, -1, 0, -1}, {176, 177, -1, 0, -1}, + { -1, -1, 16, 3, 8}, { -1, -1, 16, 4, 8}, + {179, 180, -1, 0, -1}, { -1, -1, 16, 5, 8}, + { -1, -1, 16, 6, 8}, {182, 185, -1, 0, -1}, + {183, 184, -1, 0, -1}, { -1, -1, 16, 7, 8}, + { -1, -1, 16, 8, 8}, {186, 187, -1, 0, -1}, + { -1, -1, 16, 9, 8}, { -1, -1, 16, 10, 8}, + { -1, -1, 9, 1, 9}, {190, 257, -1, 0, -1}, + {191, 224, -1, 0, -1}, {192, 207, -1, 0, -1}, + {193, 200, -1, 0, -1}, {194, 197, -1, 0, -1}, + {195, 196, -1, 0, -1}, { -1, -1, 16, 2, 9}, + { -1, -1, 16, 3, 9}, {198, 199, -1, 0, -1}, + { -1, -1, 16, 4, 9}, { -1, -1, 16, 5, 9}, + {201, 204, -1, 0, -1}, {202, 203, -1, 0, -1}, + { -1, -1, 16, 6, 9}, { -1, -1, 16, 7, 9}, + {205, 206, -1, 0, -1}, { -1, -1, 16, 8, 9}, + { -1, -1, 16, 9, 9}, {208, 217, -1, 0, -1}, + {209, 214, -1, 0, -1}, {210, 213, -1, 0, -1}, + { -1, -1, 16, 10, 9}, {212, 230, -1, 0, -1}, + { -1, -1, 9, 1, 10}, { -1, -1, 16, 2, 10}, + {215, 216, -1, 0, -1}, { -1, -1, 16, 3, 10}, + { -1, -1, 16, 4, 10}, {218, 221, -1, 0, -1}, + {219, 220, -1, 0, -1}, { -1, -1, 16, 5, 10}, + { -1, -1, 16, 6, 10}, {222, 223, -1, 0, -1}, + { -1, -1, 16, 7, 10}, { -1, -1, 16, 8, 10}, + {225, 241, -1, 0, -1}, {226, 234, -1, 0, -1}, + {227, 231, -1, 0, -1}, {228, 229, -1, 0, -1}, + { -1, -1, 16, 9, 10}, { -1, -1, 16, 10, 10}, + { -1, -1, 9, 1, 11}, {232, 233, -1, 0, -1}, + { -1, -1, 16, 2, 11}, { -1, -1, 16, 3, 11}, + {235, 238, -1, 0, -1}, {236, 237, -1, 0, -1}, + { -1, -1, 16, 4, 11}, { -1, -1, 16, 5, 11}, + {239, 240, -1, 0, -1}, { -1, -1, 16, 6, 11}, + { -1, -1, 16, 7, 11}, {242, 250, -1, 0, -1}, + {243, 246, -1, 0, -1}, {244, 245, -1, 0, -1}, + { -1, -1, 16, 8, 11}, { -1, -1, 16, 9, 11}, + {247, 249, -1, 0, -1}, { -1, -1, 16, 10, 11}, + { -1, -1, 9, 1, 12}, { -1, -1, 16, 2, 12}, + {251, 254, -1, 0, -1}, {252, 253, -1, 0, -1}, + { -1, -1, 16, 3, 12}, { -1, -1, 16, 4, 12}, + {255, 256, -1, 0, -1}, { -1, -1, 16, 5, 12}, + { -1, -1, 16, 6, 12}, {258, 291, -1, 0, -1}, + {259, 275, -1, 0, -1}, {260, 268, -1, 0, -1}, + {261, 264, -1, 0, -1}, {262, 263, -1, 0, -1}, + { -1, -1, 16, 7, 12}, { -1, -1, 16, 8, 12}, + {265, 266, -1, 0, -1}, { -1, -1, 16, 9, 12}, + { -1, -1, 16, 10, 12}, { -1, -1, 11, 1, 13}, + {269, 272, -1, 0, -1}, {270, 271, -1, 0, -1}, + { -1, -1, 16, 2, 13}, { -1, -1, 16, 3, 13}, + {273, 274, -1, 0, -1}, { -1, -1, 16, 4, 13}, + { -1, -1, 16, 5, 13}, {276, 283, -1, 0, -1}, + {277, 280, -1, 0, -1}, {278, 279, -1, 0, -1}, + { -1, -1, 16, 6, 13}, { -1, -1, 16, 7, 13}, + {281, 282, -1, 0, -1}, { -1, -1, 16, 8, 13}, + { -1, -1, 16, 9, 13}, {284, 288, -1, 0, -1}, + {285, 287, -1, 0, -1}, { -1, -1, 16, 10, 13}, + { -1, -1, 14, 1, 14}, { -1, -1, 16, 2, 14}, + {289, 290, -1, 0, -1}, { -1, -1, 16, 3, 14}, + { -1, -1, 16, 4, 14}, {292, 308, -1, 0, -1}, + {293, 300, -1, 0, -1}, {294, 297, -1, 0, -1}, + {295, 296, -1, 0, -1}, { -1, -1, 16, 5, 14}, + { -1, -1, 16, 6, 14}, {298, 299, -1, 0, -1}, + { -1, -1, 16, 7, 14}, { -1, -1, 16, 8, 14}, + {301, 305, -1, 0, -1}, {302, 303, -1, 0, -1}, + { -1, -1, 16, 9, 14}, { -1, -1, 16, 10, 14}, + { -1, -1, 15, 1, 15}, {306, 307, -1, 0, -1}, + { -1, -1, 16, 2, 15}, { -1, -1, 16, 3, 15}, + {309, 316, -1, 0, -1}, {310, 313, -1, 0, -1}, + {311, 312, -1, 0, -1}, { -1, -1, 16, 4, 15}, + { -1, -1, 16, 5, 15}, {314, 315, -1, 0, -1}, + { -1, -1, 16, 6, 15}, { -1, -1, 16, 7, 15}, + {317, 320, -1, 0, -1}, {318, 319, -1, 0, -1}, + { -1, -1, 16, 8, 15}, { -1, -1, 16, 9, 15}, + {321, -1, -1, 0, -1}, { -1, -1, 16, 10, 15}, + { -1, -1, 10, 0, 16}, { -1, -1, 2, 0, -1}, +}; + +static const struct tree_node treeYDC[] = { + { 1, 6, -1, 0}, { 2, 3, -1, 0}, + { -1, -1, 2, 0}, { 4, 5, -1, 0}, + { -1, -1, 3, 1}, { -1, -1, 3, 2}, + { 7, 10, -1, 0}, { 8, 9, -1, 0}, + { -1, -1, 3, 3}, { -1, -1, 3, 4}, + { 11, 12, -1, 0}, { -1, -1, 3, 5}, + { 13, 14, -1, 0}, { -1, -1, 4, 6}, + { 15, 16, -1, 0}, { -1, -1, 5, 7}, + { 17, 18, -1, 0}, { -1, -1, 6, 8}, + { 19, 20, -1, 0}, { -1, -1, 7, 9}, + { 21, 22, -1, 0}, { -1, -1, 8, 10}, + { 23, -1, -1, 0}, { -1, -1, 9, 11}, +}; + +static const struct tree_node treeUVDC[] = { + { 1, 4, -1, 0}, { 2, 3, -1, 0}, + { -1, -1, 2, 0}, { -1, -1, 2, 1}, + { 5, 6, -1, 0}, { -1, -1, 2, 2}, + { 7, 8, -1, 0}, { -1, -1, 3, 3}, + { 9, 10, -1, 0}, { -1, -1, 4, 4}, + { 11, 12, -1, 0}, { -1, -1, 5, 5}, + { 13, 14, -1, 0}, { -1, -1, 6, 6}, + { 15, 16, -1, 0}, { -1, -1, 7, 7}, + { 17, 18, -1, 0}, { -1, -1, 8, 8}, + { 19, 20, -1, 0}, { -1, -1, 9, 9}, + { 21, 22, -1, 0}, { -1, -1, 10, 10}, + { 23, -1, -1, 0}, { -1, -1, 11, 11}, +}; + +/****************************************************************************** + * Huffman Decoder + ******************************************************************************/ + +/* Note: There is no penalty for passing the tree as an argument, since dummy + * args are passed anyway (to maintain 16-byte stack alignment), and since the + * address is loaded into a register either way. */ + +/* If no node is found, coeffbits and skip will not be modified */ +/* Return: Depth of node found, or -1 if invalid input code */ +static int +getNodeAC(unsigned int in, signed char *coeffbits, signed char *skip, + const struct tree_node *tree) +{ + int node = 0; + int i = 0; + int depth; + + do { + if ((in & 0x80000000) == 0) + node = tree[node].left; + else + node = tree[node].right; + + if (node == -1) + break; + + depth = tree[node].depth; + + /* Is it a leaf? If not, branch downward */ + if (depth != -1) { + *coeffbits = tree[node].coeffbits; + *skip = tree[node].skip; + return depth; + } + + in <<= 1; + ++i; + } while (i <= 15); + + return -1; +} + +/* If no node is found, coeffbits will not be modified */ +/* Return: Depth of node found, or -1 if invalid input code */ +static int +getNodeDC(unsigned int in, signed char *coeffbits, const struct tree_node *tree) +{ + int node = 0; + int i = 0; + int depth; + + do { + if ((in & 0x80000000) == 0) + node = tree[node].left; + else + node = tree[node].right; + + if (node == -1) + break; + + depth = tree[node].depth; + + /* Is it a leaf? If not, branch downward */ + if (depth != -1) { + *coeffbits = tree[node].coeffbits; + return depth; + } + + in <<= 1; + ++i; + } while (i <= 15); + + return -1; +} + +static inline unsigned int +getBytes(int *rawData, struct comp_info *cinfo) +{ + int bufLen = cinfo->rawLen; + int bits = cinfo->bits; + int bytes = cinfo->bytes; + unsigned char *in = bytes + (unsigned char *) rawData; + unsigned char b1, b2, b3, b4, b5; + unsigned int packedIn; + + /* Pull 5 bytes out of raw data */ + if (bytes < bufLen - 4) { + b1 = in[0]; + b2 = in[1]; + b3 = in[2]; + b4 = in[3]; + b5 = in[4]; + } else { + if (bytes < bufLen - 3) { + b1 = in[0]; + b2 = in[1]; + b3 = in[2]; + b4 = in[3]; + } else { + if (bytes < bufLen - 2) { + b1 = in[0]; + b2 = in[1]; + b3 = in[2]; + } else { + if (bytes < bufLen - 1) { + b1 = in[0]; + b2 = in[1]; + } else { + if (bytes <= bufLen) { + b1 = in[0]; + } else { + b1 = 0; + } + b2 = 0; + } + b3 = 0; + } + b4 = 0; + } + b5 = 0; + } + + /* Pack the bytes */ + packedIn = b1 << 24; + packedIn += b2 << 16; + packedIn += b3 << 8; + packedIn += b4; + + if (bits != 0) { + packedIn = packedIn << bits; + packedIn += b5 >> (8 - bits); + } + + return packedIn; +} + +static int +getACCoefficient(int *rawData, int *coeff, struct comp_info *cinfo, + const struct tree_node *tree) +{ + int input, bits, bytes, tmp_c; + signed char coeffbits = 0; + signed char skip = 0; + + input = getBytes(rawData, cinfo); + bits = getNodeAC(input, &coeffbits, &skip, tree); + + if (coeffbits) { + input = input << (bits - 1); + input &= 0x7fffffff; + if (! (input & 0x40000000)) + input |= 0x80000000; + + tmp_c = input >> (31 - coeffbits); + if (tmp_c < 0) + tmp_c++; + *coeff = tmp_c; + + bits += coeffbits; + } + + bytes = (bits + cinfo->bits) >> 3; + cinfo->bytes += bytes; + cinfo->bits += bits - (bytes << 3); + + return skip; +} + +static void +getDCCoefficient(int *rawData, int *coeff, struct comp_info *cinfo, + const struct tree_node *tree) +{ + int input, bits, bytes, tmp_c; + signed char coeffbits = 0; + + input = getBytes(rawData, cinfo); + bits = getNodeDC(input, &coeffbits, tree); + + if (bits == -1) { + bits = 1; /* Try to re-sync at the next bit */ + *coeff = 0; /* Indicates no change from last DC */ + } else { + + input = input << (bits - 1); + input &= 0x7fffffff; + if (! (input & 0x40000000)) + input |= 0x80000000; + + tmp_c = input >> (31 - coeffbits); + if (tmp_c < 0) + tmp_c++; + *coeff = tmp_c; + + bits += coeffbits; + } + + bytes = (bits + cinfo->bits) >> 3; + cinfo->bytes += bytes; + cinfo->bits += bits - (bytes << 3); +} + +/* For AC coefficients, here is what the "skip" value means: + * -1: Either the 8x4 block has ended, or the decoding failed. + * 0: Use the returned coeff. Don't skip anything. + * 1-15: The next coeffs are zero. The returned coeff is used. + * 16: The next 16 coeffs are zero. The returned coeff is ignored. + * + * You must ensure that the C[] array not be overrun, or stack corruption will + * result. + */ +static void +huffmanDecoderY(int *C, int *pIn, struct comp_info *cinfo) +{ + int coeff = 0; + int i = 1; + int k, skip; + + getDCCoefficient(pIn, C, cinfo, treeYDC); + + i = 1; + do { + skip = getACCoefficient(pIn, &coeff, cinfo, treeYAC); + + if (skip == -1) { + break; + } else if (skip == 0) { + C[i++] = coeff; + } else if (skip == 16) { + k = 16; + if (i > 16) + k = 32 - i; + + while (k--) + C[i++] = 0; + } else { + k = skip; + if (skip > 31 - i) + k = 31 - i; + + while (k--) + C[i++] = 0; + + C[i++] = coeff; + } + } while (i <= 31); + + if (skip == -1) + while (i <= 31) C[i++] = 0; + else + getACCoefficient(pIn, &coeff, cinfo, treeYAC); +} + +/* Same as huffmanDecoderY, except for the tables used */ +static void +huffmanDecoderUV(int *C, int *pIn, struct comp_info *cinfo) +{ + int coeff = 0; + int i = 1; + int k, skip; + + getDCCoefficient(pIn, C, cinfo, treeUVDC); + + i = 1; + do { + skip = getACCoefficient(pIn, &coeff, cinfo, treeUVAC); + + if (skip == -1) { + break; + } else if (skip == 0) { + C[i++] = coeff; + } else if (skip == 16) { + k = 16; + if (i > 16) + k = 32 - i; + + while (k--) + C[i++] = 0; + } else { + k = skip; + if (skip > 31 - i) + k = 31 - i; + + while (k--) + C[i++] = 0; + + C[i++] = coeff; + } + } while (i <= 31); + + if (skip == -1) + while (i <= 31) C[i++] = 0; + else + getACCoefficient(pIn, &coeff, cinfo, treeUVAC); +} + +/****************************************************************************** + * iDCT Functions + ******************************************************************************/ + +#ifndef APPROXIMATE_MUL_BY_SHIFT + +#define IDCT_MESSAGE "iDCT with multiply" + +#define TIMES_16382(u) ((u)? 16382 * (u):0) +#define TIMES_23168(u) ((u)? 23168 * (u):0) +#define TIMES_30270(u) ((u)? 30270 * (u):0) +#define TIMES_41986(u) ((u)? 41986 * (u):0) +#define TIMES_35594(u) ((u)? 35594 * (u):0) +#define TIMES_23783(u) ((u)? 23783 * (u):0) +#define TIMES_8351(u) ((u)? 8351 * (u):0) +#define TIMES_17391(u) ((u)? 17391 * (u):0) +#define TIMES_14743(u) ((u)? 14743 * (u):0) +#define TIMES_9851(u) ((u)? 9851 * (u):0) +#define TIMES_3459(u) ((u)? 3459 * (u):0) +#define TIMES_32134(u) ((u)? 32134 * (u):0) +#define TIMES_27242(u) ((u)? 27242 * (u):0) +#define TIMES_18202(u) ((u)? 18202 * (u):0) +#define TIMES_6392(u) ((u)? 6392 * (u):0) +#define TIMES_39550(u) ((u)? 39550 * (u):0) +#define TIMES_6785(u) ((u)? 6785 * (u):0) +#define TIMES_12538(u) ((u)? 12538 * (u):0) + +#else + +#define IDCT_MESSAGE "iDCT with shift" + +#define TIMES_16382(u) ( (u)? x=(u) , (x<<14) - (x<<1) :0 ) +#define TIMES_23168(u) ( (u)? x=(u) , (x<<14) + (x<<12) + (x<<11) + (x<<9) :0 ) +#define TIMES_30270(u) ( (u)? x=(u) , (x<<15) - (x<<11) :0 ) +#define TIMES_41986(u) ( (u)? x=(u) , (x<<15) + (x<<13) + (x<<10) :0 ) +#define TIMES_35594(u) ( (u)? x=(u) , (x<<15) + (x<<11) + (x<<9) + (x<<8) :0 ) +#define TIMES_23783(u) ( (u)? x=(u) , (x<<14) + (x<<13) - (x<<9) - (x<<8) :0 ) +#define TIMES_8351(u) ( (u)? x=(u) , (x<<13) :0 ) +#define TIMES_17391(u) ( (u)? x=(u) , (x<<14) + (x<<10) :0 ) +#define TIMES_14743(u) ( (u)? x=(u) , (x<<14) - (x<<10) - (x<<9) :0 ) +#define TIMES_9851(u) ( (u)? x=(u) , (x<<13) + (x<<10) + (x<<9) :0 ) +#define TIMES_3459(u) ( (u)? x=(u) , (x<<12) - (x<<9) :0 ) +#define TIMES_32134(u) ( (u)? x=(u) , (x<<15) - (x<<9) :0 ) +#define TIMES_27242(u) ( (u)? x=(u) , (x<<14) + (x<<13) + (x<<11) + (x<<9) :0 ) +#define TIMES_18202(u) ( (u)? x=(u) , (x<<14) + (x<<11) - (x<<8) :0 ) +#define TIMES_6392(u) ( (u)? x=(u) , (x<<13) - (x<<11) + (x<<8) :0 ) +#define TIMES_39550(u) ( (u)? x=(u) , (x<<15) + (x<<12) + (x<<11) + (x<<9) :0 ) +#define TIMES_6785(u) ( (u)? x=(u) , (x<<12) + (x<<11) + (x<<9) :0 ) +#define TIMES_12538(u) ( (u)? x=(u) , (x<<13) + (x<<12) + (x<<8) :0 ) + +/* + * The variables C0, C4, C16 and C20 can also be removed from the algorithm + * if APPROXIMATE_MUL_BY_SHIFTS is defined. They store correction values + * and can be considered insignificant. + */ + +#endif + +static void +DCT_8x4(int *coeff, unsigned char *out) +/* pre: coeff == coefficients + post: coeff != coefficients + ** DO NOT ASSUME coeff TO BE THE SAME BEFORE AND AFTER CALLING THIS FUNCTION! +*/ +{ + register int base,val1,val2,val3; + int tmp1,tmp2; + int C0,C4,C16,C20; + int C2_18,C6_22,C1_17,C3_19,C5_21,C7_23; + register int t; +#ifdef APPROXIMATE_MUL_BY_SHIFT + register int x; +#endif + + C0=coeff[0]; + C4=coeff[4]; + C16=coeff[16]; + C20=coeff[20]; + + coeff[0]=TIMES_23168(coeff[0]); + coeff[4]=TIMES_23168(coeff[4]); + coeff[16]=TIMES_23168(coeff[16]); + coeff[20]=TIMES_23168(coeff[20]); + + C2_18 = coeff[2]+coeff[18]; + C6_22 = coeff[6]+coeff[22]; + C1_17 = coeff[1]+coeff[17]; + C3_19 = coeff[3]+coeff[19]; + C5_21 = coeff[5]+coeff[21]; + C7_23 = coeff[7]+coeff[23]; + +// 0,7,25,32 + + base = 0x1000000; + base += coeff[0]+coeff[4]+coeff[16]+coeff[20]; + base += TIMES_30270(C2_18); + base += TIMES_12538(C6_22); + + val1 = TIMES_41986(coeff[9]); + val1 += TIMES_35594(coeff[11]); + val1 += TIMES_23783(coeff[13]); + val1 += TIMES_8351(coeff[15]); + val1 += TIMES_17391(coeff[25]); + val1 += TIMES_14743(coeff[27]); + val1 += TIMES_9851(coeff[29]); + val1 += TIMES_3459(coeff[31]); + + val2 = TIMES_32134(C1_17); + val2 += TIMES_27242(C3_19); + val2 += TIMES_18202(C5_21); + val2 += TIMES_6392(C7_23); + + val3 = TIMES_39550(coeff[10]); + val3 += TIMES_16382(coeff[14]+coeff[26]); + val3 += TIMES_6785(coeff[30]); + val3 += TIMES_30270(coeff[8]+coeff[12]); + val3 += TIMES_12538(coeff[24]+coeff[28]); + + t=(base + val1 + val2 + val3) >> 17; + out[0]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base - val1 - val2 + val3 - C4 - C20) >> 17; + out[7]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base - val1 + val2 - val3 - C16- C20) >> 17; + out[24]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base + val1 - val2 - val3 - C4 - C16 - C20) >> 17; + out[31]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + +//1,6,25,30 + + base = 0x1000000; + base += coeff[0]-coeff[4]+coeff[16]-coeff[20]; + base += TIMES_12538(C2_18); + base -= TIMES_30270(C6_22); + + val1 = TIMES_35594(coeff[9]); + val1 -= TIMES_8351(coeff[11]); + val1 -= TIMES_41986(coeff[13]); + val1 -= TIMES_23783(coeff[15]); + val1 -= TIMES_14743(coeff[25]); + val1 -= TIMES_3459(coeff[27]); + val1 -= TIMES_17391(coeff[29]); + val1 -= TIMES_9851(coeff[31]); + + val2 = TIMES_27242(C1_17); + val2 -= TIMES_6392(C3_19); + val2 -= TIMES_32134(C5_21); + val2 -= TIMES_18202(C7_23); + + val3 = TIMES_16382(coeff[10]-coeff[30]); + val3 -= TIMES_39550(coeff[14]); + val3 += TIMES_6785(coeff[26]); + val3 += TIMES_12538(coeff[24]-coeff[28]); + val3 += TIMES_30270(coeff[8]-coeff[12]); + + t=(base + val1 + val2 + val3 + C4 + C20) >> 17; + out[1]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base - val1 - val2 + val3) >> 17; + out[6]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base - val1 + val2 - val3 + C4 - C16 + C20) >> 17; + out[25]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base + val1 - val2 - val3 + C20) >> 17; + out[30]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + +//2,5,26,29 + + base = 0x1000000; + base += coeff[0] - coeff[4] + coeff[16] - coeff[20]; + base -= TIMES_12538(C2_18); + base += TIMES_30270(C6_22); + + val1 = TIMES_23783(coeff[9]); + val1 -= TIMES_41986(coeff[11]); + val1 += TIMES_8351(coeff[13]); + val1 += TIMES_35594(coeff[15]); + val1 += TIMES_9851(coeff[25]); + val1 -= TIMES_17391(coeff[27]); + val1 += TIMES_3459(coeff[29]); + val1 += TIMES_14743(coeff[31]); + + val2 = TIMES_18202(C1_17); + val2 -= TIMES_32134(C3_19); + val2 += TIMES_6392(C5_21); + val2 += TIMES_27242(C7_23); + + val3 = -TIMES_16382(coeff[10] - coeff[30]); + val3 += TIMES_39550(coeff[14]); + val3 -= TIMES_6785(coeff[26]); + val3 += TIMES_12538(coeff[24] - coeff[28]); + val3 += TIMES_30270(coeff[8] - coeff[12]); + + t=(base + val1 + val2 + val3) >> 17; + out[2]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base - val1 - val2 + val3) >> 17; + out[5]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base - val1 + val2 - val3 - C16) >> 17; + out[26]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base + val1 - val2 - val3 + C4 - C16 + C20) >> 17; + out[29]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + +//3,4,27,28 + + base = 0x1000000; + base += coeff[0] + coeff[4] + coeff[16] + coeff[20]; + base -= TIMES_30270(C2_18); + base -= TIMES_12538(C6_22); + + val1 = TIMES_8351(coeff[9]); + val1 -= TIMES_23783(coeff[11]); + val1 += TIMES_35594(coeff[13]); + val1 += TIMES_3459(coeff[25]); + val1 -= TIMES_9851(coeff[27]); + val1 += TIMES_14743(coeff[29]); + + val2 = TIMES_6392(C1_17); + val2 -= TIMES_18202(C3_19); + val2 += TIMES_27242(C5_21); + + val3 = -TIMES_39550(coeff[10]); + val3 += TIMES_16382(coeff[14] + coeff[26]); + val3 -= TIMES_6785(coeff[30]); + val3 += TIMES_30270(coeff[8] + coeff[12]); + val3 += TIMES_12538(coeff[24] + coeff[28]); + + tmp1 = TIMES_32134(C7_23); + tmp2 = TIMES_41986(coeff[15]) + TIMES_17391(coeff[31]); + + t=(base + val1 + val2 + val3 - tmp1 - tmp2 - C4 - C20) >> 17; + out[3]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base - val1 - val2 + val3) >> 17; + out[4]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base - val1 + val2 - val3 - tmp1 + tmp2) >> 17; + out[27]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base + val1 - val2 - val3 - C16 - C20) >> 17; + out[28]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + +// Second half + C2_18 = coeff[2] - coeff[18]; + C6_22 = coeff[6] - coeff[22]; + C1_17 = coeff[1] - coeff[17]; + C3_19 = coeff[3] - coeff[19]; + C5_21 = coeff[5] - coeff[21]; + C7_23 = coeff[7] - coeff[23]; + +// 8,15,16,23 + + base = 0x1000000; + base += coeff[0] + coeff[4] - coeff[16] - coeff[20]; + base +=TIMES_30270(C2_18); + base +=TIMES_12538(C6_22); + + val1 = TIMES_17391(coeff[9]); + val1 += TIMES_14743(coeff[11]); + val1 += TIMES_9851(coeff[13]); + val1 += TIMES_3459(coeff[15]); + val1 -= TIMES_41986(coeff[25]); + val1 -= TIMES_35594(coeff[27]); + val1 -= TIMES_23783(coeff[29]); + val1 -= TIMES_8351(coeff[31]); + + val2 = TIMES_32134(C1_17); + val2 += TIMES_27242(C3_19); + val2 += TIMES_18202(C5_21); + val2 += TIMES_6392(C7_23); + + val3 = TIMES_16382(coeff[10] - coeff[30]); + val3 += TIMES_6785(coeff[14]); + val3 -= TIMES_39550(coeff[26]); + val3 -=TIMES_30270(coeff[24] + coeff[28]); + val3 +=TIMES_12538(coeff[8] + coeff[12]); + + t=(base + val1 + val2 + val3) >> 17; + out[8]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base - val1 - val2 + val3 - C4 + C16 + C20) >> 17; + out[15]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base - val1 + val2 - val3) >> 17; + out[16]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base + val1 - val2 - val3 - C4 + C20) >> 17; + out[23]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + +//9,14,17,22 + + base = 0x1000000; + base += coeff[0] - coeff[4] - coeff[16] + coeff[20]; + base += TIMES_12538(C2_18); + base -= TIMES_30270(C6_22); + + val1 = TIMES_14743(coeff[9]); + val1 -= TIMES_3459(coeff[11]); + val1 -= TIMES_17391(coeff[13]); + val1 -= TIMES_9851(coeff[15]); + val1 -= TIMES_35594(coeff[25]); + val1 += TIMES_8351(coeff[27]); + val1 += TIMES_41986(coeff[29]); + val1 += TIMES_23783(coeff[31]); + + val2 = TIMES_27242(C1_17); + val2 -= TIMES_6392(C3_19); + val2 -= TIMES_32134(C5_21); + val2 -= TIMES_18202(C7_23); + + val3 = TIMES_6785(coeff[10]); + val3 -= TIMES_16382(coeff[14] + coeff[26]); + val3 += TIMES_39550(coeff[30]); + val3 += TIMES_12538(coeff[8] - coeff[12]); + val3 -= TIMES_30270(coeff[24] - coeff[28]); + + t=(base + val1 + val2 + val3 + C4 + C16 - C20) >> 17; + out[9]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base - val1 - val2 + val3 + C16) >> 17; + out[14]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base - val1 + val2 - val3 + C4) >> 17; + out[17]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base + val1 - val2 - val3) >> 17; + out[22]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + +//10,13,18,21 + + base = 0x1000000; + base += coeff[0] - coeff[4] - coeff[16] + coeff[20]; + base -= TIMES_12538(C2_18); + base += TIMES_30270(C6_22); + + val1 = TIMES_9851(coeff[9]); + val1 -= TIMES_17391(coeff[11]); + val1 += TIMES_3459(coeff[13]); + val1 += TIMES_14743(coeff[15]); + val1 -= TIMES_23783(coeff[25]); + val1 += TIMES_41986(coeff[27]); + val1 -= TIMES_8351(coeff[29]); + val1 -= TIMES_35594(coeff[31]); + + val2 = TIMES_18202(C1_17); + val2 -= TIMES_32134(C3_19); + val2 += TIMES_6392(C5_21); + val2 += TIMES_27242(C7_23); + + val3 = -TIMES_6785(coeff[10]); + val3 += TIMES_16382(coeff[14]+coeff[26]); + val3 -= TIMES_39550(coeff[30]); + val3 += TIMES_12538(coeff[8]-coeff[12]); + val3 -= TIMES_30270(coeff[24]-coeff[28]); + + t=(base + val1 + val2 + val3) >> 17; + out[10]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base - val1 - val2 + val3 + C4 + C16 - C20) >> 17; + out[13]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base - val1 + val2 - val3) >> 17; + out[18]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base + val1 - val2 - val3 + C4) >> 17; + out[21]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + +// 11,12,19,20 + + base = 0x1000000; + base += coeff[0]+coeff[4]-coeff[16]-coeff[20]; + base -= TIMES_30270(C2_18); + base -= TIMES_12538(C6_22); + + val1 = TIMES_3459(coeff[9]); + val1 -= TIMES_9851(coeff[11]); + val1 += TIMES_14743(coeff[13]); + val1 -= TIMES_8351(coeff[25]); + val1 += TIMES_23783(coeff[27]); + val1 -= TIMES_35594(coeff[29]); + + val2 = TIMES_6392(C1_17); + val2 -= TIMES_18202(C3_19); + val2 += TIMES_27242(C5_21); + + val3 = -TIMES_16382(coeff[10] - coeff[30]); + val3 -= TIMES_6785(coeff[14]); + val3 += TIMES_39550(coeff[26]); + val3 -= TIMES_30270(coeff[24]+coeff[28]); + val3 += TIMES_12538(coeff[8]+coeff[12]); + + tmp1 = TIMES_32134(C7_23); + tmp2 = -TIMES_17391(coeff[15]) + TIMES_41986(coeff[31]); + + t=(base + val1 + val2 + val3 - tmp1 + tmp2 + C16 + C20) >> 17; + out[11]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base - val1 - val2 + val3 + C16 + C20) >> 17; + out[12]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base - val1 + val2 - val3 - tmp1 - tmp2 - C4 + C20) >> 17; + out[19]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base + val1 - val2 - val3) >> 17; + out[20]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; +} + +#undef TIMES_16382 +#undef TIMES_23168 +#undef TIMES_30270 +#undef TIMES_41986 +#undef TIMES_35594 +#undef TIMES_23783 +#undef TIMES_8351 +#undef TIMES_17391 +#undef TIMES_14743 +#undef TIMES_9851 +#undef TIMES_3459 +#undef TIMES_32134 +#undef TIMES_27242 +#undef TIMES_18202 +#undef TIMES_6392 +#undef TIMES_39550 +#undef TIMES_6785 +#undef TIMES_12538 + +/****************************************************************************** + * Main Decoder Functions + ******************************************************************************/ + +/* This function handles the decompression of a single 8x4 block. It is + * independent of the palette (YUV422, YUV420, YUV400, GBR422...). cinfo->bytes + * determines the positin in the input buffer. + */ +static int +decompress8x4(unsigned char *pOut, + unsigned char *pIn, + int *lastDC, + int uvFlag, + struct comp_info *cinfo) +{ + int i, x, y, dc; + int coeffs[32]; + int deZigZag[32]; + int *dest; + int *src; + unsigned char *qt = cinfo->qt; + + if (! uvFlag) { + huffmanDecoderY(coeffs, (int*) pIn, cinfo); + + /* iDPCM and dequantize first coefficient */ + dc = (*lastDC) + coeffs[0]; + coeffs[0] = dc * (qt[0] + 1); + *lastDC = dc; + + /* ...and the second coefficient */ + coeffs[1] = ((qt[1] + 1) * coeffs[1]) >> 1; + + /* Dequantize, starting at 3rd element */ + for (i = 2; i < 32; i++) + coeffs[i] = (qt[i] + 1) * coeffs[i]; + } else { + huffmanDecoderUV(coeffs, (int*) pIn, cinfo); + + /* iDPCM */ + dc = (*lastDC) + coeffs[0]; + coeffs[0] = dc; + *lastDC = dc; + + /* Dequantize */ + for (i = 0; i < 32; i++) + coeffs[i] = (qt[32 + i] + 1) * coeffs[i]; + } + + /* Dezigzag */ + for (i = 0; i < 32; i++) + deZigZag[i] = coeffs[ZigZag518[i]]; + + /* Transpose the dezigzagged coefficient matrix */ + src = deZigZag; + dest = coeffs; + for (y = 0; y <= 3; ++y) { + for (x = 0; x <= 7; ++x) { + dest[x] = src[x * 4]; + } + src += 1; + dest += 8; + } + + /* Do the inverse DCT transform */ + DCT_8x4(coeffs, pOut); + + return 0; /* Always returns 0 */ +} + +static inline void +copyBlock(unsigned char *src, unsigned char *dest, int destInc) +{ + int i; + unsigned int *pSrc, *pDest; + + for (i = 0; i <= 3; i++) { + pSrc = (unsigned int *) src; + pDest = (unsigned int *) dest; + pDest[0] = pSrc[0]; + pDest[1] = pSrc[1]; + src += 8; + dest += destInc; + } +} + +#if 0 +static inline int +decompress400NoMMXOV518(unsigned char *pIn, + unsigned char *pOut, + unsigned char *pTmp, + const int w, + const int h, + const int numpix, + struct comp_info *cinfo) +{ + int iOutY, x, y; + int lastYDC = 0; + + /* Start Y loop */ + y = 0; + do { + iOutY = w * y; + x = 0; + do { + decompress8x4(pTmp, pIn, &lastYDC, 0, cinfo); + copyBlock(pTmp, pOut + iOutY, w); + iOutY += 8; + x += 8; + } while (x < w); + y += 4; + } while (y < h); + + /* Did we decode too much? */ + if (cinfo->bytes > cinfo->rawLen + 897) + return 1; + + /* Did we decode enough? */ + if (cinfo->bytes >= cinfo->rawLen - 897) + return 0; + else + return 1; +} +#endif + +static inline int +decompress420NoMMXOV518(unsigned char *pIn, + unsigned char *pOut, + unsigned char *pTmp, + const int w, + const int h, + const int numpix, + struct comp_info *cinfo, + int yvu) +{ + unsigned char *pOutU, *pOutV; + int iOutY, iOutU, iOutV, x, y; + int lastYDC = 0; + int lastUDC = 0; + int lastVDC = 0; + + if (yvu) { + pOutV = pOut + numpix; + pOutU = pOutV + numpix / 4; + } else { + pOutU = pOut + numpix; + pOutV = pOutU + numpix / 4; + } + + /* Start Y loop */ + y = 0; + do { + iOutY = w * y; + iOutV = iOutU = iOutY / 4; + + x = 0; + do { + decompress8x4(pTmp, pIn, &lastYDC, 0, cinfo); + copyBlock(pTmp, pOut + iOutY, w); + iOutY += 8; + x += 8; + } while (x < w); + + + + iOutY = w * (y + 4); + x = 0; + do { + decompress8x4(pTmp, pIn, &lastUDC, 1, cinfo); + copyBlock(pTmp, pOutU + iOutU, w/2); + iOutU += 8; + + decompress8x4(pTmp, pIn, &lastVDC, 1, cinfo); + copyBlock(pTmp, pOutV + iOutV, w/2); + iOutV += 8; + + decompress8x4(pTmp, pIn, &lastYDC, 0, cinfo); + copyBlock(pTmp, pOut + iOutY, w); + iOutY += 8; + + decompress8x4(pTmp, pIn, &lastYDC, 0, cinfo); + copyBlock(pTmp, pOut + iOutY, w); + iOutY += 8; + + x += 16; + } while (x < w); + + y += 8; + } while (y < h); + + /* Did we decode too much? */ + if (cinfo->bytes > cinfo->rawLen + 897) + return 1; + + /* Did we decode enough? */ + if (cinfo->bytes >= cinfo->rawLen - 897) + return 0; + else + return 1; +} + +/* Get quantization tables from input + * Returns: <0 if error, or >=0 otherwise */ +static int +get_qt_dynamic(unsigned char *pIn, struct comp_info *cinfo) +{ + int rawLen = cinfo->rawLen; + + /* Make sure input is actually big enough to hold trailer */ + if (rawLen < 72) { + return -1; + } + + cinfo->qt = pIn + rawLen - 64; + + return 0; +} + +/* Remove all 0 blocks from input */ +static void remove0blocks(unsigned char *pIn, int *inSize) +{ + long long *in = (long long *)pIn; + long long *out = (long long *)pIn; + int i; + + for (i = 0; i < *inSize; i += 8, in++) + /* Skip 8 byte blocks of all 0 */ + if (*in) + *out++ = *in; + + *inSize -= (in - out) * 8; +} + +#if 0 /* not used */ +/* Input format is raw isoc. data (with intact SOF header, packet numbers + * stripped, and all-zero blocks removed). + * Output format is planar YUV400 + * Returns uncompressed data length if success, or zero if error + */ +static int +Decompress400(unsigned char *pIn, + unsigned char *pOut, + int w, + int h, + int inSize) +{ + struct comp_info cinfo; + int numpix = w * h; + unsigned char pTmp[32]; + + remove0blocks(pIn, &inSize); + + cinfo.bytes = 0; + cinfo.bits = 0; + cinfo.rawLen = inSize; + + if (get_qt_dynamic(pIn, &cinfo) < 0) + return 0; + + /* Decompress, skipping the 8-byte SOF header */ + if (decompress400NoMMXOV518(pIn + 8, pOut, pTmp, w, h, numpix, &cinfo)) +// return 0; + ; /* Don't return error yet */ + + return (numpix); +} +#endif + +/* Input format is raw isoc. data (with intact SOF header, packet numbers + * stripped, and all-zero blocks removed). + * Output format is planar YUV420 + * Returns uncompressed data length if success, or zero if error + */ +void v4lconvert_ov518_to_yuv420(unsigned char *src, unsigned char *dst, + int w, int h, int yvu, int inSize) +{ + struct comp_info cinfo; + int numpix = w * h; + unsigned char pTmp[32]; + + remove0blocks(src, &inSize); + + cinfo.bytes = 0; + cinfo.bits = 0; + cinfo.rawLen = inSize; + + if (get_qt_dynamic(src, &cinfo) < 0) + return; + + /* Decompress, skipping the 8-byte SOF header */ + decompress420NoMMXOV518(src + 8, dst, pTmp, w, h, numpix, &cinfo, yvu); + + return; +} -- cgit v1.2.3 From 77e3c46ba9e763ac240f56d9365208c422fc6b20 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Mon, 8 Jun 2009 11:16:43 +0200 Subject: libv4l: move ov518 decompression code to an external helper From: Hans de Goede Change support for decompressing ov518 "JPEG" to piping data through an external helper as I've failed to contact Mark W. McClelland to get permission to relicense the code. If you know a working email address for Mark W. McClelland, please let me know. Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 8 +- v4l2-apps/libv4l/libv4lconvert/Makefile | 12 +- .../libv4l/libv4lconvert/control/libv4lcontrol.c | 4 +- v4l2-apps/libv4l/libv4lconvert/helper-funcs.h | 76 +++++++ v4l2-apps/libv4l/libv4lconvert/helper.c | 224 +++++++++++++++++++++ .../libv4l/libv4lconvert/libv4lconvert-priv.h | 16 +- v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 28 ++- v4l2-apps/libv4l/libv4lconvert/ov518-decomp.c | 63 +++++- 8 files changed, 407 insertions(+), 24 deletions(-) create mode 100644 v4l2-apps/libv4l/libv4lconvert/helper-funcs.h create mode 100644 v4l2-apps/libv4l/libv4lconvert/helper.c (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index ce0ea821d..dbcff3b54 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -2,10 +2,10 @@ libv4l-0.6.0 ------------ * Recognize disabled controls and replace with fake equivalents where available -* Add support for decompressing ov518 "JPEG", note this code is not - LGPL yet, I'm waiting for a license change permission. If I do not - get one this will be moved to an external helper and the data - will be piped through this, to keep libv4l2.so LGPL +* Add support for decompressing ov518 "JPEG", by piping data through an + external helper as I've failed to contact Mark W. McClelland to get + permission to relicense the code. If you know a working email address for + Mark W. McClelland, please let me know. libv4l-0.5.99 ------------- diff --git a/v4l2-apps/libv4l/libv4lconvert/Makefile b/v4l2-apps/libv4l/libv4lconvert/Makefile index 997bd6bff..86d6012ac 100644 --- a/v4l2-apps/libv4l/libv4lconvert/Makefile +++ b/v4l2-apps/libv4l/libv4lconvert/Makefile @@ -14,11 +14,11 @@ 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 ov518-decomp.o \ + rgbyuv.o spca501.o sq905c.o bayer.o hm12.o helper.o \ control/libv4lcontrol.o processing/libv4lprocessing.o \ processing/whitebalance.o processing/autogain.o \ processing/gamma.o -TARGETS = $(CONVERT_LIB) libv4lconvert.pc +TARGETS = $(CONVERT_LIB) libv4lconvert.pc ov518-decomp INCLUDES = ../include/libv4lconvert.h ifeq ($(LIB_RELEASE),) @@ -33,6 +33,8 @@ ifeq ($(LIBDIR),) LIBDIR = $(PREFIX)/lib endif +override CPPFLAGS += -DLIBDIR=\"$(LIBDIR)/\" + all: $(TARGETS) -include $(CONVERT_OBJS:.o=.d) @@ -53,15 +55,15 @@ libv4lconvert.pc: install: all mkdir -p $(DESTDIR)$(PREFIX)/include install -p -m 644 $(INCLUDES) $(DESTDIR)$(PREFIX)/include - mkdir -p $(DESTDIR)$(LIBDIR) + mkdir -p $(DESTDIR)$(LIBDIR)/libv4l ifeq ($(LINKTYPE),static) - mkdir -p $(DESTDIR)$(LIBDIR) install -m 644 $(CONVERT_LIB) $(DESTDIR)$(LIBDIR) else install -m 755 $(CONVERT_LIB).$(LIB_RELEASE) $(DESTDIR)$(LIBDIR) cd $(DESTDIR)$(LIBDIR) && \ ln -f -s $(CONVERT_LIB).$(LIB_RELEASE) $(CONVERT_LIB) endif + install -m 755 *-decomp $(DESTDIR)$(LIBDIR)/libv4l mkdir -p $(DESTDIR)$(LIBDIR)/pkgconfig install -m 644 libv4lconvert.pc $(DESTDIR)$(LIBDIR)/pkgconfig @@ -78,3 +80,5 @@ clean:: %.a: $(AR) cqs $@ $^ + +ov518-decomp: ov518-decomp.o diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c index b50b686df..8a77728a6 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c @@ -316,7 +316,7 @@ static const struct v4l2_queryctrl fake_controls[V4LCONTROL_COUNT] = { { .id = V4L2_CID_HFLIP, .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Horizontal flip", + .name = "Horizontal flip (sw)", .minimum = 0, .maximum = 1, .step = 1, @@ -326,7 +326,7 @@ static const struct v4l2_queryctrl fake_controls[V4LCONTROL_COUNT] = { { .id = V4L2_CID_VFLIP, .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Vertical flip", + .name = "Vertical flip (sw)", .minimum = 0, .maximum = 1, .step = 1, diff --git a/v4l2-apps/libv4l/libv4lconvert/helper-funcs.h b/v4l2-apps/libv4l/libv4lconvert/helper-funcs.h new file mode 100644 index 000000000..e27f21e42 --- /dev/null +++ b/v4l2-apps/libv4l/libv4lconvert/helper-funcs.h @@ -0,0 +1,76 @@ +/* Utility functions for decompression helpers + * + * Copyright (c) 2009 Hans de Goede + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +static int v4lconvert_helper_write(int fd, const void *b, size_t count, + char *progname) +{ + const unsigned char *buf = b; + size_t ret, written = 0; + + while (written < count) { + ret = write(fd, buf + written, count - written); + if (ret == -1) { + if (errno == EINTR) + continue; + + fprintf(stderr, "%s: error writing: %s\n", progname, strerror(errno)); + return -1; + } + written += ret; + } + + return 0; +} + +static int v4lconvert_helper_read(int fd, void *b, size_t count, + char *progname) +{ + unsigned char *buf = b; + size_t ret, r = 0; + + while (r < count) { + ret = read(fd, buf + r, count - r); + if (ret == -1) { + if (errno == EINTR) + continue; + + fprintf(stderr, "%s: error reading: %s\n", progname, strerror(errno)); + return -1; + } + if (ret == 0) /* EOF */ + exit(0); + + r += ret; + } + + return 0; +} diff --git a/v4l2-apps/libv4l/libv4lconvert/helper.c b/v4l2-apps/libv4l/libv4lconvert/helper.c new file mode 100644 index 000000000..c1d55c2e5 --- /dev/null +++ b/v4l2-apps/libv4l/libv4lconvert/helper.c @@ -0,0 +1,224 @@ +/* +# (C) 2009 Hans de Goede + +# 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 +#include +#include +#include +#include +#include +#include +#include "libv4lconvert-priv.h" + +#define READ_END 0 +#define WRITE_END 1 + +/* Unfortunately I've failed in contact some Authors of decompression + code of out of tree drivers. So I've no permission to relicense their code + their code from GPL to LGPL. To work around this, these decompression + algorithms are put in separate executables and we pipe data through these + to decompress. + + The "protocol" is very simple: + + From libv4l to the helper the following is send: + int width + int height + int flags + int data length + unsigned char[] data (data length long) + + From the helper to libv4l the following is send: + int data length (-1 in case of a decompression error) + unsigned char[] data (not present when a decompression error happened) +*/ + +static int v4lconvert_helper_start(struct v4lconvert_data *data, + const char *helper) +{ + if (pipe(data->decompress_in_pipe)) { + V4LCONVERT_ERR("with helper pipe: %s\n", strerror(errno)); + goto error; + } + + if (pipe(data->decompress_out_pipe)) { + V4LCONVERT_ERR("with helper pipe: %s\n", strerror(errno)); + goto error_close_in_pipe; + } + + data->decompress_pid = fork(); + if (data->decompress_pid == -1) { + V4LCONVERT_ERR("with helper fork: %s\n", strerror(errno)); + goto error_close_out_pipe; + } + + if (data->decompress_pid == 0) { + /* We are the child */ + + /* Closed unused read / write end of the pipes */ + close(data->decompress_out_pipe[WRITE_END]); + close(data->decompress_in_pipe[READ_END]); + + /* Connect stdin / out to the pipes */ + if (dup2(data->decompress_out_pipe[READ_END], STDIN_FILENO) == -1) { + perror("libv4lconvert: error with helper dup2"); + exit(1); + } + if (dup2(data->decompress_in_pipe[WRITE_END], STDOUT_FILENO) == -1) { + perror("libv4lconvert: error with helper dup2"); + exit(1); + } + + /* And execute the helper */ + execl(helper, helper, NULL); + + /* We should never get here */ + perror("libv4lconvert: error starting helper"); + exit(1); + } else { + /* Closed unused read / write end of the pipes */ + close(data->decompress_out_pipe[READ_END]); + close(data->decompress_in_pipe[WRITE_END]); + } + + return 0; + +error_close_out_pipe: + close(data->decompress_out_pipe[READ_END]); + close(data->decompress_out_pipe[WRITE_END]); +error_close_in_pipe: + close(data->decompress_in_pipe[READ_END]); + close(data->decompress_in_pipe[WRITE_END]); +error: + return -1; +} + +/* IMPROVE ME: we could block SIGPIPE here using pthread_sigmask() + and then in case of EPIPE consume the signal using + sigtimedwait (we need to check if a blocked signal wasn't present + before the write, otherwise we will consume that) and + after consuming the signal try to restart the helper. + + Note we currently do not do this, as SIGPIPE only happens if the + decompressor crashes, which in case of an embedded decompressor + would mean end of program, so by not handling SIGPIPE we treat + external decompressors identical. */ +static int v4lconvert_helper_write(struct v4lconvert_data *data, + const void *b, size_t count) +{ + const unsigned char *buf = b; + const int *i = b; + size_t ret, written = 0; + + while (written < count) { + ret = write(data->decompress_out_pipe[WRITE_END], buf + written, + count - written); + if (ret == -1) { + if (errno == EINTR) + continue; + + V4LCONVERT_ERR("writing to helper: %s\n", strerror(errno)); + return -1; + } + written += ret; + } + + return 0; +} + +static int v4lconvert_helper_read(struct v4lconvert_data *data, void *b, + size_t count) +{ + unsigned char *buf = b; + size_t ret, r = 0; + + while (r < count) { + ret = read(data->decompress_in_pipe[READ_END], buf + r, count - r); + if (ret == -1) { + if (errno == EINTR) + continue; + + V4LCONVERT_ERR("reading from helper: %s\n", strerror(errno)); + return -1; + } + if (ret == 0) { + V4LCONVERT_ERR("reading from helper: unexpected EOF\n"); + return -1; + } + r += ret; + } + + return 0; +} + +int v4lconvert_helper_decompress(struct v4lconvert_data *data, + const char *helper, const unsigned char *src, int src_size, + unsigned char *dest, int dest_size, int width, int height, int flags) +{ + int r; + + if (data->decompress_pid == -1) { + if (v4lconvert_helper_start(data, helper)) + return -1; + } + + if (v4lconvert_helper_write(data, &width, sizeof(int))) + return -1; + + if (v4lconvert_helper_write(data, &height, sizeof(int))) + return -1; + + if (v4lconvert_helper_write(data, &flags, sizeof(int))) + return -1; + + if (v4lconvert_helper_write(data, &src_size, sizeof(int))) + return -1; + + if (v4lconvert_helper_write(data, src, src_size)) + return -1; + + if (v4lconvert_helper_read(data, &r, sizeof(int))) + return -1; + + if (r < 0) { + V4LCONVERT_ERR("decompressing frame data\n"); + return -1; + } + + if (dest_size < r) { + V4LCONVERT_ERR("destination buffer to small\n"); + return -1; + } + + return v4lconvert_helper_read(data, dest, r); +} + +void v4lconvert_helper_cleanup(struct v4lconvert_data *data) +{ + int status; + + if (data->decompress_pid != -1) { + kill(data->decompress_pid, SIGTERM); + waitpid(data->decompress_pid, &status, 0); + + close(data->decompress_out_pipe[WRITE_END]); + close(data->decompress_in_pipe[READ_END]); + + data->decompress_pid = -1; + } +} diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h index a2242e91a..afd111da6 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h @@ -20,6 +20,7 @@ #define __LIBV4LCONVERT_PRIV_H #include +#include #include "libv4lconvert.h" #include "control/libv4lcontrol.h" #include "processing/libv4lprocessing.h" @@ -126,6 +127,11 @@ struct v4lconvert_data { unsigned char *convert_pixfmt_buf; struct v4lcontrol_data *control; struct v4lprocessing_data *processing; + + /* Data for external decompression helpers code */ + pid_t decompress_pid; + int decompress_in_pipe[2]; /* Data from helper to us */ + int decompress_out_pipe[2]; /* Data from us to helper */ }; struct v4lconvert_pixfmt { @@ -186,10 +192,6 @@ void v4lconvert_spca508_to_yuv420(const unsigned char *src, unsigned char *dst, void v4lconvert_sn9c20x_to_yuv420(const unsigned char *src, unsigned char *dst, int width, int height, int yvu); -/* Warning this one modifies its input buffer! */ -void v4lconvert_ov518_to_yuv420(unsigned char *src, unsigned char *dst, - int width, int height, int yvu, int src_size); - void v4lconvert_decode_spca561(const unsigned char *src, unsigned char *dst, int width, int height); @@ -232,4 +234,10 @@ void v4lconvert_flip(unsigned char *src, unsigned char *dest, void v4lconvert_crop(unsigned char *src, unsigned char *dest, const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt); +int v4lconvert_helper_decompress(struct v4lconvert_data *data, + const char *helper, const unsigned char *src, int src_size, + unsigned char *dest, int dest_size, int width, int height, int command); + +void v4lconvert_helper_cleanup(struct v4lconvert_data *data); + #endif diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index 47eb2272e..c9a32ce77 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -97,6 +97,7 @@ struct v4lconvert_data *v4lconvert_create(int fd) return NULL; data->fd = fd; + data->decompress_pid = -1; /* Check supported formats */ for (i = 0; ; i++) { @@ -159,6 +160,7 @@ void v4lconvert_destroy(struct v4lconvert_data *data) tinyjpeg_set_components(data->jdec, comps, 3); tinyjpeg_free(data->jdec); } + v4lconvert_helper_cleanup(data); free(data->convert1_buf); free(data->convert2_buf); free(data->rotate90_buf); @@ -505,7 +507,7 @@ static unsigned char *v4lconvert_alloc_buffer(struct v4lconvert_data *data, } static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, - unsigned char *src, int src_size, unsigned char *dest, + unsigned char *src, int src_size, unsigned char *dest, int dest_size, struct v4l2_format *fmt, unsigned int dest_pix_fmt) { unsigned int header_width, header_height; @@ -619,6 +621,7 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, case V4L2_PIX_FMT_OV518: { unsigned char *d; + int d_size; int yvu = 0; if (dest_pix_fmt != V4L2_PIX_FMT_YUV420 && @@ -627,8 +630,11 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, &data->convert_pixfmt_buf, &data->convert_pixfmt_buf_size); if (!d) return -1; - } else + d_size = width * height * 3 / 2; + } else { d = dest; + d_size = dest_size; + } if (dest_pix_fmt == V4L2_PIX_FMT_YVU420) yvu = 1; @@ -647,7 +653,12 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, v4lconvert_sn9c20x_to_yuv420(src, d, width, height, yvu); break; case V4L2_PIX_FMT_OV518: - v4lconvert_ov518_to_yuv420(src, d, width, height, yvu, src_size); + if (v4lconvert_helper_decompress(data, LIBDIR "/libv4l/ov518-decomp", + src, src_size, d, d_size, width, height, yvu)) { + /* Corrupt frame, better get another one */ + errno = -EAGAIN; + return -1; + } break; } @@ -883,7 +894,9 @@ int v4lconvert_convert(struct v4lconvert_data *data, int res, dest_needed, temp_needed, processing, convert = 0; int rotate90, vflip, hflip, crop; unsigned char *convert1_dest = dest; + int convert1_dest_size = dest_size; unsigned char *convert2_src = src, *convert2_dest = dest; + int convert2_dest_size = dest_size; unsigned char *rotate90_src = src, *rotate90_dest = dest; unsigned char *flip_src = src, *flip_dest = dest; unsigned char *crop_src = src; @@ -960,6 +973,8 @@ int v4lconvert_convert(struct v4lconvert_data *data, if (!convert1_dest) return -1; + convert1_dest_size = + my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3; convert2_src = convert1_dest; } @@ -969,6 +984,7 @@ int v4lconvert_convert(struct v4lconvert_data *data, if (!convert2_dest) return -1; + convert2_dest_size = temp_needed; rotate90_src = flip_src = crop_src = convert2_dest; } @@ -993,7 +1009,8 @@ int v4lconvert_convert(struct v4lconvert_data *data, /* Done setting sources / dest and allocating intermediate buffers, real conversion / processing / ... starts here. */ if (convert == 2) { - res = v4lconvert_convert_pixfmt(data, src, src_size, convert1_dest, + res = v4lconvert_convert_pixfmt(data, src, src_size, + convert1_dest, convert1_dest_size, &my_src_fmt, V4L2_PIX_FMT_RGB24); if (res) @@ -1007,7 +1024,8 @@ int v4lconvert_convert(struct v4lconvert_data *data, if (convert) { res = v4lconvert_convert_pixfmt(data, convert2_src, src_size, - convert2_dest, &my_src_fmt, + convert2_dest, convert2_dest_size, + &my_src_fmt, my_dest_fmt.fmt.pix.pixelformat); if (res) return res; diff --git a/v4l2-apps/libv4l/libv4lconvert/ov518-decomp.c b/v4l2-apps/libv4l/libv4lconvert/ov518-decomp.c index 6944719bc..f8f37649e 100644 --- a/v4l2-apps/libv4l/libv4lconvert/ov518-decomp.c +++ b/v4l2-apps/libv4l/libv4lconvert/ov518-decomp.c @@ -1,4 +1,6 @@ -/* FIXME FIXME FIXME: get permission to relicense this to LGPL !! */ +/* We would like to embed this inside libv4l, but we cannot as I've failed + to contact Mark W. McClelland to get permission to relicense this, + so this lives in an external (GPL licensed) helper */ /* OV518 Decompression Support Module (No-MMX version) * @@ -14,7 +16,8 @@ */ #include -#include "libv4lconvert-priv.h" +#include +#include "helper-funcs.h" /****************************************************************************** * Compile-time Options @@ -1400,7 +1403,7 @@ Decompress400(unsigned char *pIn, * Output format is planar YUV420 * Returns uncompressed data length if success, or zero if error */ -void v4lconvert_ov518_to_yuv420(unsigned char *src, unsigned char *dst, +static int v4lconvert_ov518_to_yuv420(unsigned char *src, unsigned char *dst, int w, int h, int yvu, int inSize) { struct comp_info cinfo; @@ -1414,10 +1417,60 @@ void v4lconvert_ov518_to_yuv420(unsigned char *src, unsigned char *dst, cinfo.rawLen = inSize; if (get_qt_dynamic(src, &cinfo) < 0) - return; + return -1; /* Decompress, skipping the 8-byte SOF header */ decompress420NoMMXOV518(src + 8, dst, pTmp, w, h, numpix, &cinfo, yvu); - return; + return 0; +} + +int main(int argc, char *argv[]) +{ + int width, height, yvu, src_size, dest_size; + unsigned char src_buf[200000]; + unsigned char dest_buf[500000]; + + while (1) { + if (v4lconvert_helper_read(STDIN_FILENO, &width, sizeof(int), argv[0])) + return 1; /* Erm, no way to recover without loosing sync with libv4l */ + + if (v4lconvert_helper_read(STDIN_FILENO, &height, sizeof(int), argv[0])) + return 1; /* Erm, no way to recover without loosing sync with libv4l */ + + if (v4lconvert_helper_read(STDIN_FILENO, &yvu, sizeof(int), argv[0])) + return 1; /* Erm, no way to recover without loosing sync with libv4l */ + + if (v4lconvert_helper_read(STDIN_FILENO, &src_size, sizeof(int), argv[0])) + return 1; /* Erm, no way to recover without loosing sync with libv4l */ + + if (src_size > sizeof(src_buf)) { + fprintf(stderr, "%s: error: src_buf too small, need: %d\n", + argv[0], src_size); + return 2; + } + + if (v4lconvert_helper_read(STDIN_FILENO, src_buf, src_size, argv[0])) + return 1; /* Erm, no way to recover without loosing sync with libv4l */ + + + dest_size = width * height * 3 / 2; + if (dest_size > sizeof(dest_buf)) { + fprintf(stderr, "%s: error: dest_buf too small, need: %d\n", + argv[0], dest_size); + dest_size = -1; + } else if (v4lconvert_ov518_to_yuv420(src_buf, dest_buf, width, height, + yvu, src_size)) + dest_size = -1; + + if (v4lconvert_helper_write(STDOUT_FILENO, &dest_size, sizeof(int), + argv[0])) + return 1; /* Erm, no way to recover without loosing sync with libv4l */ + + if (dest_size == -1) + continue; + + if (v4lconvert_helper_write(STDOUT_FILENO, dest_buf, dest_size, argv[0])) + return 1; /* Erm, no way to recover without loosing sync with libv4l */ + } } -- cgit v1.2.3 From f78597ecea4ce107d99124eca84df338bfcbb29a Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Mon, 8 Jun 2009 11:22:32 +0200 Subject: libv4l: remove DEADJOE files during make clean From: Gregor Jasny libv4l: remove DEADJOE files during make clean Priority: normal Signed-off-by: Gregor Jasny Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/Makefile | 2 +- v4l2-apps/libv4l/libv4l1/Makefile | 2 +- v4l2-apps/libv4l/libv4l2/Makefile | 2 +- v4l2-apps/libv4l/libv4lconvert/Makefile | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/Makefile b/v4l2-apps/libv4l/Makefile index 374cfab7b..acec5c540 100644 --- a/v4l2-apps/libv4l/Makefile +++ b/v4l2-apps/libv4l/Makefile @@ -7,7 +7,7 @@ all install: $(MAKE) -C libv4l1 V4L2_LIB_VERSION=$(V4L2_LIB_VERSION) $@ clean: - rm -f *~ include/*~ + rm -f *~ include/*~ DEADJOE include/DEADJOE $(MAKE) -C libv4lconvert V4L2_LIB_VERSION=$(V4L2_LIB_VERSION) $@ $(MAKE) -C libv4l2 V4L2_LIB_VERSION=$(V4L2_LIB_VERSION) $@ $(MAKE) -C libv4l1 V4L2_LIB_VERSION=$(V4L2_LIB_VERSION) $@ diff --git a/v4l2-apps/libv4l/libv4l1/Makefile b/v4l2-apps/libv4l/libv4l1/Makefile index bd6687e1a..e6d306055 100644 --- a/v4l2-apps/libv4l/libv4l1/Makefile +++ b/v4l2-apps/libv4l/libv4l1/Makefile @@ -71,7 +71,7 @@ endif install -m 644 libv4l1.pc $(DESTDIR)$(LIBDIR)/pkgconfig clean:: - rm -f *.a *.so* *.o *.d libv4l1.pc log *~ *.orig *.rej + rm -f *.a *.so* *.o *.d libv4l1.pc log *~ *.orig *.rej DEADJOE %.o: %.c $(CC) -Wp,-MMD,"$*.d",-MQ,"$@",-MP -c $(CPPFLAGS) $(CFLAGS) -o $@ $< diff --git a/v4l2-apps/libv4l/libv4l2/Makefile b/v4l2-apps/libv4l/libv4l2/Makefile index 6a2271572..06c010f3c 100644 --- a/v4l2-apps/libv4l/libv4l2/Makefile +++ b/v4l2-apps/libv4l/libv4l2/Makefile @@ -71,7 +71,7 @@ endif install -m 644 libv4l2.pc $(DESTDIR)$(LIBDIR)/pkgconfig clean:: - rm -f *.a *.so* *.o *.d libv4l2.pc log *~ *.orig *.rej + rm -f *.a *.so* *.o *.d libv4l2.pc log *~ *.orig *.rej DEADJOE %.o: %.c $(CC) -Wp,-MMD,"$*.d",-MQ,"$@",-MP -c $(CPPFLAGS) $(CFLAGS) -o $@ $< diff --git a/v4l2-apps/libv4l/libv4lconvert/Makefile b/v4l2-apps/libv4l/libv4lconvert/Makefile index 86d6012ac..0e10acc8f 100644 --- a/v4l2-apps/libv4l/libv4lconvert/Makefile +++ b/v4l2-apps/libv4l/libv4lconvert/Makefile @@ -69,7 +69,7 @@ endif clean:: rm -f *.a *.so* *.o *.d */*.o */*.d libv4lconvert.pc log *~ */*~ - rm -f *.orig *.rej */*.orig */*.rej + rm -f *.orig *.rej */*.orig */*.rej DEADJOE */DEADJOE *-decomp %.o: %.c $(CC) -Wp,-MMD,"$*.d",-MQ,"$@",-MP -c $(CPPFLAGS) $(CFLAGS) -o $@ $< -- cgit v1.2.3 From fc84b59143ed42e39bed4f6005100c4b8bb18bde Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Fri, 12 Jun 2009 10:41:04 +0200 Subject: libv4l: add support for decompressing ov511 compressed frames From: Hans de Goede libv4l: add support for decompressing ov511 compressed frames Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 4 +- v4l2-apps/libv4l/libv4lconvert/Makefile | 3 +- v4l2-apps/libv4l/libv4lconvert/helper-funcs.h | 3 + .../libv4l/libv4lconvert/libv4lconvert-priv.h | 4 + v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 10 + v4l2-apps/libv4l/libv4lconvert/ov511-decomp.c | 665 +++++++++++++++++++++ 6 files changed, 686 insertions(+), 3 deletions(-) create mode 100644 v4l2-apps/libv4l/libv4lconvert/ov511-decomp.c (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index dbcff3b54..4cc6ae4f6 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -2,8 +2,8 @@ libv4l-0.6.0 ------------ * Recognize disabled controls and replace with fake equivalents where available -* Add support for decompressing ov518 "JPEG", by piping data through an - external helper as I've failed to contact Mark W. McClelland to get +* Add support for decompressing ov511 and ov518 "JPEG", by piping data through + an external helper as I've failed to contact Mark W. McClelland to get permission to relicense the code. If you know a working email address for Mark W. McClelland, please let me know. diff --git a/v4l2-apps/libv4l/libv4lconvert/Makefile b/v4l2-apps/libv4l/libv4lconvert/Makefile index 0e10acc8f..d723d54a0 100644 --- a/v4l2-apps/libv4l/libv4lconvert/Makefile +++ b/v4l2-apps/libv4l/libv4lconvert/Makefile @@ -18,7 +18,7 @@ CONVERT_OBJS = libv4lconvert.o tinyjpeg.o sn9c10x.o sn9c20x.o pac207.o \ control/libv4lcontrol.o processing/libv4lprocessing.o \ processing/whitebalance.o processing/autogain.o \ processing/gamma.o -TARGETS = $(CONVERT_LIB) libv4lconvert.pc ov518-decomp +TARGETS = $(CONVERT_LIB) libv4lconvert.pc ov511-decomp ov518-decomp INCLUDES = ../include/libv4lconvert.h ifeq ($(LIB_RELEASE),) @@ -81,4 +81,5 @@ clean:: %.a: $(AR) cqs $@ $^ +ov511-decomp: ov511-decomp.o ov518-decomp: ov518-decomp.o diff --git a/v4l2-apps/libv4l/libv4lconvert/helper-funcs.h b/v4l2-apps/libv4l/libv4lconvert/helper-funcs.h index e27f21e42..8ce12343c 100644 --- a/v4l2-apps/libv4l/libv4lconvert/helper-funcs.h +++ b/v4l2-apps/libv4l/libv4lconvert/helper-funcs.h @@ -42,6 +42,9 @@ static int v4lconvert_helper_write(int fd, const void *b, size_t count, if (errno == EINTR) continue; + if (errno == EPIPE) /* Main program has quited */ + exit(0); + fprintf(stderr, "%s: error writing: %s\n", progname, strerror(errno)); return -1; } diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h index afd111da6..2cf8f6ba4 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h @@ -84,6 +84,10 @@ #define V4L2_PIX_FMT_SN9C20X_I420 v4l2_fourcc('S', '9', '2', '0') #endif +#ifndef V4L2_PIX_FMT_OV511 +#define V4L2_PIX_FMT_OV511 v4l2_fourcc('O', '5', '1', '1') +#endif + #ifndef V4L2_PIX_FMT_OV518 #define V4L2_PIX_FMT_OV518 v4l2_fourcc('O', '5', '1', '8') /* ov518 JPEG */ #endif diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index c9a32ce77..fe3185018 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -63,6 +63,7 @@ static const struct v4lconvert_pixfmt supported_src_pixfmts[] = { { 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 }, }; @@ -618,6 +619,7 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, case V4L2_PIX_FMT_SPCA505: case V4L2_PIX_FMT_SPCA508: case V4L2_PIX_FMT_SN9C20X_I420: + case V4L2_PIX_FMT_OV511: case V4L2_PIX_FMT_OV518: { unsigned char *d; @@ -652,6 +654,14 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, case V4L2_PIX_FMT_SN9C20X_I420: v4lconvert_sn9c20x_to_yuv420(src, d, width, height, yvu); break; + case V4L2_PIX_FMT_OV511: + if (v4lconvert_helper_decompress(data, LIBDIR "/libv4l/ov511-decomp", + src, src_size, d, d_size, width, height, yvu)) { + /* Corrupt frame, better get another one */ + errno = -EAGAIN; + return -1; + } + break; case V4L2_PIX_FMT_OV518: if (v4lconvert_helper_decompress(data, LIBDIR "/libv4l/ov518-decomp", src, src_size, d, d_size, width, height, yvu)) { diff --git a/v4l2-apps/libv4l/libv4lconvert/ov511-decomp.c b/v4l2-apps/libv4l/libv4lconvert/ov511-decomp.c new file mode 100644 index 000000000..a5d7ff9d1 --- /dev/null +++ b/v4l2-apps/libv4l/libv4lconvert/ov511-decomp.c @@ -0,0 +1,665 @@ +/* We would like to embed this inside libv4l, but we cannot as I've failed + to contact Mark W. McClelland to get permission to relicense this, + so this lives in an external (GPL licensed) helper */ + +/* OV511 Decompression Support Module + * + * Copyright (c) 1999-2003 Mark W. McClelland. All rights reserved. + * http://alpha.dyndns.org/ov511/ + * + * Original decompression code Copyright 1998-2000 OmniVision Technologies + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2 of the License. + */ + +#include +#include +#include "helper-funcs.h" + +/****************************************************************************** + * Decompression Functions + ******************************************************************************/ + +static void +DecompressYHI(unsigned char *pIn, + unsigned char *pOut, + int *iIn, /* in/out */ + int *iOut, /* in/out */ + const int w, + const int YUVFlag) +{ + short ZigZag[64]; + int temp[64]; + int Zcnt_Flag = 0; + int Num8_Flag = 0; + int in_pos = *iIn; + int out_pos = *iOut; + int tmp, tmp1, tmp2, tmp3; + unsigned char header, ZTable[64]; + short tmpl, tmph, half_byte, idx, count; + unsigned long ZigZag_length = 0, ZT_length, i, j; + short DeZigZag[64]; + + const short a = 11584; + const short b = 16068; + const short c = 15136; + const short d = 13624; + const short e = 9104; + const short f = 6270; + const short g = 3196; + + int out_idx; + + /* Take off every 'Zig' */ + for (i = 0; i < 64; i++) { + ZigZag[i] = 0; + } + + /***************************** + * Read in the Y header byte * + *****************************/ + + header = pIn[in_pos]; + in_pos++; + + ZigZag_length = header & 0x3f; + ZigZag_length = ZigZag_length + 1; + + Num8_Flag = header & 0x40; + Zcnt_Flag = header & 0x80; + + /************************* + * Read in the Y content * + *************************/ + + if (Zcnt_Flag == 0) { /* Without Zero Table read contents directly */ + /* Read in ZigZag[0] */ + ZigZag[0] = pIn[in_pos++]; + tmpl = pIn[in_pos++]; + tmph = tmpl<<8; + ZigZag[0] = ZigZag[0] | tmph; + ZigZag[0] = ZigZag[0]<<4; + ZigZag[0] = ZigZag[0]>>4; + + if (Num8_Flag) { /* 8 Bits */ + for (i = 1; i < ZigZag_length; i++) { + ZigZag[i] = pIn[in_pos++]; + ZigZag[i] = ZigZag[i]<<8; + ZigZag[i] = ZigZag[i]>>8; + } + } else { /* 12 bits and has no Zero Table */ + idx = 1; + half_byte = 0; + for (i = 1; i < ZigZag_length; i++) { + if (half_byte == 0) { + ZigZag[i] = pIn[in_pos++]; + tmpl = pIn[in_pos++]; + tmph = tmpl<<8; + tmph = tmph&0x0f00; + ZigZag[i] = ZigZag[i] | tmph; + ZigZag[i] = ZigZag[i]<<4; + ZigZag[i] = ZigZag[i]>>4; + half_byte = 1; + } else { + ZigZag[i] = pIn[in_pos++]; + ZigZag[i] = ZigZag[i]<<8; + tmpl = tmpl & 0x00f0; + ZigZag[i] = ZigZag[i] | tmpl; + ZigZag[i] = ZigZag[i]>>4; + half_byte = 0; + } + } + } + } else { /* Has Zero Table */ + /* Calculate Z-Table length */ + ZT_length = ZigZag_length/8; + tmp = ZigZag_length%8; + + if (tmp > 0) { + ZT_length = ZT_length + 1; + } + + /* Read in Zero Table */ + for (j = 0; j < ZT_length; j++) { + ZTable[j] = pIn[in_pos++]; + } + + /* Read in ZigZag[0] */ + ZigZag[0] = pIn[in_pos++]; + tmpl = pIn[in_pos++]; + tmph = tmpl<<8; + ZigZag[0] = ZigZag[0] | tmph; + ZigZag[0] = ZigZag[0]<<4; + ZigZag[0] = ZigZag[0]>>4; + + /* Decode ZigZag */ + idx = 0; + ZTable[idx] = ZTable[idx]<<1; + count = 7; + + if (Num8_Flag) { /* 8 Bits and has zero table */ + for (i = 1; i < ZigZag_length; i++) { + if ((ZTable[idx]&0x80)) { + ZigZag[i] = pIn[in_pos++]; + ZigZag[i] = ZigZag[i]<<8; + ZigZag[i] = ZigZag[i]>>8; + } + + ZTable[idx]=ZTable[idx]<<1; + count--; + if (count == 0) { + count = 8; + idx++; + } + } + } else { /* 12 bits and has Zero Table */ + half_byte = 0; + for (i = 1; i < ZigZag_length; i++) { + if (ZTable[idx]&0x80) { + if (half_byte == 0) { + ZigZag[i] = pIn[in_pos++]; + tmpl = pIn[in_pos++]; + tmph = tmpl <<8; + tmph = tmph & 0x0f00; + ZigZag[i] = ZigZag[i] | tmph; + ZigZag[i] = ZigZag[i]<<4; + ZigZag[i] = ZigZag[i]>>4; + half_byte = 1; + } else { + ZigZag[i] = pIn[in_pos++]; + ZigZag[i] = ZigZag[i]<<8; + tmpl = tmpl & 0x00f0; + ZigZag[i] = ZigZag[i] | tmpl; + ZigZag[i] = ZigZag[i]>>4; + half_byte = 0; + } + } + + ZTable[idx] = ZTable[idx]<<1; + count--; + if (count == 0) { + count = 8; + idx++; + } + } + } + } + + /************* + * De-ZigZag * + *************/ + + for (j = 0; j < 64; j++) { + DeZigZag[j] = 0; + } + + if (YUVFlag == 1) { + DeZigZag[0] = ZigZag[0]; + DeZigZag[1] = ZigZag[1]<<1; + DeZigZag[2] = ZigZag[5]<<1; + DeZigZag[3] = ZigZag[6]<<2; + + DeZigZag[8] = ZigZag[2]<<1; + DeZigZag[9] = ZigZag[4]<<1; + DeZigZag[10] = ZigZag[7]<<1; + DeZigZag[11] = ZigZag[13]<<2; + + DeZigZag[16] = ZigZag[3]<<1; + DeZigZag[17] = ZigZag[8]<<1; + DeZigZag[18] = ZigZag[12]<<2; + DeZigZag[19] = ZigZag[17]<<2; + + DeZigZag[24] = ZigZag[9]<<2; + DeZigZag[25] = ZigZag[11]<<2; + DeZigZag[26] = ZigZag[18]<<2; + DeZigZag[27] = ZigZag[24]<<3; + } else { + DeZigZag[0] = ZigZag[0]; + DeZigZag[1] = ZigZag[1]<<2; + DeZigZag[2] = ZigZag[5]<<2; + DeZigZag[3] = ZigZag[6]<<3; + + DeZigZag[8] = ZigZag[2]<<2; + DeZigZag[9] = ZigZag[4]<<2; + DeZigZag[10] = ZigZag[7]<<2; + DeZigZag[11] = ZigZag[13]<<4; + + DeZigZag[16] = ZigZag[3]<<2; + DeZigZag[17] = ZigZag[8]<<2; + DeZigZag[18] = ZigZag[12]<<3; + DeZigZag[19] = ZigZag[17]<<4; + + DeZigZag[24] = ZigZag[9]<<3; + DeZigZag[25] = ZigZag[11]<<4; + DeZigZag[26] = ZigZag[18]<<4; + DeZigZag[27] = ZigZag[24]<<4; + } + + /***************** + **** IDCT 1D **** + *****************/ + +#define IDCT_1D(c0, c1, c2, c3, in) \ + do { \ + tmp1=((c0)*DeZigZag[in])+((c2)*DeZigZag[(in)+2]); \ + tmp2=(c1)*DeZigZag[(in)+1]; \ + tmp3=(c3)*DeZigZag[(in)+3]; \ + } while (0) + +#define COMPOSE_1(out1, out2) \ + do { \ + tmp=tmp1+tmp2+tmp3; \ + temp[out1] = tmp>>15; \ + tmp=tmp1-tmp2-tmp3; \ + temp[out2] = tmp>>15; \ + } while (0) + +#define COMPOSE_2(out1, out2) \ + do { \ + tmp=tmp1+tmp2-tmp3; \ + temp[out1] = tmp>>15; \ + tmp=tmp1-tmp2+tmp3; \ + temp[out2] = tmp>>15; \ + } while (0) + + /* j = 0 */ + IDCT_1D(a, b, c, d, 0); COMPOSE_1( 0, 56); + IDCT_1D(a, b, c, d, 8); COMPOSE_1( 1, 57); + IDCT_1D(a, b, c, d, 16); COMPOSE_1( 2, 58); + IDCT_1D(a, b, c, d, 24); COMPOSE_1( 3, 59); + + /* j = 1 */ + IDCT_1D(a, d, f, g, 0); COMPOSE_2( 8, 48); + IDCT_1D(a, d, f, g, 8); COMPOSE_2( 9, 49); + IDCT_1D(a, d, f, g, 16); COMPOSE_2(10, 50); + IDCT_1D(a, d, f, g, 24); COMPOSE_2(11, 51); + + /* j = 2 */ + IDCT_1D(a, e, -f, b, 0); COMPOSE_2(16, 40); + IDCT_1D(a, e, -f, b, 8); COMPOSE_2(17, 41); + IDCT_1D(a, e, -f, b, 16); COMPOSE_2(18, 42); + IDCT_1D(a, e, -f, b, 24); COMPOSE_2(19, 43); + + /* j = 3 */ + IDCT_1D(a, g, -c, e, 0); COMPOSE_2(24, 32); + IDCT_1D(a, g, -c, e, 8); COMPOSE_2(25, 33); + IDCT_1D(a, g, -c, e, 16); COMPOSE_2(26, 34); + IDCT_1D(a, g, -c, e, 24); COMPOSE_2(27, 35); + +#undef IDCT_1D +#undef COMPOSE_1 +#undef COMPOSE_2 + + /***************** + **** IDCT 2D **** + *****************/ + +#define IDCT_2D(c0, c1, c2, c3, in) \ + do { \ + tmp = temp[in]*(c0) + temp[(in)+1]*(c1) \ + + temp[(in)+2]*(c2) + temp[(in)+3]*(c3); \ + } while (0) + +#define STORE(i) \ + do { \ + tmp = tmp >> 15; \ + tmp = tmp + 128; \ + if (tmp > 255) tmp = 255; \ + if (tmp < 0) tmp = 0; \ + pOut[i] = (unsigned char) tmp; \ + } while (0) + +#define IDCT_2D_ROW(in) \ + do { \ + IDCT_2D(a, b, c, d, in); STORE(0+out_idx); \ + IDCT_2D(a, d, f, -g, in); STORE(1+out_idx); \ + IDCT_2D(a, e, -f, -b, in); STORE(2+out_idx); \ + IDCT_2D(a, g, -c, -e, in); STORE(3+out_idx); \ + IDCT_2D(a, -g, -c, e, in); STORE(4+out_idx); \ + IDCT_2D(a, -e, -f, b, in); STORE(5+out_idx); \ + IDCT_2D(a, -d, f, g, in); STORE(6+out_idx); \ + IDCT_2D(a, -b, c, -d, in); STORE(7+out_idx); \ + } while (0) + + +#define IDCT_2D_FAST(c0, c1, c2, c3, in) \ + do { \ + tmp1=((c0)*temp[in])+((c2)*temp[(in)+2]); \ + tmp2=(c1)*temp[(in)+1]; \ + tmp3=(c3)*temp[(in)+3]; \ + } while (0) + +#define STORE_FAST_1(out1, out2) \ + do { \ + tmp=tmp1+tmp2+tmp3; \ + STORE((out1)+out_idx); \ + tmp=tmp1-tmp2-tmp3; \ + STORE((out2)+out_idx); \ + } while (0) + +#define STORE_FAST_2(out1, out2) \ + do { \ + tmp=tmp1+tmp2-tmp3; \ + STORE((out1)+out_idx); \ + tmp=tmp1-tmp2+tmp3; \ + STORE((out2)+out_idx); \ + } while (0) + +#define IDCT_2D_FAST_ROW(in) \ + do { \ + IDCT_2D_FAST(a, b, c, d, in); STORE_FAST_1(0, 7); \ + IDCT_2D_FAST(a, d, f, g, in); STORE_FAST_2(1, 6); \ + IDCT_2D_FAST(a, e, -f, b, in); STORE_FAST_2(2, 5); \ + IDCT_2D_FAST(a, g, -c, e, in); STORE_FAST_2(3, 4); \ + } while (0) + + out_idx = out_pos; + + IDCT_2D_ROW(0); out_idx += w; + IDCT_2D_ROW(8); out_idx += w; + IDCT_2D_ROW(16); out_idx += w; + IDCT_2D_ROW(24); out_idx += w; + IDCT_2D_ROW(32); out_idx += w; + IDCT_2D_ROW(40); out_idx += w; + IDCT_2D_FAST_ROW(48); out_idx += w; + IDCT_2D_FAST_ROW(56); + + *iIn = in_pos; + *iOut = out_pos + 8; +} + +#define DECOMP_Y() DecompressYHI(pIn, pY, &iIn, &iY, w, 1) +#define DECOMP_U() DecompressYHI(pIn, pU, &iIn, &iU, w/2, 2) +#define DECOMP_V() DecompressYHI(pIn, pV, &iIn, &iV, w/2, 2) + +#if 0 +inline static int +Decompress400HiNoMMX(unsigned char *pIn, + unsigned char *pOut, + const int w, + const int h, + const int inSize) +{ + unsigned char *pY = pOut; + int x, y, iIn, iY; + + iIn = 0; + for (y = 0; y < h; y += 8) { + iY = w*y; + + for (x = 0; x < w; x += 8) + DECOMP_Y(); + } + + return 0; +} +#endif + +inline static int +Decompress420HiNoMMX(unsigned char *pIn, + unsigned char *pOut, + const int w, + const int h, + const int inSize) +{ + unsigned char *pY = pOut; + unsigned char *pU = pY + w*h; + unsigned char *pV = pU + w*h/4; + int xY, xUV, iY, iU, iV, iIn, count; + const int nBlocks = (w*h) / (32*8); + + iIn = 0; + iY = iU = iV = 0; + xY = xUV = 0; + + for (count = 0; count < nBlocks; count++) { + DECOMP_U(); + DECOMP_V(); xUV += 16; + if (xUV >= w) { + iU += (w*7)/2; + iV += (w*7)/2; + xUV = 0; + } + + DECOMP_Y(); xY += 8; + DECOMP_Y(); xY += 8; + if (xY >= w) { + iY += w*7; + xY = 0; + } + DECOMP_Y(); xY += 8; + DECOMP_Y(); xY += 8; + if (xY >= w) { + iY += w*7; + xY = 0; + } + } + + return 0; +} + +/* Copies a 64-byte segment at pIn to an 8x8 block at pOut. The width of the + * image at pOut is specified by w. + */ +static inline void +make_8x8(unsigned char *pIn, unsigned char *pOut, int w) +{ + unsigned char *pOut1 = pOut; + int x, y; + + for (y = 0; y < 8; y++) { + pOut1 = pOut; + for (x = 0; x < 8; x++) { + *pOut1++ = *pIn++; + } + pOut += w; + } +} + +#if 0 +/* + * For RAW BW (YUV 4:0:0) images, data show up in 256 byte segments. + * The segments represent 4 squares of 8x8 pixels as follows: + * + * 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199 + * 8 9 ... 15 72 73 ... 79 200 201 ... 207 + * ... ... ... + * 56 57 ... 63 120 121 ... 127 248 249 ... 255 + * + */ +static void +yuv400raw_to_yuv400p(struct ov511_frame *frame, + unsigned char *pIn0, unsigned char *pOut0) +{ + int x, y; + unsigned char *pIn, *pOut, *pOutLine; + + /* Copy Y */ + pIn = pIn0; + pOutLine = pOut0; + for (y = 0; y < frame->rawheight - 1; y += 8) { + pOut = pOutLine; + for (x = 0; x < frame->rawwidth - 1; x += 8) { + make_8x8(pIn, pOut, frame->rawwidth); + pIn += 64; + pOut += 8; + } + pOutLine += 8 * frame->rawwidth; + } +} +#endif + +/* + * For YUV 4:2:0 images, the data show up in 384 byte segments. + * The first 64 bytes of each segment are U, the next 64 are V. The U and + * V are arranged as follows: + * + * 0 1 ... 7 + * 8 9 ... 15 + * ... + * 56 57 ... 63 + * + * U and V are shipped at half resolution (1 U,V sample -> one 2x2 block). + * + * The next 256 bytes are full resolution Y data and represent 4 squares + * of 8x8 pixels as follows: + * + * 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199 + * 8 9 ... 15 72 73 ... 79 200 201 ... 207 + * ... ... ... + * 56 57 ... 63 120 121 ... 127 ... 248 249 ... 255 + * + * Note that the U and V data in one segment represent a 16 x 16 pixel + * area, but the Y data represent a 32 x 8 pixel area. If the width is not an + * even multiple of 32, the extra 8x8 blocks within a 32x8 block belong to the + * next horizontal stripe. + * + * If dumppix module param is set, _parse_data just dumps the incoming segments, + * verbatim, in order, into the frame. When used with vidcat -f ppm -s 640x480 + * this puts the data on the standard output and can be analyzed with the + * parseppm.c utility I wrote. That's a much faster way for figuring out how + * these data are scrambled. + */ + +/* Converts from raw, uncompressed segments at pIn0 to a YUV420P frame at pOut0. + * + * FIXME: Currently only handles width and height that are multiples of 16 + */ +static void +yuv420raw_to_yuv420p(unsigned char *pIn0, unsigned char *pOut0, + int width, int height) +{ + int k, x, y; + unsigned char *pIn, *pOut, *pOutLine; + const unsigned int a = width * height; + const unsigned int w = width / 2; + + /* Copy U and V */ + pIn = pIn0; + pOutLine = pOut0 + a; + for (y = 0; y < height - 1; y += 16) { + pOut = pOutLine; + for (x = 0; x < width - 1; x += 16) { + make_8x8(pIn, pOut, w); + make_8x8(pIn + 64, pOut + a/4, w); + pIn += 384; + pOut += 8; + } + pOutLine += 8 * w; + } + + /* Copy Y */ + pIn = pIn0 + 128; + pOutLine = pOut0; + k = 0; + for (y = 0; y < height - 1; y += 8) { + pOut = pOutLine; + for (x = 0; x < width - 1; x += 8) { + make_8x8(pIn, pOut, width); + pIn += 64; + pOut += 8; + if ((++k) > 3) { + k = 0; + pIn += 128; + } + } + pOutLine += 8 * width; + } +} + + +/* Remove all 0 blocks from input */ +static void remove0blocks(unsigned char *pIn, int *inSize) +{ + long long *in = (long long *)pIn; + long long *out = (long long *)pIn; + int i, j; + + for (i = 0; i < *inSize; i += 32, in += 4) { + int all_zero = 1; + for (j = 0; j < 4; j++) + if (in[j]) { + all_zero = 0; + break; + } + + /* Skip 32 byte blocks of all 0 */ + if (all_zero) + continue; + + for (j = 0; j < 4; j++) + *out++ = in[j]; + } + + *inSize -= (in - out) * 8; +} + +static int v4lconvert_ov511_to_yuv420(unsigned char *src, unsigned char *dest, + int w, int h, int yvu, int src_size) +{ + int rc = 0; + + src_size -= 11; /* Remove footer */ + + /* Compressed ? */ + if (src[8] & 0x40) { + remove0blocks(src, &src_size); + rc = Decompress420HiNoMMX(src + 9, dest, w, h, src_size); + } else { + yuv420raw_to_yuv420p(src + 9, dest, w, h); + } + + return rc; +} + +int main(int argc, char *argv[]) +{ + int width, height, yvu, src_size, dest_size; + unsigned char src_buf[500000]; + unsigned char dest_buf[500000]; + + while (1) { + if (v4lconvert_helper_read(STDIN_FILENO, &width, sizeof(int), argv[0])) + return 1; /* Erm, no way to recover without loosing sync with libv4l */ + + if (v4lconvert_helper_read(STDIN_FILENO, &height, sizeof(int), argv[0])) + return 1; /* Erm, no way to recover without loosing sync with libv4l */ + + if (v4lconvert_helper_read(STDIN_FILENO, &yvu, sizeof(int), argv[0])) + return 1; /* Erm, no way to recover without loosing sync with libv4l */ + + if (v4lconvert_helper_read(STDIN_FILENO, &src_size, sizeof(int), argv[0])) + return 1; /* Erm, no way to recover without loosing sync with libv4l */ + + if (src_size > sizeof(src_buf)) { + fprintf(stderr, "%s: error: src_buf too small, need: %d\n", + argv[0], src_size); + return 2; + } + + if (v4lconvert_helper_read(STDIN_FILENO, src_buf, src_size, argv[0])) + return 1; /* Erm, no way to recover without loosing sync with libv4l */ + + + dest_size = width * height * 3 / 2; + if (dest_size > sizeof(dest_buf)) { + fprintf(stderr, "%s: error: dest_buf too small, need: %d\n", + argv[0], dest_size); + dest_size = -1; + } else if (v4lconvert_ov511_to_yuv420(src_buf, dest_buf, width, height, + yvu, src_size)) + dest_size = -1; + + if (v4lconvert_helper_write(STDOUT_FILENO, &dest_size, sizeof(int), + argv[0])) + return 1; /* Erm, no way to recover without loosing sync with libv4l */ + + if (dest_size == -1) + continue; + + if (v4lconvert_helper_write(STDOUT_FILENO, dest_buf, dest_size, argv[0])) + return 1; /* Erm, no way to recover without loosing sync with libv4l */ + } +} -- cgit v1.2.3 From 4dc7af7e5508c90e1117c8cc909ec1b7acb1979a Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Fri, 12 Jun 2009 10:42:17 +0200 Subject: libv4l: add missing stdint.h include to libv4l2.h From: Hans de Goede libv4l: add missing stdint.h include to libv4l2.h Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/include/libv4l2.h | 1 + 1 file changed, 1 insertion(+) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/include/libv4l2.h b/v4l2-apps/libv4l/include/libv4l2.h index 0403a29dd..7ecbb2cee 100644 --- a/v4l2-apps/libv4l/include/libv4l2.h +++ b/v4l2-apps/libv4l/include/libv4l2.h @@ -21,6 +21,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { -- cgit v1.2.3 From b0d33e19d6aa45f2c7504810f971d1b607faf88c Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Sun, 14 Jun 2009 22:51:13 +0200 Subject: libv4l: Remove 0 blocks from non-compresses ov511 frames too From: Hans de Goede libv4l: Remove 0 blocks from non-compresses ov511 frames too Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/libv4lconvert/Makefile | 2 +- v4l2-apps/libv4l/libv4lconvert/ov511-decomp.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/libv4lconvert/Makefile b/v4l2-apps/libv4l/libv4lconvert/Makefile index d723d54a0..036649e86 100644 --- a/v4l2-apps/libv4l/libv4lconvert/Makefile +++ b/v4l2-apps/libv4l/libv4lconvert/Makefile @@ -33,7 +33,7 @@ ifeq ($(LIBDIR),) LIBDIR = $(PREFIX)/lib endif -override CPPFLAGS += -DLIBDIR=\"$(LIBDIR)/\" +override CPPFLAGS += -DLIBDIR=\"$(LIBDIR)\" all: $(TARGETS) diff --git a/v4l2-apps/libv4l/libv4lconvert/ov511-decomp.c b/v4l2-apps/libv4l/libv4lconvert/ov511-decomp.c index a5d7ff9d1..11ed2a601 100644 --- a/v4l2-apps/libv4l/libv4lconvert/ov511-decomp.c +++ b/v4l2-apps/libv4l/libv4lconvert/ov511-decomp.c @@ -603,9 +603,10 @@ static int v4lconvert_ov511_to_yuv420(unsigned char *src, unsigned char *dest, src_size -= 11; /* Remove footer */ + remove0blocks(src, &src_size); + /* Compressed ? */ if (src[8] & 0x40) { - remove0blocks(src, &src_size); rc = Decompress420HiNoMMX(src + 9, dest, w, h, src_size); } else { yuv420raw_to_yuv420p(src + 9, dest, w, h); -- cgit v1.2.3 From a48e6ba1941c59fc3fee73372eec6d3931000982 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Sun, 14 Jun 2009 22:58:53 +0200 Subject: libv4l: Detect ov518 decompression errors From: Hans de Goede Sometimes the ov518 gives us an incomplete frame, detect this and throw it away. Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 4 ++-- v4l2-apps/libv4l/libv4lconvert/ov518-decomp.c | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index fe3185018..998bc154d 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -658,7 +658,7 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, if (v4lconvert_helper_decompress(data, LIBDIR "/libv4l/ov511-decomp", src, src_size, d, d_size, width, height, yvu)) { /* Corrupt frame, better get another one */ - errno = -EAGAIN; + errno = EAGAIN; return -1; } break; @@ -666,7 +666,7 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, if (v4lconvert_helper_decompress(data, LIBDIR "/libv4l/ov518-decomp", src, src_size, d, d_size, width, height, yvu)) { /* Corrupt frame, better get another one */ - errno = -EAGAIN; + errno = EAGAIN; return -1; } break; diff --git a/v4l2-apps/libv4l/libv4lconvert/ov518-decomp.c b/v4l2-apps/libv4l/libv4lconvert/ov518-decomp.c index f8f37649e..51b8d8c60 100644 --- a/v4l2-apps/libv4l/libv4lconvert/ov518-decomp.c +++ b/v4l2-apps/libv4l/libv4lconvert/ov518-decomp.c @@ -1325,7 +1325,7 @@ decompress420NoMMXOV518(unsigned char *pIn, return 1; /* Did we decode enough? */ - if (cinfo->bytes >= cinfo->rawLen - 897) + if (cinfo->bytes >= cinfo->rawLen - (897 + 64)) return 0; else return 1; @@ -1420,7 +1420,8 @@ static int v4lconvert_ov518_to_yuv420(unsigned char *src, unsigned char *dst, return -1; /* Decompress, skipping the 8-byte SOF header */ - decompress420NoMMXOV518(src + 8, dst, pTmp, w, h, numpix, &cinfo, yvu); + if (decompress420NoMMXOV518(src + 8, dst, pTmp, w, h, numpix, &cinfo, yvu)) + return -1; return 0; } -- cgit v1.2.3 From e4998840d5667668db3e89356e0a681f70149bd3 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Tue, 16 Jun 2009 23:51:10 +0200 Subject: libv4l: Fix a bug in the always report widths which are a multiple of 8 code From: Hans de Goede Fix a bug in the always report widths which are a multiple of 8 code added in 0.5.97 Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 2 + v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 54 ++++++++++++++++---------- 2 files changed, 35 insertions(+), 21 deletions(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index 4cc6ae4f6..e69a8c8f4 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -6,6 +6,8 @@ libv4l-0.6.0 an external helper as I've failed to contact Mark W. McClelland to get permission to relicense the code. If you know a working email address for Mark W. McClelland, please let me know. +* Fix a bug in the always report widths which are a multiple of 8 code added + in 0.5.97 libv4l-0.5.99 ------------- diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index 998bc154d..1389c58bc 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -359,7 +359,7 @@ int v4lconvert_try_format(struct v4lconvert_data *data, int i, result; unsigned int desired_width = dest_fmt->fmt.pix.width; unsigned int desired_height = dest_fmt->fmt.pix.height; - struct v4l2_format try_src, try_dest; + struct v4l2_format try_src, try_dest, try2_src, try2_dest; if (dest_fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && v4lconvert_supported_dst_fmt_only(data) && @@ -378,6 +378,29 @@ int v4lconvert_try_format(struct v4lconvert_data *data, return result; } + /* In case of a non exact resolution match, try again with a slightly larger + resolution as some weird devices are not able to crop of the number of + extra (border) pixels most sensors have compared to standard resolutions, + which we will then just crop of in software */ + if (try_dest.fmt.pix.width != desired_width || + try_dest.fmt.pix.height != desired_height) { + try2_dest = *dest_fmt; + try2_dest.fmt.pix.width = desired_width + 7; + try2_dest.fmt.pix.height = desired_height + 1; + result = v4lconvert_do_try_format(data, &try2_dest, &try2_src); + if (result == 0 && + try2_dest.fmt.pix.width >= desired_width && + try2_dest.fmt.pix.width <= desired_width + 7 && + try2_dest.fmt.pix.height >= desired_height && + try2_dest.fmt.pix.height <= desired_height + 1) { + /* Success! */ + try2_dest.fmt.pix.width = desired_width; + try2_dest.fmt.pix.height = desired_height; + try_dest = try2_dest; + try_src = try2_src; + } + } + /* In case of a non exact resolution match, see if this is a well known resolution some apps are hardcoded too and try to give the app what it asked for by cropping a slightly larger resolution or adding a small @@ -387,7 +410,7 @@ int v4lconvert_try_format(struct v4lconvert_data *data, for (i = 0; i < ARRAY_SIZE(v4lconvert_crop_res); i++) { if (v4lconvert_crop_res[i][0] == desired_width && v4lconvert_crop_res[i][1] == desired_height) { - struct v4l2_format try2_src, try2_dest = *dest_fmt; + try2_dest = *dest_fmt; /* Note these are chosen so that cropping to vga res just works for vv6410 sensor cams, which have 356x292 and 180x148 */ @@ -423,20 +446,13 @@ int v4lconvert_try_format(struct v4lconvert_data *data, /* Some applications / libs (*cough* gstreamer *cough*) will not work correctly with planar YUV formats when the width is not a multiple of 8 - or the height is not a multiple of 2 */ - if (try_dest.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420 || - try_dest.fmt.pix.pixelformat == V4L2_PIX_FMT_YVU420) { - try_dest.fmt.pix.width &= ~7; - try_dest.fmt.pix.height &= ~1; - } - - /* Likewise the width needs to be a multiple of 4 for RGB formats - (although I've never seen a device with a width not a multiple of 4) */ - if (try_dest.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24 || - try_dest.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24) - try_dest.fmt.pix.width &= ~3; + or the height is not a multiple of 2. With RGB formats these apps require + the width to be a multiple of 4. We apply the same rounding to all + formats to not end up with 2 close but different resolutions. */ + try_dest.fmt.pix.width &= ~7; + try_dest.fmt.pix.height &= ~1; - /* Are we converting? */ + /* Are we converting / cropping ? */ if(try_src.fmt.pix.width != try_dest.fmt.pix.width || try_src.fmt.pix.height != try_dest.fmt.pix.height || try_src.fmt.pix.pixelformat != try_dest.fmt.pix.pixelformat) @@ -1147,12 +1163,8 @@ int v4lconvert_enum_framesizes(struct v4lconvert_data *data, case V4L2_FRMSIZE_TYPE_DISCRETE: frmsize->discrete = data->framesizes[frmsize->index].discrete; /* Apply the same rounding algorithm as v4lconvert_try_format */ - if (frmsize->pixel_format == V4L2_PIX_FMT_YUV420 || - frmsize->pixel_format == V4L2_PIX_FMT_YVU420) { - frmsize->discrete.width &= ~7; - frmsize->discrete.height &= ~1; - } else - frmsize->discrete.width &= ~3; + frmsize->discrete.width &= ~7; + frmsize->discrete.height &= ~1; break; case V4L2_FRMSIZE_TYPE_CONTINUOUS: case V4L2_FRMSIZE_TYPE_STEPWISE: -- cgit v1.2.3 From b530bfbf669215b30f2821355ffdb9f7c4b161b6 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Tue, 16 Jun 2009 23:59:06 +0200 Subject: libv4l: Make sure Y and UV or from the same 2x2 pixel block when cropping From: Hans de Goede libv4l: Make sure Y and UV or from the same 2x2 pixel block when cropping Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/libv4lconvert/crop.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/libv4lconvert/crop.c b/v4l2-apps/libv4l/libv4lconvert/crop.c index f01772c07..46c87f0ce 100644 --- a/v4l2-apps/libv4l/libv4lconvert/crop.c +++ b/v4l2-apps/libv4l/libv4lconvert/crop.c @@ -69,8 +69,8 @@ static void v4lconvert_reduceandcrop_yuv420( int x,y; int dest_height_half = dest_fmt->fmt.pix.height / 2; int dest_width_half = dest_fmt->fmt.pix.width / 2; - int startx = src_fmt->fmt.pix.width / 2 - dest_fmt->fmt.pix.width; - int starty = src_fmt->fmt.pix.height / 2 - dest_fmt->fmt.pix.height; + int startx = (src_fmt->fmt.pix.width / 2 - dest_fmt->fmt.pix.width) & ~1; + int starty = (src_fmt->fmt.pix.height / 2 - dest_fmt->fmt.pix.height) & ~1; unsigned char *mysrc, *mysrc2; /* Y */ @@ -113,8 +113,8 @@ static void v4lconvert_crop_yuv420(unsigned char *src, unsigned char *dest, const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt) { int x; - int startx = (src_fmt->fmt.pix.width - dest_fmt->fmt.pix.width) / 2; - int starty = (src_fmt->fmt.pix.height - dest_fmt->fmt.pix.height) / 2; + int startx = ((src_fmt->fmt.pix.width - dest_fmt->fmt.pix.width) / 2) & ~1; + int starty = ((src_fmt->fmt.pix.height - dest_fmt->fmt.pix.height) / 2) & ~1; unsigned char *mysrc = src + starty * src_fmt->fmt.pix.bytesperline + startx; /* Y */ @@ -181,8 +181,8 @@ static void v4lconvert_add_border_yuv420( const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt) { int y; - int borderx = (dest_fmt->fmt.pix.width - src_fmt->fmt.pix.width) / 2; - int bordery = (dest_fmt->fmt.pix.height - src_fmt->fmt.pix.height) / 2; + int borderx = ((dest_fmt->fmt.pix.width - src_fmt->fmt.pix.width) / 2) & ~1; + int bordery = ((dest_fmt->fmt.pix.height - src_fmt->fmt.pix.height) / 2) & ~1; /* Y */ for (y = 0; y < bordery; y++) { -- cgit v1.2.3 From 7a7d2c3791928d88ef83f28a7d1fd3095f0bb459 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 17 Jun 2009 14:56:29 +0200 Subject: libv4l1: Use v4l2_ioctl when determining min/max size From: Hans de Goede Use v4l2_ioctl instead of native ioctl's when finding out what the minimum / maximum size is, so that we take the resolution aligment done by libv4l2 into account for the minimum / maximum size. Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/libv4l1/libv4l1.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/libv4l1/libv4l1.c b/v4l2-apps/libv4l/libv4l1/libv4l1.c index b676d69ed..4d251a481 100644 --- a/v4l2-apps/libv4l/libv4l1/libv4l1.c +++ b/v4l2-apps/libv4l/libv4l1/libv4l1.c @@ -219,14 +219,14 @@ static void v4l1_find_min_and_max_size(int index, struct v4l2_format *fmt2) for (i = 0; ; i++) { fmtdesc2.index = i; - if (SYS_IOCTL(devices[index].fd, VIDIOC_ENUM_FMT, &fmtdesc2)) + if (v4l2_ioctl(devices[index].fd, VIDIOC_ENUM_FMT, &fmtdesc2)) break; fmt2->fmt.pix.pixelformat = fmtdesc2.pixelformat; fmt2->fmt.pix.width = 48; fmt2->fmt.pix.height = 32; - if (SYS_IOCTL(devices[index].fd, VIDIOC_TRY_FMT, fmt2) == 0) { + if (v4l2_ioctl(devices[index].fd, VIDIOC_TRY_FMT, fmt2) == 0) { if (fmt2->fmt.pix.width < devices[index].min_width) devices[index].min_width = fmt2->fmt.pix.width; if (fmt2->fmt.pix.height < devices[index].min_height) @@ -237,7 +237,7 @@ static void v4l1_find_min_and_max_size(int index, struct v4l2_format *fmt2) fmt2->fmt.pix.width = 100000; fmt2->fmt.pix.height = 100000; - if (SYS_IOCTL(devices[index].fd, VIDIOC_TRY_FMT, fmt2) == 0) { + if (v4l2_ioctl(devices[index].fd, VIDIOC_TRY_FMT, fmt2) == 0) { if (fmt2->fmt.pix.width > devices[index].max_width) devices[index].max_width = fmt2->fmt.pix.width; if (fmt2->fmt.pix.height > devices[index].max_height) -- cgit v1.2.3 From f62a7a8cd7c03f7694ea5260ac38b1f2cf7826d5 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 17 Jun 2009 15:38:46 +0200 Subject: libv4l: Report aligned resolution on first get_fmt From: Hans de Goede When a user does a try_fmt with the current dest_fmt and the dest_fmt is a supported one we will align the resulution (see try_fmt for why). Do the on the result of the first get_fmt, so that a try_fmt on the result of a get_fmt done immediately after open leaves the fmt unchanged Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/libv4l2/libv4l2.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2.c b/v4l2-apps/libv4l/libv4l2/libv4l2.c index a12b41c2c..36fb8e21e 100644 --- a/v4l2-apps/libv4l/libv4l2/libv4l2.c +++ b/v4l2-apps/libv4l/libv4l2/libv4l2.c @@ -507,6 +507,16 @@ int v4l2_fd_open(int fd, int v4l2_flags) devices[index].src_fmt = fmt; devices[index].dest_fmt = fmt; + /* When a user does a try_fmt with the current dest_fmt and the dest_fmt + is a supported one we will align the resulution (see try_fmt for why). + Do the same here now, so that a try_fmt on the result of a get_fmt done + immediately after open leaves the fmt unchanged. */ + if (v4lconvert_supported_dst_format( + devices[index].dest_fmt.fmt.pix.pixelformat)) { + devices[index].dest_fmt.fmt.pix.width &= ~7; + devices[index].dest_fmt.fmt.pix.height &= ~1; + } + pthread_mutex_init(&devices[index].stream_lock, NULL); devices[index].no_frames = 0; @@ -748,6 +758,7 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) if (stream_needs_locking) { + pthread_mutex_lock(&devices[index].stream_lock); /* If this is the first stream related ioctl, and we should only allow libv4lconvert supported destination formats (so that it can do flipping, processing, etc.) and the current destination format is not supported, @@ -765,7 +776,6 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) v4l2_ioctl(fd, VIDIOC_S_FMT, &fmt); V4L2_LOG("Done setting pixelformat (supported_dst_fmt_only)"); } - pthread_mutex_lock(&devices[index].stream_lock); devices[index].flags |= V4L2_STREAM_TOUCHED; } -- cgit v1.2.3 From e84f05aeceff30413ad2d1ee68bb11888e04e167 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 17 Jun 2009 15:45:32 +0200 Subject: libv4l: fix deadlock introduced by locking fix in previous patch From: Hans de Goede libv4l: fix deadlock introduced by locking fix in previous patch Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/libv4l2/libv4l2.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2.c b/v4l2-apps/libv4l/libv4l2/libv4l2.c index 36fb8e21e..b71c9b4c6 100644 --- a/v4l2-apps/libv4l/libv4l2/libv4l2.c +++ b/v4l2-apps/libv4l/libv4l2/libv4l2.c @@ -773,7 +773,9 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) V4L2_LOG("Setting pixelformat to RGB24 (supported_dst_fmt_only)"); devices[index].flags |= V4L2_STREAM_TOUCHED; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24; + pthread_mutex_unlock(&devices[index].stream_lock); v4l2_ioctl(fd, VIDIOC_S_FMT, &fmt); + pthread_mutex_lock(&devices[index].stream_lock); V4L2_LOG("Done setting pixelformat (supported_dst_fmt_only)"); } devices[index].flags |= V4L2_STREAM_TOUCHED; -- cgit v1.2.3 From f475df33ab13799d25650081e64fd0f6e59d3792 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 17 Jun 2009 21:57:05 +0200 Subject: libv4l1: Emulate VIDIOCGWIN instead of passing it through to the kernel From: Hans de Goede Emulate VIDIOCGWIN instead of passing it through to the kernel, this fixes us reporting a wrong size to the app when libv4l2 / libv4lconvert is cropping / downsampling the image. Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/libv4l1/libv4l1.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/libv4l1/libv4l1.c b/v4l2-apps/libv4l/libv4l1/libv4l1.c index 4d251a481..9b23926be 100644 --- a/v4l2-apps/libv4l/libv4l1/libv4l1.c +++ b/v4l2-apps/libv4l/libv4l1/libv4l1.c @@ -307,7 +307,7 @@ int v4l1_open (const char *file, int oflag, ...) /* Register with libv4l2, as we use that todo format conversion and read() emulation for us */ - if (v4l2_fd_open(fd, V4L2_ENABLE_ENUM_FMT_EMULATION) == -1) { + if (v4l2_fd_open(fd, 0) == -1) { int saved_err = errno; SYS_CLOSE(fd); errno = saved_err; @@ -542,24 +542,27 @@ int v4l1_ioctl (int fd, unsigned long int request, ...) break; case VIDIOCSWIN: + case VIDIOCGWIN: { struct video_window *win = arg; devices[index].flags |= V4L1_PIX_SIZE_TOUCHED; - result = v4l1_set_format(index, win->width, win->height, -1, 1); + if (request == VIDIOCSWIN) + result = v4l1_set_format(index, win->width, win->height, -1, 1); + else + result = 0; + if (result == 0) { + win->x = 0; + win->y = 0; win->width = devices[index].width; win->height = devices[index].height; + win->flags = 0; } } break; - case VIDIOCGWIN: - devices[index].flags |= V4L1_PIX_SIZE_TOUCHED; - result = SYS_IOCTL(fd, request, arg); - break; - case VIDIOCGCHAN: { struct v4l2_input input2; -- cgit v1.2.3 From 5e90c221e48890f2f2433f153d9584bc4bdd327a Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 17 Jun 2009 23:35:22 +0200 Subject: libv4l: enable automatic gain / exposure control for st6422 devices From: Hans de Goede libv4l: enable automatic gain / exposure control for st6422 devices Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'v4l2-apps') diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c index 8a77728a6..4e600351b 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c @@ -78,6 +78,11 @@ static const struct v4lcontrol_flags_info v4lcontrol_flags[] = { { 0x046d, 0x0928, 7, NULL, NULL, V4LCONTROL_WANTS_WB_AUTOGAIN }, /* logitech quickcam express stv06xx + pb0100 */ { 0x046d, 0x0840, 0, NULL, NULL, V4LCONTROL_WANTS_WB }, + /* logitech quickcam messenger variants, st6422 */ + { 0x046d, 0x08f0, 0, NULL, NULL, V4LCONTROL_WANTS_AUTOGAIN }, + { 0x046d, 0x08f5, 0, NULL, NULL, V4LCONTROL_WANTS_AUTOGAIN }, + { 0x046d, 0x08f6, 0, NULL, NULL, V4LCONTROL_WANTS_AUTOGAIN }, + { 0x046d, 0x08da, 0, NULL, NULL, V4LCONTROL_WANTS_AUTOGAIN }, }; static const struct v4l2_queryctrl fake_controls[]; -- cgit v1.2.3 From 606bcfaaa02f5a901fb1d0546c1e03260a866212 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 14 Jun 2009 10:42:48 +0200 Subject: v4l2-ctl: add modulator get/set options. From: Hans Verkuil Priority: normal Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- v4l2-apps/util/v4l2-ctl.cpp | 78 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) (limited to 'v4l2-apps') diff --git a/v4l2-apps/util/v4l2-ctl.cpp b/v4l2-apps/util/v4l2-ctl.cpp index dec9edd61..309e14312 100644 --- a/v4l2-apps/util/v4l2-ctl.cpp +++ b/v4l2-apps/util/v4l2-ctl.cpp @@ -131,6 +131,8 @@ enum Option { OptOverlay, OptGetJpegComp, OptSetJpegComp, + OptGetModulator, + OptSetModulator, OptListDevices, OptLast = 256 }; @@ -260,6 +262,8 @@ static struct option long_options[] = { {"set-crop-output-overlay", required_argument, 0, OptSetOutputOverlayCrop}, {"get-jpeg-comp", no_argument, 0, OptGetJpegComp}, {"set-jpeg-comp", required_argument, 0, OptSetJpegComp}, + {"get-modulator", no_argument, 0, OptGetModulator}, + {"set-modulator", required_argument, 0, OptSetModulator}, {"overlay", required_argument, 0, OptOverlay}, {"list-devices", no_argument, 0, OptListDevices}, {0, 0, 0, 0} @@ -404,6 +408,15 @@ static void usage(void) " display audio outputs [VIDIOC_ENUMAUDOUT]\n" " --list-audio-inputs\n" " display audio inputs [VIDIOC_ENUMAUDIO]\n" + " --get-modulator query the modulator settings [VIDIOC_G_MODULATOR]\n" + " --set-modulator=\n" + " set the sub-carrier modulation [VIDIOC_S_MODULATOR]\n" + " is one of:\n" + " mono: Modulate as mono\n" + " stereo: Modulate as stereo\n" + " bilingual: Modulate as bilingual\n" + " mono-sap: Modulate as mono with Second Audio Program\n" + " stereo-sap: Modulate as stereo with Second Audio Program\n" "\n"); printf("Expert options:\n" " --streamoff turn the stream off [VIDIOC_STREAMOFF]\n" @@ -946,6 +959,21 @@ static std::string rxsubchans2s(int rxsubchans) return s; } +static std::string txsubchans2s(int txsubchans) +{ + std::string s; + + if (txsubchans & V4L2_TUNER_SUB_MONO) + s += "mono"; + if (txsubchans & V4L2_TUNER_SUB_STEREO) + s += "stereo"; + if (txsubchans & V4L2_TUNER_SUB_LANG1) + s += "bilingual"; + if (txsubchans & V4L2_TUNER_SUB_SAP) + s += "+sap"; + return s; +} + static std::string tcap2s(unsigned cap) { std::string s; @@ -1384,6 +1412,7 @@ int main(int argc, char **argv) struct v4l2_jpegcompression jpegcomp; /* jpeg compression */ int input; /* set_input/get_input */ int output; /* set_output/get_output */ + int txsubchans; /* set_modulator */ v4l2_std_id std; /* get_std/set_std */ double freq = 0; /* get/set frequency */ struct v4l2_frequency vf; /* get_freq/set_freq */ @@ -1695,6 +1724,24 @@ int main(int argc, char **argv) return 1; } break; + case OptSetModulator: + txsubchans = strtol(optarg, 0L, 0); + if (!strcmp(optarg, "stereo")) + txsubchans = V4L2_TUNER_SUB_STEREO; + else if (!strcmp(optarg, "stereo-sap")) + txsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_SAP; + else if (!strcmp(optarg, "bilingual")) + txsubchans = V4L2_TUNER_SUB_LANG1; + else if (!strcmp(optarg, "mono")) + txsubchans = V4L2_TUNER_SUB_MONO; + else if (!strcmp(optarg, "mono-sap")) + txsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_SAP; + else { + fprintf(stderr, "Unknown txsubchans value\n"); + usage(); + return 1; + } + break; case OptSetSlicedVbiFormat: case OptSetSlicedVbiOutFormat: case OptTrySlicedVbiFormat: @@ -1861,6 +1908,7 @@ int main(int argc, char **argv) options[OptGetStandard] = 1; options[OptGetFreq] = 1; options[OptGetTuner] = 1; + options[OptGetModulator] = 1; options[OptGetOverlayFormat] = 1; options[OptGetOutputOverlayFormat] = 1; options[OptGetVbiFormat] = 1; @@ -1954,6 +2002,16 @@ int main(int argc, char **argv) } } + if (options[OptSetModulator]) { + struct v4l2_modulator mt; + + memset(&mt, 0, sizeof(struct v4l2_modulator)); + if (doioctl(fd, VIDIOC_G_MODULATOR, &mt, "VIDIOC_G_MODULATOR") == 0) { + mt.txsubchans = txsubchans; + doioctl(fd, VIDIOC_S_MODULATOR, &mt, "VIDIOC_S_MODULATOR"); + } + } + if (options[OptSetVideoFormat] || options[OptTryVideoFormat]) { struct v4l2_format in_vfmt; @@ -2403,6 +2461,7 @@ set_vid_fmt_error: if (options[OptGetTuner]) { struct v4l2_tuner vt; + memset(&vt, 0, sizeof(struct v4l2_tuner)); if (doioctl(fd, VIDIOC_G_TUNER, &vt, "VIDIOC_G_TUNER") == 0) { printf("Tuner:\n"); @@ -2421,6 +2480,25 @@ set_vid_fmt_error: } } + if (options[OptGetModulator]) { + struct v4l2_modulator mt; + + memset(&mt, 0, sizeof(struct v4l2_modulator)); + if (doioctl(fd, VIDIOC_G_MODULATOR, &mt, "VIDIOC_G_MODULATOR") == 0) { + printf("Modulator:\n"); + printf("\tName : %s\n", mt.name); + printf("\tCapabilities : %s\n", tcap2s(mt.capability).c_str()); + if (mt.capability & V4L2_TUNER_CAP_LOW) + printf("\tFrequency range : %.1f MHz - %.1f MHz\n", + mt.rangelow / 16000.0, mt.rangehigh / 16000.0); + else + printf("\tFrequency range : %.1f MHz - %.1f MHz\n", + mt.rangelow / 16.0, mt.rangehigh / 16.0); + printf("\tSubchannel modulation: %s\n", + txsubchans2s(mt.txsubchans).c_str()); + } + } + if (options[OptLogStatus]) { static char buf[40960]; int len; -- cgit v1.2.3