diff options
author | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-08-22 10:34:29 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-08-22 10:34:29 -0300 |
commit | 4d3f684d3b6ab28ec9e251fff156d0b0f53d0517 (patch) | |
tree | f82a2ae2dc042d6d1de61f62babeb8c5f28b22a1 /v4l2-apps/lib/libv4l/libv4l2 | |
parent | 87eb1f67e4981f3a09825012f16af0107a7adb45 (diff) | |
parent | b5ff2cd5cc913156858a0b15a186144f146c89d7 (diff) | |
download | mediapointer-dvb-s2-4d3f684d3b6ab28ec9e251fff156d0b0f53d0517.tar.gz mediapointer-dvb-s2-4d3f684d3b6ab28ec9e251fff156d0b0f53d0517.tar.bz2 |
merge: http://linuxtv.org/hg/~mkrufky/sms1xxx
From: Mauro Carvalho Chehab <mchehab@infradead.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'v4l2-apps/lib/libv4l/libv4l2')
-rw-r--r-- | v4l2-apps/lib/libv4l/libv4l2/Makefile | 49 | ||||
-rw-r--r-- | v4l2-apps/lib/libv4l/libv4l2/libv4l2-priv.h | 16 | ||||
-rw-r--r-- | v4l2-apps/lib/libv4l/libv4l2/libv4l2.c | 305 | ||||
-rw-r--r-- | v4l2-apps/lib/libv4l/libv4l2/log.c | 12 | ||||
-rw-r--r-- | v4l2-apps/lib/libv4l/libv4l2/v4l2convert.c | 10 |
5 files changed, 243 insertions, 149 deletions
diff --git a/v4l2-apps/lib/libv4l/libv4l2/Makefile b/v4l2-apps/lib/libv4l/libv4l2/Makefile index 1258e379b..d8ac01c34 100644 --- a/v4l2-apps/lib/libv4l/libv4l2/Makefile +++ b/v4l2-apps/lib/libv4l/libv4l2/Makefile @@ -1,20 +1,25 @@ -CC = gcc -LD = gcc - -CPPFLAGS = -fPIC -I../include -I../../../../linux/include +CPPFLAGS = -I../include -I../../../../linux/include CFLAGS := -g -O1 CFLAGS += -Wall -W -Wno-unused -Wpointer-arith -Wstrict-prototypes -LDFLAGS = -shared +LIBS = -lpthread -V4L2_OBJS = libv4l2.o log.o ../libv4lconvert/libv4lconvert.so -V4L2_LIB = libv4l2.so +V4L2_OBJS = libv4l2.o log.o V4L2CONVERT = v4l2convert.so V4L2CONVERT_O = v4l2convert.o libv4l2.so -TARGETS = $(V4L2_LIB) $(V4L2CONVERT) +TARGETS = $(V4L2_LIB) libv4l2.pc INCLUDES = ../include/libv4l2.h +ifeq ($(LINKTYPE),static) +V4L2_LIB = libv4l2.a +else +V4L2_LIB = libv4l2.so +V4L2_OBJS += ../libv4lconvert/libv4lconvert.so +TARGETS += $(V4L2CONVERT) +CPPFLAGS += -fPIC +endif + ifeq ($(LIB_RELEASE),) LIB_RELEASE = 0 endif @@ -33,23 +38,45 @@ $(V4L2_LIB): $(V4L2_OBJS) $(V4L2CONVERT): $(V4L2CONVERT_O) $(V4L2_LIB) +libv4l2.pc: + @echo prefix=$(PREFIX) > libv4l2.pc + @echo libdir=$(LIBDIR) >> libv4l2.pc + @echo >> 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 'Libs: -L$${libdir} -lv4l2' >> libv4l2.pc + @echo 'Libs.private: -lpthread' >> libv4l2.pc + @echo 'Cflags: -I$${prefix}/include' >> libv4l2.pc + install: all mkdir -p $(DESTDIR)$(PREFIX)/include install -p -m 644 $(INCLUDES) $(DESTDIR)$(PREFIX)/include +ifeq ($(LINKTYPE),static) + mkdir -p $(DESTDIR)$(LIBDIR) + install -m 644 $(V4L2_LIB) $(DESTDIR)$(LIBDIR) +else mkdir -p $(DESTDIR)$(LIBDIR)/libv4l install -m 755 $(V4L2_LIB).$(LIB_RELEASE) $(DESTDIR)$(LIBDIR) cd $(DESTDIR)$(LIBDIR) && \ ln -f -s $(V4L2_LIB).$(LIB_RELEASE) $(V4L2_LIB) install -m 755 $(V4L2CONVERT).$(LIB_RELEASE) \ $(DESTDIR)$(LIBDIR)/libv4l/$(V4L2CONVERT) +endif + mkdir -p $(DESTDIR)$(LIBDIR)/pkgconfig + install -m 644 libv4l2.pc $(DESTDIR)$(LIBDIR)/pkgconfig clean:: - rm -f *.so* *.o log *~ - rm -f *.d + rm -f *.a *.so* *.o *.d libv4l2.pc log *~ %.o: %.c $(CC) -c -MMD $(CPPFLAGS) $(CFLAGS) -o $@ $< %.so: - $(CC) $(LDFLAGS) -Wl,-soname,$@.$(LIB_RELEASE) -o $@.$(LIB_RELEASE) $^ + $(CC) -shared $(LDFLAGS) -Wl,-soname,$@.$(LIB_RELEASE) -o $@.$(LIB_RELEASE) $^ $(LIBS) ln -f -s $@.$(LIB_RELEASE) $@ + +%.a: + $(AR) cqs $@ $^ + diff --git a/v4l2-apps/lib/libv4l/libv4l2/libv4l2-priv.h b/v4l2-apps/lib/libv4l/libv4l2/libv4l2-priv.h index 203dcffaf..8724832e1 100644 --- a/v4l2-apps/lib/libv4l/libv4l2/libv4l2-priv.h +++ b/v4l2-apps/lib/libv4l/libv4l2/libv4l2-priv.h @@ -8,8 +8,8 @@ # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program; if not, write to the Free Software @@ -68,8 +68,6 @@ #define MIN(a,b) (((a)<(b))?(a):(b)) -enum v4l2_io { v4l2_io_none, v4l2_io_read, v4l2_io_mmap }; - struct v4l2_dev_info { int fd; int flags; @@ -81,20 +79,14 @@ struct v4l2_dev_info { pthread_mutex_t stream_lock; unsigned int no_frames; unsigned int nreadbuffers; - enum v4l2_io io; struct v4lconvert_data *convert; unsigned char *convert_mmap_buf; /* Frame bookkeeping is only done when in read or mmap-conversion mode */ unsigned char *frame_pointers[V4L2_MAX_NO_FRAMES]; int frame_sizes[V4L2_MAX_NO_FRAMES]; int frame_queued; /* 1 status bit per frame */ - /* mapping tracking of our fake (converting mmap) frame buffers, todo this - perfect we should use a map counter per frame, this is a good - approximation but there are scenarios thinkable where this doesn't work. - However no normal application not even a buggy one is likely to exhibit - the patterns needed to fail this somewhat simplified tracking */ - int frame_mapped; /* 1 status bit per frame */ - int frame_map_count; /* total number of maps of (fake) buffers combined */ + /* mapping tracking of our fake (converting mmap) frame buffers */ + unsigned char frame_map_count[V4L2_MAX_NO_FRAMES]; }; /* From log.c */ diff --git a/v4l2-apps/lib/libv4l/libv4l2/libv4l2.c b/v4l2-apps/lib/libv4l/libv4l2/libv4l2.c index 8dfcf9b71..a40ab4ffe 100644 --- a/v4l2-apps/lib/libv4l/libv4l2/libv4l2.c +++ b/v4l2-apps/lib/libv4l/libv4l2/libv4l2.c @@ -8,8 +8,8 @@ # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program; if not, write to the Free Software @@ -35,12 +35,12 @@ capture devices. 2) libv4l2 is the base of the v4l2convert.so wrapper lib, which is a .so which can be LD_PRELOAD-ed and the overrules the libc's open/close/etc, - and when opening /dev/videoX calls v4l2_open. Because we behave as the - regular counterpart when the fd is not known (instead of say throwing - an error), v4l2convert.so can simply call the v4l2_ prefixed function - for all wrapped functions (except for v4l2_open which will fail when not - called on a v4l2 device). This way the wrapper does not have to keep - track of which fd's are being handled by libv4l2, as libv4l2 already + and when opening /dev/videoX or /dev/v4l/ calls v4l2_open. Because we + behave as the regular counterpart when the fd is not known (instead of say + throwing an error), v4l2convert.so can simply call the v4l2_ prefixed + function for all wrapped functions (except for v4l2_open which will fail + when not called on a v4l2 device). This way the wrapper does not have to + keep track of which fd's are being handled by libv4l2, as libv4l2 already keeps track of this itself. This also means that libv4l2 may not use any of the regular functions @@ -72,7 +72,10 @@ /* Note these flags are stored together with the flags passed to v4l2_fd_open() in v4l2_dev_info's flags member, so care should be taken that the do not use the same bits! */ -#define V4L2_STREAMON 0x0100 +#define V4L2_STREAMON 0x0100 +#define V4L2_BUFFERS_REQUESTED_BY_READ 0x0200 +#define V4L2_STREAM_CONTROLLED_BY_READ 0x0400 +#define V4L2_SUPPORTS_READ 0x0800 #define V4L2_MMAP_OFFSET_MAGIC 0xABCDEF00u @@ -89,52 +92,45 @@ static int v4l2_request_read_buffers(int index) int result; struct v4l2_requestbuffers req; - /* No-op if already done */ - if (devices[index].no_frames) - return 0; - - /* Request buffers */ - req.count = devices[index].nreadbuffers; + /* Note we re-request the buffers if they are already requested as the format + and thus the needed buffersize may have changed. */ + req.count = (devices[index].no_frames)? devices[index].no_frames: + devices[index].nreadbuffers; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; - if ((result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_REQBUFS, &req))){ + if ((result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_REQBUFS, &req)) < 0){ int saved_err = errno; - V4L2_LOG_ERR("requesting buffers: %s\n", strerror(errno)); + V4L2_LOG_ERR("requesting %u buffers: %s\n", req.count, strerror(errno)); errno = saved_err; return result; } + if (!devices[index].no_frames && req.count) + devices[index].flags |= V4L2_BUFFERS_REQUESTED_BY_READ; + devices[index].no_frames = MIN(req.count, V4L2_MAX_NO_FRAMES); return 0; } -static int v4l2_unrequest_read_buffers(int index) +static void v4l2_unrequest_read_buffers(int index) { - int result; struct v4l2_requestbuffers req; - /* No-op of already done */ - if (devices[index].no_frames == 0) - return 0; + if (!(devices[index].flags & V4L2_BUFFERS_REQUESTED_BY_READ) || + devices[index].no_frames == 0) + return; - /* (Un)Request buffers */ + /* (Un)Request buffers, note not all driver support this, and those + who do not support it don't need it. */ req.count = 0; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; - if ((result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_REQBUFS, &req))) { - int saved_err = errno; - V4L2_LOG_ERR("unrequesting buffers: %s\n", strerror(errno)); - errno = saved_err; - return result; - } + if(syscall(SYS_ioctl, devices[index].fd, VIDIOC_REQBUFS, &req) < 0) + return; devices[index].no_frames = MIN(req.count, V4L2_MAX_NO_FRAMES); - if (devices[index].no_frames) { - V4L2_LOG_ERR("number of buffers > 0 after requesting 0 buffers\n"); - errno = EBUSY; - return -1; - } - return 0; + if (devices[index].no_frames == 0) + devices[index].flags &= ~V4L2_BUFFERS_REQUESTED_BY_READ; } static int v4l2_map_buffers(int index) @@ -159,7 +155,7 @@ static int v4l2_map_buffers(int index) } devices[index].frame_pointers[i] = (void *)syscall(SYS_mmap2, NULL, - (size_t)buf.length, PROT_READ, MAP_SHARED, devices[index].fd, + (size_t)buf.length, PROT_READ|PROT_WRITE, MAP_SHARED, devices[index].fd, (__off_t)(buf.m.offset >> MMAP2_PAGE_SHIFT)); if (devices[index].frame_pointers[i] == MAP_FAILED) { int saved_err = errno; @@ -241,6 +237,7 @@ static int v4l2_queue_read_buffer(int index, int buffer_index) if (devices[index].frame_queued & (1 << buffer_index)) return 0; + memset(&buf, 0, sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = buffer_index; @@ -310,6 +307,8 @@ static int v4l2_activate_read_stream(int index) if ((result = v4l2_queue_read_buffers(index))) return result; + devices[index].flags |= V4L2_STREAM_CONTROLLED_BY_READ; + return result = v4l2_streamon(index); } @@ -324,12 +323,48 @@ static int v4l2_deactivate_read_stream(int index) v4l2_unmap_buffers(index); - if ((result = v4l2_unrequest_read_buffers(index))) - return result; + v4l2_unrequest_read_buffers(index); + + devices[index].flags &= ~V4L2_STREAM_CONTROLLED_BY_READ; return 0; } +static int v4l2_buffers_mapped(int index) +{ + unsigned int i; + + if (devices[index].src_fmt.fmt.pix.pixelformat == + devices[index].dest_fmt.fmt.pix.pixelformat) { + /* Normal (no conversion) mode */ + struct v4l2_buffer buf; + + for (i = 0; i < devices[index].no_frames; i++) { + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = i; + if (syscall(SYS_ioctl, devices[index].fd, VIDIOC_QUERYBUF, &buf)) { + int saved_err = errno; + V4L2_LOG_ERR("querying buffer %u: %s\n", i, strerror(errno)); + errno = saved_err; + break; + } + if (buf.flags & V4L2_BUF_FLAG_MAPPED) + break; + } + } else { + /* Conversion mode */ + for (i = 0; i < devices[index].no_frames; i++) + if (devices[index].frame_map_count[i]) + break; + } + + if (i != devices[index].no_frames) + V4L2_LOG("v4l2_buffers_mapped(): buffers still mapped\n"); + + return i != devices[index].no_frames; +} + int v4l2_open (const char *file, int oflag, ...) { @@ -386,8 +421,10 @@ int v4l2_fd_open(int fd, int v4l2_flags) return -1; } - /* we only add functionality for video capture devices */ - if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) + /* we only add functionality for video capture devices, and we do not + handle devices which don't do mmap */ + if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) || + !(cap.capabilities & V4L2_CAP_STREAMING)) return fd; /* Get current cam format */ @@ -420,6 +457,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; devices[index].open_count = 1; devices[index].src_fmt = fmt; devices[index].dest_fmt = fmt; @@ -428,15 +467,13 @@ int v4l2_fd_open(int fd, int v4l2_flags) devices[index].no_frames = 0; devices[index].nreadbuffers = V4L2_DEFAULT_NREADBUFFERS; - devices[index].io = v4l2_io_none; devices[index].convert = convert; devices[index].convert_mmap_buf = MAP_FAILED; for (i = 0; i < V4L2_MAX_NO_FRAMES; i++) { devices[index].frame_pointers[i] = MAP_FAILED; + devices[index].frame_map_count[i] = 0; } devices[index].frame_queued = 0; - devices[index].frame_mapped = 0; - devices[index].frame_map_count = 0; if (index >= devices_used) devices_used = index + 1; @@ -487,11 +524,8 @@ int v4l2_close(int fd) v4l2_unmap_buffers(index); v4lconvert_destroy(devices[index].convert); if (devices[index].convert_mmap_buf != MAP_FAILED) { - if (devices[index].frame_mapped || devices[index].frame_map_count) - V4L2_LOG( - "v4l2 mmap buffers still mapped on close(), mask: %08x, count: %d\n", - (unsigned int)devices[index].frame_mapped, - devices[index].frame_map_count); + if (v4l2_buffers_mapped(index)) + V4L2_LOG_WARN("v4l2 mmap buffers still mapped on close()\n"); else syscall(SYS_munmap, devices[index].convert_mmap_buf, devices[index].no_frames * V4L2_FRAME_BUF_SIZE); @@ -526,6 +560,34 @@ int v4l2_dup(int fd) return fd; } +static int v4l2_check_buffer_change_ok(int index) +{ + v4l2_unmap_buffers(index); + + /* Check if the app itself still is using the stream */ + if (v4l2_buffers_mapped(index) || + (!(devices[index].flags & V4L2_STREAM_CONTROLLED_BY_READ) && + ((devices[index].flags & V4L2_STREAMON) || + devices[index].frame_queued))) { + V4L2_LOG("v4l2_check_buffer_change_ok(): stream busy\n"); + errno = EBUSY; + return -1; + } + + /* We may change from convert to non conversion mode and + v4l2_unrequest_read_buffers may change the no_frames, so free the + convert mmap buffer */ + syscall(SYS_munmap, devices[index].convert_mmap_buf, + devices[index].no_frames * V4L2_FRAME_BUF_SIZE); + devices[index].convert_mmap_buf = MAP_FAILED; + + if (devices[index].flags & V4L2_STREAM_CONTROLLED_BY_READ) { + V4L2_LOG("deactivating read-stream for settings change\n"); + return v4l2_deactivate_read_stream(index); + } + + return 0; +} int v4l2_ioctl (int fd, unsigned long int request, ...) { @@ -548,6 +610,9 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) /* Is this a capture request and do we need to take the stream lock? */ switch (request) { + case VIDIOC_QUERYCAP: + is_capture_request = 1; + break; case VIDIOC_ENUM_FMT: if (((struct v4l2_fmtdesc *)arg)->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) is_capture_request = 1; @@ -603,6 +668,17 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) switch (request) { + case VIDIOC_QUERYCAP: + { + struct v4l2_capability *cap = arg; + + result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_QUERYCAP, cap); + if (result == 0) + /* We always support read() as we fake it using mmap mode */ + cap->capabilities |= V4L2_CAP_READWRITE; + } + break; + case VIDIOC_ENUM_FMT: result = v4lconvert_enum_fmt(devices[index].convert, arg); break; @@ -620,17 +696,6 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) break; } - /* Don't allow changing the format when mmap-ed IO is active, we could - allow this to happen in certain special circumstances, but it is - best to consistently deny this so that application developers do not - go expect this to work, because in their test setup it happens to - work. This also keeps the code much saner. */ - if (devices[index].io == v4l2_io_mmap) { - errno = EBUSY; - result = -1; - break; - } - if (devices[index].flags & V4L2_DISABLE_CONVERSION) { result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_TRY_FMT, dest_fmt); @@ -651,16 +716,8 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) break; } - if (devices[index].io == v4l2_io_read) { - V4L2_LOG("deactivating read-stream for format change\n"); - if ((result = v4l2_deactivate_read_stream(index))) { - /* Undo what we've done to leave things in a consisten state */ - if (v4l2_activate_read_stream(index)) - V4L2_LOG_ERR( - "reactivating stream after deactivate failure (AAIIEEEE)\n"); - break; - } - } + if ((result = v4l2_check_buffer_change_ok(index))) + break; result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_S_FMT, &src_fmt); if (result) { @@ -690,22 +747,6 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) { struct v4l2_requestbuffers *req = arg; - /* Don't allow mixing read / mmap io, either we control the buffers - (read based io), or the app does */ - if (devices[index].io == v4l2_io_read) { - V4L2_LOG_ERR("to change from read io to mmap io open and close the device first!\n"); - errno = EBUSY; - result = -1; - break; - } - - /* Are any of our fake (convert_mmap_buf) buffers still mapped ? */ - if (devices[index].frame_mapped || devices[index].frame_map_count) { - errno = EBUSY; - result = -1; - break; - } - /* IMPROVEME (maybe?) add support for userptr's? */ if (req->memory != V4L2_MEMORY_MMAP) { errno = EINVAL; @@ -713,29 +754,20 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) break; } + if ((result = v4l2_check_buffer_change_ok(index))) + break; + /* No more buffers then we can manage please */ if (req->count > V4L2_MAX_NO_FRAMES) req->count = V4L2_MAX_NO_FRAMES; - /* Stop stream and unmap our real mapping of the buffers - (only relevant when we're converting, otherwise a no-op) */ - v4l2_streamoff(index); - v4l2_unmap_buffers(index); - result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_REQBUFS, req); - if (result) + if (result < 0) break; + result = 0; /* some drivers return the number of buffers on success */ - /* If we got more frames then we can handle lie to the app */ - if (req->count > V4L2_MAX_NO_FRAMES) - req->count = V4L2_MAX_NO_FRAMES; - - /* Force reallocation of convert_mmap_buf to fit the new no_frames */ - syscall(SYS_munmap, devices[index].convert_mmap_buf, - devices[index].no_frames * V4L2_FRAME_BUF_SIZE); - devices[index].convert_mmap_buf = MAP_FAILED; - devices[index].no_frames = req->count; - devices[index].io = req->count? v4l2_io_mmap:v4l2_io_none; + devices[index].no_frames = MIN(req->count, V4L2_MAX_NO_FRAMES); + devices[index].flags &= ~V4L2_BUFFERS_REQUESTED_BY_READ; } break; @@ -743,6 +775,10 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) { struct v4l2_buffer *buf = arg; + if (devices[index].flags & V4L2_STREAM_CONTROLLED_BY_READ) + if ((result = v4l2_deactivate_read_stream(index))) + break; + /* Do a real query even when converting to let the driver fill in things like buf->field */ result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_QUERYBUF, buf); @@ -751,10 +787,23 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) buf->m.offset = V4L2_MMAP_OFFSET_MAGIC | buf->index; buf->length = V4L2_FRAME_BUF_SIZE; + if (devices[index].frame_map_count[buf->index]) + buf->flags |= V4L2_BUF_FLAG_MAPPED; + else + buf->flags &= ~V4L2_BUF_FLAG_MAPPED; } break; case VIDIOC_QBUF: + if (devices[index].flags & V4L2_STREAM_CONTROLLED_BY_READ) + if ((result = v4l2_deactivate_read_stream(index))) + break; + + /* With some drivers the buffers must be mapped before queuing */ + if (converting) + if ((result = v4l2_map_buffers(index))) + break; + result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_QBUF, arg); break; @@ -762,6 +811,10 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) { struct v4l2_buffer *buf = arg; + if (devices[index].flags & V4L2_STREAM_CONTROLLED_BY_READ) + if ((result = v4l2_deactivate_read_stream(index))) + break; + result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_DQBUF, buf); if (result) { V4L2_LOG_ERR("dequeing buffer: %s\n", strerror(errno)); @@ -810,7 +863,12 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) } buf->bytesused = result; + buf->m.offset = V4L2_MMAP_OFFSET_MAGIC | buf->index; buf->length = V4L2_FRAME_BUF_SIZE; + if (devices[index].frame_map_count[buf->index]) + buf->flags |= V4L2_BUF_FLAG_MAPPED; + else + buf->flags &= ~V4L2_BUF_FLAG_MAPPED; result = 0; } @@ -818,11 +876,9 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) case VIDIOC_STREAMON: case VIDIOC_STREAMOFF: - if (devices[index].io != v4l2_io_mmap) { - errno = EINVAL; - result = -1; - break; - } + if (devices[index].flags & V4L2_STREAM_CONTROLLED_BY_READ) + if ((result = v4l2_deactivate_read_stream(index))) + break; if (request == VIDIOC_STREAMON) result = v4l2_streamon(index); @@ -855,22 +911,36 @@ ssize_t v4l2_read (int fd, void* buffer, size_t n) pthread_mutex_lock(&devices[index].stream_lock); - if (devices[index].io == v4l2_io_mmap) { - V4L2_LOG_ERR("to change from mmap io to read io first do request_buffers with a count of 0\n"); - errno = EBUSY; - result = -1; + /* When not converting and the device supports read let the kernel handle + it */ + if ((devices[index].flags & V4L2_SUPPORTS_READ) && + devices[index].src_fmt.fmt.pix.pixelformat == + devices[index].dest_fmt.fmt.pix.pixelformat) { + result = syscall(SYS_read, fd, buffer, n); goto leave; } - devices[index].io = v4l2_io_read; - if ((result = v4l2_activate_read_stream(index))) - goto leave; + if (!(devices[index].flags & V4L2_STREAM_CONTROLLED_BY_READ)) { + if ((devices[index].flags & V4L2_STREAMON) || + devices[index].frame_queued) { + errno = EBUSY; + result = -1; + goto leave; + } + if ((result = v4l2_activate_read_stream(index))) + goto leave; + } if ((frame_index = v4l2_dequeue_read_buffer(index, &bytesused)) < 0) { result = -1; goto leave; } + /* ensure buffers are mapped before using them (they could have been + unmapped by a s_fmt ioctl) */ + if ((result = v4l2_map_buffers(index))) + goto leave; + result = v4lconvert_convert(devices[index].convert, &devices[index].src_fmt, &devices[index].dest_fmt, devices[index].frame_pointers[frame_index], bytesused, @@ -917,7 +987,6 @@ void *v4l2_mmap(void *start, size_t length, int prot, int flags, int fd, buffer_index = offset & 0xff; if (buffer_index >= devices[index].no_frames || - devices[index].io != v4l2_io_mmap || /* Got magic offset and not converting ?? */ devices[index].src_fmt.fmt.pix.pixelformat == devices[index].dest_fmt.fmt.pix.pixelformat) { @@ -943,8 +1012,7 @@ void *v4l2_mmap(void *start, size_t length, int prot, int flags, int fd, } } - devices[index].frame_mapped |= 1 << buffer_index; - devices[index].frame_map_count++; + devices[index].frame_map_count[buffer_index]++; result = devices[index].convert_mmap_buf + buffer_index * V4L2_FRAME_BUF_SIZE; @@ -985,9 +1053,8 @@ int v4l2_munmap(void *_start, size_t length) start >= devices[index].convert_mmap_buf && (start - devices[index].convert_mmap_buf) % length == 0 && buffer_index < devices[index].no_frames) { - devices[index].frame_mapped &= ~(1 << buffer_index); - if (devices[index].frame_map_count > 0) - devices[index].frame_map_count--; + if (devices[index].frame_map_count[buffer_index] > 0) + devices[index].frame_map_count[buffer_index]--; unmapped = 1; } diff --git a/v4l2-apps/lib/libv4l/libv4l2/log.c b/v4l2-apps/lib/libv4l/libv4l2/log.c index 982a185c6..05f6c46d7 100644 --- a/v4l2-apps/lib/libv4l/libv4l2/log.c +++ b/v4l2-apps/lib/libv4l/libv4l2/log.c @@ -8,8 +8,8 @@ # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program; if not, write to the Free Software @@ -131,6 +131,14 @@ void v4l2_log_ioctl(unsigned long int request, void *arg, int result) } } break; + case VIDIOC_REQBUFS: + { + struct v4l2_requestbuffers *req = arg; + + fprintf(v4l2_log_file, " count: %u type: %d memory: %d\n", + req->count, req->type, req->memory); + } + break; } fprintf(v4l2_log_file, "result == %d\n", result); diff --git a/v4l2-apps/lib/libv4l/libv4l2/v4l2convert.c b/v4l2-apps/lib/libv4l/libv4l2/v4l2convert.c index 7db1ca6d6..f312828c6 100644 --- a/v4l2-apps/lib/libv4l/libv4l2/v4l2convert.c +++ b/v4l2-apps/lib/libv4l/libv4l2/v4l2convert.c @@ -12,8 +12,8 @@ # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program; if not, write to the Free Software @@ -66,7 +66,7 @@ int open (const char *file, int oflag, ...) return fd; /* check if we're opening a video4linux2 device */ - if (strncmp(file, "/dev/video", 10)) + if (strncmp(file, "/dev/video", 10) && strncmp(file, "/dev/v4l/", 9)) return fd; /* check that this is an v4l2 device, libv4l2 only supports v4l2 devices */ @@ -134,13 +134,13 @@ ssize_t read (int fd, void* buffer, size_t n) return v4l2_read (fd, buffer, n); } -void mmap(void *start, size_t length, int prot, int flags, int fd, +void *mmap(void *start, size_t length, int prot, int flags, int fd, __off_t offset) { return v4l2_mmap(start, length, prot, flags, fd, offset); } -void mmap64(void *start, size_t length, int prot, int flags, int fd, +void *mmap64(void *start, size_t length, int prot, int flags, int fd, __off64_t offset) { return v4l2_mmap(start, length, prot, flags, fd, offset); |