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/libv4l2 | |
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/libv4l2')
-rw-r--r-- | v4l2-apps/libv4l/libv4l2/Makefile | 8 | ||||
-rw-r--r-- | v4l2-apps/libv4l/libv4l2/libv4l2.c | 88 | ||||
-rw-r--r-- | v4l2-apps/libv4l/libv4l2/log.c | 80 |
3 files changed, 159 insertions, 17 deletions
diff --git a/v4l2-apps/libv4l/libv4l2/Makefile b/v4l2-apps/libv4l/libv4l2/Makefile index 648d27c0c..614b36cf8 100644 --- a/v4l2-apps/libv4l/libv4l2/Makefile +++ b/v4l2-apps/libv4l/libv4l2/Makefile @@ -3,7 +3,7 @@ override CPPFLAGS += -I../include -I../../../include -fvisibility=hidden CFLAGS := -g -O1 CFLAGS += -Wall -Wno-unused -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -LIBS = -lpthread +LIBS_libv4l2 = -lpthread V4L2_OBJS = libv4l2.o log.o V4L2CONVERT = v4l2convert.so @@ -45,7 +45,7 @@ libv4l2.pc: @echo 'Name: libv4l2' >> libv4l2.pc @echo 'Description: v4l2 device access library' >> libv4l2.pc @echo 'Version: '$(V4L2_LIB_VERSION) >> libv4l2.pc - @echo 'Requires: libv4lconvert' >> libv4l2.pc + @echo 'Requires.private: libv4lconvert' >> libv4l2.pc @echo 'Libs: -L$${libdir} -lv4l2' >> libv4l2.pc @echo 'Libs.private: -lpthread' >> libv4l2.pc @echo 'Cflags: -I$${prefix}/include' >> libv4l2.pc @@ -68,13 +68,13 @@ endif install -m 644 libv4l2.pc $(DESTDIR)$(LIBDIR)/pkgconfig clean:: - rm -f *.a *.so* *.o *.d libv4l2.pc log *~ + rm -f *.a *.so* *.o *.d libv4l2.pc log *~ *.orig *.rej %.o: %.c $(CC) -c -MMD $(CPPFLAGS) $(CFLAGS) -o $@ $< %.so: - $(CC) -shared $(LDFLAGS) -Wl,-soname,$@.$(LIB_RELEASE) -o $@.$(LIB_RELEASE) $^ $(LIBS) + $(CC) -shared $(LDFLAGS) -Wl,-soname,$@.$(LIB_RELEASE) -o $@.$(LIB_RELEASE) $^ $(LIBS_$*) ln -f -s $@.$(LIB_RELEASE) $@ %.a: diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2.c b/v4l2-apps/libv4l/libv4l2/libv4l2.c index b4a10afac..b6ddef6e8 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 @@ -264,9 +265,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; } @@ -490,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; @@ -620,6 +625,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; @@ -725,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: @@ -734,12 +772,27 @@ 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 (!memcmp(&devices[index].dest_fmt, dest_fmt, sizeof(*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; } + 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); @@ -749,8 +802,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) { @@ -765,8 +822,10 @@ 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 (!(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; break; } @@ -774,6 +833,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; @@ -783,9 +843,17 @@ 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; + } - devices[index].src_fmt = src_fmt; - devices[index].dest_fmt = *dest_fmt; + v4l2_set_src_and_dest_format(index, &src_fmt, dest_fmt); } break; @@ -884,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), diff --git a/v4l2-apps/libv4l/libv4l2/log.c b/v4l2-apps/libv4l/libv4l2/log.c index 6237d55ec..c29086ff4 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 :( */ @@ -89,12 +91,17 @@ static const char *v4l2_ioctls[] = { [_IOC_NR(VIDIOC_G_EXT_CTRLS)] = "VIDIOC_G_EXT_CTRLS", [_IOC_NR(VIDIOC_S_EXT_CTRLS)] = "VIDIOC_S_EXT_CTRLS", [_IOC_NR(VIDIOC_TRY_EXT_CTRLS)] = "VIDIOC_TRY_EXT_CTRLS", +#ifdef VIDIOC_ENUM_FRAMESIZES + [_IOC_NR(VIDIOC_ENUM_FRAMESIZES)] = "VIDIOC_ENUM_FRAMESIZES", + [_IOC_NR(VIDIOC_ENUM_FRAMEINTERVALS)] = "VIDIOC_ENUM_FRAMEINTERVALS", +#endif }; 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; @@ -102,7 +109,7 @@ void v4l2_log_ioctl(unsigned long int request, void *arg, int result) if (_IOC_TYPE(request) == 'V' && _IOC_NR(request) < ARRAY_SIZE(v4l2_ioctls)) ioctl_str = v4l2_ioctls[_IOC_NR(request)]; else { - snprintf(buf, sizeof(buf), "unknown request: %c %d\n", + snprintf(buf, sizeof(buf), "unknown request: %c %d", (int)_IOC_TYPE(request), (int)_IOC_NR(request)); ioctl_str = buf; } @@ -110,11 +117,18 @@ void v4l2_log_ioctl(unsigned long int request, void *arg, int result) fprintf(v4l2_log_file, "request == %s\n", ioctl_str); switch (request) { + case VIDIOC_ENUM_FMT: + { + struct v4l2_fmtdesc *fmt = arg; + fprintf(v4l2_log_file, " index: %u, description: %s\n", + fmt->index, (result < 0) ? "" : (const char *)fmt->description); + } + break; case VIDIOC_G_FMT: case VIDIOC_S_FMT: case VIDIOC_TRY_FMT: { - struct v4l2_format* fmt = arg; + struct v4l2_format *fmt = arg; int pixfmt = fmt->fmt.pix.pixelformat; if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { @@ -141,8 +155,68 @@ void v4l2_log_ioctl(unsigned long int request, void *arg, int result) req->count, (int)req->type, (int)req->memory); } break; +#ifdef VIDIOC_ENUM_FRAMESIZES + case VIDIOC_ENUM_FRAMESIZES: + { + struct v4l2_frmsizeenum *frmsize = arg; + int pixfmt = frmsize->pixel_format; + + fprintf(v4l2_log_file, " index: %u pixelformat: %c%c%c%c", + frmsize->index, + pixfmt & 0xff, + (pixfmt >> 8) & 0xff, + (pixfmt >> 16) & 0xff, + pixfmt >> 24); + switch (frmsize->type) { + case V4L2_FRMSIZE_TYPE_DISCRETE: + fprintf(v4l2_log_file, " %ux%u\n", frmsize->discrete.width, + frmsize->discrete.height); + break; + case V4L2_FRMSIZE_TYPE_CONTINUOUS: + case V4L2_FRMSIZE_TYPE_STEPWISE: + fprintf(v4l2_log_file, " %ux%u -> %ux%u\n", + frmsize->stepwise.min_width, frmsize->stepwise.min_height, + frmsize->stepwise.max_width, frmsize->stepwise.max_height); + break; + } + } + break; + case VIDIOC_ENUM_FRAMEINTERVALS: + { + struct v4l2_frmivalenum *frmival = arg; + int pixfmt = frmival->pixel_format; + + fprintf(v4l2_log_file, " index: %u pixelformat: %c%c%c%c %ux%u: ", + frmival->index, + pixfmt & 0xff, + (pixfmt >> 8) & 0xff, + (pixfmt >> 16) & 0xff, + pixfmt >> 24, + frmival->width, + frmival->height); + switch (frmival->type) { + case V4L2_FRMIVAL_TYPE_DISCRETE: + fprintf(v4l2_log_file, "%u/%u\n", frmival->discrete.numerator, + frmival->discrete.denominator); + break; + case V4L2_FRMIVAL_TYPE_CONTINUOUS: + case V4L2_FRMIVAL_TYPE_STEPWISE: + fprintf(v4l2_log_file, "%u/%u -> %u/%u\n", + frmival->stepwise.min.numerator, + frmival->stepwise.min.denominator, + frmival->stepwise.max.numerator, + frmival->stepwise.max.denominator); + break; + } + } + break; +#endif } - 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); } |