summaryrefslogtreecommitdiff
path: root/v4l2-apps
diff options
context:
space:
mode:
Diffstat (limited to 'v4l2-apps')
-rw-r--r--v4l2-apps/libv4l/ChangeLog70
-rw-r--r--v4l2-apps/libv4l/Makefile4
-rw-r--r--v4l2-apps/libv4l/README28
-rw-r--r--v4l2-apps/libv4l/TODO5
-rw-r--r--v4l2-apps/libv4l/include/libv4l1.h2
-rw-r--r--v4l2-apps/libv4l/include/libv4l2.h24
-rw-r--r--v4l2-apps/libv4l/include/libv4lconvert.h40
-rw-r--r--v4l2-apps/libv4l/libv4l1/Makefile10
-rw-r--r--v4l2-apps/libv4l/libv4l1/libv4l1-priv.h9
-rw-r--r--v4l2-apps/libv4l/libv4l1/libv4l1.c76
-rw-r--r--v4l2-apps/libv4l/libv4l1/log.c7
-rw-r--r--v4l2-apps/libv4l/libv4l1/v4l1compat.c5
-rw-r--r--v4l2-apps/libv4l/libv4l2/Makefile12
-rw-r--r--v4l2-apps/libv4l/libv4l2/libv4l2-priv.h9
-rw-r--r--v4l2-apps/libv4l/libv4l2/libv4l2.c174
-rw-r--r--v4l2-apps/libv4l/libv4l2/log.c23
-rw-r--r--v4l2-apps/libv4l/libv4l2/v4l2convert.c20
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/Makefile28
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h54
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c504
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h70
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/crop.c138
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/flip.c158
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/helper-funcs.h79
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/helper.c224
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h65
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c488
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/libv4lsyscall-priv.h112
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/ov511-decomp.c666
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/ov518-decomp.c1477
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/autogain.c140
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/gamma.c57
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h60
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c181
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.h43
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c142
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/rgbyuv.c5
-rw-r--r--v4l2-apps/util/v4l2-ctl.cpp78
38 files changed, 4903 insertions, 384 deletions
diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog
index 11f6ca2fd..e69a8c8f4 100644
--- a/v4l2-apps/libv4l/ChangeLog
+++ b/v4l2-apps/libv4l/ChangeLog
@@ -1,3 +1,73 @@
+libv4l-0.6.0
+------------
+* Recognize disabled controls and replace with fake equivalents where
+ available
+* 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.
+* Fix a bug in the always report widths which are a multiple of 8 code added
+ in 0.5.97
+
+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 <hselasky@freebsd.org>, 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
+-------------
+* 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
+* 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
+-------------
+* 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
+* 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.
+* 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 <gilles.gigan@gmail.com>
+* Add support to use orientation from VIDIOC_ENUMINPUT by:
+ Adam Baker <linux@baker-net.org.uk>
+* sn9c20x cams have occasional bad jpeg frames, drop these to avoid the
+ flickering effect they cause, by: Brian Johnson <brijohn@gmail.com>
+* 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
------------
* Add support for MR97310A decompression by Kyle Guinn <elyk03@gmail.com>
diff --git a/v4l2-apps/libv4l/Makefile b/v4l2-apps/libv4l/Makefile
index 703f3298f..acec5c540 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.99
all install:
$(MAKE) -C libv4lconvert V4L2_LIB_VERSION=$(V4L2_LIB_VERSION) $@
@@ -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/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..8f7744337 100644
--- a/v4l2-apps/libv4l/TODO
+++ b/v4l2-apps/libv4l/TODO
@@ -8,3 +8,8 @@
necessary to implement CGMBUF in the kernel for each driver.
-take the possibility of pitch != width into account everywhere
+
+-make updating of parameters happen based on time elapsed rather then
+ frames
+
+-get standardized CID for AUTOGAIN_TARGET upstream and switch to that
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 b05b57cb6..7ecbb2cee 100644
--- a/v4l2-apps/libv4l/include/libv4l2.h
+++ b/v4l2-apps/libv4l/include/libv4l2.h
@@ -21,6 +21,7 @@
#include <stdio.h>
#include <unistd.h>
+#include <stdint.h>
#ifdef __cplusplus
extern "C" {
@@ -41,18 +42,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.
@@ -64,7 +59,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);
@@ -89,11 +84,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/include/libv4lconvert.h b/v4l2-apps/libv4l/include/libv4lconvert.h
index 626c43473..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 <sys/time.h>
#include <linux/types.h>
#include <linux/ioctl.h>
+#endif
+
+#ifdef __FreeBSD__
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#endif
+
/* end broken header workaround includes */
+
#include <linux/videodev2.h>
#ifdef __cplusplus
@@ -42,18 +53,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? */
@@ -81,6 +104,17 @@ 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);
+
+/* 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/Makefile b/v4l2-apps/libv4l/libv4l1/Makefile
index 9f30cbb0f..e6d306055 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)
@@ -69,10 +71,10 @@ 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) -c -MMD $(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/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 <stdio.h>
#include <pthread.h>
-/* 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 797c8768a..9b23926be 100644
--- a/v4l2-apps/libv4l/libv4l1/libv4l1.c
+++ b/v4l2-apps/libv4l/libv4l1/libv4l1.c
@@ -44,18 +44,12 @@
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
-#include <syscall.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.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 <sys/time.h>
-#include <asm/types.h>
-#include <linux/ioctl.h>
-/* end broken header workaround includes */
+#include "../libv4lconvert/libv4lsyscall-priv.h"
#include <linux/videodev.h>
#include <linux/videodev2.h>
#include <libv4l2.h>
@@ -155,8 +149,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))) {
@@ -223,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 (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 (syscall(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)
@@ -241,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 (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)
@@ -278,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)
@@ -290,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 */
@@ -308,21 +305,20 @@ 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, 0) == -1) {
int saved_err = errno;
- V4L1_LOG_ERR("getting pixformat: %s\n", strerror(errno));
- syscall(SYS_close, fd);
+ 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);
+ SYS_CLOSE(fd);
errno = saved_err;
return -1;
}
@@ -399,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 */
@@ -417,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;
}
@@ -446,7 +442,6 @@ int v4l1_dup(int fd)
return v4l2_dup(fd);
}
-
int v4l1_ioctl (int fd, unsigned long int request, ...)
{
void *arg;
@@ -458,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
@@ -485,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 */
@@ -547,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 = syscall(SYS_ioctl, fd, request, arg);
- break;
-
case VIDIOCGCHAN:
{
struct v4l2_input input2;
@@ -572,7 +570,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;
}
@@ -614,7 +612,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
@@ -650,7 +648,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);
@@ -747,7 +745,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);
@@ -758,7 +756,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 <stdio.h>
#include <stdlib.h>
-#include <linux/ioctl.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 <sys/time.h>
-#include <asm/types.h>
-/* end broken header workaround includes */
+#include "../libv4lconvert/libv4lsyscall-priv.h"
#include <linux/videodev.h>
#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 <stdarg.h>
#include <fcntl.h>
#include <libv4l1.h>
+#include "../libv4lconvert/libv4lsyscall-priv.h" /* for __off_t */
#include <sys/ioctl.h>
#include <sys/mman.h>
@@ -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/Makefile b/v4l2-apps/libv4l/libv4l2/Makefile
index 614b36cf8..06c010f3c 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)
@@ -68,10 +71,10 @@ 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) -c -MMD $(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_$*)
@@ -79,4 +82,3 @@ clean::
%.a:
$(AR) cqs $@ $^
-
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 <pthread.h>
#include <libv4lconvert.h> /* 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 b6ddef6e8..b71c9b4c6 100644
--- a/v4l2-apps/libv4l/libv4l2/libv4l2.c
+++ b/v4l2-apps/libv4l/libv4l2/libv4l2.c
@@ -59,7 +59,6 @@
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
-#include <syscall.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
@@ -77,6 +76,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
@@ -99,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;
@@ -126,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);
@@ -147,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));
@@ -155,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));
@@ -181,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);
@@ -195,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));
@@ -214,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));
@@ -242,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;
@@ -264,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));
@@ -364,12 +364,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 (devices[index].src_fmt.fmt.pix.pixelformat ==
- devices[index].dest_fmt.fmt.pix.pixelformat) {
+ if (!v4l2_needs_conversion(index)) {
/* Normal (no conversion) mode */
struct v4l2_buffer buf;
@@ -377,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;
@@ -413,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)
@@ -426,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;
}
@@ -448,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;
@@ -463,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;
@@ -499,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;
@@ -544,7 +562,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 */
@@ -558,15 +576,15 @@ 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");
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;
}
+ 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
@@ -576,7 +594,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);
@@ -613,7 +631,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;
@@ -659,7 +677,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);
@@ -667,7 +685,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
@@ -676,21 +694,28 @@ 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:
+ if (!(devices[index].flags & V4L2_DISABLE_CONVERSION))
+ is_capture_request = 1;
+ break;
case VIDIOC_QUERYCAP:
is_capture_request = 1;
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:
- 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:
@@ -724,7 +749,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;
@@ -732,18 +757,48 @@ int v4l2_ioctl (int fd, unsigned long int request, ...)
}
- if (stream_needs_locking)
+ if (stream_needs_locking) {
pthread_mutex_lock(&devices[index].stream_lock);
-
- converting = v4lconvert_needs_conversion(devices[index].convert,
- &devices[index].src_fmt, &devices[index].dest_fmt);
+ /* 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;
+ 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;
+ }
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;
- 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;
@@ -794,7 +849,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 {
@@ -834,7 +889,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));
@@ -884,7 +939,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 */
@@ -904,8 +959,8 @@ 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)
+ result = SYS_IOCTL(devices[index].fd, VIDIOC_QUERYBUF, buf);
+ if (result || !v4l2_needs_conversion(index))
break;
buf->m.offset = V4L2_MMAP_OFFSET_MAGIC | buf->index;
@@ -923,11 +978,11 @@ 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;
- result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_QBUF, arg);
+ result = SYS_IOCTL(devices[index].fd, VIDIOC_QBUF, arg);
break;
case VIDIOC_DQBUF:
@@ -938,8 +993,8 @@ int v4l2_ioctl (int fd, unsigned long int request, ...)
if ((result = v4l2_deactivate_read_stream(index)))
break;
- if (!converting) {
- result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_DQBUF, buf);
+ if (!v4l2_needs_conversion(index)) {
+ result = SYS_IOCTL(devices[index].fd, VIDIOC_DQBUF, buf);
if (result) {
int saved_err = errno;
V4L2_LOG_ERR("dequeuing buf: %s\n", strerror(errno));
@@ -952,7 +1007,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),
@@ -997,7 +1052,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)
@@ -1018,16 +1073,15 @@ 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);
/* 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)) {
- result = syscall(SYS_read, fd, dest, n);
+ !v4l2_needs_conversion(index)) {
+ result = SYS_READ(fd, dest, n);
goto leave;
}
@@ -1056,7 +1110,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;
@@ -1076,8 +1130,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);
@@ -1085,15 +1138,14 @@ 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;
}
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),
@@ -1166,7 +1218,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 */
@@ -1176,7 +1228,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) &&
@@ -1187,7 +1239,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;
@@ -1198,13 +1250,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 c29086ff4..86d71b64e 100644
--- a/v4l2-apps/libv4l/libv4l2/log.c
+++ b/v4l2-apps/libv4l/libv4l2/log.c
@@ -1,5 +1,7 @@
/*
-# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+# (C) 2008 Elmar Kleijn <elmar_kleijn@hotmail.com>
+# (C) 2008 Sjoerd Piepenbrink <need4weed@gmail.com>
+# (C) 2008 Hans de Goede <hdegoede@redhat.com>
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
@@ -20,12 +22,7 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
-#include <linux/ioctl.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 <sys/time.h>
-#include <asm/types.h>
-/* end broken header workaround includes */
+#include "../libv4lconvert/libv4lsyscall-priv.h"
#include <linux/videodev2.h>
#include "libv4l2.h"
#include "libv4l2-priv.h"
@@ -161,7 +158,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,
@@ -169,12 +166,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;
@@ -186,7 +183,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,
@@ -196,12 +193,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/libv4l2/v4l2convert.c b/v4l2-apps/libv4l/libv4l2/v4l2convert.c
index 307a03ce5..4b75a5ebf 100644
--- a/v4l2-apps/libv4l/libv4l2/v4l2convert.c
+++ b/v4l2-apps/libv4l/libv4l2/v4l2convert.c
@@ -24,17 +24,11 @@
#include <stdarg.h>
#include <stdlib.h>
-#include <syscall.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.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 <sys/time.h>
-#include <asm/types.h>
-#include <linux/ioctl.h>
-/* end broken header workaround includes */
+#include "../libv4lconvert/libv4lsyscall-priv.h"
#include <linux/videodev2.h>
#include <libv4l2.h>
@@ -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 */
@@ -92,11 +86,12 @@ 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;
}
+#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/Makefile b/v4l2-apps/libv4l/libv4lconvert/Makefile
index f779011b4..036649e86 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 -lm
+
ifeq ($(LINKTYPE),static)
CONVERT_LIB = libv4lconvert.a
else
@@ -12,8 +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
-TARGETS = $(CONVERT_LIB) libv4lconvert.pc
+ 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 ov511-decomp ov518-decomp
INCLUDES = ../include/libv4lconvert.h
ifeq ($(LIB_RELEASE),)
@@ -28,8 +33,12 @@ ifeq ($(LIBDIR),)
LIBDIR = $(PREFIX)/lib
endif
+override CPPFLAGS += -DLIBDIR=\"$(LIBDIR)\"
+
all: $(TARGETS)
+-include $(CONVERT_OBJS:.o=.d)
+
$(CONVERT_LIB): $(CONVERT_OBJS)
libv4lconvert.pc:
@@ -40,32 +49,37 @@ 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 -lm' >> libv4lconvert.pc
@echo 'Cflags: -I$${prefix}/include' >> 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
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 DEADJOE */DEADJOE *-decomp
%.o: %.c
- $(CC) -c -MMD $(CPPFLAGS) $(CFLAGS) -o $@ $<
+ $(CC) -Wp,-MMD,"$*.d",-MQ,"$@",-MP -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:
$(AR) cqs $@ $^
+
+ov511-decomp: ov511-decomp.o
+ov518-decomp: ov518-decomp.o
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..6211ee22a
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h
@@ -0,0 +1,54 @@
+/*
+# (C) 2008-2009 Elmar Kleijn <elmar_kleijn@hotmail.com>
+# (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com>
+# (C) 2008-2009 Radjnies Bhansingh <radjnies@gmail.com>
+# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
+
+# 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
+
+#define V4LCONTROL_SUPPORTS_NEXT_CTRL 0x01
+
+struct v4lcontrol_flags_info;
+
+struct v4lcontrol_data {
+ int fd; /* Device fd */
+ 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() */
+ const struct v4lcontrol_flags_info *flags_info;
+};
+
+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; */
+ int flags;
+ int default_gamma;
+};
+
+#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..4e600351b
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c
@@ -0,0 +1,504 @@
+/*
+# (C) 2008-2009 Elmar Kleijn <elmar_kleijn@hotmail.com>
+# (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com>
+# (C) 2008-2009 Radjnies Bhansingh <radjnies@gmail.com>
+# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
+
+# 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 <sys/types.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "libv4lcontrol.h"
+#include "libv4lcontrol-priv.h"
+#include "../libv4lsyscall-priv.h"
+#include <linux/videodev2.h>
+
+#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, NULL, NULL, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ /* Philips SPC300NC */
+ { 0x0471, 0x0326, 0, NULL, NULL, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ /* Philips SPC210NC */
+ { 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, 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, 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 },
+ /* 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 },
+ /* 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[];
+
+static void v4lcontrol_init_flags(struct v4lcontrol_data *data)
+{
+ struct stat st;
+ FILE *f;
+ 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;
+
+ 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)
+ data->flags |= V4LCONTROL_VFLIPPED;
+ }
+
+ if (fstat(data->fd, &st) || !S_ISCHR(st.st_mode)) {
+ return; /* Should never happen */
+ }
+
+ /* <Sigh> find ourselve in sysfs */
+ for (i = 0; i < 256; i++) {
+ snprintf(sysfs_name, sizeof(sysfs_name),
+ "/sys/class/video4linux/video%d/dev", i);
+ f = fopen(sysfs_name, "r");
+ if (!f)
+ continue;
+
+ s = fgets(buf, sizeof(buf), f);
+ fclose(f);
+
+ if (s && sscanf(buf, "%*d:%d%c", &minor, &c) == 2 && c == '\n' &&
+ minor == minor(st.st_rdev))
+ break;
+ }
+ if (i == 256)
+ return; /* Not found, sysfs not mounted? */
+
+ /* Get vendor and product ID */
+ snprintf(sysfs_name, sizeof(sysfs_name),
+ "/sys/class/video4linux/video%d/device/modalias", i);
+ f = fopen(sysfs_name, "r");
+ if (f) {
+ s = fgets(buf, sizeof(buf), f);
+ fclose(f);
+
+ if (!s ||
+ sscanf(s, "usb:v%4hxp%4hx%c", &vendor_id, &product_id, &c) != 3 ||
+ c != 'd')
+ return; /* Not an USB device */
+ } else {
+ /* Try again assuming the device link points to the usb
+ device instead of the usb interface (bug in older versions
+ of gspca) */
+
+ /* Get product ID */
+ snprintf(sysfs_name, sizeof(sysfs_name),
+ "/sys/class/video4linux/video%d/device/idVendor", i);
+ f = fopen(sysfs_name, "r");
+ if (!f)
+ return; /* Not an USB device (or no sysfs) */
+
+ s = fgets(buf, sizeof(buf), f);
+ fclose(f);
+
+ if (!s || sscanf(s, "%04hx%c", &vendor_id, &c) != 2 || c != '\n')
+ return; /* Should never happen */
+
+ /* Get product ID */
+ snprintf(sysfs_name, sizeof(sysfs_name),
+ "/sys/class/video4linux/video%d/device/idProduct", i);
+ f = fopen(sysfs_name, "r");
+ if (!f)
+ return; /* Should never happen */
+
+ s = fgets(buf, sizeof(buf), f);
+ fclose(f);
+
+ if (!s || sscanf(s, "%04hx%c", &product_id, &c) != 2 || c != '\n')
+ return; /* Should never happen */
+ }
+
+ /* 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) &&
+ (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->flags_info = &v4lcontrol_flags[i];
+ break;
+ }
+}
+
+struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion)
+{
+ int shm_fd;
+ int i, rc, 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));
+
+ 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);
+
+ ctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL;
+ 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
+ (no cost when not activated by the user that is) */
+ if (always_needs_conversion || v4lcontrol_needs_conversion(data)) {
+ for (i = 0; i < V4LCONTROL_AUTO_ENABLE_COUNT; i++) {
+ ctrl.id = fake_controls[i].id;
+ rc = SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL, &ctrl);
+ if (rc == -1 || (rc == 0 && (ctrl.flags & V4L2_CTRL_FLAG_DISABLED)))
+ 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);
+
+ if (data->controls == 0)
+ return data; /* No need to create a shared memory segment */
+
+ SYS_IOCTL(fd, VIDIOC_QUERYCAP, &cap);
+ snprintf(shm_name, 256, "/%s:%s", cap.bus_info, cap.card);
+
+ /* / 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)
+ 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;
+
+ 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;
+
+ if (data->flags_info && data->flags_info->default_gamma)
+ data->shm_values[V4LCONTROL_GAMMA] = data->flags_info->default_gamma;
+ }
+
+ return data;
+
+error:
+ free(data);
+ return NULL;
+}
+
+void v4lcontrol_destroy(struct v4lcontrol_data *data)
+{
+ if (data->controls)
+ munmap(data->shm_values, V4LCONTROL_SHM_SIZE);
+ free(data);
+}
+
+/* FIXME get better CID's for normalize */
+static const struct v4l2_queryctrl fake_controls[V4LCONTROL_COUNT] = {
+{
+ .id = V4L2_CID_AUTO_WHITE_BALANCE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Whitebalance (software)",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0
+},
+{
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Horizontal flip (sw)",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0
+},
+{
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Vertical flip (sw)",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .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,
+ .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
+},
+};
+
+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;
+
+ 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)
+{
+ 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) {
+ v4lcontrol_copy_queryctrl(data, ctrl, i);
+ return 0;
+ }
+
+ /* find out what the kernel driver would respond. */
+ retval = SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL, arg);
+
+ 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)) {
+ v4lcontrol_copy_queryctrl(data, ctrl, i);
+ retval = 0;
+ }
+ }
+
+ return retval;
+}
+
+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 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 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)) {
+ /* 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;
+}
+
+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));
+
+ 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
new file mode 100644
index 000000000..e29fde3d4
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h
@@ -0,0 +1,70 @@
+/*
+# (C) 2008-2009 Elmar Kleijn <elmar_kleijn@hotmail.com>
+# (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com>
+# (C) 2008-2009 Radjnies Bhansingh <radjnies@gmail.com>
+# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
+
+# 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_H
+#define __LIBV4LCONTROL_H
+
+/* Flags */
+#define V4LCONTROL_HFLIPPED 0x01
+#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_GAMMA,
+ /* 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;
+
+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 */
+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
+ 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);
+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/crop.c b/v4l2-apps/libv4l/libv4lconvert/crop.c
index 4294fbeaf..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 */
@@ -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) & ~1;
+ int bordery = ((dest_fmt->fmt.pix.height - src_fmt->fmt.pix.height) / 2) & ~1;
+
+ /* 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/flip.c b/v4l2-apps/libv4l/libv4lconvert/flip.c
index f47afde72..8c4d8233c 100644
--- a/v4l2-apps/libv4l/libv4lconvert/flip.c
+++ b/v4l2-apps/libv4l/libv4lconvert/flip.c
@@ -20,8 +20,100 @@
*/
+#include <string.h>
#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)
{
@@ -106,37 +198,69 @@ 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)
+{
+ 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 hflip, int vflip)
{
- switch (rotate) {
- case 0:
- break;
- case 90:
- switch (pix_fmt) {
+ if (vflip && hflip) {
+ 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);
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YVU420:
+ v4lconvert_rotate180_yuv420(src, dest, fmt->fmt.pix.width,
+ fmt->fmt.pix.height);
+ break;
+ }
+ } else if (hflip) {
+ switch (fmt->fmt.pix.pixelformat) {
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_BGR24:
- v4lconvert_rotate90_rgbbgr24(src, dest, width, height);
+ v4lconvert_hflip_rgbbgr24(src, dest, fmt);
break;
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
- v4lconvert_rotate90_yuv420(src, dest, width, height);
+ v4lconvert_hflip_yuv420(src, dest, fmt);
break;
}
- break;
- case 180:
- switch (pix_fmt) {
+ } else if (vflip) {
+ switch (fmt->fmt.pix.pixelformat) {
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_BGR24:
- v4lconvert_rotate180_rgbbgr24(src, dest, width, height);
+ v4lconvert_vflip_rgbbgr24(src, dest, fmt);
break;
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
- v4lconvert_rotate180_yuv420(src, dest, width, height);
+ v4lconvert_vflip_yuv420(src, dest, fmt);
break;
}
- break;
- default:
- printf("FIXME add %d degrees rotation\n", rotate);
}
+
+ /* Our newly written data has no padding */
+ v4lconvert_fixup_fmt(fmt);
}
diff --git a/v4l2-apps/libv4l/libv4lconvert/helper-funcs.h b/v4l2-apps/libv4l/libv4lconvert/helper-funcs.h
new file mode 100644
index 000000000..8ce12343c
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/helper-funcs.h
@@ -0,0 +1,79 @@
+/* Utility functions for decompression helpers
+ *
+ * Copyright (c) 2009 Hans de Goede <hdegoede@redhat.com>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+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;
+
+ if (errno == EPIPE) /* Main program has quited */
+ exit(0);
+
+ 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 <hdegoede@redhat.com>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include "libv4lconvert-priv.h"
+
+#define READ_END 0
+#define WRITE_END 1
+
+/* <sigh> 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 5ce7bde3b..2cf8f6ba4 100644
--- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h
+++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h
@@ -20,9 +20,14 @@
#define __LIBV4LCONVERT_PRIV_H
#include <stdio.h>
+#include <sys/types.h>
#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 +84,16 @@
#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
+
+#define ARRAY_SIZE(x) ((int)sizeof(x)/(int)sizeof((x)[0]))
+
#define V4LCONVERT_ERROR_MSG_SIZE 256
#define V4LCONVERT_MAX_FRAMESIZES 16
@@ -87,37 +102,40 @@
"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_UVC 0x01
+#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;
int flags; /* bitfield */
+ int control_flags; /* bitfield */
int supported_src_formats; /* bitfield */
unsigned int no_formats;
char error_msg[V4LCONVERT_ERROR_MSG_SIZE];
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 {
- 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;
+ /* 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 {
@@ -125,6 +143,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);
@@ -209,10 +229,19 @@ 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 hflip, int vflip);
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 1204e8ef2..1389c58bc 100644
--- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c
+++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c
@@ -19,15 +19,14 @@
#include <errno.h>
#include <string.h>
#include <stdlib.h>
-#include <syscall.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "libv4lconvert.h"
#include "libv4lconvert-priv.h"
+#include "libv4lsyscall-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 */
@@ -47,15 +46,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 },
@@ -64,20 +63,14 @@ 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 },
};
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_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 */
-};
-
/* List of well known resolutions which we can get by cropping somewhat larger
resolutions */
static const int v4lconvert_crop_res[][2] = {
@@ -91,56 +84,21 @@ 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;
-
- 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);
-
- /* Get product ID */
- snprintf(sysfs_name, sizeof(sysfs_name),
- "/sys/class/video4linux/video%d/device/idProduct",
- minor(st.st_rdev));
- f = fopen(sysfs_name, "r");
- if (!f)
- return 0; /* Should never happen */
- i = fscanf(f, "%hx", &product_id);
- fclose(f);
-
- 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;
+ /* 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;
data->fd = fd;
+ data->decompress_pid = -1;
/* Check supported formats */
for (i = 0; ; i++) {
@@ -148,24 +106,47 @@ 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++)
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;
/* Check if this cam has any special flags */
- data->flags = v4lconvert_get_flags(data->fd);
- 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"))
+ 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);
+ if (!data->control) {
+ free(data);
+ return NULL;
+ }
+ data->control_flags = v4lcontrol_get_flags(data->control);
+
+ data->processing = v4lprocessing_create(fd, data->control);
+ if (!data->processing) {
+ v4lcontrol_destroy(data->control);
+ free(data);
+ return NULL;
}
return data;
@@ -173,18 +154,23 @@ struct v4lconvert_data *v4lconvert_create(int fd)
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);
+ v4lconvert_helper_cleanup(data);
+ free(data->convert1_buf);
+ free(data->convert2_buf);
+ free(data->rotate90_buf);
+ free(data->flip_buf);
free(data->convert_pixfmt_buf);
free(data);
}
-static int v4lconvert_supported_dst_format(unsigned int pixelformat)
+int v4lconvert_supported_dst_format(unsigned int pixelformat)
{
int i;
@@ -195,6 +181,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)
{
@@ -202,17 +194,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)
- return syscall(SYS_ioctl, data->fd, VIDIOC_ENUM_FMT, fmt);
+ (!v4lconvert_supported_dst_fmt_only(data) &&
+ fmt->index < data->no_formats))
+ return 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;
@@ -307,7 +304,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 -
@@ -339,7 +336,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:
@@ -362,27 +359,58 @@ 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, try2_src, try2_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) ||
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;
}
+ /* 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 */
+ 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++) {
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 */
@@ -390,13 +418,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;
@@ -409,7 +444,15 @@ int v4lconvert_try_format(struct v4lconvert_data *data,
}
}
- /* Are we converting? */
+ /* 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. 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 / 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)
@@ -427,19 +470,40 @@ 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 (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;
- if (!(data->flags & (V4LCONVERT_ROTATE_90|V4LCONVERT_ROTATE_180)))
- return 0; /* Formats identical and we don't need flip */
+ return 0;
+}
- /* 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 */
+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,
@@ -460,15 +524,15 @@ 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)
+ 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;
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:
@@ -496,12 +560,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)) {
- V4LCONVERT_ERR("JPEG needs 90 degree rotation\n");
- data->flags |= V4LCONVERT_ROTATE_90;
- errno = EAGAIN;
+ if (!(data->control_flags & V4LCONTROL_ROTATED_90_JPEG)) {
+ V4LCONVERT_ERR("JPEG needs 90° rotation, please report "
+ "this to <hdegoede@redhat.com>\n");
+ errno = EIO;
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,
@@ -509,6 +575,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 <hdegoede@redhat.com>\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;
@@ -541,7 +614,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;
@@ -561,8 +635,11 @@ 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;
+ int d_size;
int yvu = 0;
if (dest_pix_fmt != V4L2_PIX_FMT_YUV420 &&
@@ -571,8 +648,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;
@@ -590,6 +670,22 @@ 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)) {
+ /* Corrupt frame, better get another one */
+ errno = EAGAIN;
+ return -1;
+ }
+ break;
}
switch (dest_pix_fmt) {
@@ -631,6 +727,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);
@@ -640,27 +737,33 @@ 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 */
+ 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;
+ src = tmpbuf;
}
/* Raw bayer formats */
@@ -690,10 +793,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;
@@ -704,10 +807,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;
@@ -723,7 +826,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;
@@ -739,7 +842,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;
@@ -802,6 +905,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;
}
@@ -810,14 +917,31 @@ 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;
+ 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;
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);
+ 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.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)) {
int to_copy = MIN(dest_size, src_size);
memcpy(dest, src, to_copy);
return to_copy;
@@ -856,52 +980,96 @@ int v4lconvert_convert(struct v4lconvert_data *data,
return -1;
}
- if (my_dest_fmt.fmt.pix.pixelformat != my_src_fmt.fmt.pix.pixelformat)
+
+ /* 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 (data->flags & V4LCONVERT_ROTATE_90)
- rotate += 90;
- if (data->flags & V4LCONVERT_ROTATE_180)
- rotate += 180;
+ /* 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;
+
+ convert1_dest_size =
+ my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3;
+ convert2_src = convert1_dest;
+ }
+
+ if (convert && (rotate90 || hflip || vflip || crop)) {
+ convert2_dest = v4lconvert_alloc_buffer(data, temp_needed,
+ &data->convert2_buf, &data->convert2_buf_size);
+ if (!convert2_dest)
+ return -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;
+ convert2_dest_size = temp_needed;
+ rotate90_src = flip_src = crop_src = convert2_dest;
+ }
- /* 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)
+ if (rotate90 && (hflip || vflip || crop)) {
+ rotate90_dest = v4lconvert_alloc_buffer(data, temp_needed,
+ &data->rotate90_buf, &data->rotate90_buf_size);
+ if (!rotate90_dest)
return -1;
- rotate_src = crop_src = convert_dest;
+ flip_src = crop_src = rotate90_dest;
}
- if (rotate && crop) {
- rotate_dest = v4lconvert_alloc_buffer(data, temp_needed,
- &data->rotate_buf, &data->rotate_buf_size);
- if (!rotate_dest)
+ if ((vflip || hflip) && crop) {
+ flip_dest = v4lconvert_alloc_buffer(data, temp_needed, &data->flip_buf,
+ &data->flip_buf_size);
+ if (!flip_dest)
return -1;
- crop_src = rotate_dest;
+ 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, convert1_dest_size,
+ &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, src, src_size, convert_dest,
+ res = v4lconvert_convert_pixfmt(data, convert2_src, src_size,
+ convert2_dest, convert2_dest_size,
&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;
+
+ /* 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 (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);
+ if (rotate90)
+ v4lconvert_rotate90(rotate90_src, rotate90_dest, &my_src_fmt);
+
+ 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);
@@ -922,7 +1090,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 */
@@ -977,8 +1145,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))
- return syscall(SYS_ioctl, data->fd, VIDIOC_ENUM_FRAMESIZES, frmsize);
+ if (!v4lconvert_supported_dst_format(frmsize->pixel_format)) {
+ if (v4lconvert_supported_dst_fmt_only(data)) {
+ errno = EINVAL;
+ return -1;
+ }
+ return SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMESIZES, frmsize);
+ }
if (frmsize->index >= data->no_framesizes) {
errno = EINVAL;
@@ -989,6 +1162,9 @@ 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 */
+ frmsize->discrete.width &= ~7;
+ frmsize->discrete.height &= ~1;
break;
case V4L2_FRMSIZE_TYPE_CONTINUOUS:
case V4L2_FRMSIZE_TYPE_STEPWISE:
@@ -1006,7 +1182,11 @@ int v4lconvert_enum_frameintervals(struct v4lconvert_data *data,
struct v4l2_format src_fmt, dest_fmt;
if (!v4lconvert_supported_dst_format(frmival->pixel_format)) {
- res = syscall(SYS_ioctl, data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival);
+ if (v4lconvert_supported_dst_fmt_only(data)) {
+ errno = EINVAL;
+ return -1;
+ }
+ res = SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival);
if (res)
V4LCONVERT_ERR("%s\n", strerror(errno));
return res;
@@ -1050,7 +1230,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;
@@ -1076,3 +1256,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/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 <sys/time.h>
+#include <syscall.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+/* 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 <sys/time.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#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/ov511-decomp.c b/v4l2-apps/libv4l/libv4lconvert/ov511-decomp.c
new file mode 100644
index 000000000..11ed2a601
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/ov511-decomp.c
@@ -0,0 +1,666 @@
+/* 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 <string.h>
+#include <unistd.h>
+#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 */
+
+ remove0blocks(src, &src_size);
+
+ /* Compressed ? */
+ if (src[8] & 0x40) {
+ 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 */
+ }
+}
diff --git a/v4l2-apps/libv4l/libv4lconvert/ov518-decomp.c b/v4l2-apps/libv4l/libv4lconvert/ov518-decomp.c
new file mode 100644
index 000000000..51b8d8c60
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/ov518-decomp.c
@@ -0,0 +1,1477 @@
+/* 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)
+ *
+ * Copyright (c) 2002-2003 Mark W. McClelland. All rights reserved.
+ * http://alpha.dyndns.org/ov511/
+ *
+ * Fast integer iDCT by Yuri van Oers <yvanoers AT xs4all.nl>
+ * 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 <string.h>
+#include <unistd.h>
+#include "helper-funcs.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 <skip> 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 + 64))
+ 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
+ */
+static int 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 -1;
+
+ /* Decompress, skipping the 8-byte SOF header */
+ if (decompress420NoMMXOV518(src + 8, dst, pTmp, w, h, numpix, &cinfo, yvu))
+ return -1;
+
+ 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 */
+ }
+}
diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/autogain.c b/v4l2-apps/libv4l/libv4lconvert/processing/autogain.c
new file mode 100644
index 000000000..358264c68
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/autogain.c
@@ -0,0 +1,140 @@
+/*
+# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#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);
+}
+
+/* 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 (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 (SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL, &gainctrl) ||
+ 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;
+ SYS_IOCTL(data->fd, VIDIOC_S_CTRL, &ctrl);
+ }
+ if (exposure != orig_exposure) {
+ ctrl.id = V4L2_CID_EXPOSURE;
+ ctrl.value = exposure;
+ 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/gamma.c b/v4l2-apps/libv4l/libv4lconvert/processing/gamma.c
new file mode 100644
index 000000000..fcb5bb0cf
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/gamma.c
@@ -0,0 +1,57 @@
+/*
+# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <math.h>
+#include "libv4lprocessing.h"
+#include "libv4lprocessing-priv.h"
+
+#define CLIP(color) (unsigned char)(((color)>0xff)?0xff:(((color)<0)?0:(color)))
+
+static int gamma_active(struct v4lprocessing_data *data) {
+ int gamma = v4lcontrol_get_ctrl(data->control, V4LCONTROL_GAMMA);
+
+ return gamma && 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
new file mode 100644
index 000000000..b73c73b53
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h
@@ -0,0 +1,60 @@
+/*
+# (C) 2008-2009 Elmar Kleijn <elmar_kleijn@hotmail.com>
+# (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com>
+# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef __LIBV4LPROCESSING_PRIV_H
+#define __LIBV4LPROCESSING_PRIV_H
+
+#include "../control/libv4lcontrol.h"
+#include "../libv4lsyscall-priv.h"
+
+#define V4L2PROCESSING_UPDATE_RATE 10
+
+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 */
+ int lookup_table_active;
+ /* Counts the number of processed frames until a
+ V4L2PROCESSING_UPDATE_RATE overflow happens */
+ int lookup_table_update_counter;
+ /* RGB/BGR lookup tables */
+ 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 {
+ /* 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);
+};
+
+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
new file mode 100644
index 000000000..cbbcca73c
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c
@@ -0,0 +1,181 @@
+/*
+# (C) 2008-2009 Elmar Kleijn <elmar_kleijn@hotmail.com>
+# (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com>
+# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "libv4lprocessing.h"
+#include "libv4lprocessing-priv.h"
+#include "../libv4lconvert-priv.h" /* for PIX_FMT defines */
+
+static struct v4lprocessing_filter *filters[] = {
+ &whitebalance_filter,
+ &autogain_filter,
+ &gamma_filter,
+};
+
+struct v4lprocessing_data *v4lprocessing_create(int fd, struct v4lcontrol_data* control)
+{
+ struct v4lprocessing_data *data =
+ calloc(1, sizeof(struct v4lprocessing_data));
+
+ if (!data)
+ return NULL;
+
+ data->fd = fd;
+ data->control = control;
+
+ return data;
+}
+
+void v4lprocessing_destroy(struct v4lprocessing_data *data)
+{
+ free(data);
+}
+
+int v4lprocessing_pre_processing(struct v4lprocessing_data *data)
+{
+ int i;
+
+ data->do_process = 0;
+ for (i = 0; i < ARRAY_SIZE(filters); i++) {
+ if (filters[i]->active(data))
+ data->do_process = 1;
+ }
+
+ return data->do_process;
+}
+
+static void v4lprocessing_update_lookup_tables(struct v4lprocessing_data *data,
+ unsigned char *buf, const struct v4l2_format *fmt)
+{
+ int i;
+
+ for (i = 0; i < 256; i++) {
+ data->comp1[i] = i;
+ data->green[i] = i;
+ data->comp2[i] = i;
+ }
+
+ 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;
+
+ 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 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 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;
+ }
+}
+
+void v4lprocessing_processing(struct v4lprocessing_data *data,
+ unsigned char *buf, const struct v4l2_format *fmt)
+{
+ if (!data->do_process)
+ return;
+
+ /* 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 (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->lookup_table_update_counter++;
+
+ if (data->lookup_table_active)
+ v4lprocessing_do_processing(data, buf, fmt);
+
+ 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..69d8865b2
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.h
@@ -0,0 +1,43 @@
+/*
+# (C) 2008-2009 Elmar Kleijn <elmar_kleijn@hotmail.com>
+# (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com>
+# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU 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
+
+#include "../libv4lsyscall-priv.h"
+#include <linux/videodev2.h>
+
+struct v4lprocessing_data;
+struct v4lcontrol_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,
+ 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/whitebalance.c b/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c
new file mode 100644
index 000000000..64d20b3ff
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c
@@ -0,0 +1,142 @@
+/*
+# (C) 2008-2009 Elmar Kleijn <elmar_kleijn@hotmail.com>
+# (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com>
+# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#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 };
diff --git a/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c b/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c
index 00706be9d..31cbc3c68 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;
}
@@ -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;
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=<txsubchans>\n"
+ " set the sub-carrier modulation [VIDIOC_S_MODULATOR]\n"
+ " <txsubchans> 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;