From 58ac859aa5234712be79b741f5e0d27c27b91bb3 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 7 Jun 2011 16:38:31 +0200 Subject: [PATCH] Add support for SE401 pixelformat Signed-off-by: Hans de Goede --- ChangeLog | 6 ++ Make.rules | 2 +- include/linux/videodev2.h | 1 + lib/libv4lconvert/Makefile | 2 +- lib/libv4lconvert/control/libv4lcontrol.c | 11 +++ lib/libv4lconvert/libv4lconvert-priv.h | 4 + lib/libv4lconvert/libv4lconvert.c | 39 ++++++++ lib/libv4lconvert/se401.c | 159 ++++++++++++++++++++++++++++++ 8 files changed, 222 insertions(+), 2 deletions(-) create mode 100644 lib/libv4lconvert/se401.c diff --git a/ChangeLog b/ChangeLog index dc60d30..af66c24 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +v4l-utils-0.8.5 +--------------- +* libv4l changes + * Add some more laptop models to the upside down devices table (hdegoede) + * Add support for SE401 pixelformat (hdegoede) + v4l-utils-0.8.4 --------------- * Utils changes diff --git a/Make.rules b/Make.rules index 9a96a8d..463a34f 100644 --- a/Make.rules +++ b/Make.rules @@ -1,4 +1,4 @@ -V4L_UTILS_VERSION=0.8.4 +V4L_UTILS_VERSION=0.8.5-test # These ones can be overriden from the cmdline diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index 8a4c309..4c80dcb 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -402,6 +402,7 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_CIT_YYVYUY v4l2_fourcc('C', 'I', 'T', 'V') /* one line of Y then 1 line of VYUY */ #define V4L2_PIX_FMT_KONICA420 v4l2_fourcc('K', 'O', 'N', 'I') /* YUV420 planar in blocks of 256 pixels */ #define V4L2_PIX_FMT_JPGL v4l2_fourcc('J', 'P', 'G', 'L') /* JPEG-Lite */ +#define V4L2_PIX_FMT_SE401 v4l2_fourcc('S', '4', '0', '1') /* se401 janggu compressed rgb */ /* * F O R M A T E N U M E R A T I O N diff --git a/lib/libv4lconvert/Makefile b/lib/libv4lconvert/Makefile index a9791f7..1376c21 100644 --- a/lib/libv4lconvert/Makefile +++ b/lib/libv4lconvert/Makefile @@ -12,7 +12,7 @@ endif CONVERT_OBJS = libv4lconvert.o tinyjpeg.o sn9c10x.o sn9c20x.o pac207.o \ mr97310a.o flip.o crop.o jidctflt.o spca561-decompress.o \ rgbyuv.o sn9c2028-decomp.o spca501.o sq905c.o bayer.o hm12.o \ - stv0680.o cpia1.o jpgl.o jpeg.o jpeg_memsrcdest.o \ + stv0680.o cpia1.o se401.o jpgl.o jpeg.o jpeg_memsrcdest.o \ control/libv4lcontrol.o processing/libv4lprocessing.o \ processing/whitebalance.o processing/autogain.o \ processing/gamma.o helper.o diff --git a/lib/libv4lconvert/control/libv4lcontrol.c b/lib/libv4lconvert/control/libv4lcontrol.c index a051482..2fddf43 100644 --- a/lib/libv4lconvert/control/libv4lcontrol.c +++ b/lib/libv4lconvert/control/libv4lcontrol.c @@ -613,6 +613,17 @@ static const struct v4lcontrol_flags_info v4lcontrol_flags[] = { /* vicam based cams */ { 0x04c1, 0x009d, 0, NULL, NULL, V4LCONTROL_WANTS_WB_AUTOGAIN, 1500 }, { 0x0602, 0x1001, 0, NULL, NULL, V4LCONTROL_WANTS_WB_AUTOGAIN, 1500 }, + /* se401 cams, mirrored and need wb + autogain */ + { 0x03e8, 0x0004, 0, NULL, NULL, + V4LCONTROL_HFLIPPED | V4LCONTROL_WANTS_WB_AUTOGAIN }, + { 0x0471, 0x030b, 0, NULL, NULL, + V4LCONTROL_HFLIPPED | V4LCONTROL_WANTS_WB_AUTOGAIN }, + { 0x047d, 0x5001, 0, NULL, NULL, + V4LCONTROL_HFLIPPED | V4LCONTROL_WANTS_WB_AUTOGAIN }, + { 0x047d, 0x5002, 0, NULL, NULL, + V4LCONTROL_HFLIPPED | V4LCONTROL_WANTS_WB_AUTOGAIN }, + { 0x047d, 0x5003, 0, NULL, NULL, + V4LCONTROL_HFLIPPED | V4LCONTROL_WANTS_WB_AUTOGAIN }, }; static const struct v4l2_queryctrl fake_controls[]; diff --git a/lib/libv4lconvert/libv4lconvert-priv.h b/lib/libv4lconvert/libv4lconvert-priv.h index a4aa316..2cd7a22 100644 --- a/lib/libv4lconvert/libv4lconvert-priv.h +++ b/lib/libv4lconvert/libv4lconvert-priv.h @@ -187,6 +187,10 @@ int v4lconvert_cpia1_to_yuv420(struct v4lconvert_data *data, void v4lconvert_sn9c20x_to_yuv420(const unsigned char *src, unsigned char *dst, int width, int height, int yvu); +int v4lconvert_se401_to_rgb24(struct v4lconvert_data *data, + const unsigned char *src, int src_size, + unsigned char *dest, int width, int height); + int v4lconvert_decode_jpeg_tinyjpeg(struct v4lconvert_data *data, unsigned char *src, int src_size, unsigned char *dest, struct v4l2_format *fmt, unsigned int dest_pix_fmt, int flags); diff --git a/lib/libv4lconvert/libv4lconvert.c b/lib/libv4lconvert/libv4lconvert.c index 3ea270b..6935e65 100644 --- a/lib/libv4lconvert/libv4lconvert.c +++ b/lib/libv4lconvert/libv4lconvert.c @@ -79,6 +79,8 @@ static const struct v4lconvert_pixfmt supported_src_pixfmts[] = { { V4L2_PIX_FMT_PAC207, 0, 9, 9, 1 }, { V4L2_PIX_FMT_MR97310A, 0, 9, 9, 1 }, { V4L2_PIX_FMT_SQ905C, 0, 9, 9, 1 }, + /* special */ + { V4L2_PIX_FMT_SE401, 0, 8, 9, 1 }, /* grey formats */ { V4L2_PIX_FMT_GREY, 8, 20, 20, 0 }, { V4L2_PIX_FMT_Y10BPACK, 10, 20, 20, 0 }, @@ -860,6 +862,43 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, } break; + case V4L2_PIX_FMT_SE401: { + unsigned char *d = NULL; + + switch (dest_pix_fmt) { + case V4L2_PIX_FMT_RGB24: + d = dest; + break; + case V4L2_PIX_FMT_BGR24: + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + d = v4lconvert_alloc_buffer(width * height * 3, + &data->convert_pixfmt_buf, + &data->convert_pixfmt_buf_size); + if (!d) + return v4lconvert_oom_error(data); + + fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24; + v4lconvert_fixup_fmt(fmt); + break; + } + + result = v4lconvert_se401_to_rgb24(data, src, src_size, d, + width, height); + switch (dest_pix_fmt) { + case V4L2_PIX_FMT_BGR24: + v4lconvert_swap_rgb(d, dest, width, height); + break; + case V4L2_PIX_FMT_YUV420: + v4lconvert_rgb24_to_yuv420(d, dest, fmt, 0, 0); + break; + case V4L2_PIX_FMT_YVU420: + v4lconvert_rgb24_to_yuv420(d, dest, fmt, 0, 1); + break; + } + break; + } + case V4L2_PIX_FMT_GREY: switch (dest_pix_fmt) { case V4L2_PIX_FMT_RGB24: diff --git a/lib/libv4lconvert/se401.c b/lib/libv4lconvert/se401.c new file mode 100644 index 0000000..ccfcda0 --- /dev/null +++ b/lib/libv4lconvert/se401.c @@ -0,0 +1,159 @@ +/* +# (C) 2011 Hans de Goede + +# The compression algorithm has been taken from the v4l1 se401 linux kernel +# driver by Jeroen B. Vreeken (pe1rxq@amsat.org) + +# 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA + */ + +#include "libv4lconvert-priv.h" +#include + +/* The se401 compression algorithm uses a fixed quant factor, which + can be configured by setting the high nibble of the SE401_OPERATINGMODE + feature. This needs to exactly match what is in the SE401 driver! */ +#define SE401_QUANT_FACT 8 + +static void wr_pixel(int p, uint8_t **dest, int pitch, int *x) +{ + int i = *x; + + /* First 3 pixels of each line are absolute */ + if (i < 3) { + (*dest)[i] = p * SE401_QUANT_FACT; + } else { + (*dest)[i] = (*dest)[i - 3] + p * SE401_QUANT_FACT; + } + + *x += 1; + if (*x == pitch) { + *x = 0; + *dest += pitch; + } +} + +enum decode_state { + get_len, + sign_bit, + other_bits, +}; + +static int decode_JangGu(const uint8_t *data, int bits, int plen, int pixels, + uint8_t **dest, int pitch, int *x) +{ + enum decode_state state = get_len; + int len = 0; + int value = 0; + int bitnr; + int bit; + + while (plen) { + bitnr = 8; + while (bitnr && bits) { + bit = ((*data) >> (bitnr-1))&1; + switch (state) { + case get_len: + if (bit) { + len++; + } else { + if (!len) { + wr_pixel(0, dest, pitch, x); + if (!--pixels) + return 0; + } else { + state = sign_bit; + value = 0; + } + } + break; + case sign_bit: + if (!bit) + value = -(1 << len) + 1; + /* fall through for positive number and + len == 1 handling */ + case other_bits: + len--; + value += bit << len; + if (len == 0) { + /* Done write pixel and get bit len of + the next one */ + state = get_len; + wr_pixel(value, dest, pitch, x); + if (!--pixels) + return 0; + } + break; + } + bitnr--; + bits--; + } + data++; + plen--; + } + return -1; +} + +int v4lconvert_se401_to_rgb24(struct v4lconvert_data *data, + const unsigned char *src, int src_size, + unsigned char *dest, int width, int height) +{ + int in, plen, bits, pixels, info; + int x = 0, total_pixels = 0; + + for (in = 0; in + 4 < src_size; in += plen) { + bits = src[in + 3] + (src[in + 2] << 8); + pixels = src[in + 1] + ((src[in + 0] & 0x3f) << 8); + info = (src[in + 0] & 0xc0) >> 6; + plen = ((bits + 47) >> 4) << 1; + /* Sanity checks */ + if (plen > 1024) { + V4LCONVERT_ERR("invalid se401 packet len %d", plen); + goto error; + } + if (in + plen > src_size) { + V4LCONVERT_ERR("incomplete se401 packet"); + goto error; + } + if (total_pixels + pixels > width * height) { + V4LCONVERT_ERR("se401 frame overflow"); + goto error; + } + /* info: 0 inter packet, 1 eof, 2 sof, 3 not used */ + if ((in == 0 && info != 2) || + (in > 0 && in + plen < src_size && info != 0) || + (in + plen == src_size && info != 1)) { + V4LCONVERT_ERR("invalid se401 frame info value"); + goto error; + } + if (decode_JangGu(&src[in + 4], bits, plen, pixels * 3, + &dest, width * 3, &x)) { + V4LCONVERT_ERR("short se401 packet"); + goto error; + } + total_pixels += pixels; + } + + if (in != src_size || total_pixels != width * height) { + V4LCONVERT_ERR("se401 frame size mismatch"); + goto error; + } + + return 0; + +error: + errno = EIO; + return -1; +} -- 2.7.4