summaryrefslogtreecommitdiff
path: root/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2009-03-13 18:17:30 -0300
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-03-13 18:17:30 -0300
commitbd5114e836d5c39563589881b3d9da0cf06624f1 (patch)
treee5992f2b624f9178321dddba59e394af5e4da7cc /v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c
parent043985e41c1b3527cb1574753b3fd71c707a3d39 (diff)
parent9840199e825a71000f4d87e61380867fe3dc7f80 (diff)
downloadmediapointer-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.c839
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;