summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--v4l2-apps/libv4l/ChangeLog9
-rw-r--r--v4l2-apps/libv4l/Makefile2
-rw-r--r--v4l2-apps/libv4l/libv4l2/libv4l2.c6
-rw-r--r--v4l2-apps/libv4l/libv4l2/log.c9
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h1
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c76
6 files changed, 95 insertions, 8 deletions
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 <stdio.h>
#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
#include <linux/ioctl.h>
/* These headers are not needed by us, but by linux/videodev2.h,
which is broken on some systems and doesn't include them itself :( */
@@ -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;
}
}