diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-03-13 18:17:30 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-03-13 18:17:30 -0300 |
commit | bd5114e836d5c39563589881b3d9da0cf06624f1 (patch) | |
tree | e5992f2b624f9178321dddba59e394af5e4da7cc /v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | |
parent | 043985e41c1b3527cb1574753b3fd71c707a3d39 (diff) | |
parent | 9840199e825a71000f4d87e61380867fe3dc7f80 (diff) | |
download | mediapointer-dvb-s2-bd5114e836d5c39563589881b3d9da0cf06624f1.tar.gz mediapointer-dvb-s2-bd5114e836d5c39563589881b3d9da0cf06624f1.tar.bz2 |
merge: http://linuxtv.org/hg/~tap/v4l-dvb
From: Mauro Carvalho Chehab <mchehab@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c')
-rw-r--r-- | v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 839 |
1 files changed, 590 insertions, 249 deletions
diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index 93bc67c7e..1204e8ef2 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -21,6 +21,8 @@ #include <stdlib.h> #include <syscall.h> #include <unistd.h> +#include <sys/stat.h> +#include <sys/types.h> #include "libv4lconvert.h" #include "libv4lconvert-priv.h" @@ -32,30 +34,36 @@ #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); + unsigned int pixelformat, int index); /* Note uncompressed formats must go first so that they are prefered by 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_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_YUYV, 0 }, + { V4L2_PIX_FMT_YVYU, 0 }, + { V4L2_PIX_FMT_UYVY, 0 }, + { V4L2_PIX_FMT_SN9C20X_I420, 0 }, + { V4L2_PIX_FMT_SBGGR8, 0 }, + { V4L2_PIX_FMT_SGBRG8, 0 }, + { V4L2_PIX_FMT_SGRBG8, 0 }, + { V4L2_PIX_FMT_SRGGB8, 0 }, + { V4L2_PIX_FMT_SPCA501, 0 }, + { V4L2_PIX_FMT_SPCA505, 0 }, + { V4L2_PIX_FMT_SPCA508, 0 }, + { V4L2_PIX_FMT_HM12, 0 }, + { V4L2_PIX_FMT_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_SQ905C, V4LCONVERT_COMPRESSED }, + { V4L2_PIX_FMT_PJPG, V4LCONVERT_COMPRESSED }, }; static const struct v4lconvert_pixfmt supported_dst_pixfmts[] = { @@ -64,13 +72,65 @@ 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 */ + { 0x0471, 0x0325, V4LCONVERT_ROTATE_180 }, /* Philips SPC200NC */ + { 0x0471, 0x0326, V4LCONVERT_ROTATE_180 }, /* Philips SPC300NC */ + { 0x0471, 0x032d, V4LCONVERT_ROTATE_180 }, /* Philips SPC210NC */ + { 0x093a, 0x2476, V4LCONVERT_ROTATE_180 }, /* Genius E-M 112 */ }; +/* List of well known resolutions which we can get by cropping somewhat larger + resolutions */ +static const int v4lconvert_crop_res[][2] = { + /* 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 }, +}; + +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; @@ -81,7 +141,6 @@ struct v4lconvert_data *v4lconvert_create(int fd) return NULL; data->fd = fd; - data->jdec = NULL; /* Check supported formats */ for (i = 0; ; i++) { @@ -95,21 +154,18 @@ 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; /* 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; } return data; @@ -122,6 +178,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); } @@ -171,8 +230,65 @@ 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, +/* 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) { + closest_fmt_size_diff = 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) { int i; @@ -180,14 +296,8 @@ 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; - } + 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? */ @@ -209,7 +319,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 +328,96 @@ 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: + 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; + } +} + +/* 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 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_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 */ + 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 <= 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; + try_dest = try2_dest; + try_src = try2_src; + } break; + } } } + /* Are we converting? */ + 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; if (src_fmt) - *src_fmt = closest_fmt; + *src_fmt = try_src; return 0; } @@ -256,10 +427,12 @@ 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_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 +442,35 @@ 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 unsigned char *v4lconvert_alloc_buffer(struct v4lconvert_data *data, + int needed, unsigned char **buf, int *buf_size) { - unsigned int header_width, header_height; - int result, needed, rotate = 0, jpeg_flags = TINYJPEG_FLAGS_MJPEG_TABLE; - unsigned char *components[3]; - unsigned char *dest = _dest; - - /* Special case when no conversion is needed */ - if (!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 (*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; +} - if (data->flags & V4LCONVERT_UPSIDE_DOWN) { - rotate = 180; - dest = alloca(needed); - } +static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, + unsigned char *src, int src_size, unsigned char *dest, + const struct v4l2_format *src_fmt, unsigned int dest_pix_fmt) +{ + unsigned 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_fmt->fmt.pix.pixelformat) { + switch (src_pix_fmt) { case V4L2_PIX_FMT_PJPG: jpeg_flags |= TINYJPEG_FLAGS_PIXART_JPEG; /* Fall through */ @@ -335,31 +493,27 @@ 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\n"); + 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; - 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 +522,15 @@ 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: + 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; @@ -379,8 +541,8 @@ 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) { - V4LCONVERT_ERR("Error decompressing JPEG: %s", + if (src_pix_fmt == V4L2_PIX_FMT_PJPG) { + V4LCONVERT_ERR("decompressing JPEG: %s", tinyjpeg_get_errorstring(data->jdec)); errno = EAGAIN; return -1; @@ -394,223 +556,357 @@ int v4lconvert_convert(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_fmt->fmt.pix.pixelformat) { - 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); - 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); - break; - default: - v4lconvert_bayer_to_yuv420(src, dest, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.height, src_fmt->fmt.pix.pixelformat); - break; - } - 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 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 *d; + int yvu = 0; + + 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) + return -1; + } else + d = dest; - switch (src_fmt->fmt.pix.pixelformat) { + if (dest_pix_fmt == V4L2_PIX_FMT_YVU420) + yvu = 1; + + 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, yvu); 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, yvu); 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, yvu); + break; + case V4L2_PIX_FMT_SN9C20X_I420: + v4lconvert_sn9c20x_to_yuv420(src, d, width, height, yvu); 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(data->convert_pixfmt_buf, dest, width, + height, yvu); 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(data->convert_pixfmt_buf, dest, width, + height, yvu); break; } 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: case V4L2_PIX_FMT_PAC207: + case V4L2_PIX_FMT_MR97310A: + case V4L2_PIX_FMT_SQ905C: { - unsigned char tmpbuf[dest_fmt->fmt.pix.width*dest_fmt->fmt.pix.height]; - unsigned int bayer_fmt = 0; + unsigned char *tmpbuf; + + tmpbuf = v4lconvert_alloc_buffer(data, width * height, + &data->convert_pixfmt_buf, &data->convert_pixfmt_buf_size); + if (!tmpbuf) + return -1; - 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); - bayer_fmt = V4L2_PIX_FMT_SGBRG8; + v4lconvert_decode_spca561(src, tmpbuf, width, height); + src_pix_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); - bayer_fmt = V4L2_PIX_FMT_SBGGR8; + v4lconvert_decode_sn9c10x(src, tmpbuf, width, height); + src_pix_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); - bayer_fmt = V4L2_PIX_FMT_SBGGR8; + 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; + 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! */ + } - switch (dest_fmt->fmt.pix.pixelformat) { + /* 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, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.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, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.height, bayer_fmt); + v4lconvert_bayer_to_bgr24(src, dest, width, height, src_pix_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(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; - } 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"); + 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; + 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"); + 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; 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, 0); 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, 0); + break; + case V4L2_PIX_FMT_YVU420: + v4lconvert_swap_uv(src, dest, src_fmt); break; } break; - case V4L2_PIX_FMT_YUYV: - switch (dest_fmt->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_YVU420: + 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_yuv420_to_rgb24(src, dest, width, + height, 1); break; case V4L2_PIX_FMT_BGR24: - v4lconvert_yuyv_to_bgr24(src, dest, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.height); + v4lconvert_yuv420_to_bgr24(src, dest, width, + height, 1); break; - default: - v4lconvert_yuyv_to_yuv420(src, dest, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.height); + case V4L2_PIX_FMT_YUV420: + v4lconvert_swap_uv(src, dest, src_fmt); break; } break; - case V4L2_PIX_FMT_YVYU: - switch (dest_fmt->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_YUYV: + 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_yuyv_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_yuyv_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_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; - default: - V4LCONVERT_ERR("Unknown src format in conversion\n"); - errno = EINVAL; - return -1; - } - - /* Note when rotating dest is our temporary buffer to which our conversion - was done and _dest is the real dest! If the formats are identical no - conversion has been done! */ - if (rotate && dest_fmt->fmt.pix.pixelformat == src_fmt->fmt.pix.pixelformat) - dest = src; - - switch (rotate) { - case 0: - break; - case 90: - switch (dest_fmt->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_YVYU: + switch (dest_pix_fmt) { case V4L2_PIX_FMT_RGB24: + v4lconvert_yvyu_to_rgb24(src, dest, width, height); + break; case V4L2_PIX_FMT_BGR24: - v4lconvert_rotate90_rgbbgr24(dest, _dest, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.height); + v4lconvert_yvyu_to_bgr24(src, dest, width, height); break; case V4L2_PIX_FMT_YUV420: - v4lconvert_rotate90_yuv420(dest, _dest, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.height); + /* 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; - } - break; - case 180: - switch (dest_fmt->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_YVU420: + v4lconvert_yuyv_to_yuv420(src, dest, width, height, 0); + break; + } + 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_rotate180_rgbbgr24(dest, _dest, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.height); + v4lconvert_uyvy_to_bgr24(src, dest, width, height); break; case V4L2_PIX_FMT_YUV420: - v4lconvert_rotate180_yuv420(dest, _dest, dest_fmt->fmt.pix.width, - dest_fmt->fmt.pix.height); + v4lconvert_uyvy_to_yuv420(src, dest, width, height, 0); break; - } - break; - default: - printf("FIXME add %d degrees rotation\n", rotate); + 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; + return -1; + } + return 0; +} + +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; + struct v4l2_format my_dest_fmt = *dest_fmt; + + /* 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; + } + + /* 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 (my_dest_fmt.fmt.pix.pixelformat) { + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + 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: + case V4L2_PIX_FMT_YVU420: + 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"); + errno = EINVAL; + return -1; + } + + if (dest_size < dest_needed) { + V4LCONVERT_ERR("destination buffer too small\n"); + errno = EFAULT; + return -1; + } + + if (my_dest_fmt.fmt.pix.pixelformat != my_src_fmt.fmt.pix.pixelformat) + convert = 1; + + if (data->flags & V4LCONVERT_ROTATE_90) + rotate += 90; + if (data->flags & V4LCONVERT_ROTATE_180) + rotate += 180; + + if (my_dest_fmt.fmt.pix.width != my_src_fmt.fmt.pix.width || + my_dest_fmt.fmt.pix.height != my_src_fmt.fmt.pix.height) + crop = 1; + + /* convert_pixfmt -> rotate -> crop, all steps are optional */ + if (convert && (rotate || crop)) { + convert_dest = v4lconvert_alloc_buffer(data, temp_needed, + &data->convert_buf, &data->convert_buf_size); + if (!convert_dest) + return -1; + + rotate_src = crop_src = convert_dest; } - return needed; + if (rotate && crop) { + rotate_dest = v4lconvert_alloc_buffer(data, temp_needed, + &data->rotate_buf, &data->rotate_buf_size); + if (!rotate_dest) + return -1; + + crop_src = rotate_dest; + } + + if (convert) { + res = v4lconvert_convert_pixfmt(data, src, src_size, convert_dest, + &my_src_fmt, + my_dest_fmt.fmt.pix.pixelformat); + if (res) + return res; + + my_src_fmt.fmt.pix.pixelformat = my_dest_fmt.fmt.pix.pixelformat; + v4lconvert_fixup_fmt(&my_src_fmt); + } + + 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, &my_dest_fmt); + + return dest_needed; } const char *v4lconvert_get_error_message(struct v4lconvert_data *data) @@ -619,7 +915,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 }; @@ -631,7 +927,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; @@ -648,6 +944,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) { @@ -657,6 +955,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; @@ -668,6 +969,8 @@ static void v4lconvert_get_framesizes(struct v4lconvert_data *data, } data->no_framesizes++; } + else + data->framesizes[j].pixel_format |= 1 << index; } } @@ -702,8 +1005,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)); @@ -711,13 +1018,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; } @@ -727,6 +1051,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; |