summaryrefslogtreecommitdiff
path: root/v4l2-apps/lib/libv4l
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2008-09-05 10:20:56 -0300
committerMauro Carvalho Chehab <mchehab@redhat.com>2008-09-05 10:20:56 -0300
commit5f2d82cefe0ce930f3146875c88b993695c7e03a (patch)
tree2d33fe6b5949e509d85f48f5c8331adcb22151d3 /v4l2-apps/lib/libv4l
parentad789ba2904603896206a72f0445e8ba56da7134 (diff)
parent2257e70baa578d959dc4bdcce498ef07d2af00da (diff)
downloadmediapointer-dvb-s2-5f2d82cefe0ce930f3146875c88b993695c7e03a.tar.gz
mediapointer-dvb-s2-5f2d82cefe0ce930f3146875c88b993695c7e03a.tar.bz2
merge: http://linuxtv.org/hg/~awalls/v4l-dvb
From: Mauro Carvalho Chehab <mchehab@redhat.com> Fixed a trivial conflict between a janitor's patch from Hans Verkuil and Andy patch series. Priority: normal Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'v4l2-apps/lib/libv4l')
-rw-r--r--v4l2-apps/lib/libv4l/ChangeLog14
-rw-r--r--v4l2-apps/lib/libv4l/Makefile2
-rw-r--r--v4l2-apps/lib/libv4l/include/libv4l1.h22
-rw-r--r--v4l2-apps/lib/libv4l/include/libv4l2.h28
-rw-r--r--v4l2-apps/lib/libv4l/include/libv4lconvert.h23
-rw-r--r--v4l2-apps/lib/libv4l/libv4l1/Makefile6
-rw-r--r--v4l2-apps/lib/libv4l/libv4l1/libv4l1.c3
-rw-r--r--v4l2-apps/lib/libv4l/libv4l1/log.c7
-rw-r--r--v4l2-apps/lib/libv4l/libv4l1/v4l1compat.c28
-rw-r--r--v4l2-apps/lib/libv4l/libv4l2/Makefile6
-rw-r--r--v4l2-apps/lib/libv4l/libv4l2/libv4l2.c135
-rw-r--r--v4l2-apps/lib/libv4l/libv4l2/log.c6
-rw-r--r--v4l2-apps/lib/libv4l/libv4l2/v4l2convert.c27
-rw-r--r--v4l2-apps/lib/libv4l/libv4lconvert/Makefile8
-rw-r--r--v4l2-apps/lib/libv4l/libv4lconvert/flip.c107
-rw-r--r--v4l2-apps/lib/libv4l/libv4lconvert/jidctflt.c4
-rw-r--r--v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert-priv.h22
-rw-r--r--v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert.c150
-rw-r--r--v4l2-apps/lib/libv4l/libv4lconvert/pac207.c2
-rw-r--r--v4l2-apps/lib/libv4l/libv4lconvert/rgbyuv.c2
-rw-r--r--v4l2-apps/lib/libv4l/libv4lconvert/sn9c10x.c2
-rw-r--r--v4l2-apps/lib/libv4l/libv4lconvert/spca561-decompress.c1
-rw-r--r--v4l2-apps/lib/libv4l/libv4lconvert/tinyjpeg.c348
-rw-r--r--v4l2-apps/lib/libv4l/libv4lconvert/tinyjpeg.h1
24 files changed, 775 insertions, 179 deletions
diff --git a/v4l2-apps/lib/libv4l/ChangeLog b/v4l2-apps/lib/libv4l/ChangeLog
index 3d4e40ad2..eefe0028b 100644
--- a/v4l2-apps/lib/libv4l/ChangeLog
+++ b/v4l2-apps/lib/libv4l/ChangeLog
@@ -1,8 +1,20 @@
+libv4l-0.4.2
+------------
+* The bayer pixel order in gspca's sonixb driver was different from that in
+ the sn9c102 driver from the mainline kernel, a recent gspca patch fixes
+ this, adjust libv4l to match (and make it work properly with the sn9c102
+ driver).
+
libv4l-0.4.1
------------
* When the driver supports read() and we are not converting let the driver
handle read() instead of emulating it with mmap mode
-
+* Fix errors and warnings when compiling with ICC (Gregor Jasny)
+* Add support to libv4lconvert for rotating images 90 (for Pixart 7302 cams)
+ or 180 (Philips SPC200NC / Philips SPC300NC) degrees
+* Add support for Pixart custom JPEG format
+* Hide non public symbols (Gregor Jasny)
+* Fix and enable x86_64 asm jpeg decompress helper functions (Gregor Jasny)
libv4l-0.4.0
------------
diff --git a/v4l2-apps/lib/libv4l/Makefile b/v4l2-apps/lib/libv4l/Makefile
index 31254a09e..92928271a 100644
--- a/v4l2-apps/lib/libv4l/Makefile
+++ b/v4l2-apps/lib/libv4l/Makefile
@@ -1,5 +1,5 @@
LIB_RELEASE=0
-V4L2_LIB_VERSION=$(LIB_RELEASE).4.1
+V4L2_LIB_VERSION=$(LIB_RELEASE).4.2
all clean install:
$(MAKE) -C libv4lconvert V4L2_LIB_VERSION=$(V4L2_LIB_VERSION) $@
diff --git a/v4l2-apps/lib/libv4l/include/libv4l1.h b/v4l2-apps/lib/libv4l/include/libv4l1.h
index 9036ae869..c878cc198 100644
--- a/v4l2-apps/lib/libv4l/include/libv4l1.h
+++ b/v4l2-apps/lib/libv4l/include/libv4l1.h
@@ -26,9 +26,15 @@ extern "C" {
#include <stdio.h>
#include <unistd.h>
+#if __GNUC__ >= 4
+#define LIBV4L_PUBLIC __attribute__ ((visibility("default")))
+#else
+#define LIBV4L_PUBLIC
+#endif
+
/* Point this to a FILE opened for writing when you want to log error and
status messages to a file, when NULL errors will get send to stderr */
-extern FILE *v4l1_log_file;
+LIBV4L_PUBLIC extern FILE *v4l1_log_file;
/* Just like your regular open/close/etc, except that when opening a v4l2
capture only device, full v4l1 emulation is done including emulating the
@@ -51,14 +57,14 @@ extern FILE *v4l1_log_file;
capture formats, like hw specific bayer compression methods).
*/
-int v4l1_open (const char *file, int oflag, ...);
-int v4l1_close(int fd);
-int v4l1_dup(int fd);
-int v4l1_ioctl (int fd, unsigned long int request, ...);
-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,
+LIBV4L_PUBLIC int v4l1_open (const char *file, int oflag, ...);
+LIBV4L_PUBLIC int v4l1_close(int fd);
+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);
-int v4l1_munmap(void *_start, size_t length);
+LIBV4L_PUBLIC int v4l1_munmap(void *_start, size_t length);
#ifdef __cplusplus
}
diff --git a/v4l2-apps/lib/libv4l/include/libv4l2.h b/v4l2-apps/lib/libv4l/include/libv4l2.h
index 63529cf4b..b05b57cb6 100644
--- a/v4l2-apps/lib/libv4l/include/libv4l2.h
+++ b/v4l2-apps/lib/libv4l/include/libv4l2.h
@@ -26,9 +26,15 @@
extern "C" {
#endif /* __cplusplus */
+#if __GNUC__ >= 4
+#define LIBV4L_PUBLIC __attribute__ ((visibility("default")))
+#else
+#define LIBV4L_PUBLIC
+#endif
+
/* Point this to a FILE opened for writing when you want to log error and
status messages to a file, when NULL errors will get send to stderr */
-extern FILE *v4l2_log_file;
+LIBV4L_PUBLIC extern FILE *v4l2_log_file;
/* Just like your regular open/close/etc, except that format conversion is
done if necessary when capturing. That is if you (try to) set a capture
@@ -52,14 +58,14 @@ extern FILE *v4l2_log_file;
fail.
*/
-int v4l2_open (const char *file, int oflag, ...);
-int v4l2_close(int fd);
-int v4l2_dup(int fd);
-int v4l2_ioctl (int fd, unsigned long int request, ...);
-ssize_t v4l2_read (int fd, void* buffer, size_t n);
-void *v4l2_mmap(void *start, size_t length, int prot, int flags, int fd,
+LIBV4L_PUBLIC int v4l2_open (const char *file, int oflag, ...);
+LIBV4L_PUBLIC int v4l2_close(int fd);
+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);
-int v4l2_munmap(void *_start, size_t length);
+LIBV4L_PUBLIC int v4l2_munmap(void *_start, size_t length);
/* Misc utility functions */
@@ -70,12 +76,12 @@ int v4l2_munmap(void *_start, size_t length);
Normally returns 0, even if the cid did not exist or was locked, returns
non 0 when an other error occured. */
-int v4l2_set_control(int fd, int cid, int value);
+LIBV4L_PUBLIC int v4l2_set_control(int fd, int cid, int value);
/* This function returns a value of 0 - 65535, scaled to from the actual range
of the given v4l control id. when the cid does not exist, could not be
accessed for some reason, or some error occured 0 is returned. */
-int v4l2_get_control(int fd, int cid);
+LIBV4L_PUBLIC int v4l2_get_control(int fd, int cid);
/* "low level" access functions, these functions allow somewhat lower level
@@ -95,7 +101,7 @@ int v4l2_get_control(int fd, int cid);
Returns fd on success, -1 if the fd is not suitable for use through libv4l2
(note the fd is left open in this case). */
-int v4l2_fd_open(int fd, int v4l2_flags);
+LIBV4L_PUBLIC int v4l2_fd_open(int fd, int v4l2_flags);
#ifdef __cplusplus
}
diff --git a/v4l2-apps/lib/libv4l/include/libv4lconvert.h b/v4l2-apps/lib/libv4l/include/libv4lconvert.h
index d8446dac8..87e41ceaa 100644
--- a/v4l2-apps/lib/libv4l/include/libv4lconvert.h
+++ b/v4l2-apps/lib/libv4l/include/libv4lconvert.h
@@ -31,34 +31,45 @@
extern "C" {
#endif /* __cplusplus */
+#if __GNUC__ >= 4
+#define LIBV4L_PUBLIC __attribute__ ((visibility("default")))
+#else
+#define LIBV4L_PUBLIC
+#endif
+
struct v4lconvert_data;
-struct v4lconvert_data *v4lconvert_create(int fd);
-void v4lconvert_destroy(struct v4lconvert_data *data);
+LIBV4L_PUBLIC struct v4lconvert_data *v4lconvert_create(int fd);
+LIBV4L_PUBLIC void v4lconvert_destroy(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. */
-int v4lconvert_try_format(struct v4lconvert_data *data,
+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 */
-int v4lconvert_enum_fmt(struct v4lconvert_data *data, struct v4l2_fmtdesc *fmt);
+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? */
+LIBV4L_PUBLIC int v4lconvert_needs_conversion(struct v4lconvert_data *data,
+ const struct v4l2_format *src_fmt, /* in */
+ const struct v4l2_format *dest_fmt); /* in */
/* return value of -1 on error, otherwise the amount of bytes written to
dest */
-int v4lconvert_convert(struct v4lconvert_data *data,
+LIBV4L_PUBLIC int v4lconvert_convert(struct v4lconvert_data *data,
const struct v4l2_format *src_fmt, /* in */
const struct v4l2_format *dest_fmt, /* in */
unsigned char *src, int src_size, unsigned char *dest, int dest_size);
/* get a string describing the last error*/
-const char *v4lconvert_get_error_message(struct v4lconvert_data *data);
+LIBV4L_PUBLIC const char *v4lconvert_get_error_message(struct v4lconvert_data *data);
#ifdef __cplusplus
}
diff --git a/v4l2-apps/lib/libv4l/libv4l1/Makefile b/v4l2-apps/lib/libv4l/libv4l1/Makefile
index c92731daa..27848477e 100644
--- a/v4l2-apps/lib/libv4l/libv4l1/Makefile
+++ b/v4l2-apps/lib/libv4l/libv4l1/Makefile
@@ -1,7 +1,7 @@
-CPPFLAGS = -I../include -I../../../../linux/include
+override CPPFLAGS += -I../include -I../../../include -fvisibility=hidden
CFLAGS := -g -O1
-CFLAGS += -Wall -W -Wno-unused -Wpointer-arith -Wstrict-prototypes
+CFLAGS += -Wall -Wno-unused -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes
LIBS = -lpthread
@@ -17,7 +17,7 @@ else
V4L1_LIB = libv4l1.so
V4L1_OBJS += ../libv4l2/libv4l2.so
TARGETS += $(V4L1COMPAT)
-CPPFLAGS += -fPIC
+override CPPFLAGS += -fPIC
endif
ifeq ($(LIB_RELEASE),)
diff --git a/v4l2-apps/lib/libv4l/libv4l1/libv4l1.c b/v4l2-apps/lib/libv4l/libv4l1/libv4l1.c
index 80d2fa09b..39f2d29e0 100644
--- a/v4l2-apps/lib/libv4l/libv4l1/libv4l1.c
+++ b/v4l2-apps/lib/libv4l/libv4l1/libv4l1.c
@@ -59,6 +59,7 @@
#include <linux/videodev.h>
#include <linux/videodev2.h>
#include <libv4l2.h>
+#include "libv4l1.h"
#include "libv4l1-priv.h"
#define V4L1_SUPPORTS_ENUMINPUT 0x01
@@ -582,7 +583,7 @@ int v4l1_ioctl (int fd, unsigned long int request, ...)
input2.index = chan->channel;
result = v4l2_ioctl(fd, VIDIOC_ENUMINPUT, &input2);
if (result == 0) {
- snprintf(chan->name, sizeof(chan->name), "%s", input2.name);
+ snprintf(chan->name, sizeof(chan->name), "%s", (char*)input2.name);
if (input2.type == V4L2_INPUT_TYPE_TUNER) {
chan->tuners = 1;
chan->type = VIDEO_TYPE_TV;
diff --git a/v4l2-apps/lib/libv4l/libv4l1/log.c b/v4l2-apps/lib/libv4l/libv4l1/log.c
index cccc3e6d0..74ce0f20b 100644
--- a/v4l2-apps/lib/libv4l/libv4l1/log.c
+++ b/v4l2-apps/lib/libv4l/libv4l1/log.c
@@ -25,6 +25,7 @@
#include <asm/types.h>
/* end broken header workaround includes */
#include <linux/videodev.h>
+#include "libv4l1-priv.h"
#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
@@ -92,9 +93,9 @@ void v4l1_log_ioctl(unsigned long int request, void *arg, int result)
break;
case VIDIOCGWIN:
case VIDIOCSWIN:
- fprintf(v4l1_log_file,"width\t%d\n",
+ fprintf(v4l1_log_file,"width\t%u\n",
((struct video_window *)arg)->width);
- fprintf(v4l1_log_file,"height\t%d\n",
+ fprintf(v4l1_log_file,"height\t%u\n",
((struct video_window *)arg)->height);
break;
@@ -115,7 +116,7 @@ void v4l1_log_ioctl(unsigned long int request, void *arg, int result)
fprintf(v4l1_log_file,"palette %d\n",( (int)((struct video_picture*)arg)->palette) );
break;
- case VIDIOCCAPTURE: fprintf(v4l1_log_file,"on/of? %d\n", *((int *)arg) );
+ case VIDIOCCAPTURE: fprintf(v4l1_log_file,"on/off? %d\n", *((int *)arg) );
break;
case VIDIOCSYNC: fprintf(v4l1_log_file,"sync %d\n", *((int *)arg) );
diff --git a/v4l2-apps/lib/libv4l/libv4l1/v4l1compat.c b/v4l2-apps/lib/libv4l/libv4l1/v4l1compat.c
index f1134fe3b..e4293d2f9 100644
--- a/v4l2-apps/lib/libv4l/libv4l1/v4l1compat.c
+++ b/v4l2-apps/lib/libv4l/libv4l1/v4l1compat.c
@@ -26,12 +26,21 @@
#include <fcntl.h>
#include <libv4l1.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
/* Check that open/read/mmap is not a define */
#if defined open || defined read || defined mmap
#error open/read/mmap is a prepocessor macro !!
#endif
-int open (const char *file, int oflag, ...)
+#if __GNUC__ >= 4
+#define LIBV4L_PUBLIC __attribute__ ((visibility("default")))
+#else
+#define LIBV4L_PUBLIC
+#endif
+
+LIBV4L_PUBLIC int open (const char *file, int oflag, ...)
{
int fd;
@@ -52,7 +61,7 @@ int open (const char *file, int oflag, ...)
return fd;
}
-int open64 (const char *file, int oflag, ...)
+LIBV4L_PUBLIC int open64 (const char *file, int oflag, ...)
{
int fd;
@@ -73,16 +82,16 @@ int open64 (const char *file, int oflag, ...)
return fd;
}
-int close(int fd) {
+LIBV4L_PUBLIC int close(int fd) {
return v4l1_close(fd);
}
-int dup(int fd)
+LIBV4L_PUBLIC int dup(int fd)
{
return v4l1_dup(fd);
}
-int ioctl (int fd, unsigned long int request, ...)
+LIBV4L_PUBLIC int ioctl (int fd, unsigned long int request, ...)
{
void *arg;
va_list ap;
@@ -94,24 +103,25 @@ int ioctl (int fd, unsigned long int request, ...)
return v4l1_ioctl (fd, request, arg);
}
-ssize_t read(int fd, void* buffer, size_t n)
+LIBV4L_PUBLIC ssize_t read(int fd, void* buffer, size_t n)
{
return v4l1_read (fd, buffer, n);
}
-void *mmap(void *start, size_t length, int prot, int flags, int fd,
+LIBV4L_PUBLIC void *mmap(void *start, size_t length, int prot, int flags, int fd,
__off_t offset)
{
return v4l1_mmap(start, length, prot, flags, fd, offset);
}
-void *mmap64(void *start, size_t length, int prot, int flags, int fd,
+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);
}
-int munmap(void *start, size_t length)
+LIBV4L_PUBLIC int munmap(void *start, size_t length)
{
return v4l1_munmap(start, length);
}
+
diff --git a/v4l2-apps/lib/libv4l/libv4l2/Makefile b/v4l2-apps/lib/libv4l/libv4l2/Makefile
index d8ac01c34..648d27c0c 100644
--- a/v4l2-apps/lib/libv4l/libv4l2/Makefile
+++ b/v4l2-apps/lib/libv4l/libv4l2/Makefile
@@ -1,7 +1,7 @@
-CPPFLAGS = -I../include -I../../../../linux/include
+override CPPFLAGS += -I../include -I../../../include -fvisibility=hidden
CFLAGS := -g -O1
-CFLAGS += -Wall -W -Wno-unused -Wpointer-arith -Wstrict-prototypes
+CFLAGS += -Wall -Wno-unused -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes
LIBS = -lpthread
@@ -17,7 +17,7 @@ else
V4L2_LIB = libv4l2.so
V4L2_OBJS += ../libv4lconvert/libv4lconvert.so
TARGETS += $(V4L2CONVERT)
-CPPFLAGS += -fPIC
+override CPPFLAGS += -fPIC
endif
ifeq ($(LIB_RELEASE),)
diff --git a/v4l2-apps/lib/libv4l/libv4l2/libv4l2.c b/v4l2-apps/lib/libv4l/libv4l2/libv4l2.c
index a40ab4ffe..7029f69c3 100644
--- a/v4l2-apps/lib/libv4l/libv4l2/libv4l2.c
+++ b/v4l2-apps/lib/libv4l/libv4l2/libv4l2.c
@@ -252,23 +252,54 @@ static int v4l2_queue_read_buffer(int index, int buffer_index)
return 0;
}
-static int v4l2_dequeue_read_buffer(int index, int *bytesused)
+static int v4l2_dequeue_and_convert(int index, struct v4l2_buffer *buf,
+ unsigned char *dest, int dest_size)
{
- int result;
- struct v4l2_buffer buf;
+ const int max_tries = 10;
+ int result, tries = max_tries;
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf.memory = V4L2_MEMORY_MMAP;
- if ((result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_DQBUF, &buf))) {
- int saved_err = errno;
- V4L2_LOG_ERR("dequeuing buf: %s\n", strerror(errno));
- errno = saved_err;
+ /* Make sure we have the real v4l2 buffers mapped */
+ if ((result = v4l2_map_buffers(index)))
return result;
+
+ do {
+ if ((result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_DQBUF, buf))) {
+ int saved_err = errno;
+ V4L2_LOG_ERR("dequeuing buf: %s\n", strerror(errno));
+ errno = saved_err;
+ return result;
+ }
+
+ devices[index].frame_queued &= ~(1 << buf->index);
+
+ result = v4lconvert_convert(devices[index].convert,
+ &devices[index].src_fmt, &devices[index].dest_fmt,
+ devices[index].frame_pointers[buf->index],
+ buf->bytesused, dest ? dest : (devices[index].convert_mmap_buf +
+ buf->index * V4L2_FRAME_BUF_SIZE), dest_size);
+
+ if (result < 0) {
+ int saved_err = errno;
+
+ if(errno == EAGAIN)
+ V4L2_LOG("warning error while converting frame data: %s\n",
+ v4lconvert_get_error_message(devices[index].convert));
+ else
+ V4L2_LOG_ERR("converting / decoding frame data: %s\n",
+ v4lconvert_get_error_message(devices[index].convert));
+
+ v4l2_queue_read_buffer(index, buf->index);
+ errno = saved_err;
+ }
+ tries--;
+ } while (result < 0 && errno == EAGAIN && tries);
+
+ if (result < 0 && errno == EAGAIN) {
+ V4L2_LOG_ERR("got %d consecutive frame decode errors, last error: %s\n",
+ max_tries, v4lconvert_get_error_message(devices[index].convert));
}
- devices[index].frame_queued &= ~(1 << buf.index);
- *bytesused = buf.bytesused;
- return buf.index;
+ return result;
}
static int v4l2_queue_read_buffers(int index)
@@ -614,7 +645,8 @@ int v4l2_ioctl (int fd, unsigned long int request, ...)
is_capture_request = 1;
break;
case VIDIOC_ENUM_FMT:
- if (((struct v4l2_fmtdesc *)arg)->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (((struct v4l2_fmtdesc *)arg)->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ (devices[index].flags & V4L2_ENABLE_ENUM_FMT_EMULATION))
is_capture_request = 1;
break;
case VIDIOC_TRY_FMT:
@@ -663,9 +695,8 @@ int v4l2_ioctl (int fd, unsigned long int request, ...)
if (stream_needs_locking)
pthread_mutex_lock(&devices[index].stream_lock);
- converting = devices[index].src_fmt.fmt.pix.pixelformat !=
- devices[index].dest_fmt.fmt.pix.pixelformat;
-
+ converting = v4lconvert_needs_conversion(devices[index].convert,
+ &devices[index].src_fmt, &devices[index].dest_fmt);
switch (request) {
case VIDIOC_QUERYCAP:
@@ -815,15 +846,16 @@ int v4l2_ioctl (int fd, unsigned long int request, ...)
if ((result = v4l2_deactivate_read_stream(index)))
break;
- result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_DQBUF, buf);
- if (result) {
- V4L2_LOG_ERR("dequeing buffer: %s\n", strerror(errno));
+ if (!converting) {
+ result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_DQBUF, buf);
+ if (result) {
+ int saved_err = errno;
+ V4L2_LOG_ERR("dequeuing buf: %s\n", strerror(errno));
+ errno = saved_err;
+ }
break;
}
- if (!converting)
- break;
-
/* An application can do a DQBUF before mmap-ing in the buffer,
but we need the buffer _now_ to write our converted data
to it! */
@@ -844,23 +876,9 @@ int v4l2_ioctl (int fd, unsigned long int request, ...)
}
}
- /* Make sure we have the real v4l2 buffers mapped before trying to
- read from them */
- if ((result = v4l2_map_buffers(index)))
- break;
-
- result = v4lconvert_convert(devices[index].convert,
- &devices[index].src_fmt, &devices[index].dest_fmt,
- devices[index].frame_pointers[buf->index],
- buf->bytesused,
- devices[index].convert_mmap_buf +
- buf->index * V4L2_FRAME_BUF_SIZE,
- V4L2_FRAME_BUF_SIZE);
- if (result < 0) {
- V4L2_LOG_ERR("converting / decoding frame data: %s\n",
- v4lconvert_get_error_message(devices[index].convert));
+ result = v4l2_dequeue_and_convert(index, buf, 0, V4L2_FRAME_BUF_SIZE);
+ if (result < 0)
break;
- }
buf->bytesused = result;
buf->m.offset = V4L2_MMAP_OFFSET_MAGIC | buf->index;
@@ -901,22 +919,23 @@ int v4l2_ioctl (int fd, unsigned long int request, ...)
}
-ssize_t v4l2_read (int fd, void* buffer, size_t n)
+ssize_t v4l2_read (int fd, void* dest, size_t n)
{
ssize_t result;
- int index, bytesused = 0, frame_index;
+ int index;
+ struct v4l2_buffer buf;
if ((index = v4l2_get_index(fd)) == -1)
- return syscall(SYS_read, fd, buffer, n);
+ return syscall(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) &&
- devices[index].src_fmt.fmt.pix.pixelformat ==
- devices[index].dest_fmt.fmt.pix.pixelformat) {
- result = syscall(SYS_read, fd, buffer, n);
+ !v4lconvert_needs_conversion(devices[index].convert,
+ &devices[index].src_fmt, &devices[index].dest_fmt)) {
+ result = syscall(SYS_read, fd, dest, n);
goto leave;
}
@@ -931,26 +950,12 @@ ssize_t v4l2_read (int fd, void* buffer, size_t n)
goto leave;
}
- if ((frame_index = v4l2_dequeue_read_buffer(index, &bytesused)) < 0) {
- result = -1;
- goto leave;
- }
-
- /* ensure buffers are mapped before using them (they could have been
- unmapped by a s_fmt ioctl) */
- if ((result = v4l2_map_buffers(index)))
- goto leave;
-
- result = v4lconvert_convert(devices[index].convert,
- &devices[index].src_fmt, &devices[index].dest_fmt,
- devices[index].frame_pointers[frame_index], bytesused,
- buffer, n);
-
- v4l2_queue_read_buffer(index, frame_index);
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.memory = V4L2_MEMORY_MMAP;
+ result = v4l2_dequeue_and_convert(index, &buf, dest, n);
- if (result < 0)
- V4L2_LOG_ERR("converting / decoding frame data: %s\n",
- v4lconvert_get_error_message(devices[index].convert));
+ if (result >= 0)
+ v4l2_queue_read_buffer(index, buf.index);
leave:
pthread_mutex_unlock(&devices[index].stream_lock);
@@ -988,8 +993,8 @@ 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 ?? */
- devices[index].src_fmt.fmt.pix.pixelformat ==
- devices[index].dest_fmt.fmt.pix.pixelformat) {
+ !v4lconvert_needs_conversion(devices[index].convert,
+ &devices[index].src_fmt, &devices[index].dest_fmt)) {
errno = EINVAL;
result = MAP_FAILED;
goto leave;
diff --git a/v4l2-apps/lib/libv4l/libv4l2/log.c b/v4l2-apps/lib/libv4l/libv4l2/log.c
index 05f6c46d7..6237d55ec 100644
--- a/v4l2-apps/lib/libv4l/libv4l2/log.c
+++ b/v4l2-apps/lib/libv4l/libv4l2/log.c
@@ -25,6 +25,8 @@
#include <asm/types.h>
/* end broken header workaround includes */
#include <linux/videodev2.h>
+#include "libv4l2.h"
+#include "libv4l2-priv.h"
#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
@@ -116,7 +118,7 @@ void v4l2_log_ioctl(unsigned long int request, void *arg, int result)
int pixfmt = fmt->fmt.pix.pixelformat;
if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- fprintf(v4l2_log_file, " pixelformat: %c%c%c%c %dx%d\n",
+ fprintf(v4l2_log_file, " pixelformat: %c%c%c%c %ux%u\n",
pixfmt & 0xff,
(pixfmt >> 8) & 0xff,
(pixfmt >> 16) & 0xff,
@@ -136,7 +138,7 @@ void v4l2_log_ioctl(unsigned long int request, void *arg, int result)
struct v4l2_requestbuffers *req = arg;
fprintf(v4l2_log_file, " count: %u type: %d memory: %d\n",
- req->count, req->type, req->memory);
+ req->count, (int)req->type, (int)req->memory);
}
break;
}
diff --git a/v4l2-apps/lib/libv4l/libv4l2/v4l2convert.c b/v4l2-apps/lib/libv4l/libv4l2/v4l2convert.c
index f312828c6..e8756f338 100644
--- a/v4l2-apps/lib/libv4l/libv4l2/v4l2convert.c
+++ b/v4l2-apps/lib/libv4l/libv4l2/v4l2convert.c
@@ -27,6 +27,8 @@
#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>
@@ -41,7 +43,13 @@
#error open/read/mmap is a prepocessor macro !!
#endif
-int open (const char *file, int oflag, ...)
+#if __GNUC__ >= 4
+#define LIBV4L_PUBLIC __attribute__ ((visibility("default")))
+#else
+#define LIBV4L_PUBLIC
+#endif
+
+LIBV4L_PUBLIC int open (const char *file, int oflag, ...)
{
int fd;
struct v4l2_capability cap;
@@ -84,7 +92,7 @@ int open (const char *file, int oflag, ...)
return fd;
}
-int open64(const char *file, int oflag, ...)
+LIBV4L_PUBLIC int open64(const char *file, int oflag, ...)
{
int fd;
@@ -107,17 +115,17 @@ int open64(const char *file, int oflag, ...)
return fd;
}
-int close(int fd)
+LIBV4L_PUBLIC int close(int fd)
{
return v4l2_close(fd);
}
-int dup(int fd)
+LIBV4L_PUBLIC int dup(int fd)
{
return v4l2_dup(fd);
}
-int ioctl (int fd, unsigned long int request, ...)
+LIBV4L_PUBLIC int ioctl (int fd, unsigned long int request, ...)
{
void *arg;
va_list ap;
@@ -129,24 +137,25 @@ int ioctl (int fd, unsigned long int request, ...)
return v4l2_ioctl (fd, request, arg);
}
-ssize_t read (int fd, void* buffer, size_t n)
+LIBV4L_PUBLIC ssize_t read (int fd, void* buffer, size_t n)
{
return v4l2_read (fd, buffer, n);
}
-void *mmap(void *start, size_t length, int prot, int flags, int fd,
+LIBV4L_PUBLIC void *mmap(void *start, size_t length, int prot, int flags, int fd,
__off_t offset)
{
return v4l2_mmap(start, length, prot, flags, fd, offset);
}
-void *mmap64(void *start, size_t length, int prot, int flags, int fd,
+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);
}
-int munmap(void *start, size_t length)
+LIBV4L_PUBLIC int munmap(void *start, size_t length)
{
return v4l2_munmap(start, length);
}
+
diff --git a/v4l2-apps/lib/libv4l/libv4lconvert/Makefile b/v4l2-apps/lib/libv4l/libv4lconvert/Makefile
index c2a5be942..641d19d6e 100644
--- a/v4l2-apps/lib/libv4l/libv4lconvert/Makefile
+++ b/v4l2-apps/lib/libv4l/libv4lconvert/Makefile
@@ -1,16 +1,16 @@
-CPPFLAGS = -I../include -I../../../../linux/include
+override CPPFLAGS += -I../include -I../../../include -fvisibility=hidden
CFLAGS := -g -O1
-CFLAGS += -Wall -W -Wno-unused -Wpointer-arith -Wstrict-prototypes
+CFLAGS += -Wall -Wno-unused -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes
ifeq ($(LINKTYPE),static)
CONVERT_LIB = libv4lconvert.a
else
CONVERT_LIB = libv4lconvert.so
-CPPFLAGS += -fPIC
+override CPPFLAGS += -fPIC
endif
-CONVERT_OBJS = libv4lconvert.o tinyjpeg.o sn9c10x.o pac207.o \
+CONVERT_OBJS = libv4lconvert.o tinyjpeg.o sn9c10x.o pac207.o flip.o \
jidctflt.o spca561-decompress.o rgbyuv.o spca501.o bayer.o
TARGETS = $(CONVERT_LIB) libv4lconvert.pc
INCLUDES = ../include/libv4lconvert.h
diff --git a/v4l2-apps/lib/libv4l/libv4lconvert/flip.c b/v4l2-apps/lib/libv4l/libv4lconvert/flip.c
new file mode 100644
index 000000000..cd3468a89
--- /dev/null
+++ b/v4l2-apps/lib/libv4l/libv4lconvert/flip.c
@@ -0,0 +1,107 @@
+/*
+
+# RGB / YUV flip/rotate routines
+
+# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+#include "libv4lconvert-priv.h"
+
+void v4lconvert_rotate180_rgbbgr24(const unsigned char *src, unsigned char *dst,
+ int width, int height)
+{
+ int i;
+
+ src += 3 * width * height - 3;
+
+ for (i = 0; i < width * height; i++) {
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst += 3;
+ src -= 3;
+ }
+}
+
+void v4lconvert_rotate180_yuv420(const unsigned char *src, unsigned char *dst,
+ int width, int height)
+{
+ int i;
+
+ /* First flip x and y of the Y plane */
+ src += width * height - 1;
+ for (i = 0; i < width * height; i++)
+ *dst++ = *src--;
+
+ /* Now flip the U plane */
+ src += width * height * 5 / 4;
+ for (i = 0; i < width * height / 4; i++)
+ *dst++ = *src--;
+
+ /* Last flip the V plane */
+ src += width * height / 2;
+ for (i = 0; i < width * height / 4; i++)
+ *dst++ = *src--;
+}
+
+void v4lconvert_rotate90_rgbbgr24(const unsigned char *src, unsigned char *dst,
+ int destwidth, int destheight)
+{
+ int x, y;
+#define srcwidth destheight
+#define srcheight destwidth
+
+ for (y = 0; y < destheight; y++)
+ for (x = 0; x < destwidth; x++) {
+ int offset = ((srcheight - x - 1) * srcwidth + y) * 3;
+ *dst++ = src[offset++];
+ *dst++ = src[offset++];
+ *dst++ = src[offset];
+ }
+}
+
+void v4lconvert_rotate90_yuv420(const unsigned char *src, unsigned char *dst,
+ int destwidth, int destheight)
+{
+ int x, y;
+
+ /* Y-plane */
+ for (y = 0; y < destheight; y++)
+ for (x = 0; x < destwidth; x++) {
+ int offset = (srcheight - x - 1) * srcwidth + y;
+ *dst++ = src[offset];
+ }
+
+ /* U-plane */
+ src += srcwidth * srcheight;
+ destwidth /= 2;
+ destheight /= 2;
+ for (y = 0; y < destheight; y++)
+ for (x = 0; x < destwidth; x++) {
+ int offset = (srcheight - x - 1) * srcwidth + y;
+ *dst++ = src[offset];
+ }
+
+ /* V-plane */
+ src += srcwidth * srcheight;
+ for (y = 0; y < destheight; y++)
+ for (x = 0; x < destwidth; x++) {
+ int offset = (srcheight - x - 1) * srcwidth + y;
+ *dst++ = src[offset];
+ }
+}
diff --git a/v4l2-apps/lib/libv4l/libv4lconvert/jidctflt.c b/v4l2-apps/lib/libv4l/libv4lconvert/jidctflt.c
index ba70309c9..532abc7ea 100644
--- a/v4l2-apps/lib/libv4l/libv4lconvert/jidctflt.c
+++ b/v4l2-apps/lib/libv4l/libv4lconvert/jidctflt.c
@@ -80,7 +80,7 @@
#define DEQUANTIZE(coef,quantval) (((FAST_FLOAT) (coef)) * (quantval))
-#if defined(__GNUC__) && (defined(__i686__)) // || defined(__x86_64__))
+#if defined(__GNUC__) && (defined(__i686__) || defined(__x86_64__))
static inline unsigned char descale_and_clamp(int x, int shift)
{
@@ -92,7 +92,7 @@ static inline unsigned char descale_and_clamp(int x, int shift)
"\tcmpl %4,%1\n"
"\tcmovg %4,%1\n"
: "=r"(x)
- : "0"(x), "Ic"((unsigned char)shift), "ir"(1UL<<(shift-1)), "r" (0xff), "r" (0)
+ : "0"(x), "Ic"((unsigned char)shift), "ir"(1U<<(shift-1)), "r" (0xff), "r" (0)
);
return x;
}
diff --git a/v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert-priv.h b/v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert-priv.h
index bdf847186..915c33283 100644
--- a/v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert-priv.h
+++ b/v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert-priv.h
@@ -43,6 +43,10 @@
#define V4L2_PIX_FMT_PAC207 v4l2_fourcc('P','2','0','7')
#endif
+#ifndef V4L2_PIX_FMT_PJPG
+#define V4L2_PIX_FMT_PJPG v4l2_fourcc('P', 'J', 'P', 'G')
+#endif
+
#ifndef V4L2_PIX_FMT_SGBRG8
#define V4L2_PIX_FMT_SGBRG8 v4l2_fourcc('G','B','R','G')
#endif
@@ -61,15 +65,21 @@
snprintf(data->error_msg, V4LCONVERT_ERROR_MSG_SIZE, \
"v4l-convert: error " __VA_ARGS__)
+#define V4LCONVERT_UPSIDE_DOWN 0x01
struct v4lconvert_data {
int fd;
+ int flags; /* bitfield */
int supported_src_formats; /* bitfield */
unsigned int no_formats;
char error_msg[V4LCONVERT_ERROR_MSG_SIZE];
struct jdec_private *jdec;
};
+struct v4lconvert_flags_info {
+ const char *card;
+ int flags;
+};
void v4lconvert_yuv420_to_rgb24(const unsigned char *src, unsigned char *dst,
int width, int height);
@@ -107,4 +117,16 @@ void v4lconvert_bayer_to_bgr24(const unsigned char *bayer,
void v4lconvert_bayer_to_yuv420(const unsigned char *bayer,
unsigned char *yuv, int width, int height, unsigned int pixfmt);
+void v4lconvert_rotate90_rgbbgr24(const unsigned char *src, unsigned char *dst,
+ int destwidth, int destheight);
+
+void v4lconvert_rotate90_yuv420(const unsigned char *src, unsigned char *dst,
+ int destwidth, int destheight);
+
+void v4lconvert_rotate180_rgbbgr24(const unsigned char *src, unsigned char *dst,
+ int width, int height);
+
+void v4lconvert_rotate180_yuv420(const unsigned char *src, unsigned char *dst,
+ int width, int height);
+
#endif
diff --git a/v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert.c
index 4c9e67d52..4b48bfac4 100644
--- a/v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert.c
+++ b/v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert.c
@@ -48,17 +48,26 @@ static const unsigned int supported_src_pixfmts[] = {
V4L2_PIX_FMT_SPCA561,
V4L2_PIX_FMT_SN9C10X,
V4L2_PIX_FMT_PAC207,
+ V4L2_PIX_FMT_PJPG,
};
static const unsigned int supported_dst_pixfmts[] = {
SUPPORTED_DST_PIXFMTS
};
+/* List of cams which need special flags */
+static const struct v4lconvert_flags_info v4lconvert_flags[] = {
+ { "USB Camera (0471:0325)", V4LCONVERT_UPSIDE_DOWN }, /* SPC200NC */
+ { "USB Camera (0471:0326)", V4LCONVERT_UPSIDE_DOWN }, /* SPC300NC */
+ { "SPC 200NC ", V4LCONVERT_UPSIDE_DOWN },
+ { "SPC 300NC ", V4LCONVERT_UPSIDE_DOWN },
+};
struct v4lconvert_data *v4lconvert_create(int fd)
{
int i, j;
struct v4lconvert_data *data = calloc(1, sizeof(struct v4lconvert_data));
+ struct v4l2_capability cap;
if (!data)
return NULL;
@@ -84,6 +93,15 @@ struct v4lconvert_data *v4lconvert_create(int fd)
data->no_formats = i;
+ /* Check if this cam has any special flags */
+ if (syscall(SYS_ioctl, fd, VIDIOC_QUERYCAP, &cap) == 0) {
+ for (i = 0; i < ARRAY_SIZE(v4lconvert_flags); i++)
+ if (!strcmp((const char *)v4lconvert_flags[i].card, (char *)cap.card)) {
+ data->flags = v4lconvert_flags[i].flags;
+ break;
+ }
+ }
+
return data;
}
@@ -214,17 +232,42 @@ int v4lconvert_try_format(struct v4lconvert_data *data,
return 0;
}
+/* Is conversion necessary ? */
+int v4lconvert_needs_conversion(struct v4lconvert_data *data,
+ const struct v4l2_format *src_fmt, /* in */
+ const struct v4l2_format *dest_fmt) /* in */
+{
+ int i;
+
+ if(memcmp(src_fmt, dest_fmt, sizeof(*src_fmt)))
+ return 1; /* Formats differ */
+
+ if (!(data->flags & V4LCONVERT_UPSIDE_DOWN))
+ return 0; /* Formats identical and we don't need flip */
+
+ /* Formats are identical, but we need flip, do we support the dest_fmt? */
+ for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++)
+ if (supported_dst_pixfmts[i] == dest_fmt->fmt.pix.pixelformat)
+ break;
+
+ if (i == ARRAY_SIZE(supported_dst_pixfmts))
+ return 0; /* Needs flip but we cannot do it :( */
+ else
+ return 1; /* Needs flip and thus conversion */
+}
+
int v4lconvert_convert(struct v4lconvert_data *data,
const struct v4l2_format *src_fmt, /* in */
const struct v4l2_format *dest_fmt, /* in */
- unsigned char *src, int src_size, unsigned char *dest, int dest_size)
+ unsigned char *src, int src_size, unsigned char *_dest, int dest_size)
{
unsigned int header_width, header_height;
- int result, needed;
+ int result, needed, rotate = 0, jpeg_flags = TINYJPEG_FLAGS_MJPEG_TABLE;
unsigned char *components[3];
+ unsigned char *dest = _dest;
/* Special case when no conversion is needed */
- if(!memcmp(src_fmt, dest_fmt, sizeof(*src_fmt))) {
+ if (!v4lconvert_needs_conversion(data, src_fmt, dest_fmt)) {
int to_copy = MIN(dest_size, src_size);
memcpy(dest, src, to_copy);
return to_copy;
@@ -251,7 +294,15 @@ int v4lconvert_convert(struct v4lconvert_data *data,
return -1;
}
+ if (data->flags & V4LCONVERT_UPSIDE_DOWN) {
+ rotate = 180;
+ dest = alloca(needed);
+ }
+
switch (src_fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_PJPG:
+ jpeg_flags |= TINYJPEG_FLAGS_PIXART_JPEG;
+ /* Fall through */
case V4L2_PIX_FMT_MJPEG:
case V4L2_PIX_FMT_JPEG:
if (!data->jdec) {
@@ -262,9 +313,7 @@ int v4lconvert_convert(struct v4lconvert_data *data,
return -1;
}
}
- tinyjpeg_set_flags(data->jdec,
- (src_fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG)?
- TINYJPEG_FLAGS_MJPEG_TABLE : 0);
+ tinyjpeg_set_flags(data->jdec, jpeg_flags);
if (tinyjpeg_parse_header(data->jdec, src, src_size)) {
V4LCONVERT_ERR("parsing JPEG header: %s\n",
tinyjpeg_get_errorstring(data->jdec));
@@ -273,13 +322,22 @@ int v4lconvert_convert(struct v4lconvert_data *data,
}
tinyjpeg_get_size(data->jdec, &header_width, &header_height);
- if (header_width != dest_fmt->fmt.pix.width || header_height != dest_fmt->fmt.pix.height) {
- V4LCONVERT_ERR("unexpected width / height in JPEG header\n");
- V4LCONVERT_ERR("expected: %dx%d, header: %ux%u\n",
- dest_fmt->fmt.pix.width, dest_fmt->fmt.pix.height,
- header_width, header_height);
- errno = EIO;
- return -1;
+ if (header_width != dest_fmt->fmt.pix.width ||
+ header_height != dest_fmt->fmt.pix.height) {
+ /* Check for (pixart) rotated JPEG */
+ if (header_width == dest_fmt->fmt.pix.height ||
+ header_height == dest_fmt->fmt.pix.width) {
+ if (!rotate)
+ dest = alloca(needed);
+ rotate += 90;
+ } else {
+ V4LCONVERT_ERR("unexpected width / height in JPEG header"
+ "expected: %ux%u, header: %ux%u\n",
+ dest_fmt->fmt.pix.width, dest_fmt->fmt.pix.height,
+ header_width, header_height);
+ errno = EIO;
+ return -1;
+ }
}
components[0] = dest;
@@ -303,13 +361,24 @@ int v4lconvert_convert(struct v4lconvert_data *data,
break;
}
- /* If the JPEG header checked out ok and we get an error during actual
- decompression, log the error, but don't return an errorcode to the
- application, so that the user gets what we managed to decompress */
- if (result)
- fprintf(stderr, "libv4lconvert: Error decompressing JPEG: %s",
- tinyjpeg_get_errorstring(data->jdec));
-
+ if (result) {
+ /* Pixart webcam's seem to regulary generate corrupt frames, which
+ 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_fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_PJPG) {
+ V4LCONVERT_ERR("Error decompressing JPEG: %s",
+ tinyjpeg_get_errorstring(data->jdec));
+ errno = EAGAIN;
+ return -1;
+ } else {
+ /* If the JPEG header checked out ok and we get an error during actual
+ decompression, log the error, but don't return an errorcode to the
+ application, so that the user gets what we managed to decompress */
+ fprintf(stderr, "libv4lconvert: Error decompressing JPEG: %s",
+ tinyjpeg_get_errorstring(data->jdec));
+ }
+ }
break;
case V4L2_PIX_FMT_SBGGR8:
@@ -387,7 +456,7 @@ int v4lconvert_convert(struct v4lconvert_data *data,
case V4L2_PIX_FMT_SN9C10X:
v4lconvert_decode_sn9c10x(src, tmpbuf, dest_fmt->fmt.pix.width,
dest_fmt->fmt.pix.height);
- bayer_fmt = V4L2_PIX_FMT_SGBRG8;
+ bayer_fmt = V4L2_PIX_FMT_SBGGR8;
break;
case V4L2_PIX_FMT_PAC207:
v4lconvert_decode_pac207(src, tmpbuf, dest_fmt->fmt.pix.width,
@@ -455,6 +524,45 @@ int v4lconvert_convert(struct v4lconvert_data *data,
return -1;
}
+ /* Note when rotating dest is our temporary buffer to which our conversion
+ was done and _dest is the real dest! If the formats are identical no
+ conversion has been done! */
+ if (rotate && dest_fmt->fmt.pix.pixelformat == src_fmt->fmt.pix.pixelformat)
+ dest = src;
+
+ switch (rotate) {
+ case 0:
+ break;
+ case 90:
+ switch (dest_fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_BGR24:
+ v4lconvert_rotate90_rgbbgr24(dest, _dest, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height);
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ v4lconvert_rotate90_yuv420(dest, _dest, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height);
+ break;
+ }
+ break;
+ case 180:
+ switch (dest_fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_BGR24:
+ v4lconvert_rotate180_rgbbgr24(dest, _dest, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height);
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ v4lconvert_rotate180_yuv420(dest, _dest, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height);
+ break;
+ }
+ break;
+ default:
+ printf("FIXME add %d degrees rotation\n", rotate);
+ }
+
return needed;
}
diff --git a/v4l2-apps/lib/libv4l/libv4lconvert/pac207.c b/v4l2-apps/lib/libv4l/libv4lconvert/pac207.c
index 4887c25ee..97ef4ebc0 100644
--- a/v4l2-apps/lib/libv4l/libv4lconvert/pac207.c
+++ b/v4l2-apps/lib/libv4l/libv4lconvert/pac207.c
@@ -38,7 +38,7 @@ static struct {
signed char val;
} table[256];
-void init_pixart_decoder(void)
+static void init_pixart_decoder(void)
{
int i;
int is_abs, val, len;
diff --git a/v4l2-apps/lib/libv4l/libv4lconvert/rgbyuv.c b/v4l2-apps/lib/libv4l/libv4lconvert/rgbyuv.c
index 742dd06ce..883d62330 100644
--- a/v4l2-apps/lib/libv4l/libv4lconvert/rgbyuv.c
+++ b/v4l2-apps/lib/libv4l/libv4lconvert/rgbyuv.c
@@ -20,6 +20,8 @@
*/
+#include "libv4lconvert-priv.h"
+
#define RGB2YUV(r,g,b,y,u,v) \
(y) = (( 8453*(r) + 16594*(g) + 3223*(b) + 524288) >> 15); \
(u) = (( -4878*(r) - 9578*(g) + 14456*(b) + 4210688) >> 15); \
diff --git a/v4l2-apps/lib/libv4l/libv4lconvert/sn9c10x.c b/v4l2-apps/lib/libv4l/libv4lconvert/sn9c10x.c
index 98a513378..4ea526d49 100644
--- a/v4l2-apps/lib/libv4l/libv4lconvert/sn9c10x.c
+++ b/v4l2-apps/lib/libv4l/libv4lconvert/sn9c10x.c
@@ -50,7 +50,7 @@ static int sonix_unknown = 0;
present at the MSB of byte x.
*/
-void sonix_decompress_init(void)
+static void sonix_decompress_init(void)
{
int i;
int is_abs, val, len, unk;
diff --git a/v4l2-apps/lib/libv4l/libv4lconvert/spca561-decompress.c b/v4l2-apps/lib/libv4l/libv4lconvert/spca561-decompress.c
index 802345af0..01eed4ec5 100644
--- a/v4l2-apps/lib/libv4l/libv4lconvert/spca561-decompress.c
+++ b/v4l2-apps/lib/libv4l/libv4lconvert/spca561-decompress.c
@@ -28,6 +28,7 @@
* but it might work with other spca561 cameras
*/
#include <string.h>
+#include "libv4lconvert-priv.h"
/*fixme: not reentrant */
static unsigned int bit_bucket;
diff --git a/v4l2-apps/lib/libv4l/libv4lconvert/tinyjpeg.c b/v4l2-apps/lib/libv4l/libv4lconvert/tinyjpeg.c
index 5c3b4e26d..fc9efbeb2 100644
--- a/v4l2-apps/lib/libv4l/libv4lconvert/tinyjpeg.c
+++ b/v4l2-apps/lib/libv4l/libv4lconvert/tinyjpeg.c
@@ -214,6 +214,28 @@ static const unsigned char val_ac_chrominance[] =
0xf9, 0xfa
};
+const unsigned char pixart_quantization[][64] = {
+ {
+ 0x07, 0x07, 0x08, 0x0a, 0x09, 0x07, 0x0d, 0x0b,
+ 0x0c, 0x0d, 0x11, 0x10, 0x0f, 0x12, 0x17, 0x27,
+ 0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25,
+ 0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33,
+ 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44,
+ 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57,
+ 0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71,
+ 0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63,
+ },
+ {
+ 0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a,
+ 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63,
+ 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+ 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+ 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+ 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+ 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+ 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+ },
+};
/*
* 4 functions to manage the stream
@@ -246,7 +268,7 @@ static const unsigned char val_ac_chrominance[] =
unsigned char c; \
if (stream >= priv->stream_end) { \
snprintf(priv->error_string, sizeof(priv->error_string), \
- "fill_nbits error: need %d more bits\n", \
+ "fill_nbits error: need %u more bits\n", \
nbits_wanted - nbits_in_reservoir); \
longjmp(priv->jump_state, -EIO); \
} \
@@ -288,6 +310,74 @@ static const unsigned char val_ac_chrominance[] =
} while(0);
+/* Special Pixart versions of the *_nbits functions, these remove the special
+ ff ff ff xx sequences pixart cams insert from the bitstream */
+#define pixart_fill_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted) \
+do { \
+ while (nbits_in_reservoir<nbits_wanted) \
+ { \
+ unsigned char c; \
+ if (stream >= priv->stream_end) { \
+ snprintf(priv->error_string, sizeof(priv->error_string), \
+ "fill_nbits error: need %u more bits\n", \
+ nbits_wanted - nbits_in_reservoir); \
+ longjmp(priv->jump_state, -EIO); \
+ } \
+ c = *stream++; \
+ reservoir <<= 8; \
+ if (c == 0xff) { \
+ switch (stream[0]) { \
+ case 0x00: \
+ stream++; \
+ break; \
+ case 0xd9: /* EOF marker */ \
+ stream++; \
+ if (stream != priv->stream_end) { \
+ snprintf(priv->error_string, sizeof(priv->error_string), \
+ "Pixart JPEG error: premature EOF\n"); \
+ longjmp(priv->jump_state, -EIO); \
+ } \
+ break; \
+ case 0xff: \
+ if (stream[1] == 0xff && (stream[2] < 7 || stream[2] == 0xff)) { \
+ stream += 3; \
+ c = *stream++; \
+ break; \
+ } \
+ /* Error fall through */ \
+ default: \
+ snprintf(priv->error_string, sizeof(priv->error_string), \
+ "Pixart JPEG error: invalid JPEG marker: 0xff 0x%02x 0x%02x 0x%02x\n", \
+ (unsigned int)stream[0], (unsigned int)stream[1], \
+ (unsigned int)stream[2]); \
+ longjmp(priv->jump_state, -EIO); \
+ } \
+ } \
+ reservoir |= c; \
+ nbits_in_reservoir+=8; \
+ } \
+} while(0);
+
+/* Signed version !!!! */
+#define pixart_get_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted,result) \
+do { \
+ pixart_fill_nbits(reservoir,nbits_in_reservoir,stream,(nbits_wanted)); \
+ result = ((reservoir)>>(nbits_in_reservoir-(nbits_wanted))); \
+ nbits_in_reservoir -= (nbits_wanted); \
+ reservoir &= ((1U<<nbits_in_reservoir)-1); \
+ if ((unsigned int)result < (1UL<<((nbits_wanted)-1))) \
+ result += (0xFFFFFFFFUL<<(nbits_wanted))+1; \
+} while(0);
+
+#define pixart_look_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted,result) \
+do { \
+ pixart_fill_nbits(reservoir,nbits_in_reservoir,stream,(nbits_wanted)); \
+ result = ((reservoir)>>(nbits_in_reservoir-(nbits_wanted))); \
+} while(0);
+
+/* Note skip_nbits is identical for both */
+
+
#define be16_to_cpu(x) (((x)[0]<<8)|(x)[1])
static void resync(struct jdec_private *priv);
@@ -334,9 +424,50 @@ static int get_next_huffman_code(struct jdec_private *priv, struct huffman_table
slowtable+=2;
}
}
+ snprintf(priv->error_string, sizeof(priv->error_string),
+ "unknown huffman code: %08x\n", (unsigned int)hcode);
+ longjmp(priv->jump_state, -EIO);
return 0;
}
+/* identical as above but with *_nbits replaced with pixart_*_nbits */
+static int pixart_get_next_huffman_code(struct jdec_private *priv,
+ struct huffman_table *huffman_table)
+{
+ int value, hcode;
+ unsigned int extra_nbits, nbits;
+ uint16_t *slowtable;
+
+ pixart_look_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, HUFFMAN_HASH_NBITS, hcode);
+ value = huffman_table->lookup[hcode];
+ if (value >= 0)
+ {
+ unsigned int code_size = huffman_table->code_size[value];
+ skip_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, code_size);
+ return value;
+ }
+
+ /* Decode more bits each time ... */
+ for (extra_nbits=0; extra_nbits<16-HUFFMAN_HASH_NBITS; extra_nbits++)
+ {
+ nbits = HUFFMAN_HASH_NBITS + 1 + extra_nbits;
+
+ pixart_look_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, nbits, hcode);
+ slowtable = huffman_table->slowtable[extra_nbits];
+ /* Search if the code is in this array */
+ while (slowtable[0]) {
+ if (slowtable[0] == hcode) {
+ skip_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, nbits);
+ return slowtable[1];
+ }
+ slowtable+=2;
+ }
+ }
+ snprintf(priv->error_string, sizeof(priv->error_string),
+ "unknown huffman code: %08x\n", (unsigned int)hcode);
+ longjmp(priv->jump_state, -EIO);
+ return 0;
+}
@@ -388,15 +519,84 @@ static void process_Huffman_data_unit(struct jdec_private *priv, int component)
else
{
j += count_0; /* skip count_0 zeroes */
- get_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, size_val, DCT[j]);
- j++;
+ if (j < 64) {
+ get_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, size_val, DCT[j]);
+ j++;
+ }
}
}
+ if (j > 64) {
+ snprintf(priv->error_string, sizeof(priv->error_string),
+ "error: more then 63 AC components (%d) in huffman unit\n", (int)j);
+ longjmp(priv->jump_state, -EIO);
+ }
+
for (j = 0; j < 64; j++)
c->DCT[j] = DCT[zigzag[j]];
}
+/* identical as above both with *_nbits replaced with pixart_*_nbits */
+static void pixart_process_Huffman_data_unit(struct jdec_private *priv, int component)
+{
+ unsigned char j;
+ unsigned int huff_code;
+ unsigned char size_val, count_0;
+
+ struct component *c = &priv->component_infos[component];
+ short int DCT[64];
+
+ /* Initialize the DCT coef table */
+ memset(DCT, 0, sizeof(DCT));
+
+ /* DC coefficient decoding */
+ huff_code = pixart_get_next_huffman_code(priv, c->DC_table);
+ if (huff_code) {
+ pixart_get_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, huff_code, DCT[0]);
+ DCT[0] += c->previous_DC;
+ c->previous_DC = DCT[0];
+ } else {
+ DCT[0] = c->previous_DC;
+ }
+
+
+ /* AC coefficient decoding */
+ j = 1;
+ while (j<64)
+ {
+ huff_code = pixart_get_next_huffman_code(priv, c->AC_table);
+
+ size_val = huff_code & 0xF;
+ count_0 = huff_code >> 4;
+
+ if (size_val == 0)
+ { /* RLE */
+ if (count_0 == 0)
+ break; /* EOB found, go out */
+ else if (count_0 == 0xF)
+ j += 16; /* skip 16 zeros */
+ }
+ else
+ {
+ j += count_0; /* skip count_0 zeroes */
+ if (j < 64 ) {
+ pixart_get_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, size_val, DCT[j]);
+ j++;
+ }
+ }
+ }
+
+ if (j > 64) {
+ snprintf(priv->error_string, sizeof(priv->error_string),
+ "error: more then 63 AC components (%d) in huffman unit\n", (int)j);
+ longjmp(priv->jump_state, -EIO);
+ }
+
+ for (j = 0; j < 64; j++)
+ c->DCT[j] = DCT[zigzag[j]];
+}
+
+
/*
* Takes two array of bits, and build the huffman table for size, and code
*
@@ -404,12 +604,13 @@ static void process_Huffman_data_unit(struct jdec_private *priv, int component)
* code_size will be used to known how many bits this symbol is encoded.
* slowtable will be used when the first lookup didn't give the result.
*/
-static void build_huffman_table(const unsigned char *bits, const unsigned char *vals, struct huffman_table *table)
+static int build_huffman_table(struct jdec_private *priv, const unsigned char *bits, const unsigned char *vals, struct huffman_table *table)
{
unsigned int i, j, code, code_size, val, nbits;
unsigned char huffsize[257], *hz;
unsigned int huffcode[257], *hc;
int next_free_entry;
+ int slowtable_used[16-HUFFMAN_HASH_NBITS];
/*
* Build a temp array
@@ -425,7 +626,7 @@ static void build_huffman_table(const unsigned char *bits, const unsigned char *
memset(table->lookup, 0xff, sizeof(table->lookup));
for (i=0; i<(16-HUFFMAN_HASH_NBITS); i++)
- table->slowtable[i][0] = 0;
+ slowtable_used[i] = 0;
/* Build a temp array
* huffcode[X] => code used to write vals[X]
@@ -472,32 +673,43 @@ static void build_huffman_table(const unsigned char *bits, const unsigned char *
else
{
/* Perhaps sorting the array will be an optimization */
- uint16_t *slowtable = table->slowtable[code_size-HUFFMAN_HASH_NBITS-1];
- while(slowtable[0])
- slowtable+=2;
- slowtable[0] = code;
- slowtable[1] = val;
- slowtable[2] = 0;
- /* TODO: NEED TO CHECK FOR AN OVERFLOW OF THE TABLE */
- }
+ int slowtable_index = code_size-HUFFMAN_HASH_NBITS-1;
+
+ if (slowtable_used[slowtable_index] == 254)
+ error("slow Huffman table overflow\n");
+ table->slowtable[slowtable_index][slowtable_used[slowtable_index]]
+ = code;
+ table->slowtable[slowtable_index][slowtable_used[slowtable_index] + 1]
+ = val;
+ slowtable_used[slowtable_index] += 2;
+ }
}
+ for (i=0; i<(16-HUFFMAN_HASH_NBITS); i++)
+ table->slowtable[i][slowtable_used[i]] = 0;
+
+ return 0;
}
-static void build_default_huffman_tables(struct jdec_private *priv)
+static int build_default_huffman_tables(struct jdec_private *priv)
{
if ( (priv->flags & TINYJPEG_FLAGS_MJPEG_TABLE)
&& priv->default_huffman_table_initialized)
- return;
+ return 0;
- build_huffman_table(bits_dc_luminance, val_dc_luminance, &priv->HTDC[0]);
- build_huffman_table(bits_ac_luminance, val_ac_luminance, &priv->HTAC[0]);
+ if (build_huffman_table(priv, bits_dc_luminance, val_dc_luminance, &priv->HTDC[0]))
+ return -1;
+ if (build_huffman_table(priv, bits_ac_luminance, val_ac_luminance, &priv->HTAC[0]))
+ return -1;
- build_huffman_table(bits_dc_chrominance, val_dc_chrominance, &priv->HTDC[1]);
- build_huffman_table(bits_ac_chrominance, val_ac_chrominance, &priv->HTAC[1]);
+ if (build_huffman_table(priv, bits_dc_chrominance, val_dc_chrominance, &priv->HTDC[1]))
+ return -1;
+ if (build_huffman_table(priv, bits_ac_chrominance, val_ac_chrominance, &priv->HTAC[1]))
+ return -1;
priv->default_huffman_table_initialized = 1;
+ return 0;
}
@@ -1390,6 +1602,44 @@ static void decode_MCU_2x1_3planes(struct jdec_private *priv)
IDCT(&priv->component_infos[cCr], priv->Cr, 8);
}
+static void pixart_decode_MCU_2x1_3planes(struct jdec_private *priv)
+{
+ unsigned char marker;
+
+ pixart_look_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream,
+ 8, marker);
+ /* I think the marker indicates which quantization table to use, iow
+ a Pixart JPEG may have a different quantization table per MCU, most
+ MCU's have 0x44 as marker for which our special Pixart quantization
+ tables are correct. Unfortunately with a 7302 some blocks also have 0x48,
+ and sometimes even other values. As 0x48 is quite common too, we really
+ need to find out the correct table for that, as currently the blocks
+ with a 0x48 marker look wrong. During normal operation the marker stays
+ within the range below, if it gets out of this range we're most likely
+ decoding garbage */
+ if (marker < 0x20 || marker > 0x7f) {
+ snprintf(priv->error_string, sizeof(priv->error_string),
+ "Pixart JPEG error: invalid MCU marker: 0x%02x\n",
+ (unsigned int)marker);
+ longjmp(priv->jump_state, -EIO);
+ }
+ skip_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, 8);
+
+ // Y
+ pixart_process_Huffman_data_unit(priv, cY);
+ IDCT(&priv->component_infos[cY], priv->Y, 16);
+ pixart_process_Huffman_data_unit(priv, cY);
+ IDCT(&priv->component_infos[cY], priv->Y+8, 16);
+
+ // Cb
+ pixart_process_Huffman_data_unit(priv, cCb);
+ IDCT(&priv->component_infos[cCb], priv->Cb, 8);
+
+ // Cr
+ pixart_process_Huffman_data_unit(priv, cCr);
+ IDCT(&priv->component_infos[cCr], priv->Cr, 8);
+}
+
/*
* Decode a 2x1
* .-------.
@@ -1676,9 +1926,9 @@ static int parse_SOS(struct jdec_private *priv, const unsigned char *stream)
error("We do not support more than %d DC Huffman table\n",
HUFFMAN_TABLES);
if (cid != priv->component_infos[i].cid)
- error("SOS cid order (%d:%d) isn't compatible with the SOF marker (%d:%d)\n",
+ error("SOS cid order (%u:%u) isn't compatible with the SOF marker (%u:%u)\n",
i, cid, i, priv->component_infos[i].cid);
- trace("ComponentId:%d tableAC:%d tableDC:%d\n", cid, table&0xf, table>>4);
+ trace("ComponentId:%u tableAC:%d tableDC:%d\n", cid, table&0xf, table>>4);
#endif
priv->component_infos[i].AC_table = &priv->HTAC[table&0xf];
priv->component_infos[i].DC_table = &priv->HTDC[table>>4];
@@ -1723,10 +1973,13 @@ static int parse_DHT(struct jdec_private *priv, const unsigned char *stream)
trace("Length of the table: %d\n", count);
#endif
- if (index & 0xf0 )
- build_huffman_table(huff_bits, stream, &priv->HTAC[index&0xf]);
- else
- build_huffman_table(huff_bits, stream, &priv->HTDC[index&0xf]);
+ if (index & 0xf0 ) {
+ if (build_huffman_table(priv, huff_bits, stream, &priv->HTAC[index&0xf]))
+ return -1;
+ } else {
+ if (build_huffman_table(priv, huff_bits, stream, &priv->HTDC[index&0xf]))
+ return -1;
+ }
length -= 1;
length -= 16;
@@ -1817,6 +2070,8 @@ static int parse_JFIF(struct jdec_private *priv, const unsigned char *stream)
{
int chuck_len;
int marker;
+ int sof_marker_found = 0;
+ int dqt_marker_found = 0;
int sos_marker_found = 0;
int dht_marker_found = 0;
const unsigned char *next_chunck;
@@ -1838,10 +2093,12 @@ static int parse_JFIF(struct jdec_private *priv, const unsigned char *stream)
case SOF:
if (parse_SOF(priv, stream) < 0)
return -1;
+ sof_marker_found = 1;
break;
case DQT:
if (parse_DQT(priv, stream) < 0)
return -1;
+ dqt_marker_found = 1;
break;
case SOS:
if (parse_SOS(priv, stream) < 0)
@@ -1865,9 +2122,24 @@ static int parse_JFIF(struct jdec_private *priv, const unsigned char *stream)
stream = next_chunck;
}
+ if ( !sof_marker_found ||
+ (!dqt_marker_found && !(priv->flags & TINYJPEG_FLAGS_PIXART_JPEG)))
+ goto bogus_jpeg_format;
+
+ if (priv->flags & TINYJPEG_FLAGS_PIXART_JPEG) {
+ if (!priv->default_huffman_table_initialized) {
+ build_quantization_table(priv->Q_tables[0], pixart_quantization[0]);
+ build_quantization_table(priv->Q_tables[1], pixart_quantization[1]);
+ }
+
+ /* Pixart JPEG data starts with one unknown / unused byte */
+ priv->stream++;
+ }
+
if (!dht_marker_found) {
trace("No Huffman table loaded, using the default one\n");
- build_default_huffman_tables(priv);
+ if (build_default_huffman_tables(priv))
+ return -1;
}
#ifdef SANITY_CHECK
@@ -1962,6 +2234,13 @@ static const decode_MCU_fct decode_mcu_3comp_table[4] = {
decode_MCU_2x2_3planes,
};
+static const decode_MCU_fct pixart_decode_mcu_3comp_table[4] = {
+ NULL,
+ NULL,
+ pixart_decode_MCU_2x1_3planes,
+ NULL,
+};
+
static const decode_MCU_fct decode_mcu_1comp_table[4] = {
decode_MCU_1x1_1plane,
decode_MCU_1x2_1plane,
@@ -2021,6 +2300,9 @@ int tinyjpeg_decode(struct jdec_private *priv, int pixfmt)
bytes_per_blocklines[2] = 0;
decode_mcu_table = decode_mcu_3comp_table;
+ if (priv->flags & TINYJPEG_FLAGS_PIXART_JPEG)
+ decode_mcu_table = pixart_decode_mcu_3comp_table;
+
switch (pixfmt) {
case TINYJPEG_FMT_YUV420P:
colorspace_array_conv = convert_colorspace_yuv420p;
@@ -2056,6 +2338,8 @@ int tinyjpeg_decode(struct jdec_private *priv, int pixfmt)
case TINYJPEG_FMT_GREY:
decode_mcu_table = decode_mcu_1comp_table;
+ if (priv->flags & TINYJPEG_FLAGS_PIXART_JPEG)
+ error("Greyscale output not support for PIXART JPEG's\n");
colorspace_array_conv = convert_colorspace_grey;
if (priv->components[0] == NULL)
priv->components[0] = (uint8_t *)malloc(priv->width * priv->height);
@@ -2064,8 +2348,7 @@ int tinyjpeg_decode(struct jdec_private *priv, int pixfmt)
break;
default:
- trace("Bad pixel format\n");
- return -1;
+ error("Bad pixel format\n");
}
xstride_by_mcu = ystride_by_mcu = 8;
@@ -2091,6 +2374,9 @@ int tinyjpeg_decode(struct jdec_private *priv, int pixfmt)
trace("Use decode 2x1 sampling\n");
}
+ if (decode_MCU == NULL)
+ error("no decode MCU function for this JPEG format (PIXART?)\n");
+
resync(priv);
/* Don't forget to that block can be either 8 or 16 lines */
@@ -2130,6 +2416,12 @@ int tinyjpeg_decode(struct jdec_private *priv, int pixfmt)
}
}
+ if (priv->flags & TINYJPEG_FLAGS_PIXART_JPEG) {
+ /* Additional sanity check for funky Pixart format */
+ if ((priv->stream_end - priv->stream) > 5)
+ error("Pixart JPEG error, stream does not end with EOF marker\n");
+ }
+
return 0;
}
diff --git a/v4l2-apps/lib/libv4l/libv4lconvert/tinyjpeg.h b/v4l2-apps/lib/libv4l/libv4lconvert/tinyjpeg.h
index 42b60c1ee..b0096f0de 100644
--- a/v4l2-apps/lib/libv4l/libv4lconvert/tinyjpeg.h
+++ b/v4l2-apps/lib/libv4l/libv4lconvert/tinyjpeg.h
@@ -43,6 +43,7 @@ struct jdec_private;
/* Flags that can be set by any applications */
#define TINYJPEG_FLAGS_MJPEG_TABLE (1<<1)
+#define TINYJPEG_FLAGS_PIXART_JPEG (1<<2)
/* Format accepted in outout */
enum tinyjpeg_fmt {