From 222cbd6fd0bec2c2e4566a251729f1329e031a22 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 13:06:14 +0100 Subject: libv4l: Add software cropping from CIF to VGA modes (fix skype) From: Hans de Goede * Add support for software cropping from 352x288 -> 320x240 / 176x144 -> 160x120, so that apps which will only work with vga resolutions like 320x240 (Skype!) will work with cams/drivers which do not support cropping CIF resolutions to VGA resolutions in hardware. This makes all 2.6.27 gspca supported cams, except for the pac7302 which only does 640x480 (and skype wants 320x240), work with skype * The v4lconvert_convert function was becoming a bit of a mess, so split the functionailiy into seperate v4lconvert_convert_pixfmt, v4lconvert_rotate and v4lconvert_crop functions, and make v4lconvert_convert a frontend to these Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/libv4l2/libv4l2.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'v4l2-apps/libv4l/libv4l2/libv4l2.c') diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2.c b/v4l2-apps/libv4l/libv4l2/libv4l2.c index b4a10afac..0a05623cb 100644 --- a/v4l2-apps/libv4l/libv4l2/libv4l2.c +++ b/v4l2-apps/libv4l/libv4l2/libv4l2.c @@ -740,6 +740,16 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) break; } + if (v4l2_log_file) { + int pixfmt = dest_fmt->fmt.pix.pixelformat; + + fprintf(v4l2_log_file, "VIDIOC_S_FMT app requesting: %c%c%c%c\n", + pixfmt & 0xff, + (pixfmt >> 8) & 0xff, + (pixfmt >> 16) & 0xff, + pixfmt >> 24); + } + if (devices[index].flags & V4L2_DISABLE_CONVERSION) { result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_TRY_FMT, dest_fmt); -- cgit v1.2.3 From 20b5011195e9b98e0cd6904e7a82d735ee542a52 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 13:07:28 +0100 Subject: libv4l: Make S_FMT handling more robust From: Hans de Goede Some drivers (pwc) do not properly reflect what one really gets after a s_fmt in their try_fmt answer. So update dest format (which we report as result from s_fmt / g_fmt to the app) with all info from the src format not changed by conversion. Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/libv4l2/libv4l2.c | 41 +++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) (limited to 'v4l2-apps/libv4l/libv4l2/libv4l2.c') diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2.c b/v4l2-apps/libv4l/libv4l2/libv4l2.c index 0a05623cb..dd422ea34 100644 --- a/v4l2-apps/libv4l/libv4l2/libv4l2.c +++ b/v4l2-apps/libv4l/libv4l2/libv4l2.c @@ -620,6 +620,36 @@ static int v4l2_check_buffer_change_ok(int index) return 0; } +static int v4l2_pix_fmt_identical(struct v4l2_format *a, struct v4l2_format *b) +{ + if (a->fmt.pix.width == b->fmt.pix.width && + a->fmt.pix.height == b->fmt.pix.height && + a->fmt.pix.pixelformat == b->fmt.pix.pixelformat && + a->fmt.pix.field == b->fmt.pix.field) + return 1; + + return 0; +} + +static void v4l2_set_src_and_dest_format(int index, + struct v4l2_format *src_fmt, struct v4l2_format *dest_fmt) +{ + /* Sigh some drivers (pwc) do not properly reflect what one really gets + after a s_fmt in their try_fmt answer. So update dest format (which we + report as result from s_fmt / g_fmt to the app) with all info from the src + format not changed by conversion */ + dest_fmt->fmt.pix.field = src_fmt->fmt.pix.field; + dest_fmt->fmt.pix.colorspace = src_fmt->fmt.pix.colorspace; + /* When we're not converting use bytesperline and imagesize from src_fmt */ + if (v4l2_pix_fmt_identical(src_fmt, dest_fmt)) { + dest_fmt->fmt.pix.bytesperline = src_fmt->fmt.pix.bytesperline; + dest_fmt->fmt.pix.sizeimage = src_fmt->fmt.pix.sizeimage; + } + + devices[index].src_fmt = *src_fmt; + devices[index].dest_fmt = *dest_fmt; +} + int v4l2_ioctl (int fd, unsigned long int request, ...) { void *arg; @@ -735,7 +765,8 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) { struct v4l2_format src_fmt, *dest_fmt = arg; - if (!memcmp(&devices[index].dest_fmt, dest_fmt, sizeof(*dest_fmt))) { + if (v4l2_pix_fmt_identical(&devices[index].dest_fmt, dest_fmt)) { + *dest_fmt = devices[index].dest_fmt; result = 0; break; } @@ -775,8 +806,9 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) /* Maybe after try format has adjusted width/height etc, to whats available nothing has changed (on the cam side) ? */ - if (!memcmp(&devices[index].src_fmt, &src_fmt, sizeof(src_fmt))) { - devices[index].dest_fmt = *dest_fmt; + if (v4l2_pix_fmt_identical(&devices[index].src_fmt, &src_fmt)) { + v4l2_set_src_and_dest_format(index, &devices[index].src_fmt, + dest_fmt); result = 0; break; } @@ -794,8 +826,7 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) break; } - devices[index].src_fmt = src_fmt; - devices[index].dest_fmt = *dest_fmt; + v4l2_set_src_and_dest_format(index, &src_fmt, dest_fmt); } break; -- cgit v1.2.3 From a5d0ef3556720bdb676c2c752b27e02be2d7e869 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 13:07:44 +0100 Subject: libv4l: make s_fmt more robust part 2 From: Hans de Goede Check that s_fmt atleast gives us the width, height and pixelformat try_fmt promised us, and if not disable conversion Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/libv4l2/libv4l2.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'v4l2-apps/libv4l/libv4l2/libv4l2.c') diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2.c b/v4l2-apps/libv4l/libv4l2/libv4l2.c index dd422ea34..d60ed6d39 100644 --- a/v4l2-apps/libv4l/libv4l2/libv4l2.c +++ b/v4l2-apps/libv4l/libv4l2/libv4l2.c @@ -764,6 +764,7 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) case VIDIOC_S_FMT: { struct v4l2_format src_fmt, *dest_fmt = arg; + struct v4l2_pix_format req_pix_fmt; if (v4l2_pix_fmt_identical(&devices[index].dest_fmt, dest_fmt)) { *dest_fmt = devices[index].dest_fmt; @@ -816,6 +817,7 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) if ((result = v4l2_check_buffer_change_ok(index))) break; + req_pix_fmt = src_fmt.fmt.pix; result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_S_FMT, &src_fmt); if (result) { saved_err = errno; @@ -825,6 +827,15 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) errno = saved_err; break; } + /* See if we've gotten what try_fmt promised us + (this check should never fail) */ + if (src_fmt.fmt.pix.width != req_pix_fmt.width || + src_fmt.fmt.pix.height != req_pix_fmt.height || + src_fmt.fmt.pix.pixelformat != req_pix_fmt.pixelformat) { + V4L2_LOG_ERR("set_fmt gave us a different result then try_fmt!\n"); + /* Not what we expected / wanted, disable conversion */ + *dest_fmt = src_fmt; + } v4l2_set_src_and_dest_format(index, &src_fmt, dest_fmt); } -- cgit v1.2.3 From 93d4ae910ce9eeaa5998e3aa1980c3647d959fc6 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 13:09:27 +0100 Subject: libv4l: Don't report DQBUF errors when errno is EAGAIN From: Hans de Goede Don't report DQBUF errors when errno is EAGAIN, this fixes flooding the screen with errors when applications use non blocking mode Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/libv4l2/libv4l2.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'v4l2-apps/libv4l/libv4l2/libv4l2.c') diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2.c b/v4l2-apps/libv4l/libv4l2/libv4l2.c index d60ed6d39..314087255 100644 --- a/v4l2-apps/libv4l/libv4l2/libv4l2.c +++ b/v4l2-apps/libv4l/libv4l2/libv4l2.c @@ -264,9 +264,11 @@ static int v4l2_dequeue_and_convert(int index, struct v4l2_buffer *buf, do { if ((result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_DQBUF, buf))) { - int saved_err = errno; - V4L2_LOG_ERR("dequeuing buf: %s\n", strerror(errno)); - errno = saved_err; + if (errno != EAGAIN) { + int saved_err = errno; + V4L2_LOG_ERR("dequeuing buf: %s\n", strerror(errno)); + errno = saved_err; + } return result; } -- cgit v1.2.3 From 17bb671ca3461d5aacfe3ca34adb4694a3b25949 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 13:12:08 +0100 Subject: libv4l: avoid try_fmt on UVC cams if possible From: Hans de Goede Avoid the use of try_fmt as much as possible on UVC cams, instead use the results of the enum_framesizes ioctl. This is because: 1) try_fmt actually causes IO with UVC cams making apps which do lot of querying of device capabilities slow (cheese) 2) some buggy cams don't like getting lots of UVC video probes and crash when they do Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/libv4l2/libv4l2.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'v4l2-apps/libv4l/libv4l2/libv4l2.c') 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) { -- cgit v1.2.3 From fdad77d57046fd18b1b2fdb063af3b78096cc125 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 13:15:10 +0100 Subject: libv4l: Always do a s_fmt on uvc cams From: Hans de Goede Always do a s_fmt on uvc cams even if this changes nothing, as not doing the s_fmt triggers a bug in the uvcvideo driver in kernel <= 2.6.28 (with certain cams) Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/libv4l2/libv4l2.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'v4l2-apps/libv4l/libv4l2/libv4l2.c') diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2.c b/v4l2-apps/libv4l/libv4l2/libv4l2.c index 2685b9e19..720e91975 100644 --- a/v4l2-apps/libv4l/libv4l2/libv4l2.c +++ b/v4l2-apps/libv4l/libv4l2/libv4l2.c @@ -76,6 +76,7 @@ #define V4L2_BUFFERS_REQUESTED_BY_READ 0x0200 #define V4L2_STREAM_CONTROLLED_BY_READ 0x0400 #define V4L2_SUPPORTS_READ 0x0800 +#define V4L2_IS_UVC 0x1000 #define V4L2_MMAP_OFFSET_MAGIC 0xABCDEF00u @@ -492,6 +493,8 @@ int v4l2_fd_open(int fd, int v4l2_flags) devices[index].flags = v4l2_flags; if (cap.capabilities & V4L2_CAP_READWRITE) devices[index].flags |= V4L2_SUPPORTS_READ; + if (!strcmp((char *)cap.driver, "uvcvideo")) + devices[index].flags |= V4L2_IS_UVC; devices[index].open_count = 1; devices[index].src_fmt = fmt; devices[index].dest_fmt = fmt; @@ -768,7 +771,10 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) struct v4l2_format src_fmt, *dest_fmt = arg; struct v4l2_pix_format req_pix_fmt; - if (v4l2_pix_fmt_identical(&devices[index].dest_fmt, dest_fmt)) { + /* Don't be lazy on uvc cams, as this triggers a bug in the uvcvideo + driver in kernel <= 2.6.28 (with certain cams) */ + if (!(devices[index].flags & V4L2_IS_UVC) && + v4l2_pix_fmt_identical(&devices[index].dest_fmt, dest_fmt)) { *dest_fmt = devices[index].dest_fmt; result = 0; break; @@ -813,7 +819,8 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) /* Maybe after try format has adjusted width/height etc, to whats available nothing has changed (on the cam side) ? */ - if (v4l2_pix_fmt_identical(&devices[index].src_fmt, &src_fmt)) { + if (!(devices[index].flags & V4L2_IS_UVC) && + v4l2_pix_fmt_identical(&devices[index].src_fmt, &src_fmt)) { v4l2_set_src_and_dest_format(index, &devices[index].src_fmt, dest_fmt); result = 0; -- cgit v1.2.3 From f7cf759077f7b829a1cb451fcef9868b693ec3fe Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 11 Mar 2009 13:15:43 +0100 Subject: libv4l: 0.5.7 release From: Hans de Goede * Fix a nasty (and stupid) bug in the special try_fmt handling for UVC cams * Add some more verbose logging of various calls when asking libv4l to log calls to a file, to assist in (future) debugging Priority: normal Signed-off-by: Hans de Goede --- v4l2-apps/libv4l/libv4l2/libv4l2.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'v4l2-apps/libv4l/libv4l2/libv4l2.c') diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2.c b/v4l2-apps/libv4l/libv4l2/libv4l2.c index 720e91975..b6ddef6e8 100644 --- a/v4l2-apps/libv4l/libv4l2/libv4l2.c +++ b/v4l2-apps/libv4l/libv4l2/libv4l2.c @@ -760,6 +760,9 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) case VIDIOC_ENUM_FRAMEINTERVALS: result = v4lconvert_enum_frameintervals(devices[index].convert, arg); + if (result) + V4L2_LOG("ENUM_FRAMEINTERVALS Error: %s", + v4lconvert_get_error_message(devices[index].convert)); break; case VIDIOC_TRY_FMT: @@ -949,7 +952,7 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) but we need the buffer _now_ to write our converted data to it! */ if (devices[index].convert_mmap_buf == MAP_FAILED) { - devices[index].convert_mmap_buf = (void *)syscall(SYS_mmap2, + devices[index].convert_mmap_buf = (void *)syscall(SYS_mmap2, NULL, (size_t)( devices[index].no_frames * V4L2_FRAME_BUF_SIZE), -- cgit v1.2.3