From 222cbd6fd0bec2c2e4566a251729f1329e031a22 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 13:06:14 +0100 Subject: libv4l: Add software cropping from CIF to VGA modes (fix skype) From: Hans de Goede * Add support for software cropping from 352x288 -> 320x240 / 176x144 -> 160x120, so that apps which will only work with vga resolutions like 320x240 (Skype!) will work with cams/drivers which do not support cropping CIF resolutions to VGA resolutions in hardware. This makes all 2.6.27 gspca supported cams, except for the pac7302 which only does 640x480 (and skype wants 320x240), work with skype * The v4lconvert_convert function was becoming a bit of a mess, so split the functionailiy into seperate v4lconvert_convert_pixfmt, v4lconvert_rotate and v4lconvert_crop functions, and make v4lconvert_convert a frontend to these Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 13 + v4l2-apps/libv4l/Makefile | 2 +- v4l2-apps/libv4l/libv4l2/libv4l2.c | 10 + v4l2-apps/libv4l/libv4lconvert/Makefile | 2 +- v4l2-apps/libv4l/libv4lconvert/crop.c | 88 ++++ v4l2-apps/libv4l/libv4lconvert/flip.c | 49 ++- .../libv4l/libv4lconvert/libv4lconvert-priv.h | 17 +- v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 445 ++++++++++++--------- 8 files changed, 406 insertions(+), 220 deletions(-) create mode 100644 v4l2-apps/libv4l/libv4lconvert/crop.c (limited to 'v4l2-apps/libv4l') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index dd53eced9..294bb9ad2 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -1,3 +1,16 @@ +libv4l-0.5.1 +------------ +* Add support for software cropping from 352x288 -> 320x240 / 176x144 -> + 160x120, so that apps which will only work with vga resolutions like + 320x240 (Skype!) will work with cams/drivers which do not support cropping + CIF resolutions to VGA resolutions in hardware. This makes all 2.6.27 gspca + supported cams, except for the pac7302 which only does 640x480 (and skype + wants 320x240), work with skype +* The v4lconvert_convert function was becoming a bit of a mess, so split the + functionailiy into seperate v4lconvert_convert_pixfmt, v4lconvert_rotate and + v4lconvert_crop functions, and make v4lconvert_convert a frontend to + these + libv4l-0.5.0 ------------ * Add support for enumerating framesizes and frameintervals of emulated diff --git a/v4l2-apps/libv4l/Makefile b/v4l2-apps/libv4l/Makefile index 4c99c3167..13f216bc1 100644 --- a/v4l2-apps/libv4l/Makefile +++ b/v4l2-apps/libv4l/Makefile @@ -1,5 +1,5 @@ LIB_RELEASE=0 -V4L2_LIB_VERSION=$(LIB_RELEASE).5.0 +V4L2_LIB_VERSION=$(LIB_RELEASE).5.1 all clean install: $(MAKE) -C libv4lconvert V4L2_LIB_VERSION=$(V4L2_LIB_VERSION) $@ diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2.c b/v4l2-apps/libv4l/libv4l2/libv4l2.c index b4a10afac..0a05623cb 100644 --- a/v4l2-apps/libv4l/libv4l2/libv4l2.c +++ b/v4l2-apps/libv4l/libv4l2/libv4l2.c @@ -740,6 +740,16 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) break; } + if (v4l2_log_file) { + int pixfmt = dest_fmt->fmt.pix.pixelformat; + + fprintf(v4l2_log_file, "VIDIOC_S_FMT app requesting: %c%c%c%c\n", + pixfmt & 0xff, + (pixfmt >> 8) & 0xff, + (pixfmt >> 16) & 0xff, + pixfmt >> 24); + } + if (devices[index].flags & V4L2_DISABLE_CONVERSION) { result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_TRY_FMT, dest_fmt); diff --git a/v4l2-apps/libv4l/libv4lconvert/Makefile b/v4l2-apps/libv4l/libv4lconvert/Makefile index 641d19d6e..fa0f3f5e0 100644 --- a/v4l2-apps/libv4l/libv4lconvert/Makefile +++ b/v4l2-apps/libv4l/libv4lconvert/Makefile @@ -10,7 +10,7 @@ CONVERT_LIB = libv4lconvert.so override CPPFLAGS += -fPIC endif -CONVERT_OBJS = libv4lconvert.o tinyjpeg.o sn9c10x.o pac207.o flip.o \ +CONVERT_OBJS = libv4lconvert.o tinyjpeg.o sn9c10x.o pac207.o flip.o crop.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/libv4l/libv4lconvert/crop.c b/v4l2-apps/libv4l/libv4lconvert/crop.c new file mode 100644 index 000000000..290756b99 --- /dev/null +++ b/v4l2-apps/libv4l/libv4lconvert/crop.c @@ -0,0 +1,88 @@ +/* + +# RGB and YUV crop routines + +# (C) 2008 Hans de Goede + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include +#include "libv4lconvert-priv.h" + +static void v4lconvert_crop_rgbbgr24(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; + + src += starty * src_fmt->fmt.pix.bytesperline + 3 * startx; + + for (x = 0; x < dest_fmt->fmt.pix.height; x++) { + memcpy(dest, src, dest_fmt->fmt.pix.width * 3); + src += src_fmt->fmt.pix.bytesperline; + dest += dest_fmt->fmt.pix.bytesperline; + } +} + +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; + unsigned char *mysrc = src + starty * src_fmt->fmt.pix.bytesperline + startx; + + /* Y */ + for (x = 0; x < dest_fmt->fmt.pix.height; x++) { + memcpy(dest, mysrc, dest_fmt->fmt.pix.width); + mysrc += src_fmt->fmt.pix.bytesperline; + dest += dest_fmt->fmt.pix.bytesperline; + } + + /* U */ + mysrc = src + src_fmt->fmt.pix.height * src_fmt->fmt.pix.bytesperline + + (starty / 2) * src_fmt->fmt.pix.bytesperline / 2 + startx / 2; + for (x = 0; x < dest_fmt->fmt.pix.height / 2; x++) { + memcpy(dest, mysrc, dest_fmt->fmt.pix.width / 2); + mysrc += src_fmt->fmt.pix.bytesperline / 2; + dest += dest_fmt->fmt.pix.bytesperline / 2; + } + + /* V */ + mysrc = src + src_fmt->fmt.pix.height * src_fmt->fmt.pix.bytesperline * 5 / 4 + + (starty / 2) * src_fmt->fmt.pix.bytesperline / 2 + startx / 2; + for (x = 0; x < dest_fmt->fmt.pix.height / 2; x++) { + memcpy(dest, mysrc, dest_fmt->fmt.pix.width / 2); + mysrc += src_fmt->fmt.pix.bytesperline / 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: + v4lconvert_crop_rgbbgr24(src, dest, src_fmt, dest_fmt); + break; + case V4L2_PIX_FMT_YUV420: + 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 cd3468a89..5a108c8d9 100644 --- a/v4l2-apps/libv4l/libv4lconvert/flip.c +++ b/v4l2-apps/libv4l/libv4lconvert/flip.c @@ -22,8 +22,8 @@ #include "libv4lconvert-priv.h" -void v4lconvert_rotate180_rgbbgr24(const unsigned char *src, unsigned char *dst, - int width, int height) +static void v4lconvert_rotate180_rgbbgr24(const unsigned char *src, + unsigned char *dst, int width, int height) { int i; @@ -38,8 +38,8 @@ void v4lconvert_rotate180_rgbbgr24(const unsigned char *src, unsigned char *dst, } } -void v4lconvert_rotate180_yuv420(const unsigned char *src, unsigned char *dst, - int width, int height) +static void v4lconvert_rotate180_yuv420(const unsigned char *src, + unsigned char *dst, int width, int height) { int i; @@ -59,8 +59,8 @@ void v4lconvert_rotate180_yuv420(const unsigned char *src, unsigned char *dst, *dst++ = *src--; } -void v4lconvert_rotate90_rgbbgr24(const unsigned char *src, unsigned char *dst, - int destwidth, int destheight) +static void v4lconvert_rotate90_rgbbgr24(const unsigned char *src, + unsigned char *dst, int destwidth, int destheight) { int x, y; #define srcwidth destheight @@ -75,8 +75,8 @@ void v4lconvert_rotate90_rgbbgr24(const unsigned char *src, unsigned char *dst, } } -void v4lconvert_rotate90_yuv420(const unsigned char *src, unsigned char *dst, - int destwidth, int destheight) +static void v4lconvert_rotate90_yuv420(const unsigned char *src, + unsigned char *dst, int destwidth, int destheight) { int x, y; @@ -105,3 +105,36 @@ void v4lconvert_rotate90_yuv420(const unsigned char *src, unsigned char *dst, *dst++ = src[offset]; } } + +void v4lconvert_rotate(unsigned char *src, unsigned char *dest, + int width, int height, unsigned int pix_fmt, int rotate) +{ + switch (rotate) { + case 0: + break; + case 90: + switch (pix_fmt) { + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + v4lconvert_rotate90_rgbbgr24(src, dest, width, height); + break; + case V4L2_PIX_FMT_YUV420: + v4lconvert_rotate90_yuv420(src, dest, width, height); + break; + } + break; + case 180: + switch (pix_fmt) { + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + v4lconvert_rotate180_rgbbgr24(src, dest, width, height); + break; + case V4L2_PIX_FMT_YUV420: + v4lconvert_rotate180_yuv420(src, dest, width, height); + break; + } + break; + default: + printf("FIXME add %d degrees rotation\n", rotate); + } +} diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h index 0c4eff6ce..99ffdec20 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h @@ -71,7 +71,8 @@ "v4l-convert: error " __VA_ARGS__) /* Card flags */ -#define V4LCONVERT_UPSIDE_DOWN 0x01 +#define V4LCONVERT_ROTATE_90 0x01 +#define V4LCONVERT_ROTATE_180 0x02 /* Pixformat flags */ #define V4LCONVERT_COMPRESSED 0x01 @@ -151,16 +152,10 @@ 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_rotate(unsigned char *src, unsigned char *dest, + int width, int height, unsigned int pix_fmt, int rotate); -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); +void v4lconvert_crop(unsigned char *src, unsigned char *dest, + const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt); #endif diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index 93bc67c7e..362ac1914 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -64,11 +64,24 @@ static const struct v4lconvert_pixfmt supported_dst_pixfmts[] = { /* List of cams which need special flags */ static const struct v4lconvert_flags_info v4lconvert_flags[] = { - { "SPC 200NC ", V4LCONVERT_UPSIDE_DOWN }, - { "SPC 300NC ", V4LCONVERT_UPSIDE_DOWN }, - { "USB Camera (0471:0325)", V4LCONVERT_UPSIDE_DOWN }, /* SPC200NC */ - { "USB Camera (0471:0326)", V4LCONVERT_UPSIDE_DOWN }, /* SPC300NC */ - { "USB Camera (093a:2476)", V4LCONVERT_UPSIDE_DOWN }, /* Genius E-M 112 */ + { "SPC 200NC ", V4LCONVERT_ROTATE_180 }, + { "SPC 300NC ", V4LCONVERT_ROTATE_180 }, + { "USB Camera (0471:0325)", V4LCONVERT_ROTATE_180 }, /* SPC200NC */ + { "USB Camera (0471:0326)", V4LCONVERT_ROTATE_180 }, /* SPC300NC */ + { "USB Camera (093a:2476)", 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] = { + /* low res VGA resolutions, can be made by software cropping SIF resolutions + for cam/drivers which do not support this in hardware */ + { 320, 240 }, + { 160, 120 }, + /* Some CIF cams (with vv6410 sensor) have slightly larger then usual CIF + resolutions, make regular CIF resolutions available on these by sw crop */ + { 352, 288 }, + { 176, 144 }, }; struct v4lconvert_data *v4lconvert_create(int fd) @@ -171,8 +184,7 @@ int v4lconvert_enum_fmt(struct v4lconvert_data *data, struct v4l2_fmtdesc *fmt) return 0; } -/* See libv4lconvert.h for description of in / out parameters */ -int v4lconvert_try_format(struct v4lconvert_data *data, +static int v4lconvert_do_try_format(struct v4lconvert_data *data, struct v4l2_format *dest_fmt, struct v4l2_format *src_fmt) { int i; @@ -180,15 +192,6 @@ int v4lconvert_try_format(struct v4lconvert_data *data, unsigned int desired_pixfmt = dest_fmt->fmt.pix.pixelformat; struct v4l2_format try_fmt, closest_fmt = { .type = 0 }; - /* Can we do conversion to the requested format & type? */ - if (!v4lconvert_supported_dst_format(desired_pixfmt) || - dest_fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - int ret = syscall(SYS_ioctl, data->fd, VIDIOC_TRY_FMT, dest_fmt); - if (src_fmt) - *src_fmt = *dest_fmt; - return ret; - } - for (i = 0; i < ARRAY_SIZE(supported_src_pixfmts); i++) { /* is this format supported? */ if (!(data->supported_src_formats & (1 << i))) @@ -209,7 +212,7 @@ int v4lconvert_try_format(struct v4lconvert_data *data, if (size_diff < closest_fmt_size_diff || (size_diff == closest_fmt_size_diff && (supported_src_pixfmts[i].fmt == desired_pixfmt || - ((try_fmt.fmt.pix.width > 176 || try_fmt.fmt.pix.height > 144) && + ((try_fmt.fmt.pix.width > 180 || try_fmt.fmt.pix.height > 148) && (supported_src_pixfmts[i].flags & V4LCONVERT_COMPRESSED))))) { closest_fmt_size_diff = size_diff; closest_fmt = try_fmt; @@ -218,35 +221,92 @@ int v4lconvert_try_format(struct v4lconvert_data *data, } } - if (closest_fmt.type == 0) { - int ret = syscall(SYS_ioctl, data->fd, VIDIOC_TRY_FMT, dest_fmt); + if (closest_fmt.type == 0) + return -1; + + *dest_fmt = closest_fmt; + if (closest_fmt.fmt.pix.pixelformat != desired_pixfmt) + dest_fmt->fmt.pix.pixelformat = desired_pixfmt; + *src_fmt = closest_fmt; + + return 0; +} + +static void v4lconvert_fixup_fmt(struct v4l2_format *fmt) +{ + switch (fmt->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + fmt->fmt.pix.bytesperline = fmt->fmt.pix.width * 3; + fmt->fmt.pix.sizeimage = fmt->fmt.pix.width * fmt->fmt.pix.height * 3; + break; + case V4L2_PIX_FMT_YUV420: + fmt->fmt.pix.bytesperline = fmt->fmt.pix.width; + fmt->fmt.pix.sizeimage = fmt->fmt.pix.width * fmt->fmt.pix.height * 3 / 2; + break; + } +} + +/* See libv4lconvert.h for description of in / out parameters */ +int v4lconvert_try_format(struct v4lconvert_data *data, + struct v4l2_format *dest_fmt, struct v4l2_format *src_fmt) +{ + 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; + + /* 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); if (src_fmt) *src_fmt = *dest_fmt; - return ret; + return result; } - *dest_fmt = closest_fmt; - - /* Are we converting? */ - if (closest_fmt.fmt.pix.pixelformat != desired_pixfmt) { - dest_fmt->fmt.pix.pixelformat = desired_pixfmt; - switch (dest_fmt->fmt.pix.pixelformat) { - case V4L2_PIX_FMT_RGB24: - case V4L2_PIX_FMT_BGR24: - dest_fmt->fmt.pix.bytesperline = dest_fmt->fmt.pix.width * 3; - dest_fmt->fmt.pix.sizeimage = dest_fmt->fmt.pix.width * - dest_fmt->fmt.pix.height * 3; - break; - case V4L2_PIX_FMT_YUV420: - dest_fmt->fmt.pix.bytesperline = dest_fmt->fmt.pix.width; - dest_fmt->fmt.pix.sizeimage = (dest_fmt->fmt.pix.width * - dest_fmt->fmt.pix.height * 3) / 2; + /* In case of a non exact resolution match, see if this is a resolution we + can support by cropping a slightly larger resolution to give the app + exactly what it asked for */ + 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_dest, try2_src; + /* Note these are chosen so that cropping to vga res just works for + vv6410 sensor cams, which have 356x292 and 180x148 */ + unsigned int max_width = desired_width * 113 / 100; + unsigned int max_height = desired_height * 124 / 100; + + try2_dest = *dest_fmt; + try2_dest.fmt.pix.width = max_width; + try2_dest.fmt.pix.height = max_height; + 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 <= max_width && + try2_dest.fmt.pix.height >= desired_height && + try2_dest.fmt.pix.height <= max_height) { + /* Success! */ + try2_dest.fmt.pix.width = desired_width; + try2_dest.fmt.pix.height = desired_height; + try_dest = try2_dest; + try_src = try2_src; + } break; + } } } + /* Are we converting? */ + if(memcmp(&try_src, &try_dest, sizeof(try_src))) + v4lconvert_fixup_fmt(&try_dest); + + *dest_fmt = try_dest; if (src_fmt) - *src_fmt = closest_fmt; + *src_fmt = try_src; return 0; } @@ -259,7 +319,7 @@ int v4lconvert_needs_conversion(struct v4lconvert_data *data, if(memcmp(src_fmt, dest_fmt, sizeof(*src_fmt))) return 1; /* Formats differ */ - if (!(data->flags & V4LCONVERT_UPSIDE_DOWN)) + if (!(data->flags & (V4LCONVERT_ROTATE_90|V4LCONVERT_ROTATE_180))) return 0; /* Formats identical and we don't need flip */ /* Formats are identical, but we need flip, do we support the dest_fmt? */ @@ -269,50 +329,16 @@ int v4lconvert_needs_conversion(struct v4lconvert_data *data, 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) +static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, + unsigned int src_pix_fmt, unsigned int dest_pix_fmt, + unsigned int width, unsigned int height, + unsigned char *src, int src_size, unsigned char *dest) { unsigned int header_width, header_height; - int result, needed, rotate = 0, jpeg_flags = TINYJPEG_FLAGS_MJPEG_TABLE; + int result = 0, jpeg_flags = TINYJPEG_FLAGS_MJPEG_TABLE; unsigned char *components[3]; - unsigned char *dest = _dest; - - /* Special case when no conversion is needed */ - 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; - } - /* sanity check, is the dest buffer large enough? */ - switch (dest_fmt->fmt.pix.pixelformat) { - case V4L2_PIX_FMT_RGB24: - case V4L2_PIX_FMT_BGR24: - needed = dest_fmt->fmt.pix.width * dest_fmt->fmt.pix.height * 3; - break; - case V4L2_PIX_FMT_YUV420: - needed = (dest_fmt->fmt.pix.width * dest_fmt->fmt.pix.height * 3) / 2; - break; - default: - V4LCONVERT_ERR("Unknown dest format in conversion\n"); - errno = EINVAL; - return -1; - } - - if (dest_size < needed) { - V4LCONVERT_ERR("destination buffer too small\n"); - errno = EFAULT; - return -1; - } - - if (data->flags & V4LCONVERT_UPSIDE_DOWN) { - rotate = 180; - dest = alloca(needed); - } - - switch (src_fmt->fmt.pix.pixelformat) { + switch (src_pix_fmt) { case V4L2_PIX_FMT_PJPG: jpeg_flags |= TINYJPEG_FLAGS_PIXART_JPEG; /* Fall through */ @@ -335,31 +361,29 @@ 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) { + if (header_width != width || header_height != 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; + if (header_width == height && header_height == width) { + if (!(data->flags & V4LCONVERT_ROTATE_90)) { + V4LCONVERT_ERR("JPEG needs 90 degree rotation"); + data->flags |= V4LCONVERT_ROTATE_90; + errno = EAGAIN; + return -1; + } } 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); + "expected: %ux%u, header: %ux%u\n", width, height, + header_width, header_height); errno = EIO; return -1; } } components[0] = dest; - components[1] = components[0] + dest_fmt->fmt.pix.width * - dest_fmt->fmt.pix.height; - components[2] = components[1] + (dest_fmt->fmt.pix.width * - dest_fmt->fmt.pix.height) / 4; + components[1] = components[0] + width * height; + components[2] = components[1] + width * height / 4; - switch (dest_fmt->fmt.pix.pixelformat) { + switch (dest_pix_fmt) { case V4L2_PIX_FMT_RGB24: tinyjpeg_set_components(data->jdec, components, 1); result = tinyjpeg_decode(data->jdec, TINYJPEG_FMT_RGB24); @@ -368,7 +392,7 @@ int v4lconvert_convert(struct v4lconvert_data *data, tinyjpeg_set_components(data->jdec, components, 1); result = tinyjpeg_decode(data->jdec, TINYJPEG_FMT_BGR24); break; - default: + case V4L2_PIX_FMT_YUV420: tinyjpeg_set_components(data->jdec, components, 3); result = tinyjpeg_decode(data->jdec, TINYJPEG_FMT_YUV420P); break; @@ -379,7 +403,7 @@ int v4lconvert_convert(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_fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_PJPG) { + if (src_pix_fmt == V4L2_PIX_FMT_PJPG) { V4LCONVERT_ERR("Error decompressing JPEG: %s", tinyjpeg_get_errorstring(data->jdec)); errno = EAGAIN; @@ -398,18 +422,15 @@ int v4lconvert_convert(struct v4lconvert_data *data, case V4L2_PIX_FMT_SGBRG8: case V4L2_PIX_FMT_SGRBG8: case V4L2_PIX_FMT_SRGGB8: - switch (dest_fmt->fmt.pix.pixelformat) { + switch (dest_pix_fmt) { case V4L2_PIX_FMT_RGB24: - v4lconvert_bayer_to_rgb24(src, dest, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.height, src_fmt->fmt.pix.pixelformat); + v4lconvert_bayer_to_rgb24(src, dest, width, height, src_pix_fmt); break; case V4L2_PIX_FMT_BGR24: - v4lconvert_bayer_to_bgr24(src, dest, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.height, src_fmt->fmt.pix.pixelformat); + v4lconvert_bayer_to_bgr24(src, dest, width, height, src_pix_fmt); break; - default: - v4lconvert_bayer_to_yuv420(src, dest, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.height, src_fmt->fmt.pix.pixelformat); + case V4L2_PIX_FMT_YUV420: + v4lconvert_bayer_to_yuv420(src, dest, width, height, src_pix_fmt); break; } break; @@ -419,34 +440,27 @@ int v4lconvert_convert(struct v4lconvert_data *data, case V4L2_PIX_FMT_SPCA505: case V4L2_PIX_FMT_SPCA508: { - unsigned char tmpbuf[dest_fmt->fmt.pix.width * dest_fmt->fmt.pix.height * - 3 / 2]; - unsigned char *my_dst = (dest_fmt->fmt.pix.pixelformat != - V4L2_PIX_FMT_YUV420) ? tmpbuf : dest; + unsigned char tmpbuf[width * height * 3 / 2]; + unsigned char *d = (dest_pix_fmt != V4L2_PIX_FMT_YUV420) ? tmpbuf : dest; - switch (src_fmt->fmt.pix.pixelformat) { + switch (src_pix_fmt) { case V4L2_PIX_FMT_SPCA501: - v4lconvert_spca501_to_yuv420(src, my_dst, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.height); + v4lconvert_spca501_to_yuv420(src, d, width, height); break; case V4L2_PIX_FMT_SPCA505: - v4lconvert_spca505_to_yuv420(src, my_dst, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.height); + v4lconvert_spca505_to_yuv420(src, d, width, height); break; case V4L2_PIX_FMT_SPCA508: - v4lconvert_spca508_to_yuv420(src, my_dst, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.height); + v4lconvert_spca508_to_yuv420(src, d, width, height); break; } - switch (dest_fmt->fmt.pix.pixelformat) { + switch (dest_pix_fmt) { case V4L2_PIX_FMT_RGB24: - v4lconvert_yuv420_to_rgb24(tmpbuf, dest, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.height); + v4lconvert_yuv420_to_rgb24(tmpbuf, dest, width, height); break; case V4L2_PIX_FMT_BGR24: - v4lconvert_yuv420_to_bgr24(tmpbuf, dest, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.height); + v4lconvert_yuv420_to_bgr24(tmpbuf, dest, width, height); break; } break; @@ -457,60 +471,53 @@ int v4lconvert_convert(struct v4lconvert_data *data, case V4L2_PIX_FMT_SN9C10X: case V4L2_PIX_FMT_PAC207: { - unsigned char tmpbuf[dest_fmt->fmt.pix.width*dest_fmt->fmt.pix.height]; + unsigned char tmpbuf[width * height]; unsigned int bayer_fmt = 0; - switch (src_fmt->fmt.pix.pixelformat) { + switch (src_pix_fmt) { case V4L2_PIX_FMT_SPCA561: - v4lconvert_decode_spca561(src, tmpbuf, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.height); + v4lconvert_decode_spca561(src, tmpbuf, width, height); bayer_fmt = V4L2_PIX_FMT_SGBRG8; break; case V4L2_PIX_FMT_SN9C10X: - v4lconvert_decode_sn9c10x(src, tmpbuf, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.height); + v4lconvert_decode_sn9c10x(src, tmpbuf, width, height); bayer_fmt = V4L2_PIX_FMT_SBGGR8; break; case V4L2_PIX_FMT_PAC207: - v4lconvert_decode_pac207(src, tmpbuf, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.height); + v4lconvert_decode_pac207(src, tmpbuf, width, height); bayer_fmt = V4L2_PIX_FMT_SBGGR8; break; } - switch (dest_fmt->fmt.pix.pixelformat) { + switch (dest_pix_fmt) { case V4L2_PIX_FMT_RGB24: - v4lconvert_bayer_to_rgb24(tmpbuf, dest, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.height, bayer_fmt); + v4lconvert_bayer_to_rgb24(tmpbuf, dest, width, height, bayer_fmt); break; case V4L2_PIX_FMT_BGR24: - v4lconvert_bayer_to_bgr24(tmpbuf, dest, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.height, bayer_fmt); + v4lconvert_bayer_to_bgr24(tmpbuf, dest, width, height, bayer_fmt); break; - default: - v4lconvert_bayer_to_yuv420(tmpbuf, dest, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.height, bayer_fmt); + case V4L2_PIX_FMT_YUV420: + v4lconvert_bayer_to_yuv420(tmpbuf, dest, width, height, bayer_fmt); break; } break; } case V4L2_PIX_FMT_RGB24: - switch (dest_fmt->fmt.pix.pixelformat) { + switch (dest_pix_fmt) { case V4L2_PIX_FMT_BGR24: - v4lconvert_swap_rgb(src, dest, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.height); + v4lconvert_swap_rgb(src, dest, width, height); break; case V4L2_PIX_FMT_YUV420: printf("FIXME add rgb24 -> yuv420 conversion\n"); break; } break; + case V4L2_PIX_FMT_BGR24: - switch (dest_fmt->fmt.pix.pixelformat) { + switch (dest_pix_fmt) { case V4L2_PIX_FMT_RGB24: - v4lconvert_swap_rgb(src, dest, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.height); + v4lconvert_swap_rgb(src, dest, width, height); break; case V4L2_PIX_FMT_YUV420: printf("FIXME add bgr24 -> yuv420 conversion\n"); @@ -519,48 +526,42 @@ int v4lconvert_convert(struct v4lconvert_data *data, break; case V4L2_PIX_FMT_YUV420: - switch (dest_fmt->fmt.pix.pixelformat) { + switch (dest_pix_fmt) { case V4L2_PIX_FMT_RGB24: - v4lconvert_yuv420_to_rgb24(src, dest, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.height); + v4lconvert_yuv420_to_rgb24(src, dest, width, + height); break; case V4L2_PIX_FMT_BGR24: - v4lconvert_yuv420_to_bgr24(src, dest, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.height); + v4lconvert_yuv420_to_bgr24(src, dest, width, + height); break; } break; case V4L2_PIX_FMT_YUYV: - switch (dest_fmt->fmt.pix.pixelformat) { + switch (dest_pix_fmt) { case V4L2_PIX_FMT_RGB24: - v4lconvert_yuyv_to_rgb24(src, dest, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.height); + v4lconvert_yuyv_to_rgb24(src, dest, width, height); break; case V4L2_PIX_FMT_BGR24: - v4lconvert_yuyv_to_bgr24(src, dest, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.height); + v4lconvert_yuyv_to_bgr24(src, dest, width, height); break; - default: - v4lconvert_yuyv_to_yuv420(src, dest, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.height); + case V4L2_PIX_FMT_YUV420: + v4lconvert_yuyv_to_yuv420(src, dest, width, height); break; } break; case V4L2_PIX_FMT_YVYU: - switch (dest_fmt->fmt.pix.pixelformat) { + switch (dest_pix_fmt) { case V4L2_PIX_FMT_RGB24: - v4lconvert_yvyu_to_rgb24(src, dest, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.height); + v4lconvert_yvyu_to_rgb24(src, dest, width, height); break; case V4L2_PIX_FMT_BGR24: - v4lconvert_yvyu_to_bgr24(src, dest, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.height); + v4lconvert_yvyu_to_bgr24(src, dest, width, height); break; - default: - v4lconvert_yvyu_to_yuv420(src, dest, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.height); + case V4L2_PIX_FMT_YUV420: + v4lconvert_yvyu_to_yuv420(src, dest, width, height); break; } break; @@ -570,47 +571,93 @@ int v4lconvert_convert(struct v4lconvert_data *data, errno = EINVAL; return -1; } + return 0; +} - /* 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; +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) +{ + int res, dest_needed, temp_needed, convert = 0, rotate = 0, crop = 0; + unsigned char *convert_dest = dest, *rotate_src = src, *rotate_dest = dest; + unsigned char *crop_src = src; + struct v4l2_format my_src_fmt = *src_fmt; - 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); + /* Special case when no conversion is needed */ + 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; } - return needed; + /* sanity check, is the dest buffer large enough? */ + switch (dest_fmt->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + dest_needed = dest_fmt->fmt.pix.width * dest_fmt->fmt.pix.height * 3; + temp_needed = src_fmt->fmt.pix.width * src_fmt->fmt.pix.height * 3; + break; + case V4L2_PIX_FMT_YUV420: + dest_needed = dest_fmt->fmt.pix.width * dest_fmt->fmt.pix.height * 3 / 2; + temp_needed = src_fmt->fmt.pix.width * src_fmt->fmt.pix.height * 3 / 2; + break; + default: + V4LCONVERT_ERR("Unknown dest format in conversion\n"); + errno = EINVAL; + return -1; + } + + if (dest_size < dest_needed) { + V4LCONVERT_ERR("destination buffer too small\n"); + errno = EFAULT; + return -1; + } + + if (dest_fmt->fmt.pix.pixelformat != src_fmt->fmt.pix.pixelformat) + convert = 1; + + if (data->flags & V4LCONVERT_ROTATE_90) + rotate += 90; + if (data->flags & V4LCONVERT_ROTATE_180) + rotate += 180; + + if (dest_fmt->fmt.pix.width != src_fmt->fmt.pix.width || + dest_fmt->fmt.pix.height != src_fmt->fmt.pix.height) + crop = 1; + + /* convert_pixfmt -> rotate -> crop, all steps are optional */ + if (convert && (rotate || crop)) { + convert_dest = alloca(temp_needed); + rotate_src = crop_src = convert_dest; + } + + if (rotate && crop) { + rotate_dest = alloca(temp_needed); + crop_src = rotate_dest; + } + + if (convert) { + res = v4lconvert_convert_pixfmt(data, src_fmt->fmt.pix.pixelformat, + dest_fmt->fmt.pix.pixelformat, + src_fmt->fmt.pix.width, src_fmt->fmt.pix.height, + src, src_size, convert_dest); + if (res) + return res; + + my_src_fmt.fmt.pix.pixelformat = dest_fmt->fmt.pix.pixelformat; + v4lconvert_fixup_fmt(&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 (crop) + v4lconvert_crop(crop_src, dest, &my_src_fmt, dest_fmt); + + return dest_needed; } const char *v4lconvert_get_error_message(struct v4lconvert_data *data) -- cgit v1.2.3 From e6a853deb196982b1b857f651195a41695c324dd Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 13:06:48 +0100 Subject: libv4l: Do not link the wrapper libs against libphread From: Gregor Jasny libv4l: Do not link the wrapper libs against libphread Priority: normal Signed-off-by: Gregor Jasny Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 3 ++- v4l2-apps/libv4l/libv4l1/Makefile | 4 ++-- v4l2-apps/libv4l/libv4l2/Makefile | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) (limited to 'v4l2-apps/libv4l') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index 294bb9ad2..f64525126 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -7,9 +7,10 @@ libv4l-0.5.1 supported cams, except for the pac7302 which only does 640x480 (and skype wants 320x240), work with skype * The v4lconvert_convert function was becoming a bit of a mess, so split the - functionailiy into seperate v4lconvert_convert_pixfmt, v4lconvert_rotate and + functionailiy into separate v4lconvert_convert_pixfmt, v4lconvert_rotate and v4lconvert_crop functions, and make v4lconvert_convert a frontend to these +* Do not link the wrapper libs against libpthread (patch from Gregor Jasny) libv4l-0.5.0 ------------ diff --git a/v4l2-apps/libv4l/libv4l1/Makefile b/v4l2-apps/libv4l/libv4l1/Makefile index 27848477e..7687a0a7c 100644 --- a/v4l2-apps/libv4l/libv4l1/Makefile +++ b/v4l2-apps/libv4l/libv4l1/Makefile @@ -3,7 +3,7 @@ override CPPFLAGS += -I../include -I../../../include -fvisibility=hidden CFLAGS := -g -O1 CFLAGS += -Wall -Wno-unused -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -LIBS = -lpthread +LIBS_libv4l1 = -lpthread V4L1_OBJS = libv4l1.o log.o V4L1COMPAT = v4l1compat.so @@ -75,7 +75,7 @@ clean:: $(CC) -c -MMD $(CPPFLAGS) $(CFLAGS) -o $@ $< %.so: - $(CC) -shared $(LDFLAGS) -Wl,-soname,$@.$(LIB_RELEASE) -o $@.$(LIB_RELEASE) $^ $(LIBS) + $(CC) -shared $(LDFLAGS) -Wl,-soname,$@.$(LIB_RELEASE) -o $@.$(LIB_RELEASE) $^ $(LIBS_$*) ln -f -s $@.$(LIB_RELEASE) $@ %.a: diff --git a/v4l2-apps/libv4l/libv4l2/Makefile b/v4l2-apps/libv4l/libv4l2/Makefile index 648d27c0c..8e6d2c31e 100644 --- a/v4l2-apps/libv4l/libv4l2/Makefile +++ b/v4l2-apps/libv4l/libv4l2/Makefile @@ -3,7 +3,7 @@ override CPPFLAGS += -I../include -I../../../include -fvisibility=hidden CFLAGS := -g -O1 CFLAGS += -Wall -Wno-unused -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -LIBS = -lpthread +LIBS_libv4l2 = -lpthread V4L2_OBJS = libv4l2.o log.o V4L2CONVERT = v4l2convert.so @@ -74,7 +74,7 @@ clean:: $(CC) -c -MMD $(CPPFLAGS) $(CFLAGS) -o $@ $< %.so: - $(CC) -shared $(LDFLAGS) -Wl,-soname,$@.$(LIB_RELEASE) -o $@.$(LIB_RELEASE) $^ $(LIBS) + $(CC) -shared $(LDFLAGS) -Wl,-soname,$@.$(LIB_RELEASE) -o $@.$(LIB_RELEASE) $^ $(LIBS_$*) ln -f -s $@.$(LIB_RELEASE) $@ %.a: -- cgit v1.2.3 From 8f3a94f3f8727434e98bd197727e9a8a1a8285c4 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 13:07:08 +0100 Subject: libv4l: Add Philips SPC210NC to list of cams with upside down sensor From: Hans de Goede libv4l: Add Philips SPC210NC to list of cams with upside down sensor Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 5 +++++ v4l2-apps/libv4l/Makefile | 2 +- v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 4 ++-- 3 files changed, 8 insertions(+), 3 deletions(-) (limited to 'v4l2-apps/libv4l') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index f64525126..cdb888892 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -1,3 +1,8 @@ +libv4l-0.5.2 +------------ +* Add Philips SPC210NC to list of cams with upside down sensor, reported by + Rieker Flaik + libv4l-0.5.1 ------------ * Add support for software cropping from 352x288 -> 320x240 / 176x144 -> diff --git a/v4l2-apps/libv4l/Makefile b/v4l2-apps/libv4l/Makefile index 13f216bc1..bfc31a185 100644 --- a/v4l2-apps/libv4l/Makefile +++ b/v4l2-apps/libv4l/Makefile @@ -1,5 +1,5 @@ LIB_RELEASE=0 -V4L2_LIB_VERSION=$(LIB_RELEASE).5.1 +V4L2_LIB_VERSION=$(LIB_RELEASE).5.2 all clean install: $(MAKE) -C libv4lconvert V4L2_LIB_VERSION=$(V4L2_LIB_VERSION) $@ diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index 362ac1914..3e93d98cc 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -65,8 +65,8 @@ static const struct v4lconvert_pixfmt supported_dst_pixfmts[] = { /* List of cams which need special flags */ static const struct v4lconvert_flags_info v4lconvert_flags[] = { { "SPC 200NC ", V4LCONVERT_ROTATE_180 }, - { "SPC 300NC ", V4LCONVERT_ROTATE_180 }, - { "USB Camera (0471:0325)", V4LCONVERT_ROTATE_180 }, /* SPC200NC */ + { "SPC 300NC ", V4LCONVERT_ROTATE_180 }, /* Unconfirmed ! */ + { "SPC210NC ", V4LCONVERT_ROTATE_180 }, { "USB Camera (0471:0326)", V4LCONVERT_ROTATE_180 }, /* SPC300NC */ { "USB Camera (093a:2476)", V4LCONVERT_ROTATE_180 }, /* Genius E-M 112 */ }; -- cgit v1.2.3 From 20b5011195e9b98e0cd6904e7a82d735ee542a52 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 13:07:28 +0100 Subject: libv4l: Make S_FMT handling more robust From: Hans de Goede Some drivers (pwc) do not properly reflect what one really gets after a s_fmt in their try_fmt answer. So update dest format (which we report as result from s_fmt / g_fmt to the app) with all info from the src format not changed by conversion. Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 2 ++ v4l2-apps/libv4l/libv4l2/libv4l2.c | 41 +++++++++++++++++++++++++++++++++----- 2 files changed, 38 insertions(+), 5 deletions(-) (limited to 'v4l2-apps/libv4l') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index cdb888892..509e64a62 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -2,6 +2,8 @@ libv4l-0.5.2 ------------ * Add Philips SPC210NC to list of cams with upside down sensor, reported by Rieker Flaik +* Work around some drivers (pwc) not properly reflecting what one gets after a + s_fmt in their try_fmt answer libv4l-0.5.1 ------------ diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2.c b/v4l2-apps/libv4l/libv4l2/libv4l2.c index 0a05623cb..dd422ea34 100644 --- a/v4l2-apps/libv4l/libv4l2/libv4l2.c +++ b/v4l2-apps/libv4l/libv4l2/libv4l2.c @@ -620,6 +620,36 @@ static int v4l2_check_buffer_change_ok(int index) return 0; } +static int v4l2_pix_fmt_identical(struct v4l2_format *a, struct v4l2_format *b) +{ + if (a->fmt.pix.width == b->fmt.pix.width && + a->fmt.pix.height == b->fmt.pix.height && + a->fmt.pix.pixelformat == b->fmt.pix.pixelformat && + a->fmt.pix.field == b->fmt.pix.field) + return 1; + + return 0; +} + +static void v4l2_set_src_and_dest_format(int index, + struct v4l2_format *src_fmt, struct v4l2_format *dest_fmt) +{ + /* Sigh some drivers (pwc) do not properly reflect what one really gets + after a s_fmt in their try_fmt answer. So update dest format (which we + report as result from s_fmt / g_fmt to the app) with all info from the src + format not changed by conversion */ + dest_fmt->fmt.pix.field = src_fmt->fmt.pix.field; + dest_fmt->fmt.pix.colorspace = src_fmt->fmt.pix.colorspace; + /* When we're not converting use bytesperline and imagesize from src_fmt */ + if (v4l2_pix_fmt_identical(src_fmt, dest_fmt)) { + dest_fmt->fmt.pix.bytesperline = src_fmt->fmt.pix.bytesperline; + dest_fmt->fmt.pix.sizeimage = src_fmt->fmt.pix.sizeimage; + } + + devices[index].src_fmt = *src_fmt; + devices[index].dest_fmt = *dest_fmt; +} + int v4l2_ioctl (int fd, unsigned long int request, ...) { void *arg; @@ -735,7 +765,8 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) { struct v4l2_format src_fmt, *dest_fmt = arg; - if (!memcmp(&devices[index].dest_fmt, dest_fmt, sizeof(*dest_fmt))) { + if (v4l2_pix_fmt_identical(&devices[index].dest_fmt, dest_fmt)) { + *dest_fmt = devices[index].dest_fmt; result = 0; break; } @@ -775,8 +806,9 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) /* Maybe after try format has adjusted width/height etc, to whats available nothing has changed (on the cam side) ? */ - if (!memcmp(&devices[index].src_fmt, &src_fmt, sizeof(src_fmt))) { - devices[index].dest_fmt = *dest_fmt; + if (v4l2_pix_fmt_identical(&devices[index].src_fmt, &src_fmt)) { + v4l2_set_src_and_dest_format(index, &devices[index].src_fmt, + dest_fmt); result = 0; break; } @@ -794,8 +826,7 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) break; } - devices[index].src_fmt = src_fmt; - devices[index].dest_fmt = *dest_fmt; + v4l2_set_src_and_dest_format(index, &src_fmt, dest_fmt); } break; -- cgit v1.2.3 From a5d0ef3556720bdb676c2c752b27e02be2d7e869 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 13:07:44 +0100 Subject: libv4l: make s_fmt more robust part 2 From: Hans de Goede Check that s_fmt atleast gives us the width, height and pixelformat try_fmt promised us, and if not disable conversion Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 2 ++ v4l2-apps/libv4l/libv4l2/libv4l2.c | 11 +++++++++++ 2 files changed, 13 insertions(+) (limited to 'v4l2-apps/libv4l') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index 509e64a62..04d9931b5 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -4,6 +4,8 @@ libv4l-0.5.2 Rieker Flaik * Work around some drivers (pwc) not properly reflecting what one gets after a s_fmt in their try_fmt answer +* Check that s_fmt atleast gives us the width, height and pixelformat try_fmt + promised us, and if not disable conversion libv4l-0.5.1 ------------ diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2.c b/v4l2-apps/libv4l/libv4l2/libv4l2.c index dd422ea34..d60ed6d39 100644 --- a/v4l2-apps/libv4l/libv4l2/libv4l2.c +++ b/v4l2-apps/libv4l/libv4l2/libv4l2.c @@ -764,6 +764,7 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) case VIDIOC_S_FMT: { struct v4l2_format src_fmt, *dest_fmt = arg; + struct v4l2_pix_format req_pix_fmt; if (v4l2_pix_fmt_identical(&devices[index].dest_fmt, dest_fmt)) { *dest_fmt = devices[index].dest_fmt; @@ -816,6 +817,7 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) if ((result = v4l2_check_buffer_change_ok(index))) break; + req_pix_fmt = src_fmt.fmt.pix; result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_S_FMT, &src_fmt); if (result) { saved_err = errno; @@ -825,6 +827,15 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) errno = saved_err; break; } + /* See if we've gotten what try_fmt promised us + (this check should never fail) */ + if (src_fmt.fmt.pix.width != req_pix_fmt.width || + src_fmt.fmt.pix.height != req_pix_fmt.height || + src_fmt.fmt.pix.pixelformat != req_pix_fmt.pixelformat) { + V4L2_LOG_ERR("set_fmt gave us a different result then try_fmt!\n"); + /* Not what we expected / wanted, disable conversion */ + *dest_fmt = src_fmt; + } v4l2_set_src_and_dest_format(index, &src_fmt, dest_fmt); } -- cgit v1.2.3 From ddf0a05516ddaefd3c473a3cc2bf5d6e170e5698 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 13:08:13 +0100 Subject: libv4l: don't use memcmp to compare pix_formats From: Hans de Goede Only check width, height and pixelformat when checking if we are doing conversion, instead of doing a memcmp, as that are the only things which the convert code checks Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 3 +++ v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 8 ++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'v4l2-apps/libv4l') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index 04d9931b5..c68c05445 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -6,6 +6,9 @@ libv4l-0.5.2 s_fmt in their try_fmt answer * Check that s_fmt atleast gives us the width, height and pixelformat try_fmt promised us, and if not disable conversion +* Only check width, height and pixelformat when checking if we are doing + conversion, instead of doing a memcmp, as that are the only things which + the convert code checks libv4l-0.5.1 ------------ diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index 3e93d98cc..daced73dd 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -301,7 +301,9 @@ int v4lconvert_try_format(struct v4lconvert_data *data, } /* Are we converting? */ - if(memcmp(&try_src, &try_dest, sizeof(try_src))) + 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) v4lconvert_fixup_fmt(&try_dest); *dest_fmt = try_dest; @@ -316,7 +318,9 @@ int v4lconvert_needs_conversion(struct v4lconvert_data *data, const struct v4l2_format *src_fmt, /* in */ const struct v4l2_format *dest_fmt) /* in */ { - if(memcmp(src_fmt, dest_fmt, sizeof(*src_fmt))) + if(src_fmt->fmt.pix.width != dest_fmt->fmt.pix.width || + src_fmt->fmt.pix.height != dest_fmt->fmt.pix.height || + src_fmt->fmt.pix.pixelformat != dest_fmt->fmt.pix.pixelformat) return 1; /* Formats differ */ if (!(data->flags & (V4LCONVERT_ROTATE_90|V4LCONVERT_ROTATE_180))) -- cgit v1.2.3 From 212f306971b622a70b8b3a20c61df11af814635a Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 13:08:30 +0100 Subject: libv4l: buffers only contain half of the lines with V4L2_FIELD_ALTERNATE From: Hans de Goede Take into account that the buffers only contain half of the lines when field is V4L2_FIELD_ALTERNATE Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 2 ++ v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 37 +++++++++++++++++--------- 2 files changed, 26 insertions(+), 13 deletions(-) (limited to 'v4l2-apps/libv4l') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index c68c05445..fa18321f4 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -9,6 +9,8 @@ libv4l-0.5.2 * Only check width, height and pixelformat when checking if we are doing conversion, instead of doing a memcmp, as that are the only things which the convert code checks +* Take into account that the buffers only contain half of the lines when + field is V4L2_FIELD_ALTERNATE libv4l-0.5.1 ------------ diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index daced73dd..4725e638f 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -587,6 +587,7 @@ int v4lconvert_convert(struct v4lconvert_data *data, unsigned char *convert_dest = dest, *rotate_src = src, *rotate_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)) { @@ -595,16 +596,25 @@ int v4lconvert_convert(struct v4lconvert_data *data, return to_copy; } + /* When field is V4L2_FIELD_ALTERNATE, each buffer only contains half the + lines */ + if (my_src_fmt.fmt.pix.field == V4L2_FIELD_ALTERNATE) { + my_src_fmt.fmt.pix.height /= 2; + my_dest_fmt.fmt.pix.height /= 2; + } + /* sanity check, is the dest buffer large enough? */ - switch (dest_fmt->fmt.pix.pixelformat) { + switch (my_dest_fmt.fmt.pix.pixelformat) { case V4L2_PIX_FMT_RGB24: case V4L2_PIX_FMT_BGR24: - dest_needed = dest_fmt->fmt.pix.width * dest_fmt->fmt.pix.height * 3; - temp_needed = src_fmt->fmt.pix.width * src_fmt->fmt.pix.height * 3; + dest_needed = my_dest_fmt.fmt.pix.width * my_dest_fmt.fmt.pix.height * 3; + temp_needed = my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3; break; case V4L2_PIX_FMT_YUV420: - dest_needed = dest_fmt->fmt.pix.width * dest_fmt->fmt.pix.height * 3 / 2; - temp_needed = src_fmt->fmt.pix.width * src_fmt->fmt.pix.height * 3 / 2; + dest_needed = + my_dest_fmt.fmt.pix.width * my_dest_fmt.fmt.pix.height * 3 / 2; + temp_needed = + my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3 / 2; break; default: V4LCONVERT_ERR("Unknown dest format in conversion\n"); @@ -618,7 +628,7 @@ int v4lconvert_convert(struct v4lconvert_data *data, return -1; } - if (dest_fmt->fmt.pix.pixelformat != src_fmt->fmt.pix.pixelformat) + if (my_dest_fmt.fmt.pix.pixelformat != my_src_fmt.fmt.pix.pixelformat) convert = 1; if (data->flags & V4LCONVERT_ROTATE_90) @@ -626,8 +636,8 @@ int v4lconvert_convert(struct v4lconvert_data *data, if (data->flags & V4LCONVERT_ROTATE_180) rotate += 180; - if (dest_fmt->fmt.pix.width != src_fmt->fmt.pix.width || - dest_fmt->fmt.pix.height != src_fmt->fmt.pix.height) + if (my_dest_fmt.fmt.pix.width != my_src_fmt.fmt.pix.width || + my_dest_fmt.fmt.pix.height != my_src_fmt.fmt.pix.height) crop = 1; /* convert_pixfmt -> rotate -> crop, all steps are optional */ @@ -642,14 +652,15 @@ int v4lconvert_convert(struct v4lconvert_data *data, } if (convert) { - res = v4lconvert_convert_pixfmt(data, src_fmt->fmt.pix.pixelformat, - dest_fmt->fmt.pix.pixelformat, - src_fmt->fmt.pix.width, src_fmt->fmt.pix.height, + res = v4lconvert_convert_pixfmt(data, my_src_fmt.fmt.pix.pixelformat, + my_dest_fmt.fmt.pix.pixelformat, + my_src_fmt.fmt.pix.width, + my_src_fmt.fmt.pix.height, src, src_size, convert_dest); if (res) return res; - my_src_fmt.fmt.pix.pixelformat = dest_fmt->fmt.pix.pixelformat; + my_src_fmt.fmt.pix.pixelformat = my_dest_fmt.fmt.pix.pixelformat; v4lconvert_fixup_fmt(&my_src_fmt); } @@ -659,7 +670,7 @@ int v4lconvert_convert(struct v4lconvert_data *data, my_src_fmt.fmt.pix.pixelformat, rotate); if (crop) - v4lconvert_crop(crop_src, dest, &my_src_fmt, dest_fmt); + v4lconvert_crop(crop_src, dest, &my_src_fmt, &my_dest_fmt); return dest_needed; } -- cgit v1.2.3 From e4def927f3ed43a4763652a0911f69180e803721 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 13:08:51 +0100 Subject: libv4l: dont try to allocate large buffers on the stack From: Hans de Goede When conversion requires multiple passes don't alloc the needed temporary buffer on the stack, as some apps (ekiga) use so much stack themselves this causes us to run out of stack space Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 6 +++ v4l2-apps/libv4l/Makefile | 2 +- .../libv4l/libv4lconvert/libv4lconvert-priv.h | 6 +++ v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 57 +++++++++++++++++++--- 4 files changed, 62 insertions(+), 9 deletions(-) (limited to 'v4l2-apps/libv4l') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index fa18321f4..f092cc418 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -1,3 +1,9 @@ +libv4l-0.5.3 +------------ +* When conversion requires multiple passes don't alloc the needed temporary + buffer on the stack, as some apps (ekiga) use so much stack themselves + this causes us to run out of stack space + libv4l-0.5.2 ------------ * Add Philips SPC210NC to list of cams with upside down sensor, reported by diff --git a/v4l2-apps/libv4l/Makefile b/v4l2-apps/libv4l/Makefile index bfc31a185..8de10a4cb 100644 --- a/v4l2-apps/libv4l/Makefile +++ b/v4l2-apps/libv4l/Makefile @@ -1,5 +1,5 @@ LIB_RELEASE=0 -V4L2_LIB_VERSION=$(LIB_RELEASE).5.2 +V4L2_LIB_VERSION=$(LIB_RELEASE).5.3 all clean install: $(MAKE) -C libv4lconvert V4L2_LIB_VERSION=$(V4L2_LIB_VERSION) $@ diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h index 99ffdec20..8473ba68f 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h @@ -86,6 +86,12 @@ struct v4lconvert_data { struct jdec_private *jdec; struct v4l2_frmsizeenum framesizes[V4LCONVERT_MAX_FRAMESIZES]; unsigned int no_framesizes; + int convert_buf_size; + int rotate_buf_size; + int convert_pixfmt_buf_size; + unsigned char *convert_buf; + unsigned char *rotate_buf; + unsigned char *convert_pixfmt_buf; }; struct v4lconvert_flags_info { diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index 4725e638f..ee6ef33a0 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -94,7 +94,6 @@ struct v4lconvert_data *v4lconvert_create(int fd) return NULL; data->fd = fd; - data->jdec = NULL; /* Check supported formats */ for (i = 0; ; i++) { @@ -135,6 +134,9 @@ void v4lconvert_destroy(struct v4lconvert_data *data) tinyjpeg_set_components(data->jdec, comps, 3); tinyjpeg_free(data->jdec); } + free(data->convert_buf); + free(data->rotate_buf); + free(data->convert_pixfmt_buf); free(data); } @@ -333,6 +335,23 @@ int v4lconvert_needs_conversion(struct v4lconvert_data *data, return 1; /* Needs flip and thus conversion */ } +static unsigned char *v4lconvert_alloc_buffer(struct v4lconvert_data *data, + int needed, unsigned char **buf, int *buf_size) +{ + if (*buf_size < needed) { + free(*buf); + *buf = malloc(needed); + if (*buf == NULL) { + *buf_size = 0; + V4LCONVERT_ERR("could not allocate memory\n"); + errno = ENOMEM; + return NULL; + } + *buf_size = needed; + } + return *buf; +} + static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, unsigned int src_pix_fmt, unsigned int dest_pix_fmt, unsigned int width, unsigned int height, @@ -444,8 +463,15 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, case V4L2_PIX_FMT_SPCA505: case V4L2_PIX_FMT_SPCA508: { - unsigned char tmpbuf[width * height * 3 / 2]; - unsigned char *d = (dest_pix_fmt != V4L2_PIX_FMT_YUV420) ? tmpbuf : dest; + unsigned char *d; + + if (dest_pix_fmt != V4L2_PIX_FMT_YUV420) { + d = v4lconvert_alloc_buffer(data, width * height * 3 / 2, + &data->convert_pixfmt_buf, &data->convert_pixfmt_buf_size); + if (!d) + return -1; + } else + d = dest; switch (src_pix_fmt) { case V4L2_PIX_FMT_SPCA501: @@ -461,10 +487,12 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, switch (dest_pix_fmt) { case V4L2_PIX_FMT_RGB24: - v4lconvert_yuv420_to_rgb24(tmpbuf, dest, width, height); + v4lconvert_yuv420_to_rgb24(data->convert_pixfmt_buf, dest, width, + height); break; case V4L2_PIX_FMT_BGR24: - v4lconvert_yuv420_to_bgr24(tmpbuf, dest, width, height); + v4lconvert_yuv420_to_bgr24(data->convert_pixfmt_buf, dest, width, + height); break; } break; @@ -475,9 +503,14 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, case V4L2_PIX_FMT_SN9C10X: case V4L2_PIX_FMT_PAC207: { - unsigned char tmpbuf[width * height]; + unsigned char *tmpbuf; unsigned int bayer_fmt = 0; + tmpbuf = v4lconvert_alloc_buffer(data, width * height, + &data->convert_pixfmt_buf, &data->convert_pixfmt_buf_size); + if (!tmpbuf) + return -1; + switch (src_pix_fmt) { case V4L2_PIX_FMT_SPCA561: v4lconvert_decode_spca561(src, tmpbuf, width, height); @@ -642,12 +675,20 @@ int v4lconvert_convert(struct v4lconvert_data *data, /* convert_pixfmt -> rotate -> crop, all steps are optional */ if (convert && (rotate || crop)) { - convert_dest = alloca(temp_needed); + convert_dest = v4lconvert_alloc_buffer(data, temp_needed, + &data->convert_buf, &data->convert_buf_size); + if (!convert_dest) + return -1; + rotate_src = crop_src = convert_dest; } if (rotate && crop) { - rotate_dest = alloca(temp_needed); + rotate_dest = v4lconvert_alloc_buffer(data, temp_needed, + &data->rotate_buf, &data->rotate_buf_size); + if (!rotate_dest) + return -1; + crop_src = rotate_dest; } -- cgit v1.2.3 From 93d4ae910ce9eeaa5998e3aa1980c3647d959fc6 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 13:09:27 +0100 Subject: libv4l: Don't report DQBUF errors when errno is EAGAIN From: Hans de Goede Don't report DQBUF errors when errno is EAGAIN, this fixes flooding the screen with errors when applications use non blocking mode Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 5 +++++ v4l2-apps/libv4l/Makefile | 2 +- v4l2-apps/libv4l/libv4l2/libv4l2.c | 8 +++++--- 3 files changed, 11 insertions(+), 4 deletions(-) (limited to 'v4l2-apps/libv4l') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index f092cc418..624f6dc43 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -1,3 +1,8 @@ +libv4l-0.5.4 +------------ +* Don't report DQBUF errors when errno is EAGAIN, this fixes flooding the + screen with errors when applications use non blocking mode + libv4l-0.5.3 ------------ * When conversion requires multiple passes don't alloc the needed temporary diff --git a/v4l2-apps/libv4l/Makefile b/v4l2-apps/libv4l/Makefile index 8de10a4cb..13cb6c459 100644 --- a/v4l2-apps/libv4l/Makefile +++ b/v4l2-apps/libv4l/Makefile @@ -1,5 +1,5 @@ LIB_RELEASE=0 -V4L2_LIB_VERSION=$(LIB_RELEASE).5.3 +V4L2_LIB_VERSION=$(LIB_RELEASE).5.4 all clean install: $(MAKE) -C libv4lconvert V4L2_LIB_VERSION=$(V4L2_LIB_VERSION) $@ diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2.c b/v4l2-apps/libv4l/libv4l2/libv4l2.c index d60ed6d39..314087255 100644 --- a/v4l2-apps/libv4l/libv4l2/libv4l2.c +++ b/v4l2-apps/libv4l/libv4l2/libv4l2.c @@ -264,9 +264,11 @@ static int v4l2_dequeue_and_convert(int index, struct v4l2_buffer *buf, 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; + if (errno != EAGAIN) { + int saved_err = errno; + V4L2_LOG_ERR("dequeuing buf: %s\n", strerror(errno)); + errno = saved_err; + } return result; } -- cgit v1.2.3 From b326eb353c8691cc4c32ca59c0a2cf60ca74c3b6 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 13:09:42 +0100 Subject: libv4l: add support for downscaling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From: Lukáš Karas Add support for downscaling to make apps which want low resolutions (skype, spcaview) happy when used with cams which can only do high resolutions. Priority: normal Signed-off-by: Lukáš Karas Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 3 + v4l2-apps/libv4l/libv4lconvert/crop.c | 83 +++++++++++++++++++++++++- v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 29 ++++----- 3 files changed, 99 insertions(+), 16 deletions(-) (limited to 'v4l2-apps/libv4l') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index 624f6dc43..b6097fe41 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -2,6 +2,9 @@ libv4l-0.5.4 ------------ * Don't report DQBUF errors when errno is EAGAIN, this fixes flooding the screen with errors when applications use non blocking mode +* Add support for downscaling to make apps which want low resolutions + (skype, spcaview) happy when used with cams which can only do high + resolutions (by Lukáš Karas ). libv4l-0.5.3 ------------ diff --git a/v4l2-apps/libv4l/libv4lconvert/crop.c b/v4l2-apps/libv4l/libv4lconvert/crop.c index 290756b99..dcfa5152a 100644 --- a/v4l2-apps/libv4l/libv4lconvert/crop.c +++ b/v4l2-apps/libv4l/libv4lconvert/crop.c @@ -23,6 +23,29 @@ #include #include "libv4lconvert-priv.h" + +static void v4lconvert_reduceandcrop_rgbbgr24( + unsigned char *src, unsigned char *dest, + const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt) +{ + int x, y; + 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; + + src += starty * src_fmt->fmt.pix.bytesperline + 3 * startx; + + for (y = 0; y < dest_fmt->fmt.pix.height; y++) { + unsigned char *mysrc = src; + for (x = 0; x < dest_fmt->fmt.pix.width; x++) { + *(dest++) = *(mysrc++); + *(dest++) = *(mysrc++); + *(dest++) = *(mysrc++); + mysrc += 3; /* skip one pixel */ + } + src += 2 * src_fmt->fmt.pix.bytesperline; /* skip one line */ + } +} + static void v4lconvert_crop_rgbbgr24(unsigned char *src, unsigned char *dest, const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt) { @@ -39,6 +62,53 @@ static void v4lconvert_crop_rgbbgr24(unsigned char *src, unsigned char *dest, } } +static void v4lconvert_reduceandcrop_yuv420( + unsigned char *src, unsigned char *dest, + const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt) +{ + 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; + unsigned char *mysrc, *mysrc2; + + /* Y */ + mysrc = src + starty * src_fmt->fmt.pix.bytesperline + startx; + for (y = 0; y < dest_fmt->fmt.pix.height; y++){ + mysrc2 = mysrc; + for (x = 0; x < dest_fmt->fmt.pix.width; x++){ + *(dest++) = *mysrc2; + mysrc2 += 2; /* skip one pixel */ + } + mysrc += 2 * src_fmt->fmt.pix.bytesperline; /* skip one line */ + } + + /* U */ + mysrc = src + src_fmt->fmt.pix.height * src_fmt->fmt.pix.bytesperline + + (starty / 2) * src_fmt->fmt.pix.bytesperline / 2 + startx / 2; + for (y = 0; y < dest_height_half; y++){ + mysrc2 = mysrc; + for (x = 0; x < dest_width_half; x++){ + *(dest++) = *mysrc2; + mysrc2 += 2; /* skip one pixel */ + } + mysrc += src_fmt->fmt.pix.bytesperline ; /* skip one line */ + } + + /* V */ + mysrc = src + src_fmt->fmt.pix.height * src_fmt->fmt.pix.bytesperline * 5 / 4 + + (starty / 2) * src_fmt->fmt.pix.bytesperline / 2 + startx / 2; + for (y = 0; y < dest_height_half; y++){ + mysrc2 = mysrc; + for (x = 0; x < dest_width_half; x++){ + *(dest++) = *mysrc2; + mysrc2 += 2; /* skip one pixel */ + } + mysrc += src_fmt->fmt.pix.bytesperline ; /* skip one line */ + } +} + static void v4lconvert_crop_yuv420(unsigned char *src, unsigned char *dest, const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt) { @@ -79,10 +149,19 @@ void v4lconvert_crop(unsigned char *src, unsigned char *dest, switch (dest_fmt->fmt.pix.pixelformat) { case V4L2_PIX_FMT_RGB24: case V4L2_PIX_FMT_BGR24: - v4lconvert_crop_rgbbgr24(src, dest, src_fmt, dest_fmt); + 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: - v4lconvert_crop_yuv420(src, dest, src_fmt, dest_fmt); + if (src_fmt->fmt.pix.width >= 2 * dest_fmt->fmt.pix.width && + src_fmt->fmt.pix.height >= 2 * dest_fmt->fmt.pix.height) + v4lconvert_reduceandcrop_yuv420(src, dest, src_fmt, dest_fmt); + else + v4lconvert_crop_yuv420(src, dest, src_fmt, dest_fmt); + break; } } diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index ee6ef33a0..536e5363d 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -268,29 +268,30 @@ int v4lconvert_try_format(struct v4lconvert_data *data, return result; } - /* In case of a non exact resolution match, see if this is a resolution we - can support by cropping a slightly larger resolution to give the app - exactly what it asked for */ + /* 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 */ 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_dest, try2_src; + struct v4l2_format try2_src, 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 */ - unsigned int max_width = desired_width * 113 / 100; - unsigned int max_height = desired_height * 124 / 100; - - try2_dest = *dest_fmt; - try2_dest.fmt.pix.width = max_width; - try2_dest.fmt.pix.height = max_height; + try2_dest.fmt.pix.width = desired_width * 113 / 100; + 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 && - try2_dest.fmt.pix.width <= max_width && - try2_dest.fmt.pix.height >= desired_height && - try2_dest.fmt.pix.height <= max_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) || + (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 * 5 / 2))) { /* Success! */ try2_dest.fmt.pix.width = desired_width; try2_dest.fmt.pix.height = desired_height; -- cgit v1.2.3 From 5f90628a20098c6dcde990310eaaabec2cef4694 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 13:10:27 +0100 Subject: libv4l: add support for converting to YV12 planar From: Hans de Goede Add support for converting to YV12 planar (next to the already supported YU12 / I420) and implement RGB/BGR24 -> YU/YV12 conversion Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 3 + v4l2-apps/libv4l/TODO | 4 +- v4l2-apps/libv4l/libv4lconvert/bayer.c | 17 ++- v4l2-apps/libv4l/libv4lconvert/crop.c | 1 + v4l2-apps/libv4l/libv4lconvert/flip.c | 2 + .../libv4l/libv4lconvert/libv4lconvert-priv.h | 24 ++-- v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 101 +++++++++++---- v4l2-apps/libv4l/libv4lconvert/rgbyuv.c | 139 ++++++++++++++++++--- v4l2-apps/libv4l/libv4lconvert/spca501.c | 36 ++++-- 9 files changed, 260 insertions(+), 67 deletions(-) (limited to 'v4l2-apps/libv4l') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index b6097fe41..49f1fd035 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -5,6 +5,9 @@ libv4l-0.5.4 * Add support for downscaling to make apps which want low resolutions (skype, spcaview) happy when used with cams which can only do high resolutions (by Lukáš Karas ). +* Add support for converting to YV12 planar (next to the already supported + YU12 / I420) +* Implement RGB/BGR24 -> YU/YV12 conversion libv4l-0.5.3 ------------ diff --git a/v4l2-apps/libv4l/TODO b/v4l2-apps/libv4l/TODO index f3f9ff527..debb9c78c 100644 --- a/v4l2-apps/libv4l/TODO +++ b/v4l2-apps/libv4l/TODO @@ -7,6 +7,4 @@ impossible for overlays) can be done, so that it will no longer be necessary to implement CGMBUF in the kernel for each driver. --check v4l2_field during conversion - --add conversion from bgr24 to yuv420 +-take the possibility of pitch != width into account everywhere diff --git a/v4l2-apps/libv4l/libv4lconvert/bayer.c b/v4l2-apps/libv4l/libv4lconvert/bayer.c index ca7bb486f..033ee2724 100644 --- a/v4l2-apps/libv4l/libv4lconvert/bayer.c +++ b/v4l2-apps/libv4l/libv4lconvert/bayer.c @@ -433,16 +433,23 @@ static void v4lconvert_border_bayer_line_to_y( } } -void v4lconvert_bayer_to_yuv420(const unsigned char *bayer, - unsigned char *yuv, int width, int height, unsigned int pixfmt) +void v4lconvert_bayer_to_yuv420(const unsigned char *bayer, unsigned char *yuv, + int width, int height, unsigned int src_pixfmt, int yvu) { int blue_line = 0, start_with_green = 0, x, y; unsigned char *ydst = yuv; - unsigned char *udst = yuv + width * height; - unsigned char *vdst = udst + width * height / 4; + unsigned char *udst, *vdst; + + if (yvu) { + vdst = yuv + width * height; + udst = vdst + width * height / 4; + } else { + udst = yuv + width * height; + vdst = udst + width * height / 4; + } /* First calculate the u and v planes 2x2 pixels at a time */ - switch (pixfmt) { + switch (src_pixfmt) { case V4L2_PIX_FMT_SBGGR8: for (y = 0; y < height; y += 2) { for (x = 0; x < width; x += 2) { diff --git a/v4l2-apps/libv4l/libv4lconvert/crop.c b/v4l2-apps/libv4l/libv4lconvert/crop.c index dcfa5152a..4294fbeaf 100644 --- a/v4l2-apps/libv4l/libv4lconvert/crop.c +++ b/v4l2-apps/libv4l/libv4lconvert/crop.c @@ -156,6 +156,7 @@ void v4lconvert_crop(unsigned char *src, unsigned char *dest, 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) v4lconvert_reduceandcrop_yuv420(src, dest, src_fmt, dest_fmt); diff --git a/v4l2-apps/libv4l/libv4lconvert/flip.c b/v4l2-apps/libv4l/libv4lconvert/flip.c index 5a108c8d9..f47afde72 100644 --- a/v4l2-apps/libv4l/libv4lconvert/flip.c +++ b/v4l2-apps/libv4l/libv4lconvert/flip.c @@ -119,6 +119,7 @@ void v4lconvert_rotate(unsigned char *src, unsigned char *dest, v4lconvert_rotate90_rgbbgr24(src, dest, width, height); break; case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: v4lconvert_rotate90_yuv420(src, dest, width, height); break; } @@ -130,6 +131,7 @@ void v4lconvert_rotate(unsigned char *src, unsigned char *dest, v4lconvert_rotate180_rgbbgr24(src, dest, width, height); break; case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: v4lconvert_rotate180_yuv420(src, dest, width, height); break; } diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h index 8473ba68f..a534ca321 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h @@ -104,11 +104,14 @@ struct v4lconvert_pixfmt { int flags; }; +void v4lconvert_rgb24_to_yuv420(const unsigned char *src, unsigned char *dest, + const struct v4l2_format *src_fmt, int bgr, int yvu); + void v4lconvert_yuv420_to_rgb24(const unsigned char *src, unsigned char *dst, - int width, int height); + int width, int height, int yvu); void v4lconvert_yuv420_to_bgr24(const unsigned char *src, unsigned char *dst, - int width, int height); + int width, int height, int yvu); void v4lconvert_yuyv_to_rgb24(const unsigned char *src, unsigned char *dst, int width, int height); @@ -117,7 +120,7 @@ void v4lconvert_yuyv_to_bgr24(const unsigned char *src, unsigned char *dst, int width, int height); void v4lconvert_yuyv_to_yuv420(const unsigned char *src, unsigned char *dst, - int width, int height); + int width, int height, int yvu); void v4lconvert_yvyu_to_rgb24(const unsigned char *src, unsigned char *dst, int width, int height); @@ -126,19 +129,22 @@ void v4lconvert_yvyu_to_bgr24(const unsigned char *src, unsigned char *dst, int width, int height); void v4lconvert_yvyu_to_yuv420(const unsigned char *src, unsigned char *dst, - int width, int height); + int width, int height, int yvu); void v4lconvert_swap_rgb(const unsigned char *src, unsigned char *dst, int width, int height); +void v4lconvert_swap_uv(const unsigned char *src, unsigned char *dst, + const struct v4l2_format *src_fmt); + void v4lconvert_spca501_to_yuv420(const unsigned char *src, unsigned char *dst, - int width, int height); + int width, int height, int yvu); void v4lconvert_spca505_to_yuv420(const unsigned char *src, unsigned char *dst, - int width, int height); + int width, int height, int yvu); void v4lconvert_spca508_to_yuv420(const unsigned char *src, unsigned char *dst, - int width, int height); + int width, int height, int yvu); void v4lconvert_decode_spca561(const unsigned char *src, unsigned char *dst, int width, int height); @@ -155,8 +161,8 @@ void v4lconvert_bayer_to_rgb24(const unsigned char *bayer, void v4lconvert_bayer_to_bgr24(const unsigned char *bayer, unsigned char *rgb, int width, int height, unsigned int pixfmt); -void v4lconvert_bayer_to_yuv420(const unsigned char *bayer, - unsigned char *yuv, int width, int height, unsigned int pixfmt); +void v4lconvert_bayer_to_yuv420(const unsigned char *bayer, unsigned char *yuv, + int width, int height, unsigned int src_pixfmt, int yvu); void v4lconvert_rotate(unsigned char *src, unsigned char *dest, int width, int height, unsigned int pix_fmt, int rotate); diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index 536e5363d..c6c50c2e5 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -32,7 +32,8 @@ #define SUPPORTED_DST_PIXFMTS \ { V4L2_PIX_FMT_RGB24, 0 }, \ { V4L2_PIX_FMT_BGR24, 0 }, \ - { V4L2_PIX_FMT_YUV420, 0 } + { V4L2_PIX_FMT_YUV420, 0 }, \ + { V4L2_PIX_FMT_YVU420, 0 } static void v4lconvert_get_framesizes(struct v4lconvert_data *data, unsigned int pixelformat); @@ -243,6 +244,7 @@ static void v4lconvert_fixup_fmt(struct v4l2_format *fmt) fmt->fmt.pix.sizeimage = fmt->fmt.pix.width * fmt->fmt.pix.height * 3; break; case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: fmt->fmt.pix.bytesperline = fmt->fmt.pix.width; fmt->fmt.pix.sizeimage = fmt->fmt.pix.width * fmt->fmt.pix.height * 3 / 2; break; @@ -354,13 +356,15 @@ static unsigned char *v4lconvert_alloc_buffer(struct v4lconvert_data *data, } static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, - unsigned int src_pix_fmt, unsigned int dest_pix_fmt, - unsigned int width, unsigned int height, - unsigned char *src, int src_size, unsigned char *dest) + unsigned char *src, int src_size, unsigned char *dest, + const struct v4l2_format *src_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; switch (src_pix_fmt) { case V4L2_PIX_FMT_PJPG: @@ -404,8 +408,6 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, } components[0] = dest; - components[1] = components[0] + width * height; - components[2] = components[1] + width * height / 4; switch (dest_pix_fmt) { case V4L2_PIX_FMT_RGB24: @@ -417,6 +419,14 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, result = tinyjpeg_decode(data->jdec, TINYJPEG_FMT_BGR24); break; case V4L2_PIX_FMT_YUV420: + components[1] = components[0] + width * height; + components[2] = components[1] + width * height / 4; + tinyjpeg_set_components(data->jdec, components, 3); + result = tinyjpeg_decode(data->jdec, TINYJPEG_FMT_YUV420P); + break; + case V4L2_PIX_FMT_YVU420: + components[2] = components[0] + width * height; + components[1] = components[2] + width * height / 4; tinyjpeg_set_components(data->jdec, components, 3); result = tinyjpeg_decode(data->jdec, TINYJPEG_FMT_YUV420P); break; @@ -454,7 +464,10 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, v4lconvert_bayer_to_bgr24(src, dest, width, height, src_pix_fmt); break; case V4L2_PIX_FMT_YUV420: - v4lconvert_bayer_to_yuv420(src, dest, width, height, src_pix_fmt); + v4lconvert_bayer_to_yuv420(src, dest, width, height, src_pix_fmt, 0); + break; + case V4L2_PIX_FMT_YVU420: + v4lconvert_bayer_to_yuv420(src, dest, width, height, src_pix_fmt, 1); break; } break; @@ -465,8 +478,10 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, case V4L2_PIX_FMT_SPCA508: { unsigned char *d; + int yvu = 0; - if (dest_pix_fmt != V4L2_PIX_FMT_YUV420) { + if (dest_pix_fmt != V4L2_PIX_FMT_YUV420 && + dest_pix_fmt != V4L2_PIX_FMT_YVU420) { d = v4lconvert_alloc_buffer(data, width * height * 3 / 2, &data->convert_pixfmt_buf, &data->convert_pixfmt_buf_size); if (!d) @@ -474,26 +489,29 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, } else d = dest; + if (dest_pix_fmt == V4L2_PIX_FMT_YVU420) + yvu = 1; + switch (src_pix_fmt) { case V4L2_PIX_FMT_SPCA501: - v4lconvert_spca501_to_yuv420(src, d, width, height); + v4lconvert_spca501_to_yuv420(src, d, width, height, yvu); break; case V4L2_PIX_FMT_SPCA505: - v4lconvert_spca505_to_yuv420(src, d, width, height); + v4lconvert_spca505_to_yuv420(src, d, width, height, yvu); break; case V4L2_PIX_FMT_SPCA508: - v4lconvert_spca508_to_yuv420(src, d, width, height); + v4lconvert_spca508_to_yuv420(src, d, width, height, yvu); break; } switch (dest_pix_fmt) { case V4L2_PIX_FMT_RGB24: v4lconvert_yuv420_to_rgb24(data->convert_pixfmt_buf, dest, width, - height); + height, yvu); break; case V4L2_PIX_FMT_BGR24: v4lconvert_yuv420_to_bgr24(data->convert_pixfmt_buf, dest, width, - height); + height, yvu); break; } break; @@ -535,7 +553,10 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, v4lconvert_bayer_to_bgr24(tmpbuf, dest, width, height, bayer_fmt); break; case V4L2_PIX_FMT_YUV420: - v4lconvert_bayer_to_yuv420(tmpbuf, dest, width, height, bayer_fmt); + v4lconvert_bayer_to_yuv420(tmpbuf, dest, width, height, bayer_fmt, 0); + break; + case V4L2_PIX_FMT_YVU420: + v4lconvert_bayer_to_yuv420(tmpbuf, dest, width, height, bayer_fmt, 1); break; } break; @@ -547,7 +568,10 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, v4lconvert_swap_rgb(src, dest, width, height); break; case V4L2_PIX_FMT_YUV420: - printf("FIXME add rgb24 -> yuv420 conversion\n"); + v4lconvert_rgb24_to_yuv420(src, dest, src_fmt, 0, 0); + break; + case V4L2_PIX_FMT_YVU420: + v4lconvert_rgb24_to_yuv420(src, dest, src_fmt, 0, 1); break; } break; @@ -558,7 +582,10 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, v4lconvert_swap_rgb(src, dest, width, height); break; case V4L2_PIX_FMT_YUV420: - printf("FIXME add bgr24 -> yuv420 conversion\n"); + v4lconvert_rgb24_to_yuv420(src, dest, src_fmt, 1, 0); + break; + case V4L2_PIX_FMT_YVU420: + v4lconvert_rgb24_to_yuv420(src, dest, src_fmt, 1, 1); break; } break; @@ -567,11 +594,30 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, switch (dest_pix_fmt) { case V4L2_PIX_FMT_RGB24: v4lconvert_yuv420_to_rgb24(src, dest, width, - height); + height, 0); break; case V4L2_PIX_FMT_BGR24: v4lconvert_yuv420_to_bgr24(src, dest, width, - height); + height, 0); + break; + case V4L2_PIX_FMT_YVU420: + v4lconvert_swap_uv(src, dest, src_fmt); + break; + } + break; + + case V4L2_PIX_FMT_YVU420: + switch (dest_pix_fmt) { + case V4L2_PIX_FMT_RGB24: + v4lconvert_yuv420_to_rgb24(src, dest, width, + height, 1); + break; + case V4L2_PIX_FMT_BGR24: + v4lconvert_yuv420_to_bgr24(src, dest, width, + height, 1); + break; + case V4L2_PIX_FMT_YUV420: + v4lconvert_swap_uv(src, dest, src_fmt); break; } break; @@ -585,7 +631,10 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, v4lconvert_yuyv_to_bgr24(src, dest, width, height); break; case V4L2_PIX_FMT_YUV420: - v4lconvert_yuyv_to_yuv420(src, dest, width, height); + v4lconvert_yuyv_to_yuv420(src, dest, width, height, 0); + break; + case V4L2_PIX_FMT_YVU420: + v4lconvert_yuyv_to_yuv420(src, dest, width, height, 1); break; } break; @@ -599,7 +648,10 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, v4lconvert_yvyu_to_bgr24(src, dest, width, height); break; case V4L2_PIX_FMT_YUV420: - v4lconvert_yvyu_to_yuv420(src, dest, width, height); + v4lconvert_yvyu_to_yuv420(src, dest, width, height, 0); + break; + case V4L2_PIX_FMT_YVU420: + v4lconvert_yvyu_to_yuv420(src, dest, width, height, 1); break; } break; @@ -645,6 +697,7 @@ int v4lconvert_convert(struct v4lconvert_data *data, temp_needed = my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3; break; case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: dest_needed = my_dest_fmt.fmt.pix.width * my_dest_fmt.fmt.pix.height * 3 / 2; temp_needed = @@ -694,11 +747,9 @@ int v4lconvert_convert(struct v4lconvert_data *data, } if (convert) { - res = v4lconvert_convert_pixfmt(data, my_src_fmt.fmt.pix.pixelformat, - my_dest_fmt.fmt.pix.pixelformat, - my_src_fmt.fmt.pix.width, - my_src_fmt.fmt.pix.height, - src, src_size, convert_dest); + res = v4lconvert_convert_pixfmt(data, src, src_size, convert_dest, + &my_src_fmt, + my_dest_fmt.fmt.pix.pixelformat); if (res) return res; diff --git a/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c b/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c index 0f26b227a..d5feb457e 100644 --- a/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c +++ b/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c @@ -20,13 +20,65 @@ */ +#include #include "libv4lconvert-priv.h" -#define RGB2YUV(r,g,b,y,u,v) \ - (y) = (( 8453*(r) + 16594*(g) + 3223*(b) + 524288) >> 15); \ +#define RGB2Y(r,g,b,y) \ + (y) = (( 8453*(r) + 16594*(g) + 3223*(b) + 524288) >> 15) + +#define RGB2UV(r,g,b,u,v) \ (u) = (( -4878*(r) - 9578*(g) + 14456*(b) + 4210688) >> 15); \ (v) = (( 14456*(r) - 12105*(g) - 2351*(b) + 4210688) >> 15) +void v4lconvert_rgb24_to_yuv420(const unsigned char *src, unsigned char *dest, + const struct v4l2_format *src_fmt, int bgr, int yvu) +{ + int x, y; + unsigned char *udest, *vdest; + + /* Y */ + for (y = 0; y < src_fmt->fmt.pix.height; y++) { + for (x = 0; x < src_fmt->fmt.pix.width; x++) { + if (bgr) { + RGB2Y(src[2], src[1], src[0], *dest++); + } else { + RGB2Y(src[0], src[1], src[2], *dest++); + } + src += 3; + } + src += src_fmt->fmt.pix.bytesperline - 3 * src_fmt->fmt.pix.width; + } + src -= src_fmt->fmt.pix.height * src_fmt->fmt.pix.bytesperline; + + /* U + V */ + if (yvu) { + vdest = dest; + udest = dest + src_fmt->fmt.pix.width * src_fmt->fmt.pix.height / 4; + } else { + udest = dest; + vdest = dest + src_fmt->fmt.pix.width * src_fmt->fmt.pix.height / 4; + } + + for (y = 0; y < src_fmt->fmt.pix.height / 2; y++) { + for (x = 0; x < src_fmt->fmt.pix.width / 2; x++) { + int avg_src[3]; + avg_src[0] = (src[0] + src[3] + src[src_fmt->fmt.pix.bytesperline] + + src[src_fmt->fmt.pix.bytesperline + 3]) / 4; + avg_src[1] = (src[1] + src[4] + src[src_fmt->fmt.pix.bytesperline + 1] + + src[src_fmt->fmt.pix.bytesperline + 4]) / 4; + avg_src[2] = (src[2] + src[5] + src[src_fmt->fmt.pix.bytesperline + 2] + + src[src_fmt->fmt.pix.bytesperline + 5]) / 4; + if (bgr) { + RGB2UV(avg_src[2], avg_src[1], avg_src[0], *udest++, *vdest++); + } else { + RGB2UV(avg_src[0], avg_src[1], avg_src[2], *udest++, *vdest++); + } + src += 6; + } + src += 2 * src_fmt->fmt.pix.bytesperline - 3 * src_fmt->fmt.pix.width; + } +} + #define YUV2R(y, u, v) ({ \ int r = (y) + ((((v)-128)*1436) >> 10); r > 255 ? 255 : r < 0 ? 0 : r; }) #define YUV2G(y, u, v) ({ \ @@ -37,13 +89,20 @@ #define CLIP(color) (unsigned char)(((color)>0xFF)?0xff:(((color)<0)?0:(color))) void v4lconvert_yuv420_to_bgr24(const unsigned char *src, unsigned char *dest, - int width, int height) + int width, int height, int yvu) { int i,j; const unsigned char *ysrc = src; - const unsigned char *usrc = src + width * height; - const unsigned char *vsrc = usrc + (width * height) / 4; + const unsigned char *usrc, *vsrc; + + if (yvu) { + vsrc = src + width * height; + usrc = vsrc + (width * height) / 4; + } else { + usrc = src + width * height; + vsrc = usrc + (width * height) / 4; + } for (i = 0; i < height; i++) { for (j = 0; j < width; j += 2) { @@ -84,13 +143,20 @@ void v4lconvert_yuv420_to_bgr24(const unsigned char *src, unsigned char *dest, } void v4lconvert_yuv420_to_rgb24(const unsigned char *src, unsigned char *dest, - int width, int height) + int width, int height, int yvu) { int i,j; const unsigned char *ysrc = src; - const unsigned char *usrc = src + width * height; - const unsigned char *vsrc = usrc + (width * height) / 4; + const unsigned char *usrc, *vsrc; + + if (yvu) { + vsrc = src + width * height; + usrc = vsrc + (width * height) / 4; + } else { + usrc = src + width * height; + vsrc = usrc + (width * height) / 4; + } for (i = 0; i < height; i++) { for (j = 0; j < width; j += 2) { @@ -183,11 +249,11 @@ void v4lconvert_yuyv_to_rgb24(const unsigned char *src, unsigned char *dest, } void v4lconvert_yuyv_to_yuv420(const unsigned char *src, unsigned char *dest, - int width, int height) + int width, int height, int yvu) { int i, j; const unsigned char *src1; - unsigned char *vdest; + unsigned char *udest, *vdest; /* copy the Y values */ src1 = src; @@ -202,10 +268,16 @@ void v4lconvert_yuyv_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 */ - vdest = dest + width * height / 4; + if (yvu) { + vdest = dest; + udest = dest + width * height / 4; + } else { + udest = dest; + vdest = dest + width * height / 4; + } for (i = 0; i < height; i += 2) { for (j = 0; j < width; j += 2) { - *dest++ = ((int) src[0] + src1[0]) / 2; /* U */ + *udest++ = ((int) src[0] + src1[0]) / 2; /* U */ *vdest++ = ((int) src[2] + src1[2]) / 2; /* V */ src += 4; src1 += 4; @@ -268,11 +340,11 @@ void v4lconvert_yvyu_to_rgb24(const unsigned char *src, unsigned char *dest, } void v4lconvert_yvyu_to_yuv420(const unsigned char *src, unsigned char *dest, - int width, int height) + int width, int height, int yvu) { int i, j; const unsigned char *src1; - unsigned char *vdest; + unsigned char *udest, *vdest; /* copy the Y values */ src1 = src; @@ -287,10 +359,16 @@ void v4lconvert_yvyu_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 */ - vdest = dest + width * height / 4; + if (yvu) { + vdest = dest; + udest = dest + width * height / 4; + } else { + udest = dest; + vdest = dest + width * height / 4; + } for (i = 0; i < height; i += 2) { for (j = 0; j < width; j += 2) { - *dest++ = ((int) src[2] + src1[2]) / 2; /* U */ + *udest++ = ((int) src[2] + src1[2]) / 2; /* U */ *vdest++ = ((int) src[0] + src1[0]) / 2; /* V */ src += 4; src1 += 4; @@ -314,3 +392,32 @@ void v4lconvert_swap_rgb(const unsigned char *src, unsigned char *dst, *dst++ = tmp0; } } + +void v4lconvert_swap_uv(const unsigned char *src, unsigned char *dest, + const struct v4l2_format *src_fmt) +{ + int y; + + /* Copy Y */ + for (y = 0; y < src_fmt->fmt.pix.height; y++) { + memcpy(dest, src, src_fmt->fmt.pix.width); + dest += src_fmt->fmt.pix.width; + src += src_fmt->fmt.pix.bytesperline; + } + + /* Copy component 2 */ + src += src_fmt->fmt.pix.height * src_fmt->fmt.pix.bytesperline / 4; + for (y = 0; y < src_fmt->fmt.pix.height / 2; y++) { + memcpy(dest, src, src_fmt->fmt.pix.width / 2); + dest += src_fmt->fmt.pix.width / 2; + src += src_fmt->fmt.pix.bytesperline / 2; + } + + /* Copy component 1 */ + src -= src_fmt->fmt.pix.height * src_fmt->fmt.pix.bytesperline / 2; + for (y = 0; y < src_fmt->fmt.pix.height / 2; y++) { + memcpy(dest, src, src_fmt->fmt.pix.width / 2); + dest += src_fmt->fmt.pix.width / 2; + src += src_fmt->fmt.pix.bytesperline / 2; + } +} diff --git a/v4l2-apps/libv4l/libv4lconvert/spca501.c b/v4l2-apps/libv4l/libv4lconvert/spca501.c index 9157629e3..f491512e3 100644 --- a/v4l2-apps/libv4l/libv4lconvert/spca501.c +++ b/v4l2-apps/libv4l/libv4lconvert/spca501.c @@ -20,7 +20,7 @@ /* YUYV per line */ void v4lconvert_spca501_to_yuv420(const unsigned char *src, unsigned char *dst, - int width, int height) + int width, int height, int yvu) { int i,j; unsigned long *lsrc = (unsigned long *)src; @@ -34,7 +34,10 @@ void v4lconvert_spca501_to_yuv420(const unsigned char *src, unsigned char *dst, } /* -128 - 127 --> 0 - 255 and copy 1 line U */ - ldst = (unsigned long *)(dst + width * height + i * width / 4); + if (yvu) + ldst = (unsigned long *)(dst + (width * height * 5) / 4 + i * width / 4); + else + ldst = (unsigned long *)(dst + width * height + i * width / 4); for (j = 0; j < width/2; j += sizeof(long)) { *ldst = *lsrc++; *ldst++ ^= 0x8080808080808080ULL; @@ -48,7 +51,10 @@ void v4lconvert_spca501_to_yuv420(const unsigned char *src, unsigned char *dst, } /* -128 - 127 --> 0 - 255 and copy 1 line V */ - ldst = (unsigned long *)(dst + (width * height * 5) / 4 + i * width / 4); + if (yvu) + ldst = (unsigned long *)(dst + width * height + i * width / 4); + else + ldst = (unsigned long *)(dst + (width * height * 5) / 4 + i * width / 4); for (j = 0; j < width/2; j += sizeof(long)) { *ldst = *lsrc++; *ldst++ ^= 0x8080808080808080ULL; @@ -58,7 +64,7 @@ void v4lconvert_spca501_to_yuv420(const unsigned char *src, unsigned char *dst, /* YYUV per line */ void v4lconvert_spca505_to_yuv420(const unsigned char *src, unsigned char *dst, - int width, int height) + int width, int height, int yvu) { int i,j; unsigned long *lsrc = (unsigned long *)src; @@ -72,14 +78,20 @@ void v4lconvert_spca505_to_yuv420(const unsigned char *src, unsigned char *dst, } /* -128 - 127 --> 0 - 255 and copy 1 line U */ - ldst = (unsigned long *)(dst + width * height + i * width / 4); + if (yvu) + ldst = (unsigned long *)(dst + (width * height * 5) / 4 + i * width / 4); + else + ldst = (unsigned long *)(dst + width * height + i * width / 4); for (j = 0; j < width/2; j += sizeof(long)) { *ldst = *lsrc++; *ldst++ ^= 0x8080808080808080ULL; } /* -128 - 127 --> 0 - 255 and copy 1 line V */ - ldst = (unsigned long *)(dst + (width * height * 5) / 4 + i * width / 4); + if (yvu) + ldst = (unsigned long *)(dst + width * height + i * width / 4); + else + ldst = (unsigned long *)(dst + (width * height * 5) / 4 + i * width / 4); for (j = 0; j < width/2; j += sizeof(long)) { *ldst = *lsrc++; *ldst++ ^= 0x8080808080808080ULL; @@ -89,7 +101,7 @@ void v4lconvert_spca505_to_yuv420(const unsigned char *src, unsigned char *dst, /* YUVY per line */ void v4lconvert_spca508_to_yuv420(const unsigned char *src, unsigned char *dst, - int width, int height) + int width, int height, int yvu) { int i,j; unsigned long *lsrc = (unsigned long *)src; @@ -103,14 +115,20 @@ void v4lconvert_spca508_to_yuv420(const unsigned char *src, unsigned char *dst, } /* -128 - 127 --> 0 - 255 and copy 1 line U */ - ldst = (unsigned long *)(dst + width * height + i * width / 4); + if (yvu) + ldst = (unsigned long *)(dst + (width * height * 5) / 4 + i * width / 4); + else + ldst = (unsigned long *)(dst + width * height + i * width / 4); for (j = 0; j < width/2; j += sizeof(long)) { *ldst = *lsrc++; *ldst++ ^= 0x8080808080808080ULL; } /* -128 - 127 --> 0 - 255 and copy 1 line V */ - ldst = (unsigned long *)(dst + (width * height * 5) / 4 + i * width / 4); + if (yvu) + ldst = (unsigned long *)(dst + width * height + i * width / 4); + else + ldst = (unsigned long *)(dst + (width * height * 5) / 4 + i * width / 4); for (j = 0; j < width/2; j += sizeof(long)) { *ldst = *lsrc++; *ldst++ ^= 0x8080808080808080ULL; -- cgit v1.2.3 From 17bb671ca3461d5aacfe3ca34adb4694a3b25949 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 13:12:08 +0100 Subject: libv4l: avoid try_fmt on UVC cams if possible From: Hans de Goede Avoid the use of try_fmt as much as possible on UVC cams, instead use the results of the enum_framesizes ioctl. This is because: 1) try_fmt actually causes IO with UVC cams making apps which do lot of querying of device capabilities slow (cheese) 2) some buggy cams don't like getting lots of UVC video probes and crash when they do Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 9 +++ v4l2-apps/libv4l/Makefile | 2 +- v4l2-apps/libv4l/libv4l2/libv4l2.c | 6 +- v4l2-apps/libv4l/libv4l2/log.c | 9 ++- .../libv4l/libv4lconvert/libv4lconvert-priv.h | 1 + v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 76 ++++++++++++++++++++-- 6 files changed, 95 insertions(+), 8 deletions(-) (limited to 'v4l2-apps/libv4l') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index 49f1fd035..f53c32f0e 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -1,3 +1,12 @@ +libv4l-0.5.5 +------------ +* Avoid the use of try_fmt as much as possible on UVC cams, instead use the + results of the enum_framesizes ioctl. This is because: + 1) try_fmt actually causes IO with UVC cams making apps which do lot of + querrying of device capabilities slow (cheese) + 2) some buggy cams don't like getting lots of UVC video probes and crash + when they do + libv4l-0.5.4 ------------ * Don't report DQBUF errors when errno is EAGAIN, this fixes flooding the diff --git a/v4l2-apps/libv4l/Makefile b/v4l2-apps/libv4l/Makefile index 13cb6c459..6de21ee77 100644 --- a/v4l2-apps/libv4l/Makefile +++ b/v4l2-apps/libv4l/Makefile @@ -1,5 +1,5 @@ LIB_RELEASE=0 -V4L2_LIB_VERSION=$(LIB_RELEASE).5.4 +V4L2_LIB_VERSION=$(LIB_RELEASE).5.5 all clean install: $(MAKE) -C libv4lconvert V4L2_LIB_VERSION=$(V4L2_LIB_VERSION) $@ diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2.c b/v4l2-apps/libv4l/libv4l2/libv4l2.c index 314087255..2685b9e19 100644 --- a/v4l2-apps/libv4l/libv4l2/libv4l2.c +++ b/v4l2-apps/libv4l/libv4l2/libv4l2.c @@ -793,8 +793,12 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) &src_fmt); } - if (result) + if (result) { + saved_err = errno; + V4L2_LOG("S_FMT error trying format: %s\n", strerror(errno)); + errno = saved_err; break; + } if (src_fmt.fmt.pix.pixelformat != dest_fmt->fmt.pix.pixelformat && v4l2_log_file) { diff --git a/v4l2-apps/libv4l/libv4l2/log.c b/v4l2-apps/libv4l/libv4l2/log.c index 6237d55ec..437b51d3e 100644 --- a/v4l2-apps/libv4l/libv4l2/log.c +++ b/v4l2-apps/libv4l/libv4l2/log.c @@ -18,6 +18,8 @@ #include #include +#include +#include #include /* These headers are not needed by us, but by linux/videodev2.h, which is broken on some systems and doesn't include them itself :( */ @@ -95,6 +97,7 @@ void v4l2_log_ioctl(unsigned long int request, void *arg, int result) { const char *ioctl_str; char buf[40]; + int saved_errno = errno; if (!v4l2_log_file) return; @@ -143,6 +146,10 @@ void v4l2_log_ioctl(unsigned long int request, void *arg, int result) break; } - fprintf(v4l2_log_file, "result == %d\n", result); + if (result < 0) + fprintf(v4l2_log_file, "result == %d (%s)\n", result, strerror(saved_errno)); + else + fprintf(v4l2_log_file, "result == %d\n", result); + fflush(v4l2_log_file); } diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h index a534ca321..55a5b49be 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h @@ -73,6 +73,7 @@ /* Card flags */ #define V4LCONVERT_ROTATE_90 0x01 #define V4LCONVERT_ROTATE_180 0x02 +#define V4LCONVERT_IS_UVC 0x04 /* Pixformat flags */ #define V4LCONVERT_COMPRESSED 0x01 diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index c6c50c2e5..6ec525769 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -36,7 +36,7 @@ { V4L2_PIX_FMT_YVU420, 0 } static void v4lconvert_get_framesizes(struct v4lconvert_data *data, - unsigned int pixelformat); + unsigned int pixelformat, int index); /* Note uncompressed formats must go first so that they are prefered by v4lconvert_try_format for low resolutions */ @@ -108,10 +108,9 @@ struct v4lconvert_data *v4lconvert_create(int fd) 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); break; } - - v4lconvert_get_framesizes(data, fmt.pixelformat); } data->no_formats = i; @@ -123,6 +122,8 @@ struct v4lconvert_data *v4lconvert_create(int fd) data->flags = v4lconvert_flags[i].flags; break; } + if (!strcmp((char *)cap.driver, "uvcvideo")) + data->flags |= V4LCONVERT_IS_UVC; } return data; @@ -187,6 +188,61 @@ int v4lconvert_enum_fmt(struct v4lconvert_data *data, struct v4l2_fmtdesc *fmt) return 0; } +/* Find out what format to use based on the (cached) results of enum + framesizes instead of doing a zillion try_fmt calls. This function + currently is intended for use with UVC cams only. This is esp. + important for UVC based cams as doing try_fmt there actually causes I/O */ +static int v4lconvert_do_try_format_uvc(struct v4lconvert_data *data, + struct v4l2_format *dest_fmt, struct v4l2_format *src_fmt) +{ + int i; + unsigned int closest_fmt_size_diff = -1; + int best_framesize = 0;/* Just use the first format if no small enough one */ + int best_format = 0; + + for (i = 0; i < data->no_framesizes; i++) { + if (data->framesizes[i].discrete.width <= dest_fmt->fmt.pix.width && + data->framesizes[i].discrete.height <= dest_fmt->fmt.pix.height) { + int size_x_diff = dest_fmt->fmt.pix.width - + data->framesizes[i].discrete.width; + int size_y_diff = dest_fmt->fmt.pix.height - + data->framesizes[i].discrete.height; + unsigned int size_diff = size_x_diff * size_x_diff + + size_y_diff * size_y_diff; + if (size_diff < closest_fmt_size_diff) + best_framesize = i; + } + } + + for (i = 0; i < ARRAY_SIZE(supported_src_pixfmts); i++) { + /* is this format supported? */ + if (!(data->framesizes[best_framesize].pixel_format & (1 << i))) + continue; + + if (!best_format || + supported_src_pixfmts[i].fmt == dest_fmt->fmt.pix.pixelformat || + ((data->framesizes[best_framesize].discrete.width > 180 || + data->framesizes[best_framesize].discrete.height > 148) && + (supported_src_pixfmts[i].flags & V4LCONVERT_COMPRESSED))) + best_format = supported_src_pixfmts[i].fmt; + } + + dest_fmt->fmt.pix.width = data->framesizes[best_framesize].discrete.width; + dest_fmt->fmt.pix.height = data->framesizes[best_framesize].discrete.height; + dest_fmt->fmt.pix.field = V4L2_FIELD_NONE; /* UVC has no fields */ + /* Not pretty, the pwc driver doesn't fill these in try_fmt either though, + so we should be able to get away with this. */ + dest_fmt->fmt.pix.bytesperline = 0; + dest_fmt->fmt.pix.sizeimage = 0; + dest_fmt->fmt.pix.colorspace = 0; + dest_fmt->fmt.pix.priv = 0; + + *src_fmt = *dest_fmt; + src_fmt->fmt.pix.pixelformat = best_format; + + return 0; +} + static int v4lconvert_do_try_format(struct v4lconvert_data *data, struct v4l2_format *dest_fmt, struct v4l2_format *src_fmt) { @@ -195,6 +251,9 @@ static int v4lconvert_do_try_format(struct v4lconvert_data *data, unsigned int desired_pixfmt = dest_fmt->fmt.pix.pixelformat; struct v4l2_format try_fmt, closest_fmt = { .type = 0 }; + if (data->flags & V4LCONVERT_IS_UVC) + return v4lconvert_do_try_format_uvc(data, dest_fmt, src_fmt); + for (i = 0; i < ARRAY_SIZE(supported_src_pixfmts); i++) { /* is this format supported? */ if (!(data->supported_src_formats & (1 << i))) @@ -774,7 +833,7 @@ const char *v4lconvert_get_error_message(struct v4lconvert_data *data) } static void v4lconvert_get_framesizes(struct v4lconvert_data *data, - unsigned int pixelformat) + unsigned int pixelformat, int index) { int i, j, match; struct v4l2_frmsizeenum frmsize = { .pixel_format = pixelformat }; @@ -786,7 +845,7 @@ static void v4lconvert_get_framesizes(struct v4lconvert_data *data, /* We got a framesize, check we don't have the same one already */ match = 0; - for (j = 0; j < data->no_framesizes && !match; j++) { + for (j = 0; j < data->no_framesizes; j++) { if (frmsize.type != data->framesizes[j].type) continue; @@ -803,6 +862,8 @@ static void v4lconvert_get_framesizes(struct v4lconvert_data *data, match = 1; break; } + if (match) + break; } /* Add this framesize if it is not already in our list */ if (!match) { @@ -812,6 +873,9 @@ static void v4lconvert_get_framesizes(struct v4lconvert_data *data, return; } data->framesizes[data->no_framesizes].type = frmsize.type; + /* We use the pixel_format member to store a bitmask of all + supported src_formats which can do this size */ + data->framesizes[data->no_framesizes].pixel_format = 1 << index; switch(frmsize.type) { case V4L2_FRMSIZE_TYPE_DISCRETE: data->framesizes[data->no_framesizes].discrete = frmsize.discrete; @@ -823,6 +887,8 @@ static void v4lconvert_get_framesizes(struct v4lconvert_data *data, } data->no_framesizes++; } + else + data->framesizes[j].pixel_format |= 1 << index; } } -- cgit v1.2.3 From fdad77d57046fd18b1b2fdb063af3b78096cc125 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 13:15:10 +0100 Subject: libv4l: Always do a s_fmt on uvc cams From: Hans de Goede Always do a s_fmt on uvc cams even if this changes nothing, as not doing the s_fmt triggers a bug in the uvcvideo driver in kernel <= 2.6.28 (with certain cams) Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 6 ++++++ v4l2-apps/libv4l/Makefile | 2 +- v4l2-apps/libv4l/libv4l2/libv4l2.c | 11 +++++++++-- 3 files changed, 16 insertions(+), 3 deletions(-) (limited to 'v4l2-apps/libv4l') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index f53c32f0e..a2c598d08 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -1,3 +1,9 @@ +libv4l-0.5.6 +------------ +* Always do a s_fmt on uvc cams even if this changes nothing, as not doing + the s_fmt triggers a bug in the uvcvideo driver in kernel <= 2.6.28 + (with certain cams) + libv4l-0.5.5 ------------ * Avoid the use of try_fmt as much as possible on UVC cams, instead use the diff --git a/v4l2-apps/libv4l/Makefile b/v4l2-apps/libv4l/Makefile index 6de21ee77..55b3744ea 100644 --- a/v4l2-apps/libv4l/Makefile +++ b/v4l2-apps/libv4l/Makefile @@ -1,5 +1,5 @@ LIB_RELEASE=0 -V4L2_LIB_VERSION=$(LIB_RELEASE).5.5 +V4L2_LIB_VERSION=$(LIB_RELEASE).5.6 all clean install: $(MAKE) -C libv4lconvert V4L2_LIB_VERSION=$(V4L2_LIB_VERSION) $@ diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2.c b/v4l2-apps/libv4l/libv4l2/libv4l2.c index 2685b9e19..720e91975 100644 --- a/v4l2-apps/libv4l/libv4l2/libv4l2.c +++ b/v4l2-apps/libv4l/libv4l2/libv4l2.c @@ -76,6 +76,7 @@ #define V4L2_BUFFERS_REQUESTED_BY_READ 0x0200 #define V4L2_STREAM_CONTROLLED_BY_READ 0x0400 #define V4L2_SUPPORTS_READ 0x0800 +#define V4L2_IS_UVC 0x1000 #define V4L2_MMAP_OFFSET_MAGIC 0xABCDEF00u @@ -492,6 +493,8 @@ int v4l2_fd_open(int fd, int v4l2_flags) devices[index].flags = v4l2_flags; if (cap.capabilities & V4L2_CAP_READWRITE) devices[index].flags |= V4L2_SUPPORTS_READ; + if (!strcmp((char *)cap.driver, "uvcvideo")) + devices[index].flags |= V4L2_IS_UVC; devices[index].open_count = 1; devices[index].src_fmt = fmt; devices[index].dest_fmt = fmt; @@ -768,7 +771,10 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) struct v4l2_format src_fmt, *dest_fmt = arg; struct v4l2_pix_format req_pix_fmt; - if (v4l2_pix_fmt_identical(&devices[index].dest_fmt, dest_fmt)) { + /* Don't be lazy on uvc cams, as this triggers a bug in the uvcvideo + driver in kernel <= 2.6.28 (with certain cams) */ + if (!(devices[index].flags & V4L2_IS_UVC) && + v4l2_pix_fmt_identical(&devices[index].dest_fmt, dest_fmt)) { *dest_fmt = devices[index].dest_fmt; result = 0; break; @@ -813,7 +819,8 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) /* Maybe after try format has adjusted width/height etc, to whats available nothing has changed (on the cam side) ? */ - if (v4l2_pix_fmt_identical(&devices[index].src_fmt, &src_fmt)) { + if (!(devices[index].flags & V4L2_IS_UVC) && + v4l2_pix_fmt_identical(&devices[index].src_fmt, &src_fmt)) { v4l2_set_src_and_dest_format(index, &devices[index].src_fmt, dest_fmt); result = 0; -- cgit v1.2.3 From f7cf759077f7b829a1cb451fcef9868b693ec3fe Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 13:15:43 +0100 Subject: libv4l: 0.5.7 release From: Hans de Goede * Fix a nasty (and stupid) bug in the special try_fmt handling for UVC cams * Add some more verbose logging of various calls when asking libv4l to log calls to a file, to assist in (future) debugging Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 6 +++ v4l2-apps/libv4l/Makefile | 2 +- v4l2-apps/libv4l/libv4l2/libv4l2.c | 5 +- v4l2-apps/libv4l/libv4l2/log.c | 71 +++++++++++++++++++++++++- v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 53 ++++++++++++++++--- 5 files changed, 127 insertions(+), 10 deletions(-) (limited to 'v4l2-apps/libv4l') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index a2c598d08..e2c8c43c4 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -1,3 +1,9 @@ +libv4l-0.5.7 +------------ +* Fix a nasty (and stupid) bug in the special try_fmt handling for UVC cams +* Add some more verbose logging of various calls when asking libv4l to log + calls to a file, to assist in (future) debugging + libv4l-0.5.6 ------------ * Always do a s_fmt on uvc cams even if this changes nothing, as not doing diff --git a/v4l2-apps/libv4l/Makefile b/v4l2-apps/libv4l/Makefile index 55b3744ea..09177aabb 100644 --- a/v4l2-apps/libv4l/Makefile +++ b/v4l2-apps/libv4l/Makefile @@ -1,5 +1,5 @@ LIB_RELEASE=0 -V4L2_LIB_VERSION=$(LIB_RELEASE).5.6 +V4L2_LIB_VERSION=$(LIB_RELEASE).5.7 all clean install: $(MAKE) -C libv4lconvert V4L2_LIB_VERSION=$(V4L2_LIB_VERSION) $@ diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2.c b/v4l2-apps/libv4l/libv4l2/libv4l2.c index 720e91975..b6ddef6e8 100644 --- a/v4l2-apps/libv4l/libv4l2/libv4l2.c +++ b/v4l2-apps/libv4l/libv4l2/libv4l2.c @@ -760,6 +760,9 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) case VIDIOC_ENUM_FRAMEINTERVALS: result = v4lconvert_enum_frameintervals(devices[index].convert, arg); + if (result) + V4L2_LOG("ENUM_FRAMEINTERVALS Error: %s", + v4lconvert_get_error_message(devices[index].convert)); break; case VIDIOC_TRY_FMT: @@ -949,7 +952,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, + devices[index].convert_mmap_buf = (void *)syscall(SYS_mmap2, NULL, (size_t)( devices[index].no_frames * V4L2_FRAME_BUF_SIZE), diff --git a/v4l2-apps/libv4l/libv4l2/log.c b/v4l2-apps/libv4l/libv4l2/log.c index 437b51d3e..c086ef736 100644 --- a/v4l2-apps/libv4l/libv4l2/log.c +++ b/v4l2-apps/libv4l/libv4l2/log.c @@ -91,6 +91,10 @@ static const char *v4l2_ioctls[] = { [_IOC_NR(VIDIOC_G_EXT_CTRLS)] = "VIDIOC_G_EXT_CTRLS", [_IOC_NR(VIDIOC_S_EXT_CTRLS)] = "VIDIOC_S_EXT_CTRLS", [_IOC_NR(VIDIOC_TRY_EXT_CTRLS)] = "VIDIOC_TRY_EXT_CTRLS", +#ifdef VIDIOC_ENUM_FRAMESIZES + [_IOC_NR(VIDIOC_ENUM_FRAMESIZES)] = "VIDIOC_ENUM_FRAMESIZES", + [_IOC_NR(VIDIOC_ENUM_FRAMEINTERVALS)] = "VIDIOC_ENUM_FRAMEINTERVALS", +#endif }; void v4l2_log_ioctl(unsigned long int request, void *arg, int result) @@ -105,7 +109,7 @@ void v4l2_log_ioctl(unsigned long int request, void *arg, int result) if (_IOC_TYPE(request) == 'V' && _IOC_NR(request) < ARRAY_SIZE(v4l2_ioctls)) ioctl_str = v4l2_ioctls[_IOC_NR(request)]; else { - snprintf(buf, sizeof(buf), "unknown request: %c %d\n", + snprintf(buf, sizeof(buf), "unknown request: %c %d", (int)_IOC_TYPE(request), (int)_IOC_NR(request)); ioctl_str = buf; } @@ -113,11 +117,18 @@ void v4l2_log_ioctl(unsigned long int request, void *arg, int result) fprintf(v4l2_log_file, "request == %s\n", ioctl_str); switch (request) { + case VIDIOC_ENUM_FMT: + { + struct v4l2_fmtdesc *fmt = arg; + fprintf(v4l2_log_file, " index: %u, description: %s\n", + fmt->index, (result < 0) ? "" : fmt->description); + } + break; case VIDIOC_G_FMT: case VIDIOC_S_FMT: case VIDIOC_TRY_FMT: { - struct v4l2_format* fmt = arg; + struct v4l2_format *fmt = arg; int pixfmt = fmt->fmt.pix.pixelformat; if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { @@ -144,6 +155,62 @@ void v4l2_log_ioctl(unsigned long int request, void *arg, int result) req->count, (int)req->type, (int)req->memory); } break; +#ifdef VIDIOC_ENUM_FRAMESIZES + case VIDIOC_ENUM_FRAMESIZES: + { + struct v4l2_frmsizeenum *frmsize = arg; + int pixfmt = frmsize->pixel_format; + + fprintf(v4l2_log_file, " index: %u pixelformat: %c%c%c%c", + frmsize->index, + pixfmt & 0xff, + (pixfmt >> 8) & 0xff, + (pixfmt >> 16) & 0xff, + pixfmt >> 24); + switch (frmsize->type) { + case V4L2_FRMSIZE_TYPE_DISCRETE: + 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", + frmsize->stepwise.min_width, frmsize->stepwise.min_height, + frmsize->stepwise.max_width, frmsize->stepwise.max_height); + break; + } + } + break; + case VIDIOC_ENUM_FRAMEINTERVALS: + { + struct v4l2_frmivalenum *frmival = arg; + int pixfmt = frmival->pixel_format; + + fprintf(v4l2_log_file, " index: %u pixelformat: %c%c%c%c %ux%u: ", + frmival->index, + pixfmt & 0xff, + (pixfmt >> 8) & 0xff, + (pixfmt >> 16) & 0xff, + pixfmt >> 24, + frmival->width, + frmival->height); + switch (frmival->type) { + case V4L2_FRMIVAL_TYPE_DISCRETE: + 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", + frmival->stepwise.min.numerator, + frmival->stepwise.min.denominator, + frmival->stepwise.max.numerator, + frmival->stepwise.max.denominator); + break; + } + } + break; +#endif } if (result < 0) diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index 6ec525769..889f7463a 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -209,8 +209,11 @@ static int v4lconvert_do_try_format_uvc(struct v4lconvert_data *data, data->framesizes[i].discrete.height; unsigned int size_diff = size_x_diff * size_x_diff + size_y_diff * size_y_diff; - if (size_diff < closest_fmt_size_diff) + + if (size_diff < closest_fmt_size_diff) { + closest_fmt_size_diff = size_diff; best_framesize = i; + } } } @@ -452,7 +455,7 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, /* 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"); + V4LCONVERT_ERR("JPEG needs 90 degree rotation\n"); data->flags |= V4LCONVERT_ROTATE_90; errno = EAGAIN; return -1; @@ -497,7 +500,7 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, 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) { - V4LCONVERT_ERR("Error decompressing JPEG: %s", + V4LCONVERT_ERR("decompressing JPEG: %s", tinyjpeg_get_errorstring(data->jdec)); errno = EAGAIN; return -1; @@ -923,8 +926,12 @@ int v4lconvert_enum_frameintervals(struct v4lconvert_data *data, int res; struct v4l2_format src_fmt, dest_fmt; - if (!v4lconvert_supported_dst_format(frmival->pixel_format)) - return syscall(SYS_ioctl, data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival); + if (!v4lconvert_supported_dst_format(frmival->pixel_format)) { + res = syscall(SYS_ioctl, data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival); + if (res) + V4LCONVERT_ERR("%s\n", strerror(errno)); + return res; + } /* Check which format we will be using to convert to frmival->pixel_format */ memset(&dest_fmt, 0, sizeof(dest_fmt)); @@ -932,13 +939,30 @@ int v4lconvert_enum_frameintervals(struct v4lconvert_data *data, dest_fmt.fmt.pix.pixelformat = frmival->pixel_format; dest_fmt.fmt.pix.width = frmival->width; dest_fmt.fmt.pix.height = frmival->height; - if ((res = v4lconvert_try_format(data, &dest_fmt, &src_fmt))) + if ((res = v4lconvert_try_format(data, &dest_fmt, &src_fmt))) { + if (res) + V4LCONVERT_ERR("trying format: %s\n", strerror(errno)); return res; + } /* Check the requested format is supported exactly as requested */ if (dest_fmt.fmt.pix.pixelformat != frmival->pixel_format || dest_fmt.fmt.pix.width != frmival->width || dest_fmt.fmt.pix.height != frmival->height) { + int frmival_pixformat = frmival->pixel_format; + int dest_pixformat = dest_fmt.fmt.pix.pixelformat; + V4LCONVERT_ERR("Could not find matching framesize for: %c%c%c%c %dx%d " + "closest match: %c%c%c%c %dx%d\n", + frmival_pixformat & 0xff, + (frmival_pixformat >> 8) & 0xff, + (frmival_pixformat >> 16) & 0xff, + frmival_pixformat >> 24, + frmival->width, frmival->height, + dest_pixformat & 0xff, + (dest_pixformat >> 8) & 0xff, + (dest_pixformat >> 16) & 0xff, + dest_pixformat >> 24, + dest_fmt.fmt.pix.width , dest_fmt.fmt.pix.height); errno = EINVAL; return -1; } @@ -948,6 +972,23 @@ int v4lconvert_enum_frameintervals(struct v4lconvert_data *data, frmival->width = src_fmt.fmt.pix.width; frmival->height = src_fmt.fmt.pix.height; res = syscall(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; + V4LCONVERT_ERR("Could not enum frameival index: %d for: %c%c%c%c %dx%d " + "using src: %c%c%c%c %dx%d, error: %s\n", + frmival->index, + dest_pixfmt & 0xff, + (dest_pixfmt >> 8) & 0xff, + (dest_pixfmt >> 16) & 0xff, + dest_pixfmt >> 24, + dest_fmt.fmt.pix.width , dest_fmt.fmt.pix.height, + src_pixfmt & 0xff, + (src_pixfmt >> 8) & 0xff, + (src_pixfmt >> 16) & 0xff, + src_pixfmt >> 24, + src_fmt.fmt.pix.width, src_fmt.fmt.pix.height, strerror(errno)); + } /* Restore the requested format in the frmival struct */ frmival->pixel_format = dest_fmt.fmt.pix.pixelformat; -- cgit v1.2.3 From d02d1e3c9f20e691d7d3ff62275d57bfc4766e19 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 13:16:01 +0100 Subject: libv4l: add UYVY support From: Julien BLACHE Attached is a patch to add UYVY support to libv4lconvert. It's obviously a shameless respin of the YVYU conversion routines :P Tested on a USB Apple iSight, which only supports UYVY. Priority: normal Signed-off-by: Julien BLACHE Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 5 ++ v4l2-apps/libv4l/Makefile | 2 +- v4l2-apps/libv4l/libv4l2/log.c | 2 +- .../libv4l/libv4lconvert/libv4lconvert-priv.h | 9 +++ v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 18 +++++ v4l2-apps/libv4l/libv4lconvert/rgbyuv.c | 91 ++++++++++++++++++++++ 6 files changed, 125 insertions(+), 2 deletions(-) (limited to 'v4l2-apps/libv4l') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index e2c8c43c4..fffa96f0a 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -1,3 +1,8 @@ +libv4l-0.5.8 +------------ +* Add support for UYVY (for USB Apple iSight) patch by Julien BLACHE + + libv4l-0.5.7 ------------ * Fix a nasty (and stupid) bug in the special try_fmt handling for UVC cams diff --git a/v4l2-apps/libv4l/Makefile b/v4l2-apps/libv4l/Makefile index 09177aabb..e393374df 100644 --- a/v4l2-apps/libv4l/Makefile +++ b/v4l2-apps/libv4l/Makefile @@ -1,5 +1,5 @@ LIB_RELEASE=0 -V4L2_LIB_VERSION=$(LIB_RELEASE).5.7 +V4L2_LIB_VERSION=$(LIB_RELEASE).5.8 all clean install: $(MAKE) -C libv4lconvert V4L2_LIB_VERSION=$(V4L2_LIB_VERSION) $@ diff --git a/v4l2-apps/libv4l/libv4l2/log.c b/v4l2-apps/libv4l/libv4l2/log.c index c086ef736..c29086ff4 100644 --- a/v4l2-apps/libv4l/libv4l2/log.c +++ b/v4l2-apps/libv4l/libv4l2/log.c @@ -121,7 +121,7 @@ void v4l2_log_ioctl(unsigned long int request, void *arg, int result) { struct v4l2_fmtdesc *fmt = arg; fprintf(v4l2_log_file, " index: %u, description: %s\n", - fmt->index, (result < 0) ? "" : fmt->description); + fmt->index, (result < 0) ? "" : (const char *)fmt->description); } break; case VIDIOC_G_FMT: diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h index 55a5b49be..c268375c8 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h @@ -132,6 +132,15 @@ void v4lconvert_yvyu_to_bgr24(const unsigned char *src, unsigned char *dst, void v4lconvert_yvyu_to_yuv420(const unsigned char *src, unsigned char *dst, int width, int height, int yvu); +void v4lconvert_uyvy_to_rgb24(const unsigned char *src, unsigned char *dst, + int width, int height); + +void v4lconvert_uyvy_to_bgr24(const unsigned char *src, unsigned char *dst, + int width, int height); + +void v4lconvert_uyvy_to_yuv420(const unsigned char *src, unsigned char *dst, + int width, int height, int yvu); + void v4lconvert_swap_rgb(const unsigned char *src, unsigned char *dst, int width, int height); diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index 889f7463a..c01286b73 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -44,6 +44,7 @@ static const struct v4lconvert_pixfmt supported_src_pixfmts[] = { SUPPORTED_DST_PIXFMTS, { V4L2_PIX_FMT_YUYV, 0 }, { V4L2_PIX_FMT_YVYU, 0 }, + { V4L2_PIX_FMT_UYVY, 0 }, { V4L2_PIX_FMT_SBGGR8, 0 }, { V4L2_PIX_FMT_SGBRG8, 0 }, { V4L2_PIX_FMT_SGRBG8, 0 }, @@ -718,6 +719,23 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, } break; + case V4L2_PIX_FMT_UYVY: + switch (dest_pix_fmt) { + case V4L2_PIX_FMT_RGB24: + v4lconvert_uyvy_to_rgb24(src, dest, width, height); + break; + case V4L2_PIX_FMT_BGR24: + v4lconvert_uyvy_to_bgr24(src, dest, width, height); + break; + case V4L2_PIX_FMT_YUV420: + v4lconvert_uyvy_to_yuv420(src, dest, width, height, 0); + break; + case V4L2_PIX_FMT_YVU420: + v4lconvert_uyvy_to_yuv420(src, dest, width, height, 1); + break; + } + break; + default: V4LCONVERT_ERR("Unknown src format in conversion\n"); errno = EINVAL; diff --git a/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c b/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c index d5feb457e..ec297b1f7 100644 --- a/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c +++ b/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c @@ -378,6 +378,97 @@ void v4lconvert_yvyu_to_yuv420(const unsigned char *src, unsigned char *dest, } } +void v4lconvert_uyvy_to_bgr24(const unsigned char *src, unsigned char *dest, + int width, int height) +{ + int j; + + while (--height >= 0) { + for (j = 0; j < width; j += 2) { + int u = src[0]; + int v = src[2]; + int u1 = (((u - 128) << 7) + (u - 128)) >> 6; + int rg = (((u - 128) << 1) + (u - 128) + + ((v - 128) << 2) + ((v - 128) << 1)) >> 3; + int v1 = (((v - 128) << 1) + (v - 128)) >> 1; + + *dest++ = CLIP(src[1] + u1); + *dest++ = CLIP(src[1] - rg); + *dest++ = CLIP(src[1] + v1); + + *dest++ = CLIP(src[3] + u1); + *dest++ = CLIP(src[3] - rg); + *dest++ = CLIP(src[3] + v1); + src += 4; + } + } +} + +void v4lconvert_uyvy_to_rgb24(const unsigned char *src, unsigned char *dest, + int width, int height) +{ + int j; + + while (--height >= 0) { + for (j = 0; j < width; j += 2) { + int u = src[0]; + int v = src[2]; + int u1 = (((u - 128) << 7) + (u - 128)) >> 6; + int rg = (((u - 128) << 1) + (u - 128) + + ((v - 128) << 2) + ((v - 128) << 1)) >> 3; + int v1 = (((v - 128) << 1) + (v - 128)) >> 1; + + *dest++ = CLIP(src[1] + v1); + *dest++ = CLIP(src[1] - rg); + *dest++ = CLIP(src[1] + u1); + + *dest++ = CLIP(src[3] + v1); + *dest++ = CLIP(src[3] - rg); + *dest++ = CLIP(src[3] + u1); + src += 4; + } + } +} + +void v4lconvert_uyvy_to_yuv420(const unsigned char *src, unsigned char *dest, + int width, int height, int yvu) +{ + int i, j; + const unsigned char *src1; + unsigned char *udest, *vdest; + + /* copy the Y values */ + src1 = src; + for (i = 0; i < height; i++) { + for (j = 0; j < width; j += 2) { + *dest++ = src1[1]; + *dest++ = src1[3]; + src1 += 4; + } + } + + /* copy the U and V values */ + src++; /* point to V */ + src1 = src + width * 2; /* next line */ + if (yvu) { + vdest = dest; + udest = dest + width * height / 4; + } else { + udest = dest; + vdest = dest + width * height / 4; + } + for (i = 0; i < height; i += 2) { + for (j = 0; j < width; j += 2) { + *udest++ = ((int) src[0] + src1[0]) / 2; /* U */ + *vdest++ = ((int) src[2] + src1[2]) / 2; /* V */ + src += 4; + src1 += 4; + } + src = src1; + src1 += width * 2; + } +} + void v4lconvert_swap_rgb(const unsigned char *src, unsigned char *dst, int width, int height) { -- cgit v1.2.3 From d58bea2b9caa5512cbd5136719391cc7055fe410 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 13:16:22 +0100 Subject: libv4l: remove duplicate v4lconvert_yvyu_to_yuv420 function From: Hans de Goede Remove v4lconvert_yvyu_to_yuv420 function as its functionality is duplicate with v4lconvert_yuyv_to_yuv420 Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 2 ++ .../libv4l/libv4lconvert/libv4lconvert-priv.h | 3 -- v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 6 ++-- v4l2-apps/libv4l/libv4lconvert/rgbyuv.c | 39 ---------------------- 4 files changed, 6 insertions(+), 44 deletions(-) (limited to 'v4l2-apps/libv4l') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index fffa96f0a..32c35c986 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -2,6 +2,8 @@ libv4l-0.5.8 ------------ * Add support for UYVY (for USB Apple iSight) patch by Julien BLACHE +* Remove v4lconvert_yvyu_to_yuv420 function as its functionality is + duplicate with v4lconvert_yuyv_to_yuv420 libv4l-0.5.7 ------------ diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h index c268375c8..c8fa705f0 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h @@ -129,9 +129,6 @@ void v4lconvert_yvyu_to_rgb24(const unsigned char *src, unsigned char *dst, void v4lconvert_yvyu_to_bgr24(const unsigned char *src, unsigned char *dst, int width, int height); -void v4lconvert_yvyu_to_yuv420(const unsigned char *src, unsigned char *dst, - int width, int height, int yvu); - void v4lconvert_uyvy_to_rgb24(const unsigned char *src, unsigned char *dst, int width, int height); diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index c01286b73..776bbfe14 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -711,10 +711,12 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, v4lconvert_yvyu_to_bgr24(src, dest, width, height); break; case V4L2_PIX_FMT_YUV420: - v4lconvert_yvyu_to_yuv420(src, dest, width, height, 0); + /* Note we use yuyv_to_yuv420 not v4lconvert_yvyu_to_yuv420, + with the last argument reversed to make it have as we want */ + v4lconvert_yuyv_to_yuv420(src, dest, width, height, 1); break; case V4L2_PIX_FMT_YVU420: - v4lconvert_yvyu_to_yuv420(src, dest, width, height, 1); + v4lconvert_yuyv_to_yuv420(src, dest, width, height, 0); break; } break; diff --git a/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c b/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c index ec297b1f7..00706be9d 100644 --- a/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c +++ b/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c @@ -339,45 +339,6 @@ void v4lconvert_yvyu_to_rgb24(const unsigned char *src, unsigned char *dest, } } -void v4lconvert_yvyu_to_yuv420(const unsigned char *src, unsigned char *dest, - int width, int height, int yvu) -{ - int i, j; - const unsigned char *src1; - unsigned char *udest, *vdest; - - /* copy the Y values */ - src1 = src; - for (i = 0; i < height; i++) { - for (j = 0; j < width; j += 2) { - *dest++ = src1[0]; - *dest++ = src1[2]; - src1 += 4; - } - } - - /* copy the U and V values */ - src++; /* point to V */ - src1 = src + width * 2; /* next line */ - if (yvu) { - vdest = dest; - udest = dest + width * height / 4; - } else { - udest = dest; - vdest = dest + width * height / 4; - } - for (i = 0; i < height; i += 2) { - for (j = 0; j < width; j += 2) { - *udest++ = ((int) src[2] + src1[2]) / 2; /* U */ - *vdest++ = ((int) src[0] + src1[0]) / 2; /* V */ - src += 4; - src1 += 4; - } - src = src1; - src1 += width * 2; - } -} - void v4lconvert_uyvy_to_bgr24(const unsigned char *src, unsigned char *dest, int width, int height) { -- cgit v1.2.3 From 093f82628ef903225b639005aaf13516e5144db1 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 13:17:15 +0100 Subject: libv4l: Use Requires.private where appropiate in .pc files From: Gregor Jasny Use Requires.private where appropiate in .pc files. Priority: normal Signed-off-by: Gregor Jasny Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 1 + v4l2-apps/libv4l/libv4l1/Makefile | 2 +- v4l2-apps/libv4l/libv4l2/Makefile | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) (limited to 'v4l2-apps/libv4l') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index 32c35c986..c4f6ffae5 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -4,6 +4,7 @@ libv4l-0.5.8 * Remove v4lconvert_yvyu_to_yuv420 function as its functionality is duplicate with v4lconvert_yuyv_to_yuv420 +* Use Requires.private where appropiate in .pc files (patch by Gregor Jasny) libv4l-0.5.7 ------------ diff --git a/v4l2-apps/libv4l/libv4l1/Makefile b/v4l2-apps/libv4l/libv4l1/Makefile index 7687a0a7c..80ba282a5 100644 --- a/v4l2-apps/libv4l/libv4l1/Makefile +++ b/v4l2-apps/libv4l/libv4l1/Makefile @@ -46,7 +46,7 @@ libv4l1.pc: @echo 'Name: libv4l1' >> libv4l1.pc @echo 'Description: v4l1 compatibility library' >> libv4l1.pc @echo 'Version: '$(V4L2_LIB_VERSION) >> libv4l1.pc - @echo 'Requires: libv4l2' >> libv4l1.pc + @echo 'Requires.private: libv4l2' >> libv4l1.pc @echo 'Libs: -L$${libdir} -lv4l1' >> libv4l1.pc @echo 'Libs.private: -lpthread' >> libv4l1.pc @echo 'Cflags: -I$${prefix}/include' >> libv4l1.pc diff --git a/v4l2-apps/libv4l/libv4l2/Makefile b/v4l2-apps/libv4l/libv4l2/Makefile index 8e6d2c31e..bb9e40741 100644 --- a/v4l2-apps/libv4l/libv4l2/Makefile +++ b/v4l2-apps/libv4l/libv4l2/Makefile @@ -45,7 +45,7 @@ libv4l2.pc: @echo 'Name: libv4l2' >> libv4l2.pc @echo 'Description: v4l2 device access library' >> libv4l2.pc @echo 'Version: '$(V4L2_LIB_VERSION) >> libv4l2.pc - @echo 'Requires: libv4lconvert' >> libv4l2.pc + @echo 'Requires.private: libv4lconvert' >> libv4l2.pc @echo 'Libs: -L$${libdir} -lv4l2' >> libv4l2.pc @echo 'Libs.private: -lpthread' >> libv4l2.pc @echo 'Cflags: -I$${prefix}/include' >> libv4l2.pc -- cgit v1.2.3 From ee232e3e24844fa93b83949e34e6a2cc60f8cdfc Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 13:23:30 +0100 Subject: libv4l: us USB-id's instead of USB product string in upside down dev table From: Hans de Goede Switch to using USB-id's instead of USB product string, as not all devices set a unique product string. This fixes the upside down issues with genius e-messenger 112 cams Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 3 ++ .../libv4l/libv4lconvert/libv4lconvert-priv.h | 6 ++- v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 57 ++++++++++++++++++---- 3 files changed, 55 insertions(+), 11 deletions(-) (limited to 'v4l2-apps/libv4l') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index c4f6ffae5..a23632027 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -5,6 +5,9 @@ libv4l-0.5.8 * Remove v4lconvert_yvyu_to_yuv420 function as its functionality is duplicate with v4lconvert_yuyv_to_yuv420 * Use Requires.private where appropiate in .pc files (patch by Gregor Jasny) +* Switch to using USB-id's instead of USB product string, as not all devices + set a unique product string. This fixes the upside down issues with + genius e-messenger 112 cams libv4l-0.5.7 ------------ diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h index c8fa705f0..6bcf2cb26 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h @@ -96,7 +96,11 @@ struct v4lconvert_data { }; struct v4lconvert_flags_info { - const char *card; + 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; }; diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index 776bbfe14..8cc63d47a 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include "libv4lconvert.h" #include "libv4lconvert-priv.h" @@ -66,11 +68,10 @@ static const struct v4lconvert_pixfmt supported_dst_pixfmts[] = { /* List of cams which need special flags */ static const struct v4lconvert_flags_info v4lconvert_flags[] = { - { "SPC 200NC ", V4LCONVERT_ROTATE_180 }, - { "SPC 300NC ", V4LCONVERT_ROTATE_180 }, /* Unconfirmed ! */ - { "SPC210NC ", V4LCONVERT_ROTATE_180 }, - { "USB Camera (0471:0326)", V4LCONVERT_ROTATE_180 }, /* SPC300NC */ - { "USB Camera (093a:2476)", V4LCONVERT_ROTATE_180 }, /* Genius E-M 112 */ + { 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 @@ -86,6 +87,46 @@ 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; @@ -117,12 +158,8 @@ struct v4lconvert_data *v4lconvert_create(int fd) data->no_formats = i; /* Check if this cam has any special flags */ + data->flags = v4lconvert_get_flags(data->fd); if (syscall(SYS_ioctl, fd, VIDIOC_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; - } if (!strcmp((char *)cap.driver, "uvcvideo")) data->flags |= V4LCONVERT_IS_UVC; } -- cgit v1.2.3 From dfc2a74d9ccd7ccf6115a1484ce142468866b296 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 13:26:09 +0100 Subject: libv4l: add sn9c20x-i420 decoder From: Vasily Khoruzhick Recent sn9c20x driver written by microdia project (http://groups.goolge.com/group/microdia) introduce new output format - sn9c20x-i420. This format is actually scrambled yuv420, so it's very easy and fast to convert it to yuv420. This patch adds sn9c20x-i420 decoder to the libv4l-0.5.7 This decoder is much faster than jpeg one (sn9c20x supports JPEG too): sn9c20x-i420 decoder eats only 10% of 1GHz CPU at 640x480x25fps vs 40% of 1GHz CPU in jpeg at same frame size/rate. This format should be preffered for sn9c20x, because sn9c20x driver supports SBGGR8 too, so it should go before SBGGR8 in supported_src_pixfmts. Priority: normal Signed-off-by: Vasily Khoruzhick Signed-off-by: Hans de Goede libv4l-0.5.7 ------------ diff --git a/v4l2-apps/libv4l/libv4lconvert/Makefile b/v4l2-apps/libv4l/libv4lconvert/Makefile index fa0f3f5e0..22c512cd5 100644 --- a/v4l2-apps/libv4l/libv4lconvert/Makefile +++ b/v4l2-apps/libv4l/libv4lconvert/Makefile @@ -10,7 +10,7 @@ CONVERT_LIB = libv4lconvert.so override CPPFLAGS += -fPIC endif -CONVERT_OBJS = libv4lconvert.o tinyjpeg.o sn9c10x.o pac207.o flip.o crop.o \ +CONVERT_OBJS = libv4lconvert.o tinyjpeg.o sn9c10x.o sn9c20x.o pac207.o flip.o crop.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/libv4l/libv4lconvert/libv4lconvert-priv.h b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h index 6bcf2cb26..08a7a7cfa 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h @@ -63,6 +63,10 @@ #define V4L2_PIX_FMT_YVYU v4l2_fourcc('Y', 'V', 'Y', 'U') #endif +#ifndef V4L2_PIX_FMT_SN9C20X_I420 +#define V4L2_PIX_FMT_SN9C20X_I420 v4l2_fourcc('S', '9', '2', '0') +#endif + #define V4LCONVERT_ERROR_MSG_SIZE 256 #define V4LCONVERT_MAX_FRAMESIZES 16 @@ -157,6 +161,9 @@ void v4lconvert_spca505_to_yuv420(const unsigned char *src, unsigned char *dst, void v4lconvert_spca508_to_yuv420(const unsigned char *src, unsigned char *dst, int width, int height, int yvu); +void v4lconvert_sn9c20x_to_yuv420(const unsigned char *src, unsigned char *dst, + int width, int height, int yvu); + void v4lconvert_decode_spca561(const unsigned char *src, unsigned char *dst, int width, int height); diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index 8cc63d47a..43c25ec94 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -47,6 +47,7 @@ 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 }, @@ -572,10 +573,11 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, } break; - /* YUYV line by line formats */ + /* Custom cam specific YUV formats */ case V4L2_PIX_FMT_SPCA501: case V4L2_PIX_FMT_SPCA505: case V4L2_PIX_FMT_SPCA508: + case V4L2_PIX_FMT_SN9C20X_I420: { unsigned char *d; int yvu = 0; @@ -602,6 +604,9 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, case V4L2_PIX_FMT_SPCA508: v4lconvert_spca508_to_yuv420(src, d, width, height, yvu); break; + case V4L2_PIX_FMT_SN9C20X_I420: + v4lconvert_sn9c20x_to_yuv420(src, d, width, height, yvu); + break; } switch (dest_pix_fmt) { diff --git a/v4l2-apps/libv4l/libv4lconvert/sn9c20x.c b/v4l2-apps/libv4l/libv4lconvert/sn9c20x.c new file mode 100644 index 000000000..19951300f --- /dev/null +++ b/v4l2-apps/libv4l/libv4lconvert/sn9c20x.c @@ -0,0 +1,137 @@ +/* + * Sonix SN9C20X decoder + * Vasily Khoruzhick, (C) 2008-2009 + * Algorithm based on Java code written by Jens on microdia google group + * + * 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 + * + * Note this code was originally licensed under the GNU GPL instead of the + * GNU LGPL, its license has been changed by its author. + */ + +#include "libv4lconvert-priv.h" + +#define DO_SANITY_CHECKS 0 + +static const int UVTranslate[32] = {0, 1, 2, 3, + 8, 9, 10, 11, + 16, 17, 18, 19, + 24, 25, 26, 27, + 4, 5, 6, 7, + 12, 13, 14, 15, + 20, 21, 22, 23, + 28, 29, 30, 31}; + +static const int Y_coords_624x[128][2] = { +{ 0, 0}, { 1, 0}, { 2, 0}, { 3, 0}, { 4, 0}, { 5, 0}, { 6, 0}, { 7, 0}, +{ 0, 1}, { 1, 1}, { 2, 1}, { 3, 1}, { 4, 1}, { 5, 1}, { 6, 1}, { 7, 1}, +{ 0, 2}, { 1, 2}, { 2, 2}, { 3, 2}, { 4, 2}, { 5, 2}, { 6, 2}, { 7, 2}, +{ 0, 3}, { 1, 3}, { 2, 3}, { 3, 3}, { 4, 3}, { 5, 3}, { 6, 3}, { 7, 3}, + +{ 0, 4}, { 1, 4}, { 2, 4}, { 3, 4}, { 4, 4}, { 5, 4}, { 6, 4}, { 7, 4}, +{ 0, 5}, { 1, 5}, { 2, 5}, { 3, 5}, { 4, 5}, { 5, 5}, { 6, 5}, { 7, 5}, +{ 0, 6}, { 1, 6}, { 2, 6}, { 3, 6}, { 4, 6}, { 5, 6}, { 6, 6}, { 7, 6}, +{ 0, 7}, { 1, 7}, { 2, 7}, { 3, 7}, { 4, 7}, { 5, 7}, { 6, 7}, { 7, 7}, + +{ 8, 0}, { 9, 0}, {10, 0}, {11, 0}, {12, 0}, {13, 0}, {14, 0}, {15, 0}, +{ 8, 1}, { 9, 1}, {10, 1}, {11, 1}, {12, 1}, {13, 1}, {14, 1}, {15, 1}, +{ 8, 2}, { 9, 2}, {10, 2}, {11, 2}, {12, 2}, {13, 2}, {14, 2}, {15, 2}, +{ 8, 3}, { 9, 3}, {10, 3}, {11, 3}, {12, 3}, {13, 3}, {14, 3}, {15, 3}, + +{ 8, 4}, { 9, 4}, {10, 4}, {11, 4}, {12, 4}, {13, 4}, {14, 4}, {15, 4}, +{ 8, 5}, { 9, 5}, {10, 5}, {11, 5}, {12, 5}, {13, 5}, {14, 5}, {15, 5}, +{ 8, 6}, { 9, 6}, {10, 6}, {11, 6}, {12, 6}, {13, 6}, {14, 6}, {15, 6}, +{ 8, 7}, { 9, 7}, {10, 7}, {11, 7}, {12, 7}, {13, 7}, {14, 7}, {15, 7} +}; + +static void do_write_u(const unsigned char *buf, unsigned char *ptr, + int i, int j) +{ + *ptr = buf[i + 128 + j]; +} + +static void do_write_v(const unsigned char *buf, unsigned char *ptr, + int i, int j) +{ + *ptr = buf[i + 160 + j]; +} + +void v4lconvert_sn9c20x_to_yuv420(const unsigned char *raw, unsigned char *i420, + int width, int height, int yvu) +{ + int i = 0, x = 0, y = 0, j, relX, relY, x_div2, y_div2; + const unsigned char *buf = raw; + unsigned char *ptr; + int frame_size = width * height; + int frame_size_div2 = frame_size >> 1; + int frame_size_div4 = frame_size >> 2; + int width_div2 = width >> 1; + int height_div2 = height >> 1; + void (*do_write_uv1)(const unsigned char *buf, unsigned char *ptr, int i, + int j) = NULL; + void (*do_write_uv2)(const unsigned char *buf, unsigned char *ptr, int i, + int j) = NULL; + + if (yvu) { + do_write_uv1 = do_write_v; + do_write_uv2 = do_write_u; + } + else { + do_write_uv1 = do_write_u; + do_write_uv2 = do_write_v; + } + + while (i < (frame_size + frame_size_div2)) { + for (j = 0; j < 128; j++) { + relX = x + Y_coords_624x[j][0]; + relY = y + Y_coords_624x[j][1]; + +#if (DO_SANITY_CHECKS==1) + if ((relX < width) && (relY < height)) { +#endif + ptr = i420 + relY * width + relX; + *ptr = buf[i + j]; +#if (DO_SANITY_CHECKS==1) + } +#endif + + } + x_div2 = x >> 1; + y_div2 = y >> 1; + for (j = 0; j < 32; j++) { + relX = (x_div2) + (j & 0x07); + relY = (y_div2) + (j >> 3); + +#if (DO_SANITY_CHECKS==1) + if ((relX < width_div2) && (relY < height_div2)) { +#endif + ptr = i420 + frame_size + + relY * width_div2 + relX; + do_write_uv1(buf, ptr, i, j); + ptr += frame_size_div4; + do_write_uv2(buf, ptr, i, j); +#if (DO_SANITY_CHECKS==1) + } +#endif + } + + i += 192; + x += 16; + if (x >= width) { + x = 0; + y += 8; + } + } +} -- cgit v1.2.3 From 2da5c1631758ea1e4645a2ea01006bcc460ec70c Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 13:26:35 +0100 Subject: libv4l: remove some code duplication in bayer handling From: Hans de Goede remove some code duplication in bayer handling Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 44 +++++++++----------------- 1 file changed, 15 insertions(+), 29 deletions(-) (limited to 'v4l2-apps/libv4l') diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index 43c25ec94..3c51b6c53 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -553,26 +553,6 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, } break; - case V4L2_PIX_FMT_SBGGR8: - case V4L2_PIX_FMT_SGBRG8: - case V4L2_PIX_FMT_SGRBG8: - case V4L2_PIX_FMT_SRGGB8: - switch (dest_pix_fmt) { - case V4L2_PIX_FMT_RGB24: - v4lconvert_bayer_to_rgb24(src, dest, width, height, src_pix_fmt); - break; - case V4L2_PIX_FMT_BGR24: - v4lconvert_bayer_to_bgr24(src, dest, width, height, src_pix_fmt); - break; - case V4L2_PIX_FMT_YUV420: - v4lconvert_bayer_to_yuv420(src, dest, width, height, src_pix_fmt, 0); - break; - case V4L2_PIX_FMT_YVU420: - v4lconvert_bayer_to_yuv420(src, dest, width, height, src_pix_fmt, 1); - break; - } - break; - /* Custom cam specific YUV formats */ case V4L2_PIX_FMT_SPCA501: case V4L2_PIX_FMT_SPCA505: @@ -628,7 +608,6 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, case V4L2_PIX_FMT_PAC207: { unsigned char *tmpbuf; - unsigned int bayer_fmt = 0; tmpbuf = v4lconvert_alloc_buffer(data, width * height, &data->convert_pixfmt_buf, &data->convert_pixfmt_buf_size); @@ -638,34 +617,41 @@ 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); - bayer_fmt = V4L2_PIX_FMT_SGBRG8; + src_pix_fmt = V4L2_PIX_FMT_SGBRG8; break; case V4L2_PIX_FMT_SN9C10X: v4lconvert_decode_sn9c10x(src, tmpbuf, width, height); - bayer_fmt = V4L2_PIX_FMT_SBGGR8; + src_pix_fmt = V4L2_PIX_FMT_SBGGR8; break; case V4L2_PIX_FMT_PAC207: v4lconvert_decode_pac207(src, tmpbuf, width, height); - bayer_fmt = V4L2_PIX_FMT_SBGGR8; + src_pix_fmt = V4L2_PIX_FMT_SBGGR8; break; } + src = tmpbuf; + /* Deliberate fall through to raw bayer fmt code! */ + } + /* Raw bayer formats */ + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: switch (dest_pix_fmt) { case V4L2_PIX_FMT_RGB24: - v4lconvert_bayer_to_rgb24(tmpbuf, dest, width, height, bayer_fmt); + v4lconvert_bayer_to_rgb24(src, dest, width, height, src_pix_fmt); break; case V4L2_PIX_FMT_BGR24: - v4lconvert_bayer_to_bgr24(tmpbuf, dest, width, height, bayer_fmt); + v4lconvert_bayer_to_bgr24(src, dest, width, height, src_pix_fmt); break; case V4L2_PIX_FMT_YUV420: - v4lconvert_bayer_to_yuv420(tmpbuf, dest, width, height, bayer_fmt, 0); + v4lconvert_bayer_to_yuv420(src, dest, width, height, src_pix_fmt, 0); break; case V4L2_PIX_FMT_YVU420: - v4lconvert_bayer_to_yuv420(tmpbuf, dest, width, height, bayer_fmt, 1); + v4lconvert_bayer_to_yuv420(src, dest, width, height, src_pix_fmt, 1); break; } break; - } case V4L2_PIX_FMT_RGB24: switch (dest_pix_fmt) { -- cgit v1.2.3 From 7fcf1772e48bd67d6a5a58145fd6e65c7db96b14 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 13:26:52 +0100 Subject: libv4l: change clean target to remove editor backup files in root and include From: Hans de Goede libv4l: change clean target to remove editor backup files in root and include Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/Makefile | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'v4l2-apps/libv4l') diff --git a/v4l2-apps/libv4l/Makefile b/v4l2-apps/libv4l/Makefile index e393374df..a607bc700 100644 --- a/v4l2-apps/libv4l/Makefile +++ b/v4l2-apps/libv4l/Makefile @@ -1,7 +1,13 @@ LIB_RELEASE=0 V4L2_LIB_VERSION=$(LIB_RELEASE).5.8 -all clean install: +all install: + $(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) $@ + +clean: + rm -f *~ include/*~ $(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) $@ -- cgit v1.2.3 From 26c68ea445a12d980b119bf2883329dc1cf801a0 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 13:27:13 +0100 Subject: libv4l: remove .orig and .rej files on make clean and simplify make export From: Hans de Goede libv4l: remove .orig and .rej files on make clean and simplify make export Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/Makefile | 9 ++------- v4l2-apps/libv4l/libv4l1/Makefile | 2 +- v4l2-apps/libv4l/libv4l2/Makefile | 2 +- v4l2-apps/libv4l/libv4lconvert/Makefile | 2 +- 4 files changed, 5 insertions(+), 10 deletions(-) (limited to 'v4l2-apps/libv4l') diff --git a/v4l2-apps/libv4l/Makefile b/v4l2-apps/libv4l/Makefile index a607bc700..79cc40bca 100644 --- a/v4l2-apps/libv4l/Makefile +++ b/v4l2-apps/libv4l/Makefile @@ -13,10 +13,5 @@ clean: $(MAKE) -C libv4l1 V4L2_LIB_VERSION=$(V4L2_LIB_VERSION) $@ export: clean - mkdir /tmp/libv4l-$(V4L2_LIB_VERSION) - cp -a . /tmp/libv4l-$(V4L2_LIB_VERSION)/ - cd /tmp/ && \ - tar cvf /tmp/libv4l-$(V4L2_LIB_VERSION).tar\ - libv4l-$(V4L2_LIB_VERSION) - gzip /tmp/libv4l-$(V4L2_LIB_VERSION).tar - rm -rf /tmp/libv4l-$(V4L2_LIB_VERSION) + tar --transform s/^\./libv4l-$(V4L2_LIB_VERSION)/g -zcvf \ + /tmp/libv4l-$(V4L2_LIB_VERSION).tar.gz . diff --git a/v4l2-apps/libv4l/libv4l1/Makefile b/v4l2-apps/libv4l/libv4l1/Makefile index 80ba282a5..9f30cbb0f 100644 --- a/v4l2-apps/libv4l/libv4l1/Makefile +++ b/v4l2-apps/libv4l/libv4l1/Makefile @@ -69,7 +69,7 @@ endif install -m 644 libv4l1.pc $(DESTDIR)$(LIBDIR)/pkgconfig clean:: - rm -f *.a *.so* *.o *.d libv4l1.pc log *~ + rm -f *.a *.so* *.o *.d libv4l1.pc log *~ *.orig *.rej %.o: %.c $(CC) -c -MMD $(CPPFLAGS) $(CFLAGS) -o $@ $< diff --git a/v4l2-apps/libv4l/libv4l2/Makefile b/v4l2-apps/libv4l/libv4l2/Makefile index bb9e40741..614b36cf8 100644 --- a/v4l2-apps/libv4l/libv4l2/Makefile +++ b/v4l2-apps/libv4l/libv4l2/Makefile @@ -68,7 +68,7 @@ endif install -m 644 libv4l2.pc $(DESTDIR)$(LIBDIR)/pkgconfig clean:: - rm -f *.a *.so* *.o *.d libv4l2.pc log *~ + rm -f *.a *.so* *.o *.d libv4l2.pc log *~ *.orig *.rej %.o: %.c $(CC) -c -MMD $(CPPFLAGS) $(CFLAGS) -o $@ $< diff --git a/v4l2-apps/libv4l/libv4lconvert/Makefile b/v4l2-apps/libv4l/libv4lconvert/Makefile index 22c512cd5..16ff2e1cd 100644 --- a/v4l2-apps/libv4l/libv4lconvert/Makefile +++ b/v4l2-apps/libv4l/libv4lconvert/Makefile @@ -57,7 +57,7 @@ endif install -m 644 libv4lconvert.pc $(DESTDIR)$(LIBDIR)/pkgconfig clean:: - rm -f *.a *.so* *.o *.d libv4lconvert.pc log *~ + rm -f *.a *.so* *.o *.d libv4lconvert.pc log *~ *.orig *.rej %.o: %.c $(CC) -c -MMD $(CPPFLAGS) $(CFLAGS) -o $@ $< -- cgit v1.2.3 From 46d3cd3f371db25540ace549cac1bf52a1787cd5 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 13:30:03 +0100 Subject: libv4l: Add MR97310A decompression From: Kyle Guinn libv4l: Add MR97310A decompression Priority: normal Signed-off-by: Kyle Guinn Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/libv4lconvert/Makefile | 5 +- .../libv4l/libv4lconvert/libv4lconvert-priv.h | 7 + v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 38 +++-- v4l2-apps/libv4l/libv4lconvert/mr97310a.c | 169 +++++++++++++++++++++ 4 files changed, 201 insertions(+), 18 deletions(-) create mode 100644 v4l2-apps/libv4l/libv4lconvert/mr97310a.c (limited to 'v4l2-apps/libv4l') diff --git a/v4l2-apps/libv4l/libv4lconvert/Makefile b/v4l2-apps/libv4l/libv4lconvert/Makefile index 16ff2e1cd..09e01bfb5 100644 --- a/v4l2-apps/libv4l/libv4lconvert/Makefile +++ b/v4l2-apps/libv4l/libv4lconvert/Makefile @@ -10,8 +10,9 @@ CONVERT_LIB = libv4lconvert.so override CPPFLAGS += -fPIC endif -CONVERT_OBJS = libv4lconvert.o tinyjpeg.o sn9c10x.o sn9c20x.o pac207.o flip.o crop.o \ - jidctflt.o spca561-decompress.o rgbyuv.o spca501.o bayer.o +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 bayer.o TARGETS = $(CONVERT_LIB) libv4lconvert.pc INCLUDES = ../include/libv4lconvert.h diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h index 08a7a7cfa..afe3e0047 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h +++ b/v4l2-apps/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_MR97310A +#define V4L2_PIX_FMT_MR97310A v4l2_fourcc('M','3','1','0') +#endif + #ifndef V4L2_PIX_FMT_PJPG #define V4L2_PIX_FMT_PJPG v4l2_fourcc('P', 'J', 'P', 'G') #endif @@ -173,6 +177,9 @@ void v4lconvert_decode_sn9c10x(const unsigned char *src, unsigned char *dst, void v4lconvert_decode_pac207(const unsigned char *src, unsigned char *dst, int width, int height); +void v4lconvert_decode_mr97310a(const unsigned char *src, unsigned char *dst, + int width, int height); + void v4lconvert_bayer_to_rgb24(const unsigned char *bayer, unsigned char *rgb, int width, int height, unsigned int pixfmt); diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index 3c51b6c53..a1a061f7f 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -44,23 +44,24 @@ static void v4lconvert_get_framesizes(struct v4lconvert_data *data, v4lconvert_try_format for low resolutions */ static const struct v4lconvert_pixfmt supported_src_pixfmts[] = { SUPPORTED_DST_PIXFMTS, - { V4L2_PIX_FMT_YUYV, 0 }, - { V4L2_PIX_FMT_YVYU, 0 }, - { V4L2_PIX_FMT_UYVY, 0 }, + { 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_MJPEG, V4LCONVERT_COMPRESSED }, - { V4L2_PIX_FMT_JPEG, V4LCONVERT_COMPRESSED }, - { V4L2_PIX_FMT_SPCA561, V4LCONVERT_COMPRESSED }, - { V4L2_PIX_FMT_SN9C10X, V4LCONVERT_COMPRESSED }, - { V4L2_PIX_FMT_PAC207, V4LCONVERT_COMPRESSED }, - { V4L2_PIX_FMT_PJPG, V4LCONVERT_COMPRESSED }, + { 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_MJPEG, V4LCONVERT_COMPRESSED }, + { V4L2_PIX_FMT_JPEG, V4LCONVERT_COMPRESSED }, + { V4L2_PIX_FMT_SPCA561, V4LCONVERT_COMPRESSED }, + { V4L2_PIX_FMT_SN9C10X, V4LCONVERT_COMPRESSED }, + { V4L2_PIX_FMT_PAC207, V4LCONVERT_COMPRESSED }, + { V4L2_PIX_FMT_MR97310A, V4LCONVERT_COMPRESSED }, + { V4L2_PIX_FMT_PJPG, V4LCONVERT_COMPRESSED }, }; static const struct v4lconvert_pixfmt supported_dst_pixfmts[] = { @@ -606,6 +607,7 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, case V4L2_PIX_FMT_SPCA561: case V4L2_PIX_FMT_SN9C10X: case V4L2_PIX_FMT_PAC207: + case V4L2_PIX_FMT_MR97310A: { unsigned char *tmpbuf; @@ -627,6 +629,10 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, v4lconvert_decode_pac207(src, tmpbuf, width, height); src_pix_fmt = V4L2_PIX_FMT_SBGGR8; break; + case V4L2_PIX_FMT_MR97310A: + v4lconvert_decode_mr97310a(src, tmpbuf, width, height); + src_pix_fmt = V4L2_PIX_FMT_SBGGR8; + break; } src = tmpbuf; /* Deliberate fall through to raw bayer fmt code! */ diff --git a/v4l2-apps/libv4l/libv4lconvert/mr97310a.c b/v4l2-apps/libv4l/libv4lconvert/mr97310a.c new file mode 100644 index 000000000..b5dbea7e6 --- /dev/null +++ b/v4l2-apps/libv4l/libv4lconvert/mr97310a.c @@ -0,0 +1,169 @@ +/* + * MR97310A decoder + * + * Copyright (C) 2004 Theodore Kilgore + * + * This library 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 of the License, or (at your option) any later version. + * + * This library 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 library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "libv4lconvert-priv.h" + +#define CLIP(x) ((x)<0?0:((x)>0xff)?0xff:(x)) + +/* FIXME not threadsafe */ +static int decoder_initialized = 0; + +static struct { + unsigned char is_abs; + unsigned char len; + signed char val; +} table[256]; + +static void init_mr97310a_decoder(void) +{ + int i; + int is_abs, val, len; + + for (i = 0; i < 256; ++i) { + is_abs = 0; + val = 0; + len = 0; + if ((i & 0x80) == 0) { + /* code 0 */ + val = 0; + len = 1; + } else if ((i & 0xe0) == 0xc0) { + /* code 110 */ + val = -3; + len = 3; + } else if ((i & 0xe0) == 0xa0) { + /* code 101 */ + val = +3; + len = 3; + } else if ((i & 0xf0) == 0x80) { + /* code 1000 */ + val = +7; + len = 4; + } else if ((i & 0xf0) == 0x90) { + /* code 1001 */ + val = -7; + len = 4; + } else if ((i & 0xf0) == 0xf0) { + /* code 1111 */ + val = -15; + len = 4; + } else if ((i & 0xf8) == 0xe0) { + /* code 11100 */ + val = +15; + len = 5; + } else if ((i & 0xf8) == 0xe8) { + /* code 11101xxxxx */ + is_abs = 1; + val = 0; /* value is calculated later */ + len = 5; + } + table[i].is_abs = is_abs; + table[i].val = val; + table[i].len = len; + } + decoder_initialized = 1; +} + +static inline unsigned char get_byte(const unsigned char *inp, + unsigned int bitpos) +{ + const unsigned char *addr; + addr = inp + (bitpos >> 3); + return (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7))); +} + +void v4lconvert_decode_mr97310a(const unsigned char *inp, unsigned char *outp, + int width, int height) +{ + int row, col; + int val; + int bitpos; + unsigned char code; + unsigned char lp, tp, tlp, trp; + + if (!decoder_initialized) + init_mr97310a_decoder(); + + bitpos = 0; + + /* main decoding loop */ + for (row = 0; row < height; ++row) { + col = 0; + + /* first two pixels in first two rows are stored as raw 8-bit */ + if (row < 2) { + code = get_byte(inp, bitpos); + bitpos += 8; + *outp++ = code; + + code = get_byte(inp, bitpos); + bitpos += 8; + *outp++ = code; + + col += 2; + } + + while (col < width) { + /* get bitcode */ + code = get_byte(inp, bitpos); + /* update bit position */ + bitpos += table[code].len; + + /* calculate pixel value */ + if (table[code].is_abs) { + /* get 5 more bits and use them as absolute value */ + code = get_byte(inp, bitpos); + val = (code & 0xf8); + bitpos += 5; + + } else { + /* value is relative to top or left pixel */ + val = table[code].val; + lp = outp[-2]; + if (row > 1) { + tlp = outp[-2*width-2]; + tp = outp[-2*width]; + trp = outp[-2*width+2]; + } + if (row < 2) { + /* top row: relative to left pixel */ + val += lp; + } else if (col < 2) { + /* left column: relative to top pixel */ + /* initial estimate */ + val += (2*tp + 2*trp + 1)/4; + } else if (col > width - 3) { + /* left column: relative to top pixel */ + val += (2*tp + 2*tlp + 1)/4; + /* main area: average of left and top pixel */ + } else { + /* initial estimate for predictor */ + val += (2*lp + tp + trp + 1)/4; + } + } + /* store pixel */ + *outp++ = CLIP(val); + ++col; + } + } + + return; +} -- cgit v1.2.3 From 9fbe732f5787056459b1a7a390aa6d19e3b9fba7 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 13:37:45 +0100 Subject: libv4l: Adjust mr97310a for gspca mr97310a driver changes From: Theodore Kilgore This patch introduces an offset of 12 bytes before starting the decompression of a frame. This needs to be done to compensate for a change in the gspca driver, where headers are now preserved instead of suppressed. Priority: normal Signed-off-by: Hans de Goede Signed-off-by: Theodore Kilgore --- v4l2-apps/libv4l/libv4lconvert/mr97310a.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'v4l2-apps/libv4l') diff --git a/v4l2-apps/libv4l/libv4lconvert/mr97310a.c b/v4l2-apps/libv4l/libv4lconvert/mr97310a.c index b5dbea7e6..e6ce94b29 100644 --- a/v4l2-apps/libv4l/libv4lconvert/mr97310a.c +++ b/v4l2-apps/libv4l/libv4lconvert/mr97310a.c @@ -102,6 +102,9 @@ void v4lconvert_decode_mr97310a(const unsigned char *inp, unsigned char *outp, if (!decoder_initialized) init_mr97310a_decoder(); + /* remove the header */ + inp += 12; + bitpos = 0; /* main decoding loop */ -- cgit v1.2.3 From 9a65e5e90ce0d4be59a49cd3a71d020e00cb3e0c Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 14:06:26 +0100 Subject: libv4l: libv4lconvert support for SQ905C From: Theodore Kilgore Support the decompression used by the SQ905C cameras (0x2770:0x905C) and some other related cameras. There is at the moment no support module for these cameras in streaming mode, but I intend to submit one. This contribution was created in whole by me, based upon code in libgphoto2 which was created in whole by me, and which was licensed for libgphoto2 under the LGPL license. Priority: normal Signed-off-by: Theodore Kilgore Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/libv4lconvert/Makefile | 2 +- .../libv4l/libv4lconvert/libv4lconvert-priv.h | 7 + v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 6 + v4l2-apps/libv4l/libv4lconvert/sq905c.c | 217 +++++++++++++++++++++ 4 files changed, 231 insertions(+), 1 deletion(-) create mode 100644 v4l2-apps/libv4l/libv4lconvert/sq905c.c (limited to 'v4l2-apps/libv4l') diff --git a/v4l2-apps/libv4l/libv4lconvert/Makefile b/v4l2-apps/libv4l/libv4lconvert/Makefile index 09e01bfb5..5d968057d 100644 --- a/v4l2-apps/libv4l/libv4lconvert/Makefile +++ b/v4l2-apps/libv4l/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 spca501.o bayer.o + rgbyuv.o spca501.o sq905c.o bayer.o TARGETS = $(CONVERT_LIB) libv4lconvert.pc INCLUDES = ../include/libv4lconvert.h diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h index afe3e0047..f3e80e82c 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h @@ -47,6 +47,10 @@ #define V4L2_PIX_FMT_MR97310A v4l2_fourcc('M','3','1','0') #endif +#ifndef V4L2_PIX_FMT_SQ905C +#define V4L2_PIX_FMT_SQ905C v4l2_fourcc('9', '0', '5', 'C') +#endif + #ifndef V4L2_PIX_FMT_PJPG #define V4L2_PIX_FMT_PJPG v4l2_fourcc('P', 'J', 'P', 'G') #endif @@ -180,6 +184,9 @@ void v4lconvert_decode_pac207(const unsigned char *src, unsigned char *dst, void v4lconvert_decode_mr97310a(const unsigned char *src, unsigned char *dst, int width, int height); +void v4lconvert_decode_sq905c(const unsigned char *src, unsigned char *dst, + int width, int height); + void v4lconvert_bayer_to_rgb24(const unsigned char *bayer, unsigned char *rgb, int width, int height, unsigned int pixfmt); diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index a1a061f7f..1ba7f45d7 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -61,6 +61,7 @@ static const struct v4lconvert_pixfmt supported_src_pixfmts[] = { { V4L2_PIX_FMT_SN9C10X, V4LCONVERT_COMPRESSED }, { V4L2_PIX_FMT_PAC207, V4LCONVERT_COMPRESSED }, { V4L2_PIX_FMT_MR97310A, V4LCONVERT_COMPRESSED }, + { V4L2_PIX_FMT_SQ905C, V4LCONVERT_COMPRESSED }, { V4L2_PIX_FMT_PJPG, V4LCONVERT_COMPRESSED }, }; @@ -608,6 +609,7 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, case V4L2_PIX_FMT_SN9C10X: case V4L2_PIX_FMT_PAC207: case V4L2_PIX_FMT_MR97310A: + case V4L2_PIX_FMT_SQ905C: { unsigned char *tmpbuf; @@ -633,6 +635,10 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, v4lconvert_decode_mr97310a(src, tmpbuf, width, height); src_pix_fmt = V4L2_PIX_FMT_SBGGR8; break; + case V4L2_PIX_FMT_SQ905C: + v4lconvert_decode_sq905c(src, tmpbuf, width, height); + src_pix_fmt = V4L2_PIX_FMT_SRGGB8; + break; } src = tmpbuf; /* Deliberate fall through to raw bayer fmt code! */ diff --git a/v4l2-apps/libv4l/libv4lconvert/sq905c.c b/v4l2-apps/libv4l/libv4lconvert/sq905c.c new file mode 100644 index 000000000..2610e0317 --- /dev/null +++ b/v4l2-apps/libv4l/libv4lconvert/sq905c.c @@ -0,0 +1,217 @@ +/* + * sq905c.c + * + * Here is the decompression function for the SQ905C cameras. The functions + * used are adapted from the libgphoto2 functions for the same cameras, + * which was + * Copyright (c) 2005 and 2007 Theodore Kilgore + * This version for libv4lconvert is + * Copyright (c) 2009 Theodore Kilgore + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "libv4lconvert-priv.h" + + +#define CLIP(x) ((x) < 0 ? 0 : ((x) > 0xff) ? 0xff : (x)) + + +static int +sq905c_first_decompress(unsigned char *output, unsigned char *input, + unsigned int outputsize) +{ + unsigned char parity = 0; + unsigned char nibble_to_keep[2]; + unsigned char temp1 = 0, temp2 = 0; + unsigned char input_byte; + unsigned char lookup = 0; + unsigned int i = 0; + unsigned int bytes_used = 0; + unsigned int bytes_done = 0; + unsigned int bit_counter = 8; + unsigned int cycles = 0; + int table[9] = { -1, 0, 2, 6, 0x0e, 0x0e, 0x0e, 0x0e, 0xfb}; + unsigned char lookup_table[16] + = {0, 2, 6, 0x0e, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, + 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb}; + unsigned char translator[16] = {8, 7, 9, 6, 10, 11, 12, 13, + 14, 15, 5, 4, 3, 2, 1, 0}; + + nibble_to_keep[0] = 0; + nibble_to_keep[1] = 0; + + while (bytes_done < outputsize) { + while (parity < 2) { + while (lookup > table[cycles]) { + if (bit_counter == 8) { + input_byte = input[bytes_used]; + bytes_used++; + temp1 = input_byte; + bit_counter = 0; + } + input_byte = temp1; + temp2 = (temp2 << 1) & 0xFF; + input_byte = input_byte >> 7; + temp2 = temp2 | input_byte; + temp1 = (temp1 << 1) & 0xFF; + bit_counter++; + cycles++; + if (cycles > 9) + return -1; + lookup = temp2 & 0xff; + } + temp2 = 0; + for (i = 0; i < 17; i++) { + if (lookup == lookup_table[i]) { + nibble_to_keep[parity] = translator[i]; + break; + } + if (i == 16) + return -1; + } + cycles = 0; + parity++; + } + output[bytes_done] = (nibble_to_keep[0]<<4)|nibble_to_keep[1]; + bytes_done++; + parity = 0; + } + return 0; +} + +static int +sq905c_second_decompress(unsigned char *uncomp, unsigned char *in, + int width, int height) +{ + int diff = 0; + int tempval = 0; + int i, m, parity; + unsigned char delta_left = 0; + unsigned char delta_right = 0; + int input_counter = 0; + int delta_table[] = {-144, -110, -77, -53, -35, -21, -11, -3, + 2, 10, 20, 34, 52, 76, 110, 144}; + unsigned char *templine_red; + unsigned char *templine_green; + unsigned char *templine_blue; + templine_red = malloc(width); + if (!templine_red) { + free(templine_red); + return -1; + } + for (i = 0; i < width; i++) + templine_red[i] = 0x80; + templine_green = malloc(width); + if (!templine_green) { + free(templine_green); + return -1; + } + for (i = 0; i < width; i++) + templine_green[i] = 0x80; + templine_blue = malloc(width); + if (!templine_blue) { + free(templine_blue); + return -1; + } + for (i = 0; i < width; i++) + templine_blue[i] = 0x80; + for (m = 0; m < height/2; m++) { + /* First we do an even-numbered line */ + for (i = 0; i < width/2; i++) { + parity = i&1; + delta_right = in[input_counter] & 0x0f; + delta_left = (in[input_counter]>>4)&0xff; + input_counter++; + /* left pixel (red) */ + diff = delta_table[delta_left]; + if (!i) + tempval = templine_red[0] + diff; + else + tempval = (templine_red[i] + + uncomp[2*m*width+2*i-2])/2 + diff; + tempval = CLIP(tempval); + uncomp[2*m*width+2*i] = tempval; + templine_red[i] = tempval; + /* right pixel (green) */ + diff = delta_table[delta_right]; + if (!i) + tempval = templine_green[1] + diff; + else if (2*i == width - 2) + tempval = (templine_green[i] + + uncomp[2*m*width+2*i-1])/2 + + diff; + else + tempval = (templine_green[i+1] + + uncomp[2*m*width+2*i-1])/2 + + diff; + tempval = CLIP(tempval); + uncomp[2*m*width+2*i+1] = tempval; + templine_green[i] = tempval; + } + /* then an odd-numbered line */ + for (i = 0; i < width/2; i++) { + delta_right = in[input_counter] & 0x0f; + delta_left = (in[input_counter]>>4) & 0xff; + input_counter++; + /* left pixel (green) */ + diff = delta_table[delta_left]; + if (!i) + tempval = templine_green[0] + diff; + else + tempval = (templine_green[i] + + uncomp[(2*m+1)*width+2*i-2])/2 + + diff; + tempval = CLIP(tempval); + uncomp[(2*m+1)*width+2*i] = tempval; + templine_green[i] = tempval; + /* right pixel (blue) */ + diff = delta_table[delta_right]; + if (!i) + tempval = templine_blue[0] + diff; + else + tempval = (templine_blue[i] + + uncomp[(2*m+1)*width+2*i-1])/2 + + diff; + tempval = CLIP(tempval); + uncomp[(2*m+1)*width+2*i+1] = tempval; + templine_blue[i] = tempval; + } + } + free(templine_green); + free(templine_red); + free(templine_blue); + return 0; +} + +void v4lconvert_decode_sq905c(const unsigned char *src, unsigned char *dst, + int width, int height) +{ + int size; + unsigned char *temp_data; + unsigned char *raw; + /* here we get rid of the 0x50 bytes of header in src. */ + raw = src + 0x50; + size = width*height/2; + temp_data = malloc(size); + if (!temp_data) + goto out; + sq905c_first_decompress(temp_data, raw, size); + sq905c_second_decompress(dst, temp_data, width, height); +out: + free(temp_data); +} -- cgit v1.2.3 From 7aae43b6a31c2c58a1d3841d9ea4c94f86fba6a6 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 14:10:50 +0100 Subject: libv4l: Fix compile warning in sq905c.c From: Hans de Goede Fix compile warning in sq905c.c . Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/libv4lconvert/sq905c.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'v4l2-apps/libv4l') diff --git a/v4l2-apps/libv4l/libv4lconvert/sq905c.c b/v4l2-apps/libv4l/libv4lconvert/sq905c.c index 2610e0317..a73b4da93 100644 --- a/v4l2-apps/libv4l/libv4lconvert/sq905c.c +++ b/v4l2-apps/libv4l/libv4lconvert/sq905c.c @@ -32,7 +32,7 @@ static int -sq905c_first_decompress(unsigned char *output, unsigned char *input, +sq905c_first_decompress(unsigned char *output, const unsigned char *input, unsigned int outputsize) { unsigned char parity = 0; @@ -203,7 +203,7 @@ void v4lconvert_decode_sq905c(const unsigned char *src, unsigned char *dst, { int size; unsigned char *temp_data; - unsigned char *raw; + const unsigned char *raw; /* here we get rid of the 0x50 bytes of header in src. */ raw = src + 0x50; size = width*height/2; -- cgit v1.2.3 From 5fad5d7ae948226cd5908eddd69977a1bfebb6ed Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 14:17:22 +0100 Subject: libv4l: prep for 0.5.9 release From: Hans de Goede prep for 0.5.9 release. Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 6 ++++++ v4l2-apps/libv4l/Makefile | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'v4l2-apps/libv4l') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index 3a97a1893..c6ff3c3d9 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -1,3 +1,9 @@ +libv4l-0.5.9 +------------ +* Add support for MR97310A decompression by Kyle Guinn +* Add support for sq905c decompression by Theodore Kilgore + + libv4l-0.5.8 ------------ * Add support for UYVY (for USB Apple iSight) patch by Julien BLACHE diff --git a/v4l2-apps/libv4l/Makefile b/v4l2-apps/libv4l/Makefile index 79cc40bca..703f3298f 100644 --- a/v4l2-apps/libv4l/Makefile +++ b/v4l2-apps/libv4l/Makefile @@ -1,5 +1,5 @@ LIB_RELEASE=0 -V4L2_LIB_VERSION=$(LIB_RELEASE).5.8 +V4L2_LIB_VERSION=$(LIB_RELEASE).5.9 all install: $(MAKE) -C libv4lconvert V4L2_LIB_VERSION=$(V4L2_LIB_VERSION) $@ -- cgit v1.2.3 From f689c3bd615386cf4c5238d1b4de1aaf4b58ce69 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Fri, 13 Mar 2009 12:57:33 +0100 Subject: libv4l: add hm12 support for the cx2341x MPEG encoder devices. From: Hans Verkuil Priority: normal Signed-off-by: Hans Verkuil Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/ChangeLog | 2 + v4l2-apps/libv4l/libv4lconvert/Makefile | 2 +- v4l2-apps/libv4l/libv4lconvert/hm12.c | 159 +++++++++++++++++++++ .../libv4l/libv4lconvert/libv4lconvert-priv.h | 13 ++ v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 19 +++ 5 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 v4l2-apps/libv4l/libv4lconvert/hm12.c (limited to 'v4l2-apps/libv4l') diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index c6ff3c3d9..11f6ca2fd 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -3,6 +3,8 @@ libv4l-0.5.9 * Add support for MR97310A decompression by Kyle Guinn * Add support for sq905c decompression by Theodore Kilgore +* Add hm12 support for the cx2341x MPEG encoder devices by Hans Verkuil + libv4l-0.5.8 ------------ diff --git a/v4l2-apps/libv4l/libv4lconvert/Makefile b/v4l2-apps/libv4l/libv4lconvert/Makefile index 5d968057d..f779011b4 100644 --- a/v4l2-apps/libv4l/libv4lconvert/Makefile +++ b/v4l2-apps/libv4l/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 spca501.o sq905c.o bayer.o + rgbyuv.o spca501.o sq905c.o bayer.o hm12.o TARGETS = $(CONVERT_LIB) libv4lconvert.pc INCLUDES = ../include/libv4lconvert.h diff --git a/v4l2-apps/libv4l/libv4lconvert/hm12.c b/v4l2-apps/libv4l/libv4lconvert/hm12.c new file mode 100644 index 000000000..f711627b4 --- /dev/null +++ b/v4l2-apps/libv4l/libv4lconvert/hm12.c @@ -0,0 +1,159 @@ +/* + +cx2341x HM12 conversion routines + +(C) 2009 Hans Verkuil + +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" +#include + +/* The HM12 format is used in the Conexant cx23415/6/8 MPEG encoder devices. + It is a macroblock format with separate Y and UV planes, each plane + consisting of 16x16 values. All lines are always 720 bytes long. If the + width of the image is less than 720, then the remainder is padding. + + The height has to be a multiple of 32 in order to get correct chroma + values. + + It is basically a by-product of the MPEG encoding inside the device, + which is available for raw video as a 'bonus feature'. + */ + +#define CLIP(color) \ + (unsigned char)(((color) > 0xff) ? 0xff : (((color) < 0) ? 0 : (color))) + +static const int stride = 720; + +static void v4lconvert_hm12_to_rgb(const unsigned char *src, unsigned char *dest, + int width, int height, int rgb) +{ + unsigned int y, x, i, j; + const unsigned char *y_base = src; + const unsigned char *uv_base = src + stride * height; + const unsigned char *src_y; + const unsigned char *src_uv; + int mb_size = 256; + int r = rgb ? 0 : 2; + int b = 2 - r; + + for (y = 0; y < height; y += 16) { + int mb_y = (y / 16) * (stride / 16); + int mb_uv = (y / 32) * (stride / 16); + int maxy = (height - y < 16 ? height - y : 16); + + for (x = 0; x < width; x += 16, mb_y++, mb_uv++) { + int maxx = (width - x < 16 ? width - x : 16); + + src_y = y_base + mb_y * mb_size; + src_uv = uv_base + mb_uv * mb_size; + + if (y & 0x10) + src_uv += mb_size / 2; + + for (i = 0; i < maxy; i++) { + int idx = (x + (y + i) * width) * 3; + + for (j = 0; j < maxx; j++) { + int y = src_y[j]; + int u = src_uv[j & ~1]; + int v = src_uv[j | 1]; + int u1 = (((u - 128) << 7) + (u - 128)) >> 6; + int rg = (((u - 128) << 1) + (u - 128) + + ((v - 128) << 2) + ((v - 128) << 1)) >> 3; + int v1 = (((v - 128) << 1) + (v - 128)) >> 1; + + dest[idx+r] = CLIP(y + v1); + dest[idx+1] = CLIP(y - rg); + dest[idx+b] = CLIP(y + u1); + idx += 3; + } + src_y += 16; + if (i & 1) + src_uv += 16; + } + } + } +} + +void v4lconvert_hm12_to_rgb24(const unsigned char *src, unsigned char *dest, + int width, int height) +{ + v4lconvert_hm12_to_rgb(src, dest, width, height, 1); +} + +void v4lconvert_hm12_to_bgr24(const unsigned char *src, unsigned char *dest, + int width, int height) +{ + v4lconvert_hm12_to_rgb(src, dest, width, height, 0); +} + +static void de_macro_uv(unsigned char *dstu, unsigned char *dstv, + const unsigned char *src, int w, int h) +{ + unsigned int y, x, i, j; + + for (y = 0; y < h; y += 16) { + for (x = 0; x < w; x += 8) { + const unsigned char *src_uv = src + y * stride + x * 32; + int maxy = (h - y < 16 ? h - y : 16); + int maxx = (w - x < 8 ? w - x : 8); + + for (i = 0; i < maxy; i++) { + int idx = x + (y + i) * w; + + for (j = 0; j < maxx; j++) { + dstu[idx+j] = src_uv[2 * j]; + dstv[idx+j] = src_uv[2 * j + 1]; + } + src_uv += 16; + } + } + } +} + +static void de_macro_y(unsigned char *dst, const unsigned char *src, + int w, int h) +{ + unsigned int y, x, i; + + for (y = 0; y < h; y += 16) { + for (x = 0; x < w; x += 16) { + const unsigned char *src_y = src + y * stride + x * 16; + int maxy = (h - y < 16 ? h - y : 16); + int maxx = (w - x < 16 ? w - x : 16); + + for (i = 0; i < maxy; i++) { + memcpy(dst + x + (y + i) * w, src_y, maxx); + src_y += 16; + } + } + } +} + +void v4lconvert_hm12_to_yuv420(const unsigned char *src, unsigned char *dest, + int width, int height, int yvu) +{ + de_macro_y(dest, src, width, height); + dest += width * height; + src += stride * height; + if (yvu) + de_macro_uv(dest + width * height / 4, dest, src, width / 2, height / 2); + else + de_macro_uv(dest, dest + width * height / 4, src, width / 2, height / 2); +} diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h index f3e80e82c..5ce7bde3b 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h @@ -71,6 +71,10 @@ #define V4L2_PIX_FMT_YVYU v4l2_fourcc('Y', 'V', 'Y', 'U') #endif +#ifndef V4L2_PIX_FMT_HM12 +#define V4L2_PIX_FMT_HM12 v4l2_fourcc('H', 'M', '1', '2') +#endif + #ifndef V4L2_PIX_FMT_SN9C20X_I420 #define V4L2_PIX_FMT_SN9C20X_I420 v4l2_fourcc('S', '9', '2', '0') #endif @@ -196,6 +200,15 @@ 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 src_pixfmt, int yvu); +void v4lconvert_hm12_to_rgb24(const unsigned char *src, + unsigned char *dst, int width, int height); + +void v4lconvert_hm12_to_bgr24(const unsigned char *src, + unsigned char *dst, int width, int height); + +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); diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index 1ba7f45d7..1204e8ef2 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -55,6 +55,7 @@ static const struct v4lconvert_pixfmt supported_src_pixfmts[] = { { V4L2_PIX_FMT_SPCA501, 0 }, { V4L2_PIX_FMT_SPCA505, 0 }, { V4L2_PIX_FMT_SPCA508, 0 }, + { V4L2_PIX_FMT_HM12, 0 }, { V4L2_PIX_FMT_MJPEG, V4LCONVERT_COMPRESSED }, { V4L2_PIX_FMT_JPEG, V4LCONVERT_COMPRESSED }, { V4L2_PIX_FMT_SPCA561, V4LCONVERT_COMPRESSED }, @@ -604,6 +605,24 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, break; } + /* Conexant cx2341x raw video macroblock format */ + case V4L2_PIX_FMT_HM12: + switch (dest_pix_fmt) { + case V4L2_PIX_FMT_RGB24: + v4lconvert_hm12_to_rgb24(src, dest, width, height); + break; + case V4L2_PIX_FMT_BGR24: + v4lconvert_hm12_to_bgr24(src, dest, width, height); + break; + case V4L2_PIX_FMT_YUV420: + v4lconvert_hm12_to_yuv420(src, dest, width, height, 0); + break; + case V4L2_PIX_FMT_YVU420: + v4lconvert_hm12_to_yuv420(src, dest, width, height, 1); + break; + } + break; + /* compressed bayer formats */ case V4L2_PIX_FMT_SPCA561: case V4L2_PIX_FMT_SN9C10X: -- cgit v1.2.3