diff options
author | hans@rhel5-devel.localdomain <hans@rhel5-devel.localdomain> | 2009-03-11 13:12:08 +0100 |
---|---|---|
committer | hans@rhel5-devel.localdomain <hans@rhel5-devel.localdomain> | 2009-03-11 13:12:08 +0100 |
commit | 17bb671ca3461d5aacfe3ca34adb4694a3b25949 (patch) | |
tree | 1a7ba11f5d526109f0d063cfb6c1bc7d4ed435bf /v4l2-apps/libv4l | |
parent | 5f90628a20098c6dcde990310eaaabec2cef4694 (diff) | |
download | mediapointer-dvb-s2-17bb671ca3461d5aacfe3ca34adb4694a3b25949.tar.gz mediapointer-dvb-s2-17bb671ca3461d5aacfe3ca34adb4694a3b25949.tar.bz2 |
libv4l: avoid try_fmt on UVC cams if possible
From: Hans de Goede <hdegoede@redhat.com>
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 <hdegoede@redhat.com>
Diffstat (limited to 'v4l2-apps/libv4l')
-rw-r--r-- | v4l2-apps/libv4l/ChangeLog | 9 | ||||
-rw-r--r-- | v4l2-apps/libv4l/Makefile | 2 | ||||
-rw-r--r-- | v4l2-apps/libv4l/libv4l2/libv4l2.c | 6 | ||||
-rw-r--r-- | v4l2-apps/libv4l/libv4l2/log.c | 9 | ||||
-rw-r--r-- | v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h | 1 | ||||
-rw-r--r-- | v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 76 |
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; } } |