Message ID | 1678f1f41284ad9665de8717b7b8be117ddf9596.1304435825.git.ykamenov@mm-sol.com (mailing list archive) |
---|---|
State | Not Applicable |
Headers | show |
Hi, Thanks, looks good now! I'm going to keep this in my inbox before applying for a while though, as this involves an abi change (of libv4lconvert, which is almost not used directly but still). I've a number of important fixes / changes planned which I hope to be able to do soon, and then I want to do another 0.8.x release, once that is out the door I'll merge this, and then do a 0.9.x release pretty soon after that. Regards, Hans On 05/03/2011 05:26 PM, Yordan Kamenov wrote: > A libv4l2 plugin will sit in between libv4l2 itself and the actual > /dev/video device node a fd refers to. It will be called each time > libv4l2 wants to do an operation (read/write/ioctl) on the actual > /dev/video node in question. > > Signed-off-by: Yordan Kamenov<ykamenov@mm-sol.com> > --- > lib/include/libv4l2-plugin.h | 36 ++++++ > lib/include/libv4lconvert.h | 5 +- > lib/libv4l2/Makefile | 6 +- > lib/libv4l2/libv4l2-priv.h | 10 ++ > lib/libv4l2/libv4l2.c | 88 ++++++++++---- > lib/libv4l2/v4l2-plugin.c | 158 ++++++++++++++++++++++++ > lib/libv4l2/v4l2convert.c | 9 -- > lib/libv4lconvert/control/libv4lcontrol-priv.h | 4 + > lib/libv4lconvert/control/libv4lcontrol.c | 35 ++++-- > lib/libv4lconvert/control/libv4lcontrol.h | 5 +- > lib/libv4lconvert/libv4lconvert-priv.h | 2 + > lib/libv4lconvert/libv4lconvert.c | 34 ++++-- > utils/qv4l2/qv4l2.cpp | 17 +++- > utils/qv4l2/qv4l2.h | 1 + > 14 files changed, 347 insertions(+), 63 deletions(-) > create mode 100644 lib/include/libv4l2-plugin.h > create mode 100644 lib/libv4l2/v4l2-plugin.c > > diff --git a/lib/include/libv4l2-plugin.h b/lib/include/libv4l2-plugin.h > new file mode 100644 > index 0000000..158c0c2 > --- /dev/null > +++ b/lib/include/libv4l2-plugin.h > @@ -0,0 +1,36 @@ > +/* > +* Copyright (C) 2010 Nokia Corporation<multimedia@maemo.org> > + > +* This program is free software; you can redistribute it and/or modify > +* it under the terms of the GNU Lesser General Public License as published by > +* the Free Software Foundation; either version 2.1 of the License, or > +* (at your option) any later version. > +* > +* 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 > +* 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 > +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > +*/ > + > +#ifndef __LIBV4L2_PLUGIN_H > +#define __LIBV4L2_PLUGIN_H > + > +#include<sys/types.h> > + > +/* Structure libv4l2_dev_ops holds the calls from libv4ls to video nodes. > + They can be normal open/close/ioctl etc. or any of them may be replaced > + with a callback by a loaded plugin. > +*/ > + > +struct libv4l2_dev_ops { > + void * (*init)(int fd); > + void (*close)(void *dev_ops_priv); > + int (*ioctl)(void *dev_ops_priv, int fd, unsigned long int request, void *arg); > + ssize_t (*read)(void *dev_ops_priv, int fd, void *buffer, size_t n); > +}; > + > +#endif > diff --git a/lib/include/libv4lconvert.h b/lib/include/libv4lconvert.h > index 0264290..351142e 100644 > --- a/lib/include/libv4lconvert.h > +++ b/lib/include/libv4lconvert.h > @@ -38,6 +38,8 @@ > > #include<linux/videodev2.h> > > +#include "libv4l2-plugin.h" > + > #ifdef __cplusplus > extern "C" { > #endif /* __cplusplus */ > @@ -50,7 +52,8 @@ extern "C" { > > struct v4lconvert_data; > > -LIBV4L_PUBLIC struct v4lconvert_data *v4lconvert_create(int fd); > +LIBV4L_PUBLIC struct v4lconvert_data *v4lconvert_create(int fd, > + void *dev_ops_priv, struct libv4l2_dev_ops *dev_ops); > LIBV4L_PUBLIC void v4lconvert_destroy(struct v4lconvert_data *data); > > /* When doing flipping / rotating / video-processing, only supported > diff --git a/lib/libv4l2/Makefile b/lib/libv4l2/Makefile > index d78632f..f8b3714 100644 > --- a/lib/libv4l2/Makefile > +++ b/lib/libv4l2/Makefile > @@ -1,12 +1,12 @@ > override CPPFLAGS += -I../include -fvisibility=hidden > > -LIBS_libv4l2 = -lpthread > +LIBS_libv4l2 = -lpthread -ldl > > -V4L2_OBJS = libv4l2.o log.o > +V4L2_OBJS = libv4l2.o v4l2-plugin.o log.o > V4L2CONVERT = v4l2convert.so > V4L2CONVERT_O = v4l2convert.o libv4l2.so > TARGETS = $(V4L2_LIB) libv4l2.pc > -INCLUDES = ../include/libv4l2.h > +INCLUDES = ../include/libv4l2.h ../include/libv4l2-plugin.h > > ifeq ($(LINKTYPE),static) > V4L2_LIB = libv4l2.a > diff --git a/lib/libv4l2/libv4l2-priv.h b/lib/libv4l2/libv4l2-priv.h > index 46d6103..d06a508 100644 > --- a/lib/libv4l2/libv4l2-priv.h > +++ b/lib/libv4l2/libv4l2-priv.h > @@ -85,8 +85,18 @@ struct v4l2_dev_info { > /* buffer when doing conversion and using read() for read() */ > int readbuf_size; > unsigned char *readbuf; > + struct libv4l2_dev_ops *dev_ops; > + /* plugin info */ > + void *plugin_library; > + void *dev_ops_priv; > }; > > +void v4l2_plugin_init(int fd, void **plugin_lib_ret, void **plugin_priv_ret, > + struct libv4l2_dev_ops **dev_ops_ret); > +void v4l2_plugin_cleanup(void *plugin_priv, void *plugin_lib, > + struct libv4l2_dev_ops *dev_ops); > + > + > /* From log.c */ > void v4l2_log_ioctl(unsigned long int request, void *arg, int result); > > diff --git a/lib/libv4l2/libv4l2.c b/lib/libv4l2/libv4l2.c > index ab85ea7..018350e 100644 > --- a/lib/libv4l2/libv4l2.c > +++ b/lib/libv4l2/libv4l2.c > @@ -67,6 +67,7 @@ > #include<sys/stat.h> > #include "libv4l2.h" > #include "libv4l2-priv.h" > +#include "libv4l2-plugin.h" > > /* 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 > @@ -102,7 +103,8 @@ static int v4l2_request_read_buffers(int index) > devices[index].nreadbuffers; > req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; > req.memory = V4L2_MEMORY_MMAP; > - result = SYS_IOCTL(devices[index].fd, VIDIOC_REQBUFS,&req); > + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + devices[index].fd, VIDIOC_REQBUFS,&req); > if (result< 0) { > int saved_err = errno; > > @@ -131,7 +133,8 @@ static void v4l2_unrequest_read_buffers(int index) > req.count = 0; > req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; > req.memory = V4L2_MEMORY_MMAP; > - if (SYS_IOCTL(devices[index].fd, VIDIOC_REQBUFS,&req)< 0) > + if (devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + devices[index].fd, VIDIOC_REQBUFS,&req)< 0) > return; > > devices[index].no_frames = MIN(req.count, V4L2_MAX_NO_FRAMES); > @@ -152,7 +155,8 @@ static int v4l2_map_buffers(int index) > buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; > buf.memory = V4L2_MEMORY_MMAP; > buf.index = i; > - result = SYS_IOCTL(devices[index].fd, VIDIOC_QUERYBUF,&buf); > + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + devices[index].fd, VIDIOC_QUERYBUF,&buf); > if (result) { > int saved_err = errno; > > @@ -202,7 +206,8 @@ static int v4l2_streamon(int index) > enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; > > if (!(devices[index].flags& V4L2_STREAMON)) { > - result = SYS_IOCTL(devices[index].fd, VIDIOC_STREAMON,&type); > + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + devices[index].fd, VIDIOC_STREAMON,&type); > if (result) { > int saved_err = errno; > > @@ -223,7 +228,8 @@ static int v4l2_streamoff(int index) > enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; > > if (devices[index].flags& V4L2_STREAMON) { > - result = SYS_IOCTL(devices[index].fd, VIDIOC_STREAMOFF,&type); > + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + devices[index].fd, VIDIOC_STREAMOFF,&type); > if (result) { > int saved_err = errno; > > @@ -252,7 +258,8 @@ static int v4l2_queue_read_buffer(int index, int buffer_index) > buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; > buf.memory = V4L2_MEMORY_MMAP; > buf.index = buffer_index; > - result = SYS_IOCTL(devices[index].fd, VIDIOC_QBUF,&buf); > + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + devices[index].fd, VIDIOC_QBUF,&buf); > if (result) { > int saved_err = errno; > > @@ -277,7 +284,8 @@ static int v4l2_dequeue_and_convert(int index, struct v4l2_buffer *buf, > return result; > > do { > - result = SYS_IOCTL(devices[index].fd, VIDIOC_DQBUF, buf); > + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + devices[index].fd, VIDIOC_DQBUF, buf); > if (result) { > if (errno != EAGAIN) { > int saved_err = errno; > @@ -356,7 +364,8 @@ static int v4l2_read_and_convert(int index, unsigned char *dest, int dest_size) > } > > do { > - result = SYS_READ(devices[index].fd, devices[index].readbuf, buf_size); > + result = devices[index].dev_ops->read(devices[index].dev_ops_priv, > + devices[index].fd, devices[index].readbuf, buf_size); > if (result<= 0) { > if (result&& errno != EAGAIN) { > int saved_err = errno; > @@ -496,7 +505,8 @@ static int v4l2_buffers_mapped(int index) > buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; > buf.memory = V4L2_MEMORY_MMAP; > buf.index = i; > - if (SYS_IOCTL(devices[index].fd, VIDIOC_QUERYBUF,&buf)) { > + if (devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + devices[index].fd, VIDIOC_QUERYBUF,&buf)) { > int saved_err = errno; > > V4L2_LOG_ERR("querying buffer %u: %s\n", i, strerror(errno)); > @@ -561,6 +571,11 @@ int v4l2_fd_open(int fd, int v4l2_flags) > struct v4l2_capability cap; > struct v4l2_format fmt; > struct v4lconvert_data *convert; > + struct libv4l2_dev_ops *dev_ops; > + void *plugin_library; > + void *plugin_data; > + > + v4l2_plugin_init(fd,&plugin_library,&plugin_data,&dev_ops); > > /* If no log file was set by the app, see if one was specified through the > environment */ > @@ -571,9 +586,10 @@ int v4l2_fd_open(int fd, int v4l2_flags) > } > > /* check that this is an v4l2 device */ > - if (SYS_IOCTL(fd, VIDIOC_QUERYCAP,&cap)) { > + if (dev_ops->ioctl(plugin_data, fd, VIDIOC_QUERYCAP,&cap)) { > int saved_err = errno; > > + v4l2_plugin_cleanup(plugin_data, plugin_library, dev_ops); > V4L2_LOG_ERR("getting capabilities: %s\n", strerror(errno)); > errno = saved_err; > return -1; > @@ -581,29 +597,38 @@ int v4l2_fd_open(int fd, int v4l2_flags) > > /* we only add functionality for video capture devices */ > if (!(cap.capabilities& V4L2_CAP_VIDEO_CAPTURE) || > - !(cap.capabilities& (V4L2_CAP_STREAMING | V4L2_CAP_READWRITE))) > + !(cap.capabilities& (V4L2_CAP_STREAMING | V4L2_CAP_READWRITE))) { > + v4l2_plugin_cleanup(plugin_data, plugin_library, dev_ops); > return fd; > + } > > /* Get current cam format */ > fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; > - if (SYS_IOCTL(fd, VIDIOC_G_FMT,&fmt)) { > + if (dev_ops->ioctl(plugin_data, fd, VIDIOC_G_FMT,&fmt)) { > int saved_err = errno; > > + v4l2_plugin_cleanup(plugin_data, plugin_library, dev_ops); > V4L2_LOG_ERR("getting pixformat: %s\n", strerror(errno)); > errno = saved_err; > return -1; > } > > /* init libv4lconvert */ > - convert = v4lconvert_create(fd); > - if (!convert) > + convert = v4lconvert_create(fd, plugin_data, dev_ops); > + if (!convert) { > + v4l2_plugin_cleanup(plugin_data, plugin_library, dev_ops); > return -1; > + } > > /* So we have a v4l2 capture device, register it in our devices array */ > pthread_mutex_lock(&v4l2_open_mutex); > for (index = 0; index< V4L2_MAX_DEVICES; index++) > if (devices[index].fd == -1) { > devices[index].fd = fd; > + > + devices[index].plugin_library = plugin_library; > + devices[index].dev_ops_priv = plugin_data; > + devices[index].dev_ops = dev_ops; > break; > } > pthread_mutex_unlock(&v4l2_open_mutex); > @@ -611,6 +636,7 @@ int v4l2_fd_open(int fd, int v4l2_flags) > if (index == V4L2_MAX_DEVICES) { > V4L2_LOG_ERR("attempting to open more then %d video devices\n", > V4L2_MAX_DEVICES); > + v4l2_plugin_cleanup(plugin_data, plugin_library, dev_ops); > errno = EBUSY; > return -1; > } > @@ -700,6 +726,9 @@ int v4l2_close(int fd) > if (result) > return 0; > > + v4l2_plugin_cleanup(devices[index].dev_ops_priv, > + devices[index].plugin_library, devices[index].dev_ops); > + > /* Free resources */ > v4l2_unmap_buffers(index); > if (devices[index].convert_mmap_buf != MAP_FAILED) { > @@ -879,7 +908,8 @@ int v4l2_ioctl(int fd, unsigned long int request, ...) > } > > if (!is_capture_request) { > - result = SYS_IOCTL(fd, request, arg); > + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + fd, request, arg); > saved_err = errno; > v4l2_log_ioctl(request, arg, result); > errno = saved_err; > @@ -927,7 +957,8 @@ int v4l2_ioctl(int fd, unsigned long int request, ...) > case VIDIOC_QUERYCAP: { > struct v4l2_capability *cap = arg; > > - result = SYS_IOCTL(devices[index].fd, VIDIOC_QUERYCAP, cap); > + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + 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; > @@ -977,8 +1008,8 @@ int v4l2_ioctl(int fd, unsigned long int request, ...) > } > > if (devices[index].flags& V4L2_DISABLE_CONVERSION) { > - result = SYS_IOCTL(devices[index].fd, VIDIOC_TRY_FMT, > - dest_fmt); > + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + devices[index].fd, VIDIOC_TRY_FMT, dest_fmt); > src_fmt = *dest_fmt; > } else { > result = v4lconvert_try_format(devices[index].convert, dest_fmt, > @@ -1018,7 +1049,8 @@ int v4l2_ioctl(int fd, unsigned long int request, ...) > break; > > req_pix_fmt = src_fmt.fmt.pix; > - result = SYS_IOCTL(devices[index].fd, VIDIOC_S_FMT,&src_fmt); > + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + devices[index].fd, VIDIOC_S_FMT,&src_fmt); > if (result) { > saved_err = errno; > V4L2_LOG_ERR("setting pixformat: %s\n", strerror(errno)); > @@ -1067,7 +1099,8 @@ int v4l2_ioctl(int fd, unsigned long int request, ...) > if (req->count> V4L2_MAX_NO_FRAMES) > req->count = V4L2_MAX_NO_FRAMES; > > - result = SYS_IOCTL(devices[index].fd, VIDIOC_REQBUFS, req); > + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + devices[index].fd, VIDIOC_REQBUFS, req); > if (result< 0) > break; > result = 0; /* some drivers return the number of buffers on success */ > @@ -1088,7 +1121,8 @@ int v4l2_ioctl(int fd, unsigned long int request, ...) > > /* Do a real query even when converting to let the driver fill in > things like buf->field */ > - result = SYS_IOCTL(devices[index].fd, VIDIOC_QUERYBUF, buf); > + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + devices[index].fd, VIDIOC_QUERYBUF, buf); > if (result || !v4l2_needs_conversion(index)) > break; > > @@ -1115,7 +1149,8 @@ int v4l2_ioctl(int fd, unsigned long int request, ...) > break; > } > > - result = SYS_IOCTL(devices[index].fd, VIDIOC_QBUF, arg); > + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + devices[index].fd, VIDIOC_QBUF, arg); > break; > > case VIDIOC_DQBUF: { > @@ -1128,7 +1163,8 @@ int v4l2_ioctl(int fd, unsigned long int request, ...) > } > > if (!v4l2_needs_conversion(index)) { > - result = SYS_IOCTL(devices[index].fd, VIDIOC_DQBUF, buf); > + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + devices[index].fd, VIDIOC_DQBUF, buf); > if (result) { > int saved_err = errno; > > @@ -1187,7 +1223,8 @@ int v4l2_ioctl(int fd, unsigned long int request, ...) > break; > > default: > - result = SYS_IOCTL(fd, request, arg); > + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + fd, request, arg); > break; > } > > @@ -1217,7 +1254,8 @@ ssize_t v4l2_read(int fd, void *dest, size_t n) > it */ > if ((devices[index].flags& V4L2_SUPPORTS_READ)&& > !v4l2_needs_conversion(index)) { > - result = SYS_READ(fd, dest, n); > + result = devices[index].dev_ops->read(devices[index].dev_ops_priv, > + fd, dest, n); > goto leave; > } > > diff --git a/lib/libv4l2/v4l2-plugin.c b/lib/libv4l2/v4l2-plugin.c > new file mode 100644 > index 0000000..3735193 > --- /dev/null > +++ b/lib/libv4l2/v4l2-plugin.c > @@ -0,0 +1,158 @@ > +/* > +* Copyright (C) 2010 Nokia Corporation<multimedia@maemo.org> > + > +* This program is free software; you can redistribute it and/or modify > +* it under the terms of the GNU Lesser General Public License as published by > +* the Free Software Foundation; either version 2.1 of the License, or > +* (at your option) any later version. > +* > +* 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 > +* 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 > +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > +*/ > + > +#include<stdarg.h> > +#include<dlfcn.h> > +#include<fcntl.h> > +#include<glob.h> > +#include<sys/stat.h> > +#include<sys/mman.h> > +#include "libv4l2.h" > +#include "libv4l2-priv.h" > +#include "libv4l2-plugin.h" > + > +/* libv4l plugin support: > + it is provided by functions v4l2_plugin_[open,close,etc]. > + > + When open() is called libv4l dlopens files in /usr/lib[64]/libv4l/plugins > + 1 at a time and call open callback passing through the applications > + parameters unmodified. > + > + If a plugin is relevant for the specified device node, it can indicate so > + by returning a value other then -1 (the actual file descriptor). > + As soon as a plugin returns another value then -1 plugin loading stops and > + information about it (fd and corresponding library handle) is stored. For > + each function v4l2_[ioctl,read,close,etc] is called corresponding > + v4l2_plugin_* function which looks if there is loaded plugin for that file > + and call it's callbacks. > + > + v4l2_plugin_* function indicates by it's first argument if plugin was used, > + and if it was not then v4l2_* functions proceed with their usual behavior. > +*/ > + > +#define PLUGINS_PATTERN "/usr/lib/libv4l/plugins/*.so" > + > +static void * dev_init(int fd) > +{ > + return NULL; > +} > + > +static void dev_close(void *dev_ops_priv) > +{ > +} > + > +static int dev_ioctl(void *dev_ops_priv, int fd, unsigned long cmd, void *arg) > +{ > + return SYS_IOCTL(fd, cmd, arg); > +} > + > +static ssize_t dev_read(void *dev_ops_priv, int fd, void *buf, size_t len) > +{ > + return SYS_READ(fd, buf, len); > +} > + > + > +struct libv4l2_dev_ops default_operations = { > + .init =&dev_init, > + .close =&dev_close, > + .ioctl =&dev_ioctl, > + .read =&dev_read > +}; > + > +void v4l2_plugin_init(int fd, void **plugin_lib_ret, void **plugin_priv_ret, > + struct libv4l2_dev_ops **dev_ops_ret) > +{ > + char *error; > + int glob_ret, plugin_num; > + void *plugin_library = NULL; > + struct libv4l2_dev_ops *libv4l2_plugin = NULL; > + glob_t globbuf; > + > + *dev_ops_ret =&default_operations; > + > + glob_ret = glob(PLUGINS_PATTERN, 0, NULL,&globbuf); > + > + if (glob_ret == GLOB_NOSPACE) { > + *plugin_lib_ret = NULL; > + *plugin_priv_ret = NULL; > + return; > + } > + > + if (glob_ret == GLOB_ABORTED || glob_ret == GLOB_NOMATCH) { > + *plugin_lib_ret = NULL; > + *plugin_priv_ret = NULL; > + goto leave; > + } > + > + for (plugin_num = 0; plugin_num< globbuf.gl_pathc; plugin_num++) { > + > + V4L2_LOG("PLUGIN: dlopen(%s);\n", globbuf.gl_pathv[plugin_num]); > + > + plugin_library = dlopen(globbuf.gl_pathv[plugin_num], > + RTLD_LAZY); > + > + if (!plugin_library) > + continue; > + > + dlerror(); /* Clear any existing error */ > + libv4l2_plugin = (struct libv4l2_dev_ops *) > + dlsym(plugin_library, "libv4l2_plugin"); > + > + error = dlerror(); > + if (error != NULL) { > + V4L2_LOG_ERR("PLUGIN: dlsym failed: %s\n", error); > + dlclose(plugin_library); > + > + continue; > + } > + > + *plugin_priv_ret = NULL; > + if (libv4l2_plugin->init) > + *plugin_priv_ret = libv4l2_plugin->init(fd); > + > + if (!*plugin_priv_ret) { > + V4L2_LOG("PLUGIN: plugin open() returned NULL\n"); > + dlclose(plugin_library); > + *plugin_lib_ret = NULL; > + continue; > + } > + > + (*dev_ops_ret)->init = libv4l2_plugin->init; > + if (libv4l2_plugin->close != NULL) > + (*dev_ops_ret)->close = libv4l2_plugin->close; > + if (libv4l2_plugin->ioctl != NULL) > + (*dev_ops_ret)->ioctl = libv4l2_plugin->ioctl; > + if (libv4l2_plugin->read != NULL) > + (*dev_ops_ret)->read = libv4l2_plugin->read; > + > + break; > + > + } > + > +leave: > + globfree(&globbuf); > +} > + > +void v4l2_plugin_cleanup(void *plugin_priv, void *plugin_lib, > + struct libv4l2_dev_ops *dev_ops) > +{ > + if (plugin_priv) { > + dev_ops->close(plugin_priv); > + dlclose(plugin_lib); > + } > +} > diff --git a/lib/libv4l2/v4l2convert.c b/lib/libv4l2/v4l2convert.c > index e251085..03f34ad 100644 > --- a/lib/libv4l2/v4l2convert.c > +++ b/lib/libv4l2/v4l2convert.c > @@ -46,7 +46,6 @@ > LIBV4L_PUBLIC int open(const char *file, int oflag, ...) > { > int fd; > - struct v4l2_capability cap; > int v4l_device = 0; > > /* check if we're opening a video4linux2 device */ > @@ -76,14 +75,6 @@ LIBV4L_PUBLIC int open(const char *file, int oflag, ...) > if (fd == -1 || !v4l_device) > return fd; > > - /* check that this is an v4l2 device, libv4l2 only supports v4l2 devices */ > - if (SYS_IOCTL(fd, VIDIOC_QUERYCAP,&cap)) > - return fd; > - > - /* libv4l2 only adds functionality to capture capable devices */ > - if (!(cap.capabilities& V4L2_CAP_VIDEO_CAPTURE)) > - return fd; > - > /* Try to Register with libv4l2 (in case of failure pass the fd to the > application as is) */ > v4l2_fd_open(fd, 0); > diff --git a/lib/libv4lconvert/control/libv4lcontrol-priv.h b/lib/libv4lconvert/control/libv4lcontrol-priv.h > index 22cdf34..1259e6b 100644 > --- a/lib/libv4lconvert/control/libv4lcontrol-priv.h > +++ b/lib/libv4lconvert/control/libv4lcontrol-priv.h > @@ -22,6 +22,8 @@ > #ifndef __LIBV4LCONTROL_PRIV_H > #define __LIBV4LCONTROL_PRIV_H > > +#include "libv4l2-plugin.h" > + > #define V4LCONTROL_SHM_SIZE 4096 > > #define V4LCONTROL_SUPPORTS_NEXT_CTRL 0x01 > @@ -37,6 +39,8 @@ struct v4lcontrol_data { > unsigned int *shm_values; /* shared memory control value store */ > unsigned int old_values[V4LCONTROL_COUNT]; /* for controls_changed() */ > const struct v4lcontrol_flags_info *flags_info; > + struct libv4l2_dev_ops *dev_ops; > + void *dev_ops_priv; > }; > > struct v4lcontrol_flags_info { > diff --git a/lib/libv4lconvert/control/libv4lcontrol.c b/lib/libv4lconvert/control/libv4lcontrol.c > index 116bef5..24a5600 100644 > --- a/lib/libv4lconvert/control/libv4lcontrol.c > +++ b/lib/libv4lconvert/control/libv4lcontrol.c > @@ -747,7 +747,8 @@ static void v4lcontrol_get_flags_from_db(struct v4lcontrol_data *data, > } > } > > -struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) > +struct v4lcontrol_data *v4lcontrol_create(int fd, void *dev_ops_priv, > + struct libv4l2_dev_ops *dev_ops, int always_needs_conversion) > { > int shm_fd; > int i, rc, got_usb_ids, init = 0; > @@ -767,10 +768,12 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) > } > > data->fd = fd; > + data->dev_ops = dev_ops; > + data->dev_ops_priv = dev_ops_priv; > > /* Check if the driver has indicated some form of flipping is needed */ > - if ((SYS_IOCTL(data->fd, VIDIOC_G_INPUT,&input.index) == 0)&& > - (SYS_IOCTL(data->fd, VIDIOC_ENUMINPUT,&input) == 0)) { > + if ((data->dev_ops->ioctl(data->dev_ops_priv, data->fd, VIDIOC_G_INPUT,&input.index) == 0)&& > + (data->dev_ops->ioctl(data->dev_ops_priv, data->fd, VIDIOC_ENUMINPUT,&input) == 0)) { > if (input.status& V4L2_IN_ST_HFLIP) > data->flags |= V4LCONTROL_HFLIPPED; > if (input.status& V4L2_IN_ST_VFLIP) > @@ -787,7 +790,8 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) > data->flags = strtol(s, NULL, 0); > > ctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL; > - if (SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL,&ctrl) == 0) > + if (data->dev_ops->ioctl(data->dev_ops_priv, data->fd, > + VIDIOC_QUERYCTRL,&ctrl) == 0) > data->priv_flags |= V4LCONTROL_SUPPORTS_NEXT_CTRL; > > /* If the device always needs conversion, we can add fake controls at no cost > @@ -795,7 +799,8 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) > if (always_needs_conversion || v4lcontrol_needs_conversion(data)) { > for (i = 0; i< V4LCONTROL_AUTO_ENABLE_COUNT; i++) { > ctrl.id = fake_controls[i].id; > - rc = SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL,&ctrl); > + rc = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, > + VIDIOC_QUERYCTRL,&ctrl); > if (rc == -1 || (rc == 0&& (ctrl.flags& V4L2_CTRL_FLAG_DISABLED))) > data->controls |= 1<< i; > } > @@ -807,17 +812,20 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) > different sensors with / without autogain or the necessary controls. */ > while (data->flags& V4LCONTROL_WANTS_AUTOGAIN) { > ctrl.id = V4L2_CID_AUTOGAIN; > - rc = SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL,&ctrl); > + rc = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, > + VIDIOC_QUERYCTRL,&ctrl); > if (rc == 0&& !(ctrl.flags& V4L2_CTRL_FLAG_DISABLED)) > break; > > ctrl.id = V4L2_CID_EXPOSURE; > - rc = SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL,&ctrl); > + rc = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, > + VIDIOC_QUERYCTRL,&ctrl); > if (rc != 0 || (ctrl.flags& V4L2_CTRL_FLAG_DISABLED)) > break; > > ctrl.id = V4L2_CID_GAIN; > - rc = SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL,&ctrl); > + rc = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, > + VIDIOC_QUERYCTRL,&ctrl); > if (rc != 0 || (ctrl.flags& V4L2_CTRL_FLAG_DISABLED)) > break; > > @@ -834,7 +842,7 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) > if (data->controls == 0) > return data; /* No need to create a shared memory segment */ > > - if (SYS_IOCTL(fd, VIDIOC_QUERYCAP,&cap)) { > + if (data->dev_ops->ioctl(data->dev_ops_priv, fd, VIDIOC_QUERYCAP,&cap)) { > perror("libv4lcontrol: error querying device capabilities"); > goto error; > } > @@ -1020,7 +1028,8 @@ int v4lcontrol_vidioc_queryctrl(struct v4lcontrol_data *data, void *arg) > } > > /* find out what the kernel driver would respond. */ > - retval = SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL, arg); > + retval = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, > + VIDIOC_QUERYCTRL, arg); > > if ((data->priv_flags& V4LCONTROL_SUPPORTS_NEXT_CTRL)&& > (orig_id& V4L2_CTRL_FLAG_NEXT_CTRL)) { > @@ -1057,7 +1066,8 @@ int v4lcontrol_vidioc_g_ctrl(struct v4lcontrol_data *data, void *arg) > return 0; > } > > - return SYS_IOCTL(data->fd, VIDIOC_G_CTRL, arg); > + return data->dev_ops->ioctl(data->dev_ops_priv, data->fd, > + VIDIOC_G_CTRL, arg); > } > > int v4lcontrol_vidioc_s_ctrl(struct v4lcontrol_data *data, void *arg) > @@ -1078,7 +1088,8 @@ int v4lcontrol_vidioc_s_ctrl(struct v4lcontrol_data *data, void *arg) > return 0; > } > > - return SYS_IOCTL(data->fd, VIDIOC_S_CTRL, arg); > + return data->dev_ops->ioctl(data->dev_ops_priv, data->fd, > + VIDIOC_S_CTRL, arg); > } > > int v4lcontrol_get_flags(struct v4lcontrol_data *data) > diff --git a/lib/libv4lconvert/control/libv4lcontrol.h b/lib/libv4lconvert/control/libv4lcontrol.h > index 974e97a..1c09546 100644 > --- a/lib/libv4lconvert/control/libv4lcontrol.h > +++ b/lib/libv4lconvert/control/libv4lcontrol.h > @@ -22,6 +22,8 @@ > #ifndef __LIBV4LCONTROL_H > #define __LIBV4LCONTROL_H > > +#include "libv4l2-plugin.h" > + > /* Flags */ > #define V4LCONTROL_HFLIPPED 0x01 > #define V4LCONTROL_VFLIPPED 0x02 > @@ -47,7 +49,8 @@ enum { > > struct v4lcontrol_data; > > -struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion); > +struct v4lcontrol_data *v4lcontrol_create(int fd, void *dev_ops_priv, > + struct libv4l2_dev_ops *dev_ops, int always_needs_conversion); > void v4lcontrol_destroy(struct v4lcontrol_data *data); > > /* Functions used by v4lprocessing to get the control state */ > diff --git a/lib/libv4lconvert/libv4lconvert-priv.h b/lib/libv4lconvert/libv4lconvert-priv.h > index 84c706e..9cb6e1c 100644 > --- a/lib/libv4lconvert/libv4lconvert-priv.h > +++ b/lib/libv4lconvert/libv4lconvert-priv.h > @@ -65,6 +65,8 @@ struct v4lconvert_data { > unsigned char *convert_pixfmt_buf; > struct v4lcontrol_data *control; > struct v4lprocessing_data *processing; > + struct libv4l2_dev_ops *dev_ops; > + void *dev_ops_priv; > > /* Data for external decompression helpers code */ > pid_t decompress_pid; > diff --git a/lib/libv4lconvert/libv4lconvert.c b/lib/libv4lconvert/libv4lconvert.c > index e4863fd..6861986 100644 > --- a/lib/libv4lconvert/libv4lconvert.c > +++ b/lib/libv4lconvert/libv4lconvert.c > @@ -92,7 +92,8 @@ static const int v4lconvert_crop_res[][2] = { > { 176, 144 }, > }; > > -struct v4lconvert_data *v4lconvert_create(int fd) > +struct v4lconvert_data *v4lconvert_create(int fd, void *dev_ops_priv, > + struct libv4l2_dev_ops *dev_ops) > { > int i, j; > struct v4lconvert_data *data = calloc(1, sizeof(struct v4lconvert_data)); > @@ -108,6 +109,8 @@ struct v4lconvert_data *v4lconvert_create(int fd) > } > > data->fd = fd; > + data->dev_ops = dev_ops; > + data->dev_ops_priv = dev_ops_priv; > data->decompress_pid = -1; > > /* Check supported formats */ > @@ -116,7 +119,7 @@ struct v4lconvert_data *v4lconvert_create(int fd) > > fmt.index = i; > > - if (SYS_IOCTL(data->fd, VIDIOC_ENUM_FMT,&fmt)) > + if (data->dev_ops->ioctl(data->dev_ops_priv, data->fd, VIDIOC_ENUM_FMT,&fmt)) > break; > > for (j = 0; j< ARRAY_SIZE(supported_src_pixfmts); j++) > @@ -135,7 +138,8 @@ struct v4lconvert_data *v4lconvert_create(int fd) > data->no_formats = i; > > /* Check if this cam has any special flags */ > - if (SYS_IOCTL(data->fd, VIDIOC_QUERYCAP,&cap) == 0) { > + if (data->dev_ops->ioctl(data->dev_ops_priv, > + data->fd, VIDIOC_QUERYCAP,&cap) == 0) { > if (!strcmp((char *)cap.driver, "uvcvideo")) > data->flags |= V4LCONVERT_IS_UVC; > > @@ -143,7 +147,8 @@ struct v4lconvert_data *v4lconvert_create(int fd) > always_needs_conversion = 0; > } > > - data->control = v4lcontrol_create(fd, always_needs_conversion); > + data->control = v4lcontrol_create(fd, dev_ops_priv, dev_ops, > + always_needs_conversion); > if (!data->control) { > free(data); > return NULL; > @@ -206,7 +211,8 @@ int v4lconvert_enum_fmt(struct v4lconvert_data *data, struct v4l2_fmtdesc *fmt) > if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || > (!v4lconvert_supported_dst_fmt_only(data)&& > fmt->index< data->no_formats)) > - return SYS_IOCTL(data->fd, VIDIOC_ENUM_FMT, fmt); > + return data->dev_ops->ioctl(data->dev_ops_priv, data->fd, > + VIDIOC_ENUM_FMT, fmt); > > for (i = 0; i< ARRAY_SIZE(supported_dst_pixfmts); i++) > if (v4lconvert_supported_dst_fmt_only(data) || > @@ -314,7 +320,8 @@ static int v4lconvert_do_try_format(struct v4lconvert_data *data, > try_fmt = *dest_fmt; > try_fmt.fmt.pix.pixelformat = supported_src_pixfmts[i].fmt; > > - if (!SYS_IOCTL(data->fd, VIDIOC_TRY_FMT,&try_fmt)) { > + if (!data->dev_ops->ioctl(data->dev_ops_priv, data->fd, > + VIDIOC_TRY_FMT,&try_fmt)) { > if (try_fmt.fmt.pix.pixelformat == supported_src_pixfmts[i].fmt) { > int size_x_diff = abs((int)try_fmt.fmt.pix.width - > (int)dest_fmt->fmt.pix.width); > @@ -382,7 +389,8 @@ int v4lconvert_try_format(struct v4lconvert_data *data, > if (!v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat) || > dest_fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || > v4lconvert_do_try_format(data,&try_dest,&try_src)) { > - result = SYS_IOCTL(data->fd, VIDIOC_TRY_FMT, dest_fmt); > + result = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, > + VIDIOC_TRY_FMT, dest_fmt); > if (src_fmt) > *src_fmt = *dest_fmt; > return result; > @@ -1241,7 +1249,8 @@ static void v4lconvert_get_framesizes(struct v4lconvert_data *data, > > for (i = 0; ; i++) { > frmsize.index = i; > - if (SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMESIZES,&frmsize)) > + if (data->dev_ops->ioctl(data->dev_ops_priv, data->fd, > + VIDIOC_ENUM_FRAMESIZES,&frmsize)) > break; > > /* We got a framesize, check we don't have the same one already */ > @@ -1301,7 +1310,8 @@ int v4lconvert_enum_framesizes(struct v4lconvert_data *data, > errno = EINVAL; > return -1; > } > - return SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMESIZES, frmsize); > + return data->dev_ops->ioctl(data->dev_ops_priv, data->fd, > + VIDIOC_ENUM_FRAMESIZES, frmsize); > } > > if (frmsize->index>= data->no_framesizes) { > @@ -1337,7 +1347,8 @@ int v4lconvert_enum_frameintervals(struct v4lconvert_data *data, > errno = EINVAL; > return -1; > } > - res = SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival); > + res = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, > + VIDIOC_ENUM_FRAMEINTERVALS, frmival); > if (res) > V4LCONVERT_ERR("%s\n", strerror(errno)); > return res; > @@ -1382,7 +1393,8 @@ int v4lconvert_enum_frameintervals(struct v4lconvert_data *data, > frmival->pixel_format = src_fmt.fmt.pix.pixelformat; > frmival->width = src_fmt.fmt.pix.width; > frmival->height = src_fmt.fmt.pix.height; > - res = SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival); > + res = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, > + VIDIOC_ENUM_FRAMEINTERVALS, frmival); > if (res) { > int dest_pixfmt = dest_fmt.fmt.pix.pixelformat; > int src_pixfmt = src_fmt.fmt.pix.pixelformat; > diff --git a/utils/qv4l2/qv4l2.cpp b/utils/qv4l2/qv4l2.cpp > index 232a318..349d1ca 100644 > --- a/utils/qv4l2/qv4l2.cpp > +++ b/utils/qv4l2/qv4l2.cpp > @@ -47,6 +47,17 @@ > #include<sys/mman.h> > #include<errno.h> > #include<dirent.h> > +#include<syscall.h> > + > +int defIoctl(void *dev_ops_priv, int fd, unsigned long cmd, void *arg) > +{ > + return syscall(SYS_ioctl, (int)(fd), (unsigned long)(cmd), > + (void *)(arg)); > +} > +ssize_t defRead(void *dev_ops_priv, int fd, void *buf, size_t len) > +{ > + return syscall(SYS_read, (int)(fd), (void *)(buf), (size_t)(len)); > +} > > ApplicationWindow::ApplicationWindow() : > m_capture(NULL), > @@ -59,6 +70,10 @@ ApplicationWindow::ApplicationWindow() : > m_frameData = NULL; > m_nbuffers = 0; > m_buffers = NULL; > + m_defauldDevOps.init = NULL; > + m_defauldDevOps.close = NULL; > + m_defauldDevOps.ioctl =&defIoctl; > + m_defauldDevOps.read =&defRead; > > QAction *openAct = new QAction(QIcon(":/fileopen.png"), "&Open device", this); > openAct->setStatusTip("Open a v4l device, use libv4l2 wrapper if possible"); > @@ -144,7 +159,7 @@ void ApplicationWindow::setDevice(const QString&device, bool rawOpen) > } > m_tabs->show(); > m_tabs->setFocus(); > - m_convertData = v4lconvert_create(fd()); > + m_convertData = v4lconvert_create(fd(), NULL,&m_defauldDevOps); > m_capStartAct->setEnabled(fd()>= 0); > } > > diff --git a/utils/qv4l2/qv4l2.h b/utils/qv4l2/qv4l2.h > index 0a3e5ef..d847fe6 100644 > --- a/utils/qv4l2/qv4l2.h > +++ b/utils/qv4l2/qv4l2.h > @@ -91,6 +91,7 @@ private: > unsigned char *m_frameData; > unsigned m_nbuffers; > struct v4lconvert_data *m_convertData; > + struct libv4l2_dev_ops m_defauldDevOps; > CapMethod m_capMethod; > > private slots: -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi, Sorry it took so long, but I've just merged the plugin support into v4l-utils git. I did make some minor mods / bugfixes before merging, see the commit message in git. Regards, Hans p.s. I think we should expand the plugin support with support for a output devices, iow add a write() dev_op. If you guys agree I can easily do so myself, we should do this asap before people start depending on the ABI (although there is no ABI stability promise until I release 0.10.x, see my message to the list wrt the start of the 0.9.x cycle). While on the subject of keeping the plugin ABI, I suggest that we add a number of extra dev_ops named reserved1 -- reserved8 for future use and a comment that these should all be set to NULL. Then we can easily add another op on the future while keeping compatibility with older plugins. On 05/03/2011 05:26 PM, Yordan Kamenov wrote: > A libv4l2 plugin will sit in between libv4l2 itself and the actual > /dev/video device node a fd refers to. It will be called each time > libv4l2 wants to do an operation (read/write/ioctl) on the actual > /dev/video node in question. > > Signed-off-by: Yordan Kamenov<ykamenov@mm-sol.com> > --- > lib/include/libv4l2-plugin.h | 36 ++++++ > lib/include/libv4lconvert.h | 5 +- > lib/libv4l2/Makefile | 6 +- > lib/libv4l2/libv4l2-priv.h | 10 ++ > lib/libv4l2/libv4l2.c | 88 ++++++++++---- > lib/libv4l2/v4l2-plugin.c | 158 ++++++++++++++++++++++++ > lib/libv4l2/v4l2convert.c | 9 -- > lib/libv4lconvert/control/libv4lcontrol-priv.h | 4 + > lib/libv4lconvert/control/libv4lcontrol.c | 35 ++++-- > lib/libv4lconvert/control/libv4lcontrol.h | 5 +- > lib/libv4lconvert/libv4lconvert-priv.h | 2 + > lib/libv4lconvert/libv4lconvert.c | 34 ++++-- > utils/qv4l2/qv4l2.cpp | 17 +++- > utils/qv4l2/qv4l2.h | 1 + > 14 files changed, 347 insertions(+), 63 deletions(-) > create mode 100644 lib/include/libv4l2-plugin.h > create mode 100644 lib/libv4l2/v4l2-plugin.c > > diff --git a/lib/include/libv4l2-plugin.h b/lib/include/libv4l2-plugin.h > new file mode 100644 > index 0000000..158c0c2 > --- /dev/null > +++ b/lib/include/libv4l2-plugin.h > @@ -0,0 +1,36 @@ > +/* > +* Copyright (C) 2010 Nokia Corporation<multimedia@maemo.org> > + > +* This program is free software; you can redistribute it and/or modify > +* it under the terms of the GNU Lesser General Public License as published by > +* the Free Software Foundation; either version 2.1 of the License, or > +* (at your option) any later version. > +* > +* 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 > +* 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 > +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > +*/ > + > +#ifndef __LIBV4L2_PLUGIN_H > +#define __LIBV4L2_PLUGIN_H > + > +#include<sys/types.h> > + > +/* Structure libv4l2_dev_ops holds the calls from libv4ls to video nodes. > + They can be normal open/close/ioctl etc. or any of them may be replaced > + with a callback by a loaded plugin. > +*/ > + > +struct libv4l2_dev_ops { > + void * (*init)(int fd); > + void (*close)(void *dev_ops_priv); > + int (*ioctl)(void *dev_ops_priv, int fd, unsigned long int request, void *arg); > + ssize_t (*read)(void *dev_ops_priv, int fd, void *buffer, size_t n); > +}; > + > +#endif > diff --git a/lib/include/libv4lconvert.h b/lib/include/libv4lconvert.h > index 0264290..351142e 100644 > --- a/lib/include/libv4lconvert.h > +++ b/lib/include/libv4lconvert.h > @@ -38,6 +38,8 @@ > > #include<linux/videodev2.h> > > +#include "libv4l2-plugin.h" > + > #ifdef __cplusplus > extern "C" { > #endif /* __cplusplus */ > @@ -50,7 +52,8 @@ extern "C" { > > struct v4lconvert_data; > > -LIBV4L_PUBLIC struct v4lconvert_data *v4lconvert_create(int fd); > +LIBV4L_PUBLIC struct v4lconvert_data *v4lconvert_create(int fd, > + void *dev_ops_priv, struct libv4l2_dev_ops *dev_ops); > LIBV4L_PUBLIC void v4lconvert_destroy(struct v4lconvert_data *data); > > /* When doing flipping / rotating / video-processing, only supported > diff --git a/lib/libv4l2/Makefile b/lib/libv4l2/Makefile > index d78632f..f8b3714 100644 > --- a/lib/libv4l2/Makefile > +++ b/lib/libv4l2/Makefile > @@ -1,12 +1,12 @@ > override CPPFLAGS += -I../include -fvisibility=hidden > > -LIBS_libv4l2 = -lpthread > +LIBS_libv4l2 = -lpthread -ldl > > -V4L2_OBJS = libv4l2.o log.o > +V4L2_OBJS = libv4l2.o v4l2-plugin.o log.o > V4L2CONVERT = v4l2convert.so > V4L2CONVERT_O = v4l2convert.o libv4l2.so > TARGETS = $(V4L2_LIB) libv4l2.pc > -INCLUDES = ../include/libv4l2.h > +INCLUDES = ../include/libv4l2.h ../include/libv4l2-plugin.h > > ifeq ($(LINKTYPE),static) > V4L2_LIB = libv4l2.a > diff --git a/lib/libv4l2/libv4l2-priv.h b/lib/libv4l2/libv4l2-priv.h > index 46d6103..d06a508 100644 > --- a/lib/libv4l2/libv4l2-priv.h > +++ b/lib/libv4l2/libv4l2-priv.h > @@ -85,8 +85,18 @@ struct v4l2_dev_info { > /* buffer when doing conversion and using read() for read() */ > int readbuf_size; > unsigned char *readbuf; > + struct libv4l2_dev_ops *dev_ops; > + /* plugin info */ > + void *plugin_library; > + void *dev_ops_priv; > }; > > +void v4l2_plugin_init(int fd, void **plugin_lib_ret, void **plugin_priv_ret, > + struct libv4l2_dev_ops **dev_ops_ret); > +void v4l2_plugin_cleanup(void *plugin_priv, void *plugin_lib, > + struct libv4l2_dev_ops *dev_ops); > + > + > /* From log.c */ > void v4l2_log_ioctl(unsigned long int request, void *arg, int result); > > diff --git a/lib/libv4l2/libv4l2.c b/lib/libv4l2/libv4l2.c > index ab85ea7..018350e 100644 > --- a/lib/libv4l2/libv4l2.c > +++ b/lib/libv4l2/libv4l2.c > @@ -67,6 +67,7 @@ > #include<sys/stat.h> > #include "libv4l2.h" > #include "libv4l2-priv.h" > +#include "libv4l2-plugin.h" > > /* 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 > @@ -102,7 +103,8 @@ static int v4l2_request_read_buffers(int index) > devices[index].nreadbuffers; > req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; > req.memory = V4L2_MEMORY_MMAP; > - result = SYS_IOCTL(devices[index].fd, VIDIOC_REQBUFS,&req); > + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + devices[index].fd, VIDIOC_REQBUFS,&req); > if (result< 0) { > int saved_err = errno; > > @@ -131,7 +133,8 @@ static void v4l2_unrequest_read_buffers(int index) > req.count = 0; > req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; > req.memory = V4L2_MEMORY_MMAP; > - if (SYS_IOCTL(devices[index].fd, VIDIOC_REQBUFS,&req)< 0) > + if (devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + devices[index].fd, VIDIOC_REQBUFS,&req)< 0) > return; > > devices[index].no_frames = MIN(req.count, V4L2_MAX_NO_FRAMES); > @@ -152,7 +155,8 @@ static int v4l2_map_buffers(int index) > buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; > buf.memory = V4L2_MEMORY_MMAP; > buf.index = i; > - result = SYS_IOCTL(devices[index].fd, VIDIOC_QUERYBUF,&buf); > + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + devices[index].fd, VIDIOC_QUERYBUF,&buf); > if (result) { > int saved_err = errno; > > @@ -202,7 +206,8 @@ static int v4l2_streamon(int index) > enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; > > if (!(devices[index].flags& V4L2_STREAMON)) { > - result = SYS_IOCTL(devices[index].fd, VIDIOC_STREAMON,&type); > + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + devices[index].fd, VIDIOC_STREAMON,&type); > if (result) { > int saved_err = errno; > > @@ -223,7 +228,8 @@ static int v4l2_streamoff(int index) > enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; > > if (devices[index].flags& V4L2_STREAMON) { > - result = SYS_IOCTL(devices[index].fd, VIDIOC_STREAMOFF,&type); > + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + devices[index].fd, VIDIOC_STREAMOFF,&type); > if (result) { > int saved_err = errno; > > @@ -252,7 +258,8 @@ static int v4l2_queue_read_buffer(int index, int buffer_index) > buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; > buf.memory = V4L2_MEMORY_MMAP; > buf.index = buffer_index; > - result = SYS_IOCTL(devices[index].fd, VIDIOC_QBUF,&buf); > + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + devices[index].fd, VIDIOC_QBUF,&buf); > if (result) { > int saved_err = errno; > > @@ -277,7 +284,8 @@ static int v4l2_dequeue_and_convert(int index, struct v4l2_buffer *buf, > return result; > > do { > - result = SYS_IOCTL(devices[index].fd, VIDIOC_DQBUF, buf); > + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + devices[index].fd, VIDIOC_DQBUF, buf); > if (result) { > if (errno != EAGAIN) { > int saved_err = errno; > @@ -356,7 +364,8 @@ static int v4l2_read_and_convert(int index, unsigned char *dest, int dest_size) > } > > do { > - result = SYS_READ(devices[index].fd, devices[index].readbuf, buf_size); > + result = devices[index].dev_ops->read(devices[index].dev_ops_priv, > + devices[index].fd, devices[index].readbuf, buf_size); > if (result<= 0) { > if (result&& errno != EAGAIN) { > int saved_err = errno; > @@ -496,7 +505,8 @@ static int v4l2_buffers_mapped(int index) > buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; > buf.memory = V4L2_MEMORY_MMAP; > buf.index = i; > - if (SYS_IOCTL(devices[index].fd, VIDIOC_QUERYBUF,&buf)) { > + if (devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + devices[index].fd, VIDIOC_QUERYBUF,&buf)) { > int saved_err = errno; > > V4L2_LOG_ERR("querying buffer %u: %s\n", i, strerror(errno)); > @@ -561,6 +571,11 @@ int v4l2_fd_open(int fd, int v4l2_flags) > struct v4l2_capability cap; > struct v4l2_format fmt; > struct v4lconvert_data *convert; > + struct libv4l2_dev_ops *dev_ops; > + void *plugin_library; > + void *plugin_data; > + > + v4l2_plugin_init(fd,&plugin_library,&plugin_data,&dev_ops); > > /* If no log file was set by the app, see if one was specified through the > environment */ > @@ -571,9 +586,10 @@ int v4l2_fd_open(int fd, int v4l2_flags) > } > > /* check that this is an v4l2 device */ > - if (SYS_IOCTL(fd, VIDIOC_QUERYCAP,&cap)) { > + if (dev_ops->ioctl(plugin_data, fd, VIDIOC_QUERYCAP,&cap)) { > int saved_err = errno; > > + v4l2_plugin_cleanup(plugin_data, plugin_library, dev_ops); > V4L2_LOG_ERR("getting capabilities: %s\n", strerror(errno)); > errno = saved_err; > return -1; > @@ -581,29 +597,38 @@ int v4l2_fd_open(int fd, int v4l2_flags) > > /* we only add functionality for video capture devices */ > if (!(cap.capabilities& V4L2_CAP_VIDEO_CAPTURE) || > - !(cap.capabilities& (V4L2_CAP_STREAMING | V4L2_CAP_READWRITE))) > + !(cap.capabilities& (V4L2_CAP_STREAMING | V4L2_CAP_READWRITE))) { > + v4l2_plugin_cleanup(plugin_data, plugin_library, dev_ops); > return fd; > + } > > /* Get current cam format */ > fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; > - if (SYS_IOCTL(fd, VIDIOC_G_FMT,&fmt)) { > + if (dev_ops->ioctl(plugin_data, fd, VIDIOC_G_FMT,&fmt)) { > int saved_err = errno; > > + v4l2_plugin_cleanup(plugin_data, plugin_library, dev_ops); > V4L2_LOG_ERR("getting pixformat: %s\n", strerror(errno)); > errno = saved_err; > return -1; > } > > /* init libv4lconvert */ > - convert = v4lconvert_create(fd); > - if (!convert) > + convert = v4lconvert_create(fd, plugin_data, dev_ops); > + if (!convert) { > + v4l2_plugin_cleanup(plugin_data, plugin_library, dev_ops); > return -1; > + } > > /* So we have a v4l2 capture device, register it in our devices array */ > pthread_mutex_lock(&v4l2_open_mutex); > for (index = 0; index< V4L2_MAX_DEVICES; index++) > if (devices[index].fd == -1) { > devices[index].fd = fd; > + > + devices[index].plugin_library = plugin_library; > + devices[index].dev_ops_priv = plugin_data; > + devices[index].dev_ops = dev_ops; > break; > } > pthread_mutex_unlock(&v4l2_open_mutex); > @@ -611,6 +636,7 @@ int v4l2_fd_open(int fd, int v4l2_flags) > if (index == V4L2_MAX_DEVICES) { > V4L2_LOG_ERR("attempting to open more then %d video devices\n", > V4L2_MAX_DEVICES); > + v4l2_plugin_cleanup(plugin_data, plugin_library, dev_ops); > errno = EBUSY; > return -1; > } > @@ -700,6 +726,9 @@ int v4l2_close(int fd) > if (result) > return 0; > > + v4l2_plugin_cleanup(devices[index].dev_ops_priv, > + devices[index].plugin_library, devices[index].dev_ops); > + > /* Free resources */ > v4l2_unmap_buffers(index); > if (devices[index].convert_mmap_buf != MAP_FAILED) { > @@ -879,7 +908,8 @@ int v4l2_ioctl(int fd, unsigned long int request, ...) > } > > if (!is_capture_request) { > - result = SYS_IOCTL(fd, request, arg); > + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + fd, request, arg); > saved_err = errno; > v4l2_log_ioctl(request, arg, result); > errno = saved_err; > @@ -927,7 +957,8 @@ int v4l2_ioctl(int fd, unsigned long int request, ...) > case VIDIOC_QUERYCAP: { > struct v4l2_capability *cap = arg; > > - result = SYS_IOCTL(devices[index].fd, VIDIOC_QUERYCAP, cap); > + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + 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; > @@ -977,8 +1008,8 @@ int v4l2_ioctl(int fd, unsigned long int request, ...) > } > > if (devices[index].flags& V4L2_DISABLE_CONVERSION) { > - result = SYS_IOCTL(devices[index].fd, VIDIOC_TRY_FMT, > - dest_fmt); > + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + devices[index].fd, VIDIOC_TRY_FMT, dest_fmt); > src_fmt = *dest_fmt; > } else { > result = v4lconvert_try_format(devices[index].convert, dest_fmt, > @@ -1018,7 +1049,8 @@ int v4l2_ioctl(int fd, unsigned long int request, ...) > break; > > req_pix_fmt = src_fmt.fmt.pix; > - result = SYS_IOCTL(devices[index].fd, VIDIOC_S_FMT,&src_fmt); > + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + devices[index].fd, VIDIOC_S_FMT,&src_fmt); > if (result) { > saved_err = errno; > V4L2_LOG_ERR("setting pixformat: %s\n", strerror(errno)); > @@ -1067,7 +1099,8 @@ int v4l2_ioctl(int fd, unsigned long int request, ...) > if (req->count> V4L2_MAX_NO_FRAMES) > req->count = V4L2_MAX_NO_FRAMES; > > - result = SYS_IOCTL(devices[index].fd, VIDIOC_REQBUFS, req); > + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + devices[index].fd, VIDIOC_REQBUFS, req); > if (result< 0) > break; > result = 0; /* some drivers return the number of buffers on success */ > @@ -1088,7 +1121,8 @@ int v4l2_ioctl(int fd, unsigned long int request, ...) > > /* Do a real query even when converting to let the driver fill in > things like buf->field */ > - result = SYS_IOCTL(devices[index].fd, VIDIOC_QUERYBUF, buf); > + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + devices[index].fd, VIDIOC_QUERYBUF, buf); > if (result || !v4l2_needs_conversion(index)) > break; > > @@ -1115,7 +1149,8 @@ int v4l2_ioctl(int fd, unsigned long int request, ...) > break; > } > > - result = SYS_IOCTL(devices[index].fd, VIDIOC_QBUF, arg); > + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + devices[index].fd, VIDIOC_QBUF, arg); > break; > > case VIDIOC_DQBUF: { > @@ -1128,7 +1163,8 @@ int v4l2_ioctl(int fd, unsigned long int request, ...) > } > > if (!v4l2_needs_conversion(index)) { > - result = SYS_IOCTL(devices[index].fd, VIDIOC_DQBUF, buf); > + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + devices[index].fd, VIDIOC_DQBUF, buf); > if (result) { > int saved_err = errno; > > @@ -1187,7 +1223,8 @@ int v4l2_ioctl(int fd, unsigned long int request, ...) > break; > > default: > - result = SYS_IOCTL(fd, request, arg); > + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, > + fd, request, arg); > break; > } > > @@ -1217,7 +1254,8 @@ ssize_t v4l2_read(int fd, void *dest, size_t n) > it */ > if ((devices[index].flags& V4L2_SUPPORTS_READ)&& > !v4l2_needs_conversion(index)) { > - result = SYS_READ(fd, dest, n); > + result = devices[index].dev_ops->read(devices[index].dev_ops_priv, > + fd, dest, n); > goto leave; > } > > diff --git a/lib/libv4l2/v4l2-plugin.c b/lib/libv4l2/v4l2-plugin.c > new file mode 100644 > index 0000000..3735193 > --- /dev/null > +++ b/lib/libv4l2/v4l2-plugin.c > @@ -0,0 +1,158 @@ > +/* > +* Copyright (C) 2010 Nokia Corporation<multimedia@maemo.org> > + > +* This program is free software; you can redistribute it and/or modify > +* it under the terms of the GNU Lesser General Public License as published by > +* the Free Software Foundation; either version 2.1 of the License, or > +* (at your option) any later version. > +* > +* 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 > +* 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 > +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > +*/ > + > +#include<stdarg.h> > +#include<dlfcn.h> > +#include<fcntl.h> > +#include<glob.h> > +#include<sys/stat.h> > +#include<sys/mman.h> > +#include "libv4l2.h" > +#include "libv4l2-priv.h" > +#include "libv4l2-plugin.h" > + > +/* libv4l plugin support: > + it is provided by functions v4l2_plugin_[open,close,etc]. > + > + When open() is called libv4l dlopens files in /usr/lib[64]/libv4l/plugins > + 1 at a time and call open callback passing through the applications > + parameters unmodified. > + > + If a plugin is relevant for the specified device node, it can indicate so > + by returning a value other then -1 (the actual file descriptor). > + As soon as a plugin returns another value then -1 plugin loading stops and > + information about it (fd and corresponding library handle) is stored. For > + each function v4l2_[ioctl,read,close,etc] is called corresponding > + v4l2_plugin_* function which looks if there is loaded plugin for that file > + and call it's callbacks. > + > + v4l2_plugin_* function indicates by it's first argument if plugin was used, > + and if it was not then v4l2_* functions proceed with their usual behavior. > +*/ > + > +#define PLUGINS_PATTERN "/usr/lib/libv4l/plugins/*.so" > + > +static void * dev_init(int fd) > +{ > + return NULL; > +} > + > +static void dev_close(void *dev_ops_priv) > +{ > +} > + > +static int dev_ioctl(void *dev_ops_priv, int fd, unsigned long cmd, void *arg) > +{ > + return SYS_IOCTL(fd, cmd, arg); > +} > + > +static ssize_t dev_read(void *dev_ops_priv, int fd, void *buf, size_t len) > +{ > + return SYS_READ(fd, buf, len); > +} > + > + > +struct libv4l2_dev_ops default_operations = { > + .init =&dev_init, > + .close =&dev_close, > + .ioctl =&dev_ioctl, > + .read =&dev_read > +}; > + > +void v4l2_plugin_init(int fd, void **plugin_lib_ret, void **plugin_priv_ret, > + struct libv4l2_dev_ops **dev_ops_ret) > +{ > + char *error; > + int glob_ret, plugin_num; > + void *plugin_library = NULL; > + struct libv4l2_dev_ops *libv4l2_plugin = NULL; > + glob_t globbuf; > + > + *dev_ops_ret =&default_operations; > + > + glob_ret = glob(PLUGINS_PATTERN, 0, NULL,&globbuf); > + > + if (glob_ret == GLOB_NOSPACE) { > + *plugin_lib_ret = NULL; > + *plugin_priv_ret = NULL; > + return; > + } > + > + if (glob_ret == GLOB_ABORTED || glob_ret == GLOB_NOMATCH) { > + *plugin_lib_ret = NULL; > + *plugin_priv_ret = NULL; > + goto leave; > + } > + > + for (plugin_num = 0; plugin_num< globbuf.gl_pathc; plugin_num++) { > + > + V4L2_LOG("PLUGIN: dlopen(%s);\n", globbuf.gl_pathv[plugin_num]); > + > + plugin_library = dlopen(globbuf.gl_pathv[plugin_num], > + RTLD_LAZY); > + > + if (!plugin_library) > + continue; > + > + dlerror(); /* Clear any existing error */ > + libv4l2_plugin = (struct libv4l2_dev_ops *) > + dlsym(plugin_library, "libv4l2_plugin"); > + > + error = dlerror(); > + if (error != NULL) { > + V4L2_LOG_ERR("PLUGIN: dlsym failed: %s\n", error); > + dlclose(plugin_library); > + > + continue; > + } > + > + *plugin_priv_ret = NULL; > + if (libv4l2_plugin->init) > + *plugin_priv_ret = libv4l2_plugin->init(fd); > + > + if (!*plugin_priv_ret) { > + V4L2_LOG("PLUGIN: plugin open() returned NULL\n"); > + dlclose(plugin_library); > + *plugin_lib_ret = NULL; > + continue; > + } > + > + (*dev_ops_ret)->init = libv4l2_plugin->init; > + if (libv4l2_plugin->close != NULL) > + (*dev_ops_ret)->close = libv4l2_plugin->close; > + if (libv4l2_plugin->ioctl != NULL) > + (*dev_ops_ret)->ioctl = libv4l2_plugin->ioctl; > + if (libv4l2_plugin->read != NULL) > + (*dev_ops_ret)->read = libv4l2_plugin->read; > + > + break; > + > + } > + > +leave: > + globfree(&globbuf); > +} > + > +void v4l2_plugin_cleanup(void *plugin_priv, void *plugin_lib, > + struct libv4l2_dev_ops *dev_ops) > +{ > + if (plugin_priv) { > + dev_ops->close(plugin_priv); > + dlclose(plugin_lib); > + } > +} > diff --git a/lib/libv4l2/v4l2convert.c b/lib/libv4l2/v4l2convert.c > index e251085..03f34ad 100644 > --- a/lib/libv4l2/v4l2convert.c > +++ b/lib/libv4l2/v4l2convert.c > @@ -46,7 +46,6 @@ > LIBV4L_PUBLIC int open(const char *file, int oflag, ...) > { > int fd; > - struct v4l2_capability cap; > int v4l_device = 0; > > /* check if we're opening a video4linux2 device */ > @@ -76,14 +75,6 @@ LIBV4L_PUBLIC int open(const char *file, int oflag, ...) > if (fd == -1 || !v4l_device) > return fd; > > - /* check that this is an v4l2 device, libv4l2 only supports v4l2 devices */ > - if (SYS_IOCTL(fd, VIDIOC_QUERYCAP,&cap)) > - return fd; > - > - /* libv4l2 only adds functionality to capture capable devices */ > - if (!(cap.capabilities& V4L2_CAP_VIDEO_CAPTURE)) > - return fd; > - > /* Try to Register with libv4l2 (in case of failure pass the fd to the > application as is) */ > v4l2_fd_open(fd, 0); > diff --git a/lib/libv4lconvert/control/libv4lcontrol-priv.h b/lib/libv4lconvert/control/libv4lcontrol-priv.h > index 22cdf34..1259e6b 100644 > --- a/lib/libv4lconvert/control/libv4lcontrol-priv.h > +++ b/lib/libv4lconvert/control/libv4lcontrol-priv.h > @@ -22,6 +22,8 @@ > #ifndef __LIBV4LCONTROL_PRIV_H > #define __LIBV4LCONTROL_PRIV_H > > +#include "libv4l2-plugin.h" > + > #define V4LCONTROL_SHM_SIZE 4096 > > #define V4LCONTROL_SUPPORTS_NEXT_CTRL 0x01 > @@ -37,6 +39,8 @@ struct v4lcontrol_data { > unsigned int *shm_values; /* shared memory control value store */ > unsigned int old_values[V4LCONTROL_COUNT]; /* for controls_changed() */ > const struct v4lcontrol_flags_info *flags_info; > + struct libv4l2_dev_ops *dev_ops; > + void *dev_ops_priv; > }; > > struct v4lcontrol_flags_info { > diff --git a/lib/libv4lconvert/control/libv4lcontrol.c b/lib/libv4lconvert/control/libv4lcontrol.c > index 116bef5..24a5600 100644 > --- a/lib/libv4lconvert/control/libv4lcontrol.c > +++ b/lib/libv4lconvert/control/libv4lcontrol.c > @@ -747,7 +747,8 @@ static void v4lcontrol_get_flags_from_db(struct v4lcontrol_data *data, > } > } > > -struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) > +struct v4lcontrol_data *v4lcontrol_create(int fd, void *dev_ops_priv, > + struct libv4l2_dev_ops *dev_ops, int always_needs_conversion) > { > int shm_fd; > int i, rc, got_usb_ids, init = 0; > @@ -767,10 +768,12 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) > } > > data->fd = fd; > + data->dev_ops = dev_ops; > + data->dev_ops_priv = dev_ops_priv; > > /* Check if the driver has indicated some form of flipping is needed */ > - if ((SYS_IOCTL(data->fd, VIDIOC_G_INPUT,&input.index) == 0)&& > - (SYS_IOCTL(data->fd, VIDIOC_ENUMINPUT,&input) == 0)) { > + if ((data->dev_ops->ioctl(data->dev_ops_priv, data->fd, VIDIOC_G_INPUT,&input.index) == 0)&& > + (data->dev_ops->ioctl(data->dev_ops_priv, data->fd, VIDIOC_ENUMINPUT,&input) == 0)) { > if (input.status& V4L2_IN_ST_HFLIP) > data->flags |= V4LCONTROL_HFLIPPED; > if (input.status& V4L2_IN_ST_VFLIP) > @@ -787,7 +790,8 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) > data->flags = strtol(s, NULL, 0); > > ctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL; > - if (SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL,&ctrl) == 0) > + if (data->dev_ops->ioctl(data->dev_ops_priv, data->fd, > + VIDIOC_QUERYCTRL,&ctrl) == 0) > data->priv_flags |= V4LCONTROL_SUPPORTS_NEXT_CTRL; > > /* If the device always needs conversion, we can add fake controls at no cost > @@ -795,7 +799,8 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) > if (always_needs_conversion || v4lcontrol_needs_conversion(data)) { > for (i = 0; i< V4LCONTROL_AUTO_ENABLE_COUNT; i++) { > ctrl.id = fake_controls[i].id; > - rc = SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL,&ctrl); > + rc = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, > + VIDIOC_QUERYCTRL,&ctrl); > if (rc == -1 || (rc == 0&& (ctrl.flags& V4L2_CTRL_FLAG_DISABLED))) > data->controls |= 1<< i; > } > @@ -807,17 +812,20 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) > different sensors with / without autogain or the necessary controls. */ > while (data->flags& V4LCONTROL_WANTS_AUTOGAIN) { > ctrl.id = V4L2_CID_AUTOGAIN; > - rc = SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL,&ctrl); > + rc = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, > + VIDIOC_QUERYCTRL,&ctrl); > if (rc == 0&& !(ctrl.flags& V4L2_CTRL_FLAG_DISABLED)) > break; > > ctrl.id = V4L2_CID_EXPOSURE; > - rc = SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL,&ctrl); > + rc = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, > + VIDIOC_QUERYCTRL,&ctrl); > if (rc != 0 || (ctrl.flags& V4L2_CTRL_FLAG_DISABLED)) > break; > > ctrl.id = V4L2_CID_GAIN; > - rc = SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL,&ctrl); > + rc = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, > + VIDIOC_QUERYCTRL,&ctrl); > if (rc != 0 || (ctrl.flags& V4L2_CTRL_FLAG_DISABLED)) > break; > > @@ -834,7 +842,7 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) > if (data->controls == 0) > return data; /* No need to create a shared memory segment */ > > - if (SYS_IOCTL(fd, VIDIOC_QUERYCAP,&cap)) { > + if (data->dev_ops->ioctl(data->dev_ops_priv, fd, VIDIOC_QUERYCAP,&cap)) { > perror("libv4lcontrol: error querying device capabilities"); > goto error; > } > @@ -1020,7 +1028,8 @@ int v4lcontrol_vidioc_queryctrl(struct v4lcontrol_data *data, void *arg) > } > > /* find out what the kernel driver would respond. */ > - retval = SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL, arg); > + retval = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, > + VIDIOC_QUERYCTRL, arg); > > if ((data->priv_flags& V4LCONTROL_SUPPORTS_NEXT_CTRL)&& > (orig_id& V4L2_CTRL_FLAG_NEXT_CTRL)) { > @@ -1057,7 +1066,8 @@ int v4lcontrol_vidioc_g_ctrl(struct v4lcontrol_data *data, void *arg) > return 0; > } > > - return SYS_IOCTL(data->fd, VIDIOC_G_CTRL, arg); > + return data->dev_ops->ioctl(data->dev_ops_priv, data->fd, > + VIDIOC_G_CTRL, arg); > } > > int v4lcontrol_vidioc_s_ctrl(struct v4lcontrol_data *data, void *arg) > @@ -1078,7 +1088,8 @@ int v4lcontrol_vidioc_s_ctrl(struct v4lcontrol_data *data, void *arg) > return 0; > } > > - return SYS_IOCTL(data->fd, VIDIOC_S_CTRL, arg); > + return data->dev_ops->ioctl(data->dev_ops_priv, data->fd, > + VIDIOC_S_CTRL, arg); > } > > int v4lcontrol_get_flags(struct v4lcontrol_data *data) > diff --git a/lib/libv4lconvert/control/libv4lcontrol.h b/lib/libv4lconvert/control/libv4lcontrol.h > index 974e97a..1c09546 100644 > --- a/lib/libv4lconvert/control/libv4lcontrol.h > +++ b/lib/libv4lconvert/control/libv4lcontrol.h > @@ -22,6 +22,8 @@ > #ifndef __LIBV4LCONTROL_H > #define __LIBV4LCONTROL_H > > +#include "libv4l2-plugin.h" > + > /* Flags */ > #define V4LCONTROL_HFLIPPED 0x01 > #define V4LCONTROL_VFLIPPED 0x02 > @@ -47,7 +49,8 @@ enum { > > struct v4lcontrol_data; > > -struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion); > +struct v4lcontrol_data *v4lcontrol_create(int fd, void *dev_ops_priv, > + struct libv4l2_dev_ops *dev_ops, int always_needs_conversion); > void v4lcontrol_destroy(struct v4lcontrol_data *data); > > /* Functions used by v4lprocessing to get the control state */ > diff --git a/lib/libv4lconvert/libv4lconvert-priv.h b/lib/libv4lconvert/libv4lconvert-priv.h > index 84c706e..9cb6e1c 100644 > --- a/lib/libv4lconvert/libv4lconvert-priv.h > +++ b/lib/libv4lconvert/libv4lconvert-priv.h > @@ -65,6 +65,8 @@ struct v4lconvert_data { > unsigned char *convert_pixfmt_buf; > struct v4lcontrol_data *control; > struct v4lprocessing_data *processing; > + struct libv4l2_dev_ops *dev_ops; > + void *dev_ops_priv; > > /* Data for external decompression helpers code */ > pid_t decompress_pid; > diff --git a/lib/libv4lconvert/libv4lconvert.c b/lib/libv4lconvert/libv4lconvert.c > index e4863fd..6861986 100644 > --- a/lib/libv4lconvert/libv4lconvert.c > +++ b/lib/libv4lconvert/libv4lconvert.c > @@ -92,7 +92,8 @@ static const int v4lconvert_crop_res[][2] = { > { 176, 144 }, > }; > > -struct v4lconvert_data *v4lconvert_create(int fd) > +struct v4lconvert_data *v4lconvert_create(int fd, void *dev_ops_priv, > + struct libv4l2_dev_ops *dev_ops) > { > int i, j; > struct v4lconvert_data *data = calloc(1, sizeof(struct v4lconvert_data)); > @@ -108,6 +109,8 @@ struct v4lconvert_data *v4lconvert_create(int fd) > } > > data->fd = fd; > + data->dev_ops = dev_ops; > + data->dev_ops_priv = dev_ops_priv; > data->decompress_pid = -1; > > /* Check supported formats */ > @@ -116,7 +119,7 @@ struct v4lconvert_data *v4lconvert_create(int fd) > > fmt.index = i; > > - if (SYS_IOCTL(data->fd, VIDIOC_ENUM_FMT,&fmt)) > + if (data->dev_ops->ioctl(data->dev_ops_priv, data->fd, VIDIOC_ENUM_FMT,&fmt)) > break; > > for (j = 0; j< ARRAY_SIZE(supported_src_pixfmts); j++) > @@ -135,7 +138,8 @@ struct v4lconvert_data *v4lconvert_create(int fd) > data->no_formats = i; > > /* Check if this cam has any special flags */ > - if (SYS_IOCTL(data->fd, VIDIOC_QUERYCAP,&cap) == 0) { > + if (data->dev_ops->ioctl(data->dev_ops_priv, > + data->fd, VIDIOC_QUERYCAP,&cap) == 0) { > if (!strcmp((char *)cap.driver, "uvcvideo")) > data->flags |= V4LCONVERT_IS_UVC; > > @@ -143,7 +147,8 @@ struct v4lconvert_data *v4lconvert_create(int fd) > always_needs_conversion = 0; > } > > - data->control = v4lcontrol_create(fd, always_needs_conversion); > + data->control = v4lcontrol_create(fd, dev_ops_priv, dev_ops, > + always_needs_conversion); > if (!data->control) { > free(data); > return NULL; > @@ -206,7 +211,8 @@ int v4lconvert_enum_fmt(struct v4lconvert_data *data, struct v4l2_fmtdesc *fmt) > if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || > (!v4lconvert_supported_dst_fmt_only(data)&& > fmt->index< data->no_formats)) > - return SYS_IOCTL(data->fd, VIDIOC_ENUM_FMT, fmt); > + return data->dev_ops->ioctl(data->dev_ops_priv, data->fd, > + VIDIOC_ENUM_FMT, fmt); > > for (i = 0; i< ARRAY_SIZE(supported_dst_pixfmts); i++) > if (v4lconvert_supported_dst_fmt_only(data) || > @@ -314,7 +320,8 @@ static int v4lconvert_do_try_format(struct v4lconvert_data *data, > try_fmt = *dest_fmt; > try_fmt.fmt.pix.pixelformat = supported_src_pixfmts[i].fmt; > > - if (!SYS_IOCTL(data->fd, VIDIOC_TRY_FMT,&try_fmt)) { > + if (!data->dev_ops->ioctl(data->dev_ops_priv, data->fd, > + VIDIOC_TRY_FMT,&try_fmt)) { > if (try_fmt.fmt.pix.pixelformat == supported_src_pixfmts[i].fmt) { > int size_x_diff = abs((int)try_fmt.fmt.pix.width - > (int)dest_fmt->fmt.pix.width); > @@ -382,7 +389,8 @@ int v4lconvert_try_format(struct v4lconvert_data *data, > if (!v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat) || > dest_fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || > v4lconvert_do_try_format(data,&try_dest,&try_src)) { > - result = SYS_IOCTL(data->fd, VIDIOC_TRY_FMT, dest_fmt); > + result = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, > + VIDIOC_TRY_FMT, dest_fmt); > if (src_fmt) > *src_fmt = *dest_fmt; > return result; > @@ -1241,7 +1249,8 @@ static void v4lconvert_get_framesizes(struct v4lconvert_data *data, > > for (i = 0; ; i++) { > frmsize.index = i; > - if (SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMESIZES,&frmsize)) > + if (data->dev_ops->ioctl(data->dev_ops_priv, data->fd, > + VIDIOC_ENUM_FRAMESIZES,&frmsize)) > break; > > /* We got a framesize, check we don't have the same one already */ > @@ -1301,7 +1310,8 @@ int v4lconvert_enum_framesizes(struct v4lconvert_data *data, > errno = EINVAL; > return -1; > } > - return SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMESIZES, frmsize); > + return data->dev_ops->ioctl(data->dev_ops_priv, data->fd, > + VIDIOC_ENUM_FRAMESIZES, frmsize); > } > > if (frmsize->index>= data->no_framesizes) { > @@ -1337,7 +1347,8 @@ int v4lconvert_enum_frameintervals(struct v4lconvert_data *data, > errno = EINVAL; > return -1; > } > - res = SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival); > + res = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, > + VIDIOC_ENUM_FRAMEINTERVALS, frmival); > if (res) > V4LCONVERT_ERR("%s\n", strerror(errno)); > return res; > @@ -1382,7 +1393,8 @@ int v4lconvert_enum_frameintervals(struct v4lconvert_data *data, > frmival->pixel_format = src_fmt.fmt.pix.pixelformat; > frmival->width = src_fmt.fmt.pix.width; > frmival->height = src_fmt.fmt.pix.height; > - res = SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival); > + res = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, > + VIDIOC_ENUM_FRAMEINTERVALS, frmival); > if (res) { > int dest_pixfmt = dest_fmt.fmt.pix.pixelformat; > int src_pixfmt = src_fmt.fmt.pix.pixelformat; > diff --git a/utils/qv4l2/qv4l2.cpp b/utils/qv4l2/qv4l2.cpp > index 232a318..349d1ca 100644 > --- a/utils/qv4l2/qv4l2.cpp > +++ b/utils/qv4l2/qv4l2.cpp > @@ -47,6 +47,17 @@ > #include<sys/mman.h> > #include<errno.h> > #include<dirent.h> > +#include<syscall.h> > + > +int defIoctl(void *dev_ops_priv, int fd, unsigned long cmd, void *arg) > +{ > + return syscall(SYS_ioctl, (int)(fd), (unsigned long)(cmd), > + (void *)(arg)); > +} > +ssize_t defRead(void *dev_ops_priv, int fd, void *buf, size_t len) > +{ > + return syscall(SYS_read, (int)(fd), (void *)(buf), (size_t)(len)); > +} > > ApplicationWindow::ApplicationWindow() : > m_capture(NULL), > @@ -59,6 +70,10 @@ ApplicationWindow::ApplicationWindow() : > m_frameData = NULL; > m_nbuffers = 0; > m_buffers = NULL; > + m_defauldDevOps.init = NULL; > + m_defauldDevOps.close = NULL; > + m_defauldDevOps.ioctl =&defIoctl; > + m_defauldDevOps.read =&defRead; > > QAction *openAct = new QAction(QIcon(":/fileopen.png"), "&Open device", this); > openAct->setStatusTip("Open a v4l device, use libv4l2 wrapper if possible"); > @@ -144,7 +159,7 @@ void ApplicationWindow::setDevice(const QString&device, bool rawOpen) > } > m_tabs->show(); > m_tabs->setFocus(); > - m_convertData = v4lconvert_create(fd()); > + m_convertData = v4lconvert_create(fd(), NULL,&m_defauldDevOps); > m_capStartAct->setEnabled(fd()>= 0); > } > > diff --git a/utils/qv4l2/qv4l2.h b/utils/qv4l2/qv4l2.h > index 0a3e5ef..d847fe6 100644 > --- a/utils/qv4l2/qv4l2.h > +++ b/utils/qv4l2/qv4l2.h > @@ -91,6 +91,7 @@ private: > unsigned char *m_frameData; > unsigned m_nbuffers; > struct v4lconvert_data *m_convertData; > + struct libv4l2_dev_ops m_defauldDevOps; > CapMethod m_capMethod; > > private slots: -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Hans, Hans de Goede wrote: > Hi, > > Sorry it took so long, but I've just merged the plugin > support into v4l-utils git. I did make some minor mods / > bugfixes before merging, see the commit message in git. > > Regards, > > Hans > > p.s. > > I think we should expand the plugin support with support > for a output devices, iow add a write() dev_op. If you > guys agree I can easily do so myself, we should do this > asap before people start depending on the ABI > (although there is no ABI stability promise until I > release 0.10.x, see my message to the list wrt > the start of the 0.9.x cycle). > I think that it is a good point, you can add write() and reserved dev_ops. Thanks Yordan > While on the subject of keeping the plugin ABI, I suggest > that we add a number of extra dev_ops named reserved1 -- > reserved8 for future use and a comment that these should > all be set to NULL. Then we can easily add another op > on the future while keeping compatibility with older > plugins. > > > On 05/03/2011 05:26 PM, Yordan Kamenov wrote: >> A libv4l2 plugin will sit in between libv4l2 itself and the actual >> /dev/video device node a fd refers to. It will be called each time >> libv4l2 wants to do an operation (read/write/ioctl) on the actual >> /dev/video node in question. >> >> Signed-off-by: Yordan Kamenov<ykamenov@mm-sol.com> >> --- >> lib/include/libv4l2-plugin.h | 36 ++++++ >> lib/include/libv4lconvert.h | 5 +- >> lib/libv4l2/Makefile | 6 +- >> lib/libv4l2/libv4l2-priv.h | 10 ++ >> lib/libv4l2/libv4l2.c | 88 ++++++++++---- >> lib/libv4l2/v4l2-plugin.c | 158 >> ++++++++++++++++++++++++ >> lib/libv4l2/v4l2convert.c | 9 -- >> lib/libv4lconvert/control/libv4lcontrol-priv.h | 4 + >> lib/libv4lconvert/control/libv4lcontrol.c | 35 ++++-- >> lib/libv4lconvert/control/libv4lcontrol.h | 5 +- >> lib/libv4lconvert/libv4lconvert-priv.h | 2 + >> lib/libv4lconvert/libv4lconvert.c | 34 ++++-- >> utils/qv4l2/qv4l2.cpp | 17 +++- >> utils/qv4l2/qv4l2.h | 1 + >> 14 files changed, 347 insertions(+), 63 deletions(-) >> create mode 100644 lib/include/libv4l2-plugin.h >> create mode 100644 lib/libv4l2/v4l2-plugin.c >> >> diff --git a/lib/include/libv4l2-plugin.h b/lib/include/libv4l2-plugin.h >> new file mode 100644 >> index 0000000..158c0c2 >> --- /dev/null >> +++ b/lib/include/libv4l2-plugin.h >> @@ -0,0 +1,36 @@ >> +/* >> +* Copyright (C) 2010 Nokia Corporation<multimedia@maemo.org> >> + >> +* This program is free software; you can redistribute it and/or modify >> +* it under the terms of the GNU Lesser General Public License as >> published by >> +* the Free Software Foundation; either version 2.1 of the License, or >> +* (at your option) any later version. >> +* >> +* 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 >> +* 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 >> +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA >> 02111-1307 USA >> +*/ >> + >> +#ifndef __LIBV4L2_PLUGIN_H >> +#define __LIBV4L2_PLUGIN_H >> + >> +#include<sys/types.h> >> + >> +/* Structure libv4l2_dev_ops holds the calls from libv4ls to video >> nodes. >> + They can be normal open/close/ioctl etc. or any of them may be >> replaced >> + with a callback by a loaded plugin. >> +*/ >> + >> +struct libv4l2_dev_ops { >> + void * (*init)(int fd); >> + void (*close)(void *dev_ops_priv); >> + int (*ioctl)(void *dev_ops_priv, int fd, unsigned long int >> request, void *arg); >> + ssize_t (*read)(void *dev_ops_priv, int fd, void *buffer, size_t >> n); >> +}; >> + >> +#endif >> diff --git a/lib/include/libv4lconvert.h b/lib/include/libv4lconvert.h >> index 0264290..351142e 100644 >> --- a/lib/include/libv4lconvert.h >> +++ b/lib/include/libv4lconvert.h >> @@ -38,6 +38,8 @@ >> >> #include<linux/videodev2.h> >> >> +#include "libv4l2-plugin.h" >> + >> #ifdef __cplusplus >> extern "C" { >> #endif /* __cplusplus */ >> @@ -50,7 +52,8 @@ extern "C" { >> >> struct v4lconvert_data; >> >> -LIBV4L_PUBLIC struct v4lconvert_data *v4lconvert_create(int fd); >> +LIBV4L_PUBLIC struct v4lconvert_data *v4lconvert_create(int fd, >> + void *dev_ops_priv, struct libv4l2_dev_ops *dev_ops); >> LIBV4L_PUBLIC void v4lconvert_destroy(struct v4lconvert_data *data); >> >> /* When doing flipping / rotating / video-processing, only supported >> diff --git a/lib/libv4l2/Makefile b/lib/libv4l2/Makefile >> index d78632f..f8b3714 100644 >> --- a/lib/libv4l2/Makefile >> +++ b/lib/libv4l2/Makefile >> @@ -1,12 +1,12 @@ >> override CPPFLAGS += -I../include -fvisibility=hidden >> >> -LIBS_libv4l2 = -lpthread >> +LIBS_libv4l2 = -lpthread -ldl >> >> -V4L2_OBJS = libv4l2.o log.o >> +V4L2_OBJS = libv4l2.o v4l2-plugin.o log.o >> V4L2CONVERT = v4l2convert.so >> V4L2CONVERT_O = v4l2convert.o libv4l2.so >> TARGETS = $(V4L2_LIB) libv4l2.pc >> -INCLUDES = ../include/libv4l2.h >> +INCLUDES = ../include/libv4l2.h ../include/libv4l2-plugin.h >> >> ifeq ($(LINKTYPE),static) >> V4L2_LIB = libv4l2.a >> diff --git a/lib/libv4l2/libv4l2-priv.h b/lib/libv4l2/libv4l2-priv.h >> index 46d6103..d06a508 100644 >> --- a/lib/libv4l2/libv4l2-priv.h >> +++ b/lib/libv4l2/libv4l2-priv.h >> @@ -85,8 +85,18 @@ struct v4l2_dev_info { >> /* buffer when doing conversion and using read() for read() */ >> int readbuf_size; >> unsigned char *readbuf; >> + struct libv4l2_dev_ops *dev_ops; >> + /* plugin info */ >> + void *plugin_library; >> + void *dev_ops_priv; >> }; >> >> +void v4l2_plugin_init(int fd, void **plugin_lib_ret, void >> **plugin_priv_ret, >> + struct libv4l2_dev_ops **dev_ops_ret); >> +void v4l2_plugin_cleanup(void *plugin_priv, void *plugin_lib, >> + struct libv4l2_dev_ops *dev_ops); >> + >> + >> /* From log.c */ >> void v4l2_log_ioctl(unsigned long int request, void *arg, int result); >> >> diff --git a/lib/libv4l2/libv4l2.c b/lib/libv4l2/libv4l2.c >> index ab85ea7..018350e 100644 >> --- a/lib/libv4l2/libv4l2.c >> +++ b/lib/libv4l2/libv4l2.c >> @@ -67,6 +67,7 @@ >> #include<sys/stat.h> >> #include "libv4l2.h" >> #include "libv4l2-priv.h" >> +#include "libv4l2-plugin.h" >> >> /* 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 >> @@ -102,7 +103,8 @@ static int v4l2_request_read_buffers(int index) >> devices[index].nreadbuffers; >> req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; >> req.memory = V4L2_MEMORY_MMAP; >> - result = SYS_IOCTL(devices[index].fd, VIDIOC_REQBUFS,&req); >> + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, >> + devices[index].fd, VIDIOC_REQBUFS,&req); >> if (result< 0) { >> int saved_err = errno; >> >> @@ -131,7 +133,8 @@ static void v4l2_unrequest_read_buffers(int index) >> req.count = 0; >> req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; >> req.memory = V4L2_MEMORY_MMAP; >> - if (SYS_IOCTL(devices[index].fd, VIDIOC_REQBUFS,&req)< 0) >> + if (devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, >> + devices[index].fd, VIDIOC_REQBUFS,&req)< 0) >> return; >> >> devices[index].no_frames = MIN(req.count, V4L2_MAX_NO_FRAMES); >> @@ -152,7 +155,8 @@ static int v4l2_map_buffers(int index) >> buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; >> buf.memory = V4L2_MEMORY_MMAP; >> buf.index = i; >> - result = SYS_IOCTL(devices[index].fd, VIDIOC_QUERYBUF,&buf); >> + result = >> devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, >> + devices[index].fd, VIDIOC_QUERYBUF,&buf); >> if (result) { >> int saved_err = errno; >> >> @@ -202,7 +206,8 @@ static int v4l2_streamon(int index) >> enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; >> >> if (!(devices[index].flags& V4L2_STREAMON)) { >> - result = SYS_IOCTL(devices[index].fd, VIDIOC_STREAMON,&type); >> + result = >> devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, >> + devices[index].fd, VIDIOC_STREAMON,&type); >> if (result) { >> int saved_err = errno; >> >> @@ -223,7 +228,8 @@ static int v4l2_streamoff(int index) >> enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; >> >> if (devices[index].flags& V4L2_STREAMON) { >> - result = SYS_IOCTL(devices[index].fd, VIDIOC_STREAMOFF,&type); >> + result = >> devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, >> + devices[index].fd, VIDIOC_STREAMOFF,&type); >> if (result) { >> int saved_err = errno; >> >> @@ -252,7 +258,8 @@ static int v4l2_queue_read_buffer(int index, int >> buffer_index) >> buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; >> buf.memory = V4L2_MEMORY_MMAP; >> buf.index = buffer_index; >> - result = SYS_IOCTL(devices[index].fd, VIDIOC_QBUF,&buf); >> + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, >> + devices[index].fd, VIDIOC_QBUF,&buf); >> if (result) { >> int saved_err = errno; >> >> @@ -277,7 +284,8 @@ static int v4l2_dequeue_and_convert(int index, >> struct v4l2_buffer *buf, >> return result; >> >> do { >> - result = SYS_IOCTL(devices[index].fd, VIDIOC_DQBUF, buf); >> + result = >> devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, >> + devices[index].fd, VIDIOC_DQBUF, buf); >> if (result) { >> if (errno != EAGAIN) { >> int saved_err = errno; >> @@ -356,7 +364,8 @@ static int v4l2_read_and_convert(int index, >> unsigned char *dest, int dest_size) >> } >> >> do { >> - result = SYS_READ(devices[index].fd, devices[index].readbuf, >> buf_size); >> + result = >> devices[index].dev_ops->read(devices[index].dev_ops_priv, >> + devices[index].fd, devices[index].readbuf, buf_size); >> if (result<= 0) { >> if (result&& errno != EAGAIN) { >> int saved_err = errno; >> @@ -496,7 +505,8 @@ static int v4l2_buffers_mapped(int index) >> buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; >> buf.memory = V4L2_MEMORY_MMAP; >> buf.index = i; >> - if (SYS_IOCTL(devices[index].fd, VIDIOC_QUERYBUF,&buf)) { >> + if >> (devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, >> + devices[index].fd, VIDIOC_QUERYBUF,&buf)) { >> int saved_err = errno; >> >> V4L2_LOG_ERR("querying buffer %u: %s\n", i, >> strerror(errno)); >> @@ -561,6 +571,11 @@ int v4l2_fd_open(int fd, int v4l2_flags) >> struct v4l2_capability cap; >> struct v4l2_format fmt; >> struct v4lconvert_data *convert; >> + struct libv4l2_dev_ops *dev_ops; >> + void *plugin_library; >> + void *plugin_data; >> + >> + v4l2_plugin_init(fd,&plugin_library,&plugin_data,&dev_ops); >> >> /* If no log file was set by the app, see if one was specified >> through the >> environment */ >> @@ -571,9 +586,10 @@ int v4l2_fd_open(int fd, int v4l2_flags) >> } >> >> /* check that this is an v4l2 device */ >> - if (SYS_IOCTL(fd, VIDIOC_QUERYCAP,&cap)) { >> + if (dev_ops->ioctl(plugin_data, fd, VIDIOC_QUERYCAP,&cap)) { >> int saved_err = errno; >> >> + v4l2_plugin_cleanup(plugin_data, plugin_library, dev_ops); >> V4L2_LOG_ERR("getting capabilities: %s\n", strerror(errno)); >> errno = saved_err; >> return -1; >> @@ -581,29 +597,38 @@ int v4l2_fd_open(int fd, int v4l2_flags) >> >> /* we only add functionality for video capture devices */ >> if (!(cap.capabilities& V4L2_CAP_VIDEO_CAPTURE) || >> - !(cap.capabilities& (V4L2_CAP_STREAMING | >> V4L2_CAP_READWRITE))) >> + !(cap.capabilities& (V4L2_CAP_STREAMING | >> V4L2_CAP_READWRITE))) { >> + v4l2_plugin_cleanup(plugin_data, plugin_library, dev_ops); >> return fd; >> + } >> >> /* Get current cam format */ >> fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; >> - if (SYS_IOCTL(fd, VIDIOC_G_FMT,&fmt)) { >> + if (dev_ops->ioctl(plugin_data, fd, VIDIOC_G_FMT,&fmt)) { >> int saved_err = errno; >> >> + v4l2_plugin_cleanup(plugin_data, plugin_library, dev_ops); >> V4L2_LOG_ERR("getting pixformat: %s\n", strerror(errno)); >> errno = saved_err; >> return -1; >> } >> >> /* init libv4lconvert */ >> - convert = v4lconvert_create(fd); >> - if (!convert) >> + convert = v4lconvert_create(fd, plugin_data, dev_ops); >> + if (!convert) { >> + v4l2_plugin_cleanup(plugin_data, plugin_library, dev_ops); >> return -1; >> + } >> >> /* So we have a v4l2 capture device, register it in our devices >> array */ >> pthread_mutex_lock(&v4l2_open_mutex); >> for (index = 0; index< V4L2_MAX_DEVICES; index++) >> if (devices[index].fd == -1) { >> devices[index].fd = fd; >> + >> + devices[index].plugin_library = plugin_library; >> + devices[index].dev_ops_priv = plugin_data; >> + devices[index].dev_ops = dev_ops; >> break; >> } >> pthread_mutex_unlock(&v4l2_open_mutex); >> @@ -611,6 +636,7 @@ int v4l2_fd_open(int fd, int v4l2_flags) >> if (index == V4L2_MAX_DEVICES) { >> V4L2_LOG_ERR("attempting to open more then %d video >> devices\n", >> V4L2_MAX_DEVICES); >> + v4l2_plugin_cleanup(plugin_data, plugin_library, dev_ops); >> errno = EBUSY; >> return -1; >> } >> @@ -700,6 +726,9 @@ int v4l2_close(int fd) >> if (result) >> return 0; >> >> + v4l2_plugin_cleanup(devices[index].dev_ops_priv, >> + devices[index].plugin_library, devices[index].dev_ops); >> + >> /* Free resources */ >> v4l2_unmap_buffers(index); >> if (devices[index].convert_mmap_buf != MAP_FAILED) { >> @@ -879,7 +908,8 @@ int v4l2_ioctl(int fd, unsigned long int request, >> ...) >> } >> >> if (!is_capture_request) { >> - result = SYS_IOCTL(fd, request, arg); >> + result = >> devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, >> + fd, request, arg); >> saved_err = errno; >> v4l2_log_ioctl(request, arg, result); >> errno = saved_err; >> @@ -927,7 +957,8 @@ int v4l2_ioctl(int fd, unsigned long int request, >> ...) >> case VIDIOC_QUERYCAP: { >> struct v4l2_capability *cap = arg; >> >> - result = SYS_IOCTL(devices[index].fd, VIDIOC_QUERYCAP, cap); >> + result = >> devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, >> + 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; >> @@ -977,8 +1008,8 @@ int v4l2_ioctl(int fd, unsigned long int >> request, ...) >> } >> >> if (devices[index].flags& V4L2_DISABLE_CONVERSION) { >> - result = SYS_IOCTL(devices[index].fd, VIDIOC_TRY_FMT, >> - dest_fmt); >> + result = >> devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, >> + devices[index].fd, VIDIOC_TRY_FMT, dest_fmt); >> src_fmt = *dest_fmt; >> } else { >> result = v4lconvert_try_format(devices[index].convert, >> dest_fmt, >> @@ -1018,7 +1049,8 @@ int v4l2_ioctl(int fd, unsigned long int >> request, ...) >> break; >> >> req_pix_fmt = src_fmt.fmt.pix; >> - result = SYS_IOCTL(devices[index].fd, VIDIOC_S_FMT,&src_fmt); >> + result = >> devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, >> + devices[index].fd, VIDIOC_S_FMT,&src_fmt); >> if (result) { >> saved_err = errno; >> V4L2_LOG_ERR("setting pixformat: %s\n", strerror(errno)); >> @@ -1067,7 +1099,8 @@ int v4l2_ioctl(int fd, unsigned long int >> request, ...) >> if (req->count> V4L2_MAX_NO_FRAMES) >> req->count = V4L2_MAX_NO_FRAMES; >> >> - result = SYS_IOCTL(devices[index].fd, VIDIOC_REQBUFS, req); >> + result = >> devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, >> + devices[index].fd, VIDIOC_REQBUFS, req); >> if (result< 0) >> break; >> result = 0; /* some drivers return the number of buffers on >> success */ >> @@ -1088,7 +1121,8 @@ int v4l2_ioctl(int fd, unsigned long int >> request, ...) >> >> /* Do a real query even when converting to let the driver >> fill in >> things like buf->field */ >> - result = SYS_IOCTL(devices[index].fd, VIDIOC_QUERYBUF, buf); >> + result = >> devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, >> + devices[index].fd, VIDIOC_QUERYBUF, buf); >> if (result || !v4l2_needs_conversion(index)) >> break; >> >> @@ -1115,7 +1149,8 @@ int v4l2_ioctl(int fd, unsigned long int >> request, ...) >> break; >> } >> >> - result = SYS_IOCTL(devices[index].fd, VIDIOC_QBUF, arg); >> + result = >> devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, >> + devices[index].fd, VIDIOC_QBUF, arg); >> break; >> >> case VIDIOC_DQBUF: { >> @@ -1128,7 +1163,8 @@ int v4l2_ioctl(int fd, unsigned long int >> request, ...) >> } >> >> if (!v4l2_needs_conversion(index)) { >> - result = SYS_IOCTL(devices[index].fd, VIDIOC_DQBUF, buf); >> + result = >> devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, >> + devices[index].fd, VIDIOC_DQBUF, buf); >> if (result) { >> int saved_err = errno; >> >> @@ -1187,7 +1223,8 @@ int v4l2_ioctl(int fd, unsigned long int >> request, ...) >> break; >> >> default: >> - result = SYS_IOCTL(fd, request, arg); >> + result = >> devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, >> + fd, request, arg); >> break; >> } >> >> @@ -1217,7 +1254,8 @@ ssize_t v4l2_read(int fd, void *dest, size_t n) >> it */ >> if ((devices[index].flags& V4L2_SUPPORTS_READ)&& >> !v4l2_needs_conversion(index)) { >> - result = SYS_READ(fd, dest, n); >> + result = >> devices[index].dev_ops->read(devices[index].dev_ops_priv, >> + fd, dest, n); >> goto leave; >> } >> >> diff --git a/lib/libv4l2/v4l2-plugin.c b/lib/libv4l2/v4l2-plugin.c >> new file mode 100644 >> index 0000000..3735193 >> --- /dev/null >> +++ b/lib/libv4l2/v4l2-plugin.c >> @@ -0,0 +1,158 @@ >> +/* >> +* Copyright (C) 2010 Nokia Corporation<multimedia@maemo.org> >> + >> +* This program is free software; you can redistribute it and/or modify >> +* it under the terms of the GNU Lesser General Public License as >> published by >> +* the Free Software Foundation; either version 2.1 of the License, or >> +* (at your option) any later version. >> +* >> +* 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 >> +* 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 >> +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA >> 02111-1307 USA >> +*/ >> + >> +#include<stdarg.h> >> +#include<dlfcn.h> >> +#include<fcntl.h> >> +#include<glob.h> >> +#include<sys/stat.h> >> +#include<sys/mman.h> >> +#include "libv4l2.h" >> +#include "libv4l2-priv.h" >> +#include "libv4l2-plugin.h" >> + >> +/* libv4l plugin support: >> + it is provided by functions v4l2_plugin_[open,close,etc]. >> + >> + When open() is called libv4l dlopens files in >> /usr/lib[64]/libv4l/plugins >> + 1 at a time and call open callback passing through the applications >> + parameters unmodified. >> + >> + If a plugin is relevant for the specified device node, it can >> indicate so >> + by returning a value other then -1 (the actual file descriptor). >> + As soon as a plugin returns another value then -1 plugin loading >> stops and >> + information about it (fd and corresponding library handle) is >> stored. For >> + each function v4l2_[ioctl,read,close,etc] is called corresponding >> + v4l2_plugin_* function which looks if there is loaded plugin for >> that file >> + and call it's callbacks. >> + >> + v4l2_plugin_* function indicates by it's first argument if plugin >> was used, >> + and if it was not then v4l2_* functions proceed with their usual >> behavior. >> +*/ >> + >> +#define PLUGINS_PATTERN "/usr/lib/libv4l/plugins/*.so" >> + >> +static void * dev_init(int fd) >> +{ >> + return NULL; >> +} >> + >> +static void dev_close(void *dev_ops_priv) >> +{ >> +} >> + >> +static int dev_ioctl(void *dev_ops_priv, int fd, unsigned long cmd, >> void *arg) >> +{ >> + return SYS_IOCTL(fd, cmd, arg); >> +} >> + >> +static ssize_t dev_read(void *dev_ops_priv, int fd, void *buf, >> size_t len) >> +{ >> + return SYS_READ(fd, buf, len); >> +} >> + >> + >> +struct libv4l2_dev_ops default_operations = { >> + .init =&dev_init, >> + .close =&dev_close, >> + .ioctl =&dev_ioctl, >> + .read =&dev_read >> +}; >> + >> +void v4l2_plugin_init(int fd, void **plugin_lib_ret, void >> **plugin_priv_ret, >> + struct libv4l2_dev_ops **dev_ops_ret) >> +{ >> + char *error; >> + int glob_ret, plugin_num; >> + void *plugin_library = NULL; >> + struct libv4l2_dev_ops *libv4l2_plugin = NULL; >> + glob_t globbuf; >> + >> + *dev_ops_ret =&default_operations; >> + >> + glob_ret = glob(PLUGINS_PATTERN, 0, NULL,&globbuf); >> + >> + if (glob_ret == GLOB_NOSPACE) { >> + *plugin_lib_ret = NULL; >> + *plugin_priv_ret = NULL; >> + return; >> + } >> + >> + if (glob_ret == GLOB_ABORTED || glob_ret == GLOB_NOMATCH) { >> + *plugin_lib_ret = NULL; >> + *plugin_priv_ret = NULL; >> + goto leave; >> + } >> + >> + for (plugin_num = 0; plugin_num< globbuf.gl_pathc; plugin_num++) { >> + >> + V4L2_LOG("PLUGIN: dlopen(%s);\n", >> globbuf.gl_pathv[plugin_num]); >> + >> + plugin_library = dlopen(globbuf.gl_pathv[plugin_num], >> + RTLD_LAZY); >> + >> + if (!plugin_library) >> + continue; >> + >> + dlerror(); /* Clear any existing error */ >> + libv4l2_plugin = (struct libv4l2_dev_ops *) >> + dlsym(plugin_library, "libv4l2_plugin"); >> + >> + error = dlerror(); >> + if (error != NULL) { >> + V4L2_LOG_ERR("PLUGIN: dlsym failed: %s\n", error); >> + dlclose(plugin_library); >> + >> + continue; >> + } >> + >> + *plugin_priv_ret = NULL; >> + if (libv4l2_plugin->init) >> + *plugin_priv_ret = libv4l2_plugin->init(fd); >> + >> + if (!*plugin_priv_ret) { >> + V4L2_LOG("PLUGIN: plugin open() returned NULL\n"); >> + dlclose(plugin_library); >> + *plugin_lib_ret = NULL; >> + continue; >> + } >> + >> + (*dev_ops_ret)->init = libv4l2_plugin->init; >> + if (libv4l2_plugin->close != NULL) >> + (*dev_ops_ret)->close = libv4l2_plugin->close; >> + if (libv4l2_plugin->ioctl != NULL) >> + (*dev_ops_ret)->ioctl = libv4l2_plugin->ioctl; >> + if (libv4l2_plugin->read != NULL) >> + (*dev_ops_ret)->read = libv4l2_plugin->read; >> + >> + break; >> + >> + } >> + >> +leave: >> + globfree(&globbuf); >> +} >> + >> +void v4l2_plugin_cleanup(void *plugin_priv, void *plugin_lib, >> + struct libv4l2_dev_ops *dev_ops) >> +{ >> + if (plugin_priv) { >> + dev_ops->close(plugin_priv); >> + dlclose(plugin_lib); >> + } >> +} >> diff --git a/lib/libv4l2/v4l2convert.c b/lib/libv4l2/v4l2convert.c >> index e251085..03f34ad 100644 >> --- a/lib/libv4l2/v4l2convert.c >> +++ b/lib/libv4l2/v4l2convert.c >> @@ -46,7 +46,6 @@ >> LIBV4L_PUBLIC int open(const char *file, int oflag, ...) >> { >> int fd; >> - struct v4l2_capability cap; >> int v4l_device = 0; >> >> /* check if we're opening a video4linux2 device */ >> @@ -76,14 +75,6 @@ LIBV4L_PUBLIC int open(const char *file, int >> oflag, ...) >> if (fd == -1 || !v4l_device) >> return fd; >> >> - /* check that this is an v4l2 device, libv4l2 only supports v4l2 >> devices */ >> - if (SYS_IOCTL(fd, VIDIOC_QUERYCAP,&cap)) >> - return fd; >> - >> - /* libv4l2 only adds functionality to capture capable devices */ >> - if (!(cap.capabilities& V4L2_CAP_VIDEO_CAPTURE)) >> - return fd; >> - >> /* Try to Register with libv4l2 (in case of failure pass the fd >> to the >> application as is) */ >> v4l2_fd_open(fd, 0); >> diff --git a/lib/libv4lconvert/control/libv4lcontrol-priv.h >> b/lib/libv4lconvert/control/libv4lcontrol-priv.h >> index 22cdf34..1259e6b 100644 >> --- a/lib/libv4lconvert/control/libv4lcontrol-priv.h >> +++ b/lib/libv4lconvert/control/libv4lcontrol-priv.h >> @@ -22,6 +22,8 @@ >> #ifndef __LIBV4LCONTROL_PRIV_H >> #define __LIBV4LCONTROL_PRIV_H >> >> +#include "libv4l2-plugin.h" >> + >> #define V4LCONTROL_SHM_SIZE 4096 >> >> #define V4LCONTROL_SUPPORTS_NEXT_CTRL 0x01 >> @@ -37,6 +39,8 @@ struct v4lcontrol_data { >> unsigned int *shm_values; /* shared memory control value store */ >> unsigned int old_values[V4LCONTROL_COUNT]; /* for >> controls_changed() */ >> const struct v4lcontrol_flags_info *flags_info; >> + struct libv4l2_dev_ops *dev_ops; >> + void *dev_ops_priv; >> }; >> >> struct v4lcontrol_flags_info { >> diff --git a/lib/libv4lconvert/control/libv4lcontrol.c >> b/lib/libv4lconvert/control/libv4lcontrol.c >> index 116bef5..24a5600 100644 >> --- a/lib/libv4lconvert/control/libv4lcontrol.c >> +++ b/lib/libv4lconvert/control/libv4lcontrol.c >> @@ -747,7 +747,8 @@ static void v4lcontrol_get_flags_from_db(struct >> v4lcontrol_data *data, >> } >> } >> >> -struct v4lcontrol_data *v4lcontrol_create(int fd, int >> always_needs_conversion) >> +struct v4lcontrol_data *v4lcontrol_create(int fd, void *dev_ops_priv, >> + struct libv4l2_dev_ops *dev_ops, int always_needs_conversion) >> { >> int shm_fd; >> int i, rc, got_usb_ids, init = 0; >> @@ -767,10 +768,12 @@ struct v4lcontrol_data *v4lcontrol_create(int >> fd, int always_needs_conversion) >> } >> >> data->fd = fd; >> + data->dev_ops = dev_ops; >> + data->dev_ops_priv = dev_ops_priv; >> >> /* Check if the driver has indicated some form of flipping is >> needed */ >> - if ((SYS_IOCTL(data->fd, VIDIOC_G_INPUT,&input.index) == 0)&& >> - (SYS_IOCTL(data->fd, VIDIOC_ENUMINPUT,&input) == 0)) { >> + if ((data->dev_ops->ioctl(data->dev_ops_priv, data->fd, >> VIDIOC_G_INPUT,&input.index) == 0)&& >> + (data->dev_ops->ioctl(data->dev_ops_priv, data->fd, >> VIDIOC_ENUMINPUT,&input) == 0)) { >> if (input.status& V4L2_IN_ST_HFLIP) >> data->flags |= V4LCONTROL_HFLIPPED; >> if (input.status& V4L2_IN_ST_VFLIP) >> @@ -787,7 +790,8 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, >> int always_needs_conversion) >> data->flags = strtol(s, NULL, 0); >> >> ctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL; >> - if (SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL,&ctrl) == 0) >> + if (data->dev_ops->ioctl(data->dev_ops_priv, data->fd, >> + VIDIOC_QUERYCTRL,&ctrl) == 0) >> data->priv_flags |= V4LCONTROL_SUPPORTS_NEXT_CTRL; >> >> /* If the device always needs conversion, we can add fake >> controls at no cost >> @@ -795,7 +799,8 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, >> int always_needs_conversion) >> if (always_needs_conversion || >> v4lcontrol_needs_conversion(data)) { >> for (i = 0; i< V4LCONTROL_AUTO_ENABLE_COUNT; i++) { >> ctrl.id = fake_controls[i].id; >> - rc = SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL,&ctrl); >> + rc = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, >> + VIDIOC_QUERYCTRL,&ctrl); >> if (rc == -1 || (rc == 0&& (ctrl.flags& >> V4L2_CTRL_FLAG_DISABLED))) >> data->controls |= 1<< i; >> } >> @@ -807,17 +812,20 @@ struct v4lcontrol_data *v4lcontrol_create(int >> fd, int always_needs_conversion) >> different sensors with / without autogain or the necessary >> controls. */ >> while (data->flags& V4LCONTROL_WANTS_AUTOGAIN) { >> ctrl.id = V4L2_CID_AUTOGAIN; >> - rc = SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL,&ctrl); >> + rc = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, >> + VIDIOC_QUERYCTRL,&ctrl); >> if (rc == 0&& !(ctrl.flags& V4L2_CTRL_FLAG_DISABLED)) >> break; >> >> ctrl.id = V4L2_CID_EXPOSURE; >> - rc = SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL,&ctrl); >> + rc = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, >> + VIDIOC_QUERYCTRL,&ctrl); >> if (rc != 0 || (ctrl.flags& V4L2_CTRL_FLAG_DISABLED)) >> break; >> >> ctrl.id = V4L2_CID_GAIN; >> - rc = SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL,&ctrl); >> + rc = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, >> + VIDIOC_QUERYCTRL,&ctrl); >> if (rc != 0 || (ctrl.flags& V4L2_CTRL_FLAG_DISABLED)) >> break; >> >> @@ -834,7 +842,7 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, >> int always_needs_conversion) >> if (data->controls == 0) >> return data; /* No need to create a shared memory segment */ >> >> - if (SYS_IOCTL(fd, VIDIOC_QUERYCAP,&cap)) { >> + if (data->dev_ops->ioctl(data->dev_ops_priv, fd, >> VIDIOC_QUERYCAP,&cap)) { >> perror("libv4lcontrol: error querying device capabilities"); >> goto error; >> } >> @@ -1020,7 +1028,8 @@ int v4lcontrol_vidioc_queryctrl(struct >> v4lcontrol_data *data, void *arg) >> } >> >> /* find out what the kernel driver would respond. */ >> - retval = SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL, arg); >> + retval = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, >> + VIDIOC_QUERYCTRL, arg); >> >> if ((data->priv_flags& V4LCONTROL_SUPPORTS_NEXT_CTRL)&& >> (orig_id& V4L2_CTRL_FLAG_NEXT_CTRL)) { >> @@ -1057,7 +1066,8 @@ int v4lcontrol_vidioc_g_ctrl(struct >> v4lcontrol_data *data, void *arg) >> return 0; >> } >> >> - return SYS_IOCTL(data->fd, VIDIOC_G_CTRL, arg); >> + return data->dev_ops->ioctl(data->dev_ops_priv, data->fd, >> + VIDIOC_G_CTRL, arg); >> } >> >> int v4lcontrol_vidioc_s_ctrl(struct v4lcontrol_data *data, void *arg) >> @@ -1078,7 +1088,8 @@ int v4lcontrol_vidioc_s_ctrl(struct >> v4lcontrol_data *data, void *arg) >> return 0; >> } >> >> - return SYS_IOCTL(data->fd, VIDIOC_S_CTRL, arg); >> + return data->dev_ops->ioctl(data->dev_ops_priv, data->fd, >> + VIDIOC_S_CTRL, arg); >> } >> >> int v4lcontrol_get_flags(struct v4lcontrol_data *data) >> diff --git a/lib/libv4lconvert/control/libv4lcontrol.h >> b/lib/libv4lconvert/control/libv4lcontrol.h >> index 974e97a..1c09546 100644 >> --- a/lib/libv4lconvert/control/libv4lcontrol.h >> +++ b/lib/libv4lconvert/control/libv4lcontrol.h >> @@ -22,6 +22,8 @@ >> #ifndef __LIBV4LCONTROL_H >> #define __LIBV4LCONTROL_H >> >> +#include "libv4l2-plugin.h" >> + >> /* Flags */ >> #define V4LCONTROL_HFLIPPED 0x01 >> #define V4LCONTROL_VFLIPPED 0x02 >> @@ -47,7 +49,8 @@ enum { >> >> struct v4lcontrol_data; >> >> -struct v4lcontrol_data *v4lcontrol_create(int fd, int >> always_needs_conversion); >> +struct v4lcontrol_data *v4lcontrol_create(int fd, void *dev_ops_priv, >> + struct libv4l2_dev_ops *dev_ops, int always_needs_conversion); >> void v4lcontrol_destroy(struct v4lcontrol_data *data); >> >> /* Functions used by v4lprocessing to get the control state */ >> diff --git a/lib/libv4lconvert/libv4lconvert-priv.h >> b/lib/libv4lconvert/libv4lconvert-priv.h >> index 84c706e..9cb6e1c 100644 >> --- a/lib/libv4lconvert/libv4lconvert-priv.h >> +++ b/lib/libv4lconvert/libv4lconvert-priv.h >> @@ -65,6 +65,8 @@ struct v4lconvert_data { >> unsigned char *convert_pixfmt_buf; >> struct v4lcontrol_data *control; >> struct v4lprocessing_data *processing; >> + struct libv4l2_dev_ops *dev_ops; >> + void *dev_ops_priv; >> >> /* Data for external decompression helpers code */ >> pid_t decompress_pid; >> diff --git a/lib/libv4lconvert/libv4lconvert.c >> b/lib/libv4lconvert/libv4lconvert.c >> index e4863fd..6861986 100644 >> --- a/lib/libv4lconvert/libv4lconvert.c >> +++ b/lib/libv4lconvert/libv4lconvert.c >> @@ -92,7 +92,8 @@ static const int v4lconvert_crop_res[][2] = { >> { 176, 144 }, >> }; >> >> -struct v4lconvert_data *v4lconvert_create(int fd) >> +struct v4lconvert_data *v4lconvert_create(int fd, void *dev_ops_priv, >> + struct libv4l2_dev_ops *dev_ops) >> { >> int i, j; >> struct v4lconvert_data *data = calloc(1, sizeof(struct >> v4lconvert_data)); >> @@ -108,6 +109,8 @@ struct v4lconvert_data *v4lconvert_create(int fd) >> } >> >> data->fd = fd; >> + data->dev_ops = dev_ops; >> + data->dev_ops_priv = dev_ops_priv; >> data->decompress_pid = -1; >> >> /* Check supported formats */ >> @@ -116,7 +119,7 @@ struct v4lconvert_data *v4lconvert_create(int fd) >> >> fmt.index = i; >> >> - if (SYS_IOCTL(data->fd, VIDIOC_ENUM_FMT,&fmt)) >> + if (data->dev_ops->ioctl(data->dev_ops_priv, data->fd, >> VIDIOC_ENUM_FMT,&fmt)) >> break; >> >> for (j = 0; j< ARRAY_SIZE(supported_src_pixfmts); j++) >> @@ -135,7 +138,8 @@ struct v4lconvert_data *v4lconvert_create(int fd) >> data->no_formats = i; >> >> /* Check if this cam has any special flags */ >> - if (SYS_IOCTL(data->fd, VIDIOC_QUERYCAP,&cap) == 0) { >> + if (data->dev_ops->ioctl(data->dev_ops_priv, >> + data->fd, VIDIOC_QUERYCAP,&cap) == 0) { >> if (!strcmp((char *)cap.driver, "uvcvideo")) >> data->flags |= V4LCONVERT_IS_UVC; >> >> @@ -143,7 +147,8 @@ struct v4lconvert_data *v4lconvert_create(int fd) >> always_needs_conversion = 0; >> } >> >> - data->control = v4lcontrol_create(fd, always_needs_conversion); >> + data->control = v4lcontrol_create(fd, dev_ops_priv, dev_ops, >> + always_needs_conversion); >> if (!data->control) { >> free(data); >> return NULL; >> @@ -206,7 +211,8 @@ int v4lconvert_enum_fmt(struct v4lconvert_data >> *data, struct v4l2_fmtdesc *fmt) >> if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || >> (!v4lconvert_supported_dst_fmt_only(data)&& >> fmt->index< data->no_formats)) >> - return SYS_IOCTL(data->fd, VIDIOC_ENUM_FMT, fmt); >> + return data->dev_ops->ioctl(data->dev_ops_priv, data->fd, >> + VIDIOC_ENUM_FMT, fmt); >> >> for (i = 0; i< ARRAY_SIZE(supported_dst_pixfmts); i++) >> if (v4lconvert_supported_dst_fmt_only(data) || >> @@ -314,7 +320,8 @@ static int v4lconvert_do_try_format(struct >> v4lconvert_data *data, >> try_fmt = *dest_fmt; >> try_fmt.fmt.pix.pixelformat = supported_src_pixfmts[i].fmt; >> >> - if (!SYS_IOCTL(data->fd, VIDIOC_TRY_FMT,&try_fmt)) { >> + if (!data->dev_ops->ioctl(data->dev_ops_priv, data->fd, >> + VIDIOC_TRY_FMT,&try_fmt)) { >> if (try_fmt.fmt.pix.pixelformat == >> supported_src_pixfmts[i].fmt) { >> int size_x_diff = abs((int)try_fmt.fmt.pix.width - >> (int)dest_fmt->fmt.pix.width); >> @@ -382,7 +389,8 @@ int v4lconvert_try_format(struct v4lconvert_data >> *data, >> if >> (!v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat) || >> dest_fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || >> v4lconvert_do_try_format(data,&try_dest,&try_src)) { >> - result = SYS_IOCTL(data->fd, VIDIOC_TRY_FMT, dest_fmt); >> + result = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, >> + VIDIOC_TRY_FMT, dest_fmt); >> if (src_fmt) >> *src_fmt = *dest_fmt; >> return result; >> @@ -1241,7 +1249,8 @@ static void v4lconvert_get_framesizes(struct >> v4lconvert_data *data, >> >> for (i = 0; ; i++) { >> frmsize.index = i; >> - if (SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMESIZES,&frmsize)) >> + if (data->dev_ops->ioctl(data->dev_ops_priv, data->fd, >> + VIDIOC_ENUM_FRAMESIZES,&frmsize)) >> break; >> >> /* We got a framesize, check we don't have the same one >> already */ >> @@ -1301,7 +1310,8 @@ int v4lconvert_enum_framesizes(struct >> v4lconvert_data *data, >> errno = EINVAL; >> return -1; >> } >> - return SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMESIZES, frmsize); >> + return data->dev_ops->ioctl(data->dev_ops_priv, data->fd, >> + VIDIOC_ENUM_FRAMESIZES, frmsize); >> } >> >> if (frmsize->index>= data->no_framesizes) { >> @@ -1337,7 +1347,8 @@ int v4lconvert_enum_frameintervals(struct >> v4lconvert_data *data, >> errno = EINVAL; >> return -1; >> } >> - res = SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival); >> + res = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, >> + VIDIOC_ENUM_FRAMEINTERVALS, frmival); >> if (res) >> V4LCONVERT_ERR("%s\n", strerror(errno)); >> return res; >> @@ -1382,7 +1393,8 @@ int v4lconvert_enum_frameintervals(struct >> v4lconvert_data *data, >> frmival->pixel_format = src_fmt.fmt.pix.pixelformat; >> frmival->width = src_fmt.fmt.pix.width; >> frmival->height = src_fmt.fmt.pix.height; >> - res = SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival); >> + res = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, >> + VIDIOC_ENUM_FRAMEINTERVALS, frmival); >> if (res) { >> int dest_pixfmt = dest_fmt.fmt.pix.pixelformat; >> int src_pixfmt = src_fmt.fmt.pix.pixelformat; >> diff --git a/utils/qv4l2/qv4l2.cpp b/utils/qv4l2/qv4l2.cpp >> index 232a318..349d1ca 100644 >> --- a/utils/qv4l2/qv4l2.cpp >> +++ b/utils/qv4l2/qv4l2.cpp >> @@ -47,6 +47,17 @@ >> #include<sys/mman.h> >> #include<errno.h> >> #include<dirent.h> >> +#include<syscall.h> >> + >> +int defIoctl(void *dev_ops_priv, int fd, unsigned long cmd, void *arg) >> +{ >> + return syscall(SYS_ioctl, (int)(fd), (unsigned long)(cmd), >> + (void *)(arg)); >> +} >> +ssize_t defRead(void *dev_ops_priv, int fd, void *buf, size_t len) >> +{ >> + return syscall(SYS_read, (int)(fd), (void *)(buf), (size_t)(len)); >> +} >> >> ApplicationWindow::ApplicationWindow() : >> m_capture(NULL), >> @@ -59,6 +70,10 @@ ApplicationWindow::ApplicationWindow() : >> m_frameData = NULL; >> m_nbuffers = 0; >> m_buffers = NULL; >> + m_defauldDevOps.init = NULL; >> + m_defauldDevOps.close = NULL; >> + m_defauldDevOps.ioctl =&defIoctl; >> + m_defauldDevOps.read =&defRead; >> >> QAction *openAct = new QAction(QIcon(":/fileopen.png"), "&Open >> device", this); >> openAct->setStatusTip("Open a v4l device, use libv4l2 wrapper >> if possible"); >> @@ -144,7 +159,7 @@ void ApplicationWindow::setDevice(const >> QString&device, bool rawOpen) >> } >> m_tabs->show(); >> m_tabs->setFocus(); >> - m_convertData = v4lconvert_create(fd()); >> + m_convertData = v4lconvert_create(fd(), NULL,&m_defauldDevOps); >> m_capStartAct->setEnabled(fd()>= 0); >> } >> >> diff --git a/utils/qv4l2/qv4l2.h b/utils/qv4l2/qv4l2.h >> index 0a3e5ef..d847fe6 100644 >> --- a/utils/qv4l2/qv4l2.h >> +++ b/utils/qv4l2/qv4l2.h >> @@ -91,6 +91,7 @@ private: >> unsigned char *m_frameData; >> unsigned m_nbuffers; >> struct v4lconvert_data *m_convertData; >> + struct libv4l2_dev_ops m_defauldDevOps; >> CapMethod m_capMethod; >> >> private slots: -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi, On 07/22/2011 05:39 PM, Yordan Kamenov wrote: > Hi Hans, > > Hans de Goede wrote: >> Hi, >> >> Sorry it took so long, but I've just merged the plugin >> support into v4l-utils git. I did make some minor mods / >> bugfixes before merging, see the commit message in git. >> >> Regards, >> >> Hans >> >> p.s. >> >> I think we should expand the plugin support with support >> for a output devices, iow add a write() dev_op. If you >> guys agree I can easily do so myself, we should do this >> asap before people start depending on the ABI >> (although there is no ABI stability promise until I >> release 0.10.x, see my message to the list wrt >> the start of the 0.9.x cycle). >> > > I think that it is a good point, you can add write() and > reserved dev_ops. Ok, done, this is in v4l-utils git master now. Regards, Hans -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Sun, Jul 24, 2011 at 07:36:38PM +0200, Hans de Goede wrote: > Hi, > > On 07/22/2011 05:39 PM, Yordan Kamenov wrote: > >Hi Hans, > > > >Hans de Goede wrote: > >>Hi, > >> > >>Sorry it took so long, but I've just merged the plugin > >>support into v4l-utils git. I did make some minor mods / > >>bugfixes before merging, see the commit message in git. > >> > >>Regards, > >> > >>Hans > >> > >>p.s. > >> > >>I think we should expand the plugin support with support > >>for a output devices, iow add a write() dev_op. If you > >>guys agree I can easily do so myself, we should do this > >>asap before people start depending on the ABI > >>(although there is no ABI stability promise until I > >>release 0.10.x, see my message to the list wrt > >>the start of the 0.9.x cycle). > >> > > > >I think that it is a good point, you can add write() and > >reserved dev_ops. > > Ok, done, this is in v4l-utils git master now. Wow! Thanks, Hans and Yordan! :-)
diff --git a/lib/include/libv4l2-plugin.h b/lib/include/libv4l2-plugin.h new file mode 100644 index 0000000..158c0c2 --- /dev/null +++ b/lib/include/libv4l2-plugin.h @@ -0,0 +1,36 @@ +/* +* Copyright (C) 2010 Nokia Corporation <multimedia@maemo.org> + +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License as published by +* the Free Software Foundation; either version 2.1 of the License, or +* (at your option) any later version. +* +* 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 +* 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 +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __LIBV4L2_PLUGIN_H +#define __LIBV4L2_PLUGIN_H + +#include <sys/types.h> + +/* Structure libv4l2_dev_ops holds the calls from libv4ls to video nodes. + They can be normal open/close/ioctl etc. or any of them may be replaced + with a callback by a loaded plugin. +*/ + +struct libv4l2_dev_ops { + void * (*init)(int fd); + void (*close)(void *dev_ops_priv); + int (*ioctl)(void *dev_ops_priv, int fd, unsigned long int request, void *arg); + ssize_t (*read)(void *dev_ops_priv, int fd, void *buffer, size_t n); +}; + +#endif diff --git a/lib/include/libv4lconvert.h b/lib/include/libv4lconvert.h index 0264290..351142e 100644 --- a/lib/include/libv4lconvert.h +++ b/lib/include/libv4lconvert.h @@ -38,6 +38,8 @@ #include <linux/videodev2.h> +#include "libv4l2-plugin.h" + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ @@ -50,7 +52,8 @@ extern "C" { struct v4lconvert_data; -LIBV4L_PUBLIC struct v4lconvert_data *v4lconvert_create(int fd); +LIBV4L_PUBLIC struct v4lconvert_data *v4lconvert_create(int fd, + void *dev_ops_priv, struct libv4l2_dev_ops *dev_ops); LIBV4L_PUBLIC void v4lconvert_destroy(struct v4lconvert_data *data); /* When doing flipping / rotating / video-processing, only supported diff --git a/lib/libv4l2/Makefile b/lib/libv4l2/Makefile index d78632f..f8b3714 100644 --- a/lib/libv4l2/Makefile +++ b/lib/libv4l2/Makefile @@ -1,12 +1,12 @@ override CPPFLAGS += -I../include -fvisibility=hidden -LIBS_libv4l2 = -lpthread +LIBS_libv4l2 = -lpthread -ldl -V4L2_OBJS = libv4l2.o log.o +V4L2_OBJS = libv4l2.o v4l2-plugin.o log.o V4L2CONVERT = v4l2convert.so V4L2CONVERT_O = v4l2convert.o libv4l2.so TARGETS = $(V4L2_LIB) libv4l2.pc -INCLUDES = ../include/libv4l2.h +INCLUDES = ../include/libv4l2.h ../include/libv4l2-plugin.h ifeq ($(LINKTYPE),static) V4L2_LIB = libv4l2.a diff --git a/lib/libv4l2/libv4l2-priv.h b/lib/libv4l2/libv4l2-priv.h index 46d6103..d06a508 100644 --- a/lib/libv4l2/libv4l2-priv.h +++ b/lib/libv4l2/libv4l2-priv.h @@ -85,8 +85,18 @@ struct v4l2_dev_info { /* buffer when doing conversion and using read() for read() */ int readbuf_size; unsigned char *readbuf; + struct libv4l2_dev_ops *dev_ops; + /* plugin info */ + void *plugin_library; + void *dev_ops_priv; }; +void v4l2_plugin_init(int fd, void **plugin_lib_ret, void **plugin_priv_ret, + struct libv4l2_dev_ops **dev_ops_ret); +void v4l2_plugin_cleanup(void *plugin_priv, void *plugin_lib, + struct libv4l2_dev_ops *dev_ops); + + /* From log.c */ void v4l2_log_ioctl(unsigned long int request, void *arg, int result); diff --git a/lib/libv4l2/libv4l2.c b/lib/libv4l2/libv4l2.c index ab85ea7..018350e 100644 --- a/lib/libv4l2/libv4l2.c +++ b/lib/libv4l2/libv4l2.c @@ -67,6 +67,7 @@ #include <sys/stat.h> #include "libv4l2.h" #include "libv4l2-priv.h" +#include "libv4l2-plugin.h" /* 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 @@ -102,7 +103,8 @@ static int v4l2_request_read_buffers(int index) devices[index].nreadbuffers; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; - result = SYS_IOCTL(devices[index].fd, VIDIOC_REQBUFS, &req); + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, + devices[index].fd, VIDIOC_REQBUFS, &req); if (result < 0) { int saved_err = errno; @@ -131,7 +133,8 @@ static void v4l2_unrequest_read_buffers(int index) req.count = 0; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; - if (SYS_IOCTL(devices[index].fd, VIDIOC_REQBUFS, &req) < 0) + if (devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, + devices[index].fd, VIDIOC_REQBUFS, &req) < 0) return; devices[index].no_frames = MIN(req.count, V4L2_MAX_NO_FRAMES); @@ -152,7 +155,8 @@ static int v4l2_map_buffers(int index) buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = i; - result = SYS_IOCTL(devices[index].fd, VIDIOC_QUERYBUF, &buf); + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, + devices[index].fd, VIDIOC_QUERYBUF, &buf); if (result) { int saved_err = errno; @@ -202,7 +206,8 @@ static int v4l2_streamon(int index) enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (!(devices[index].flags & V4L2_STREAMON)) { - result = SYS_IOCTL(devices[index].fd, VIDIOC_STREAMON, &type); + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, + devices[index].fd, VIDIOC_STREAMON, &type); if (result) { int saved_err = errno; @@ -223,7 +228,8 @@ static int v4l2_streamoff(int index) enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (devices[index].flags & V4L2_STREAMON) { - result = SYS_IOCTL(devices[index].fd, VIDIOC_STREAMOFF, &type); + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, + devices[index].fd, VIDIOC_STREAMOFF, &type); if (result) { int saved_err = errno; @@ -252,7 +258,8 @@ static int v4l2_queue_read_buffer(int index, int buffer_index) buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = buffer_index; - result = SYS_IOCTL(devices[index].fd, VIDIOC_QBUF, &buf); + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, + devices[index].fd, VIDIOC_QBUF, &buf); if (result) { int saved_err = errno; @@ -277,7 +284,8 @@ static int v4l2_dequeue_and_convert(int index, struct v4l2_buffer *buf, return result; do { - result = SYS_IOCTL(devices[index].fd, VIDIOC_DQBUF, buf); + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, + devices[index].fd, VIDIOC_DQBUF, buf); if (result) { if (errno != EAGAIN) { int saved_err = errno; @@ -356,7 +364,8 @@ static int v4l2_read_and_convert(int index, unsigned char *dest, int dest_size) } do { - result = SYS_READ(devices[index].fd, devices[index].readbuf, buf_size); + result = devices[index].dev_ops->read(devices[index].dev_ops_priv, + devices[index].fd, devices[index].readbuf, buf_size); if (result <= 0) { if (result && errno != EAGAIN) { int saved_err = errno; @@ -496,7 +505,8 @@ static int v4l2_buffers_mapped(int index) buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = i; - if (SYS_IOCTL(devices[index].fd, VIDIOC_QUERYBUF, &buf)) { + if (devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, + devices[index].fd, VIDIOC_QUERYBUF, &buf)) { int saved_err = errno; V4L2_LOG_ERR("querying buffer %u: %s\n", i, strerror(errno)); @@ -561,6 +571,11 @@ int v4l2_fd_open(int fd, int v4l2_flags) struct v4l2_capability cap; struct v4l2_format fmt; struct v4lconvert_data *convert; + struct libv4l2_dev_ops *dev_ops; + void *plugin_library; + void *plugin_data; + + v4l2_plugin_init(fd, &plugin_library, &plugin_data, &dev_ops); /* If no log file was set by the app, see if one was specified through the environment */ @@ -571,9 +586,10 @@ int v4l2_fd_open(int fd, int v4l2_flags) } /* check that this is an v4l2 device */ - if (SYS_IOCTL(fd, VIDIOC_QUERYCAP, &cap)) { + if (dev_ops->ioctl(plugin_data, fd, VIDIOC_QUERYCAP, &cap)) { int saved_err = errno; + v4l2_plugin_cleanup(plugin_data, plugin_library, dev_ops); V4L2_LOG_ERR("getting capabilities: %s\n", strerror(errno)); errno = saved_err; return -1; @@ -581,29 +597,38 @@ int v4l2_fd_open(int fd, int v4l2_flags) /* we only add functionality for video capture devices */ if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) || - !(cap.capabilities & (V4L2_CAP_STREAMING | V4L2_CAP_READWRITE))) + !(cap.capabilities & (V4L2_CAP_STREAMING | V4L2_CAP_READWRITE))) { + v4l2_plugin_cleanup(plugin_data, plugin_library, dev_ops); return fd; + } /* Get current cam format */ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (SYS_IOCTL(fd, VIDIOC_G_FMT, &fmt)) { + if (dev_ops->ioctl(plugin_data, fd, VIDIOC_G_FMT, &fmt)) { int saved_err = errno; + v4l2_plugin_cleanup(plugin_data, plugin_library, dev_ops); V4L2_LOG_ERR("getting pixformat: %s\n", strerror(errno)); errno = saved_err; return -1; } /* init libv4lconvert */ - convert = v4lconvert_create(fd); - if (!convert) + convert = v4lconvert_create(fd, plugin_data, dev_ops); + if (!convert) { + v4l2_plugin_cleanup(plugin_data, plugin_library, dev_ops); return -1; + } /* So we have a v4l2 capture device, register it in our devices array */ pthread_mutex_lock(&v4l2_open_mutex); for (index = 0; index < V4L2_MAX_DEVICES; index++) if (devices[index].fd == -1) { devices[index].fd = fd; + + devices[index].plugin_library = plugin_library; + devices[index].dev_ops_priv = plugin_data; + devices[index].dev_ops = dev_ops; break; } pthread_mutex_unlock(&v4l2_open_mutex); @@ -611,6 +636,7 @@ int v4l2_fd_open(int fd, int v4l2_flags) if (index == V4L2_MAX_DEVICES) { V4L2_LOG_ERR("attempting to open more then %d video devices\n", V4L2_MAX_DEVICES); + v4l2_plugin_cleanup(plugin_data, plugin_library, dev_ops); errno = EBUSY; return -1; } @@ -700,6 +726,9 @@ int v4l2_close(int fd) if (result) return 0; + v4l2_plugin_cleanup(devices[index].dev_ops_priv, + devices[index].plugin_library, devices[index].dev_ops); + /* Free resources */ v4l2_unmap_buffers(index); if (devices[index].convert_mmap_buf != MAP_FAILED) { @@ -879,7 +908,8 @@ int v4l2_ioctl(int fd, unsigned long int request, ...) } if (!is_capture_request) { - result = SYS_IOCTL(fd, request, arg); + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, + fd, request, arg); saved_err = errno; v4l2_log_ioctl(request, arg, result); errno = saved_err; @@ -927,7 +957,8 @@ int v4l2_ioctl(int fd, unsigned long int request, ...) case VIDIOC_QUERYCAP: { struct v4l2_capability *cap = arg; - result = SYS_IOCTL(devices[index].fd, VIDIOC_QUERYCAP, cap); + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, + 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; @@ -977,8 +1008,8 @@ int v4l2_ioctl(int fd, unsigned long int request, ...) } if (devices[index].flags & V4L2_DISABLE_CONVERSION) { - result = SYS_IOCTL(devices[index].fd, VIDIOC_TRY_FMT, - dest_fmt); + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, + devices[index].fd, VIDIOC_TRY_FMT, dest_fmt); src_fmt = *dest_fmt; } else { result = v4lconvert_try_format(devices[index].convert, dest_fmt, @@ -1018,7 +1049,8 @@ int v4l2_ioctl(int fd, unsigned long int request, ...) break; req_pix_fmt = src_fmt.fmt.pix; - result = SYS_IOCTL(devices[index].fd, VIDIOC_S_FMT, &src_fmt); + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, + devices[index].fd, VIDIOC_S_FMT, &src_fmt); if (result) { saved_err = errno; V4L2_LOG_ERR("setting pixformat: %s\n", strerror(errno)); @@ -1067,7 +1099,8 @@ int v4l2_ioctl(int fd, unsigned long int request, ...) if (req->count > V4L2_MAX_NO_FRAMES) req->count = V4L2_MAX_NO_FRAMES; - result = SYS_IOCTL(devices[index].fd, VIDIOC_REQBUFS, req); + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, + devices[index].fd, VIDIOC_REQBUFS, req); if (result < 0) break; result = 0; /* some drivers return the number of buffers on success */ @@ -1088,7 +1121,8 @@ int v4l2_ioctl(int fd, unsigned long int request, ...) /* Do a real query even when converting to let the driver fill in things like buf->field */ - result = SYS_IOCTL(devices[index].fd, VIDIOC_QUERYBUF, buf); + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, + devices[index].fd, VIDIOC_QUERYBUF, buf); if (result || !v4l2_needs_conversion(index)) break; @@ -1115,7 +1149,8 @@ int v4l2_ioctl(int fd, unsigned long int request, ...) break; } - result = SYS_IOCTL(devices[index].fd, VIDIOC_QBUF, arg); + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, + devices[index].fd, VIDIOC_QBUF, arg); break; case VIDIOC_DQBUF: { @@ -1128,7 +1163,8 @@ int v4l2_ioctl(int fd, unsigned long int request, ...) } if (!v4l2_needs_conversion(index)) { - result = SYS_IOCTL(devices[index].fd, VIDIOC_DQBUF, buf); + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, + devices[index].fd, VIDIOC_DQBUF, buf); if (result) { int saved_err = errno; @@ -1187,7 +1223,8 @@ int v4l2_ioctl(int fd, unsigned long int request, ...) break; default: - result = SYS_IOCTL(fd, request, arg); + result = devices[index].dev_ops->ioctl(devices[index].dev_ops_priv, + fd, request, arg); break; } @@ -1217,7 +1254,8 @@ ssize_t v4l2_read(int fd, void *dest, size_t n) it */ if ((devices[index].flags & V4L2_SUPPORTS_READ) && !v4l2_needs_conversion(index)) { - result = SYS_READ(fd, dest, n); + result = devices[index].dev_ops->read(devices[index].dev_ops_priv, + fd, dest, n); goto leave; } diff --git a/lib/libv4l2/v4l2-plugin.c b/lib/libv4l2/v4l2-plugin.c new file mode 100644 index 0000000..3735193 --- /dev/null +++ b/lib/libv4l2/v4l2-plugin.c @@ -0,0 +1,158 @@ +/* +* Copyright (C) 2010 Nokia Corporation <multimedia@maemo.org> + +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License as published by +* the Free Software Foundation; either version 2.1 of the License, or +* (at your option) any later version. +* +* 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 +* 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 +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <stdarg.h> +#include <dlfcn.h> +#include <fcntl.h> +#include <glob.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include "libv4l2.h" +#include "libv4l2-priv.h" +#include "libv4l2-plugin.h" + +/* libv4l plugin support: + it is provided by functions v4l2_plugin_[open,close,etc]. + + When open() is called libv4l dlopens files in /usr/lib[64]/libv4l/plugins + 1 at a time and call open callback passing through the applications + parameters unmodified. + + If a plugin is relevant for the specified device node, it can indicate so + by returning a value other then -1 (the actual file descriptor). + As soon as a plugin returns another value then -1 plugin loading stops and + information about it (fd and corresponding library handle) is stored. For + each function v4l2_[ioctl,read,close,etc] is called corresponding + v4l2_plugin_* function which looks if there is loaded plugin for that file + and call it's callbacks. + + v4l2_plugin_* function indicates by it's first argument if plugin was used, + and if it was not then v4l2_* functions proceed with their usual behavior. +*/ + +#define PLUGINS_PATTERN "/usr/lib/libv4l/plugins/*.so" + +static void * dev_init(int fd) +{ + return NULL; +} + +static void dev_close(void *dev_ops_priv) +{ +} + +static int dev_ioctl(void *dev_ops_priv, int fd, unsigned long cmd, void *arg) +{ + return SYS_IOCTL(fd, cmd, arg); +} + +static ssize_t dev_read(void *dev_ops_priv, int fd, void *buf, size_t len) +{ + return SYS_READ(fd, buf, len); +} + + +struct libv4l2_dev_ops default_operations = { + .init = &dev_init, + .close = &dev_close, + .ioctl = &dev_ioctl, + .read = &dev_read +}; + +void v4l2_plugin_init(int fd, void **plugin_lib_ret, void **plugin_priv_ret, + struct libv4l2_dev_ops **dev_ops_ret) +{ + char *error; + int glob_ret, plugin_num; + void *plugin_library = NULL; + struct libv4l2_dev_ops *libv4l2_plugin = NULL; + glob_t globbuf; + + *dev_ops_ret = &default_operations; + + glob_ret = glob(PLUGINS_PATTERN, 0, NULL, &globbuf); + + if (glob_ret == GLOB_NOSPACE) { + *plugin_lib_ret = NULL; + *plugin_priv_ret = NULL; + return; + } + + if (glob_ret == GLOB_ABORTED || glob_ret == GLOB_NOMATCH) { + *plugin_lib_ret = NULL; + *plugin_priv_ret = NULL; + goto leave; + } + + for (plugin_num = 0; plugin_num < globbuf.gl_pathc; plugin_num++) { + + V4L2_LOG("PLUGIN: dlopen(%s);\n", globbuf.gl_pathv[plugin_num]); + + plugin_library = dlopen(globbuf.gl_pathv[plugin_num], + RTLD_LAZY); + + if (!plugin_library) + continue; + + dlerror(); /* Clear any existing error */ + libv4l2_plugin = (struct libv4l2_dev_ops *) + dlsym(plugin_library, "libv4l2_plugin"); + + error = dlerror(); + if (error != NULL) { + V4L2_LOG_ERR("PLUGIN: dlsym failed: %s\n", error); + dlclose(plugin_library); + + continue; + } + + *plugin_priv_ret = NULL; + if (libv4l2_plugin->init) + *plugin_priv_ret = libv4l2_plugin->init(fd); + + if (!*plugin_priv_ret) { + V4L2_LOG("PLUGIN: plugin open() returned NULL\n"); + dlclose(plugin_library); + *plugin_lib_ret = NULL; + continue; + } + + (*dev_ops_ret)->init = libv4l2_plugin->init; + if (libv4l2_plugin->close != NULL) + (*dev_ops_ret)->close = libv4l2_plugin->close; + if (libv4l2_plugin->ioctl != NULL) + (*dev_ops_ret)->ioctl = libv4l2_plugin->ioctl; + if (libv4l2_plugin->read != NULL) + (*dev_ops_ret)->read = libv4l2_plugin->read; + + break; + + } + +leave: + globfree(&globbuf); +} + +void v4l2_plugin_cleanup(void *plugin_priv, void *plugin_lib, + struct libv4l2_dev_ops *dev_ops) +{ + if (plugin_priv) { + dev_ops->close(plugin_priv); + dlclose(plugin_lib); + } +} diff --git a/lib/libv4l2/v4l2convert.c b/lib/libv4l2/v4l2convert.c index e251085..03f34ad 100644 --- a/lib/libv4l2/v4l2convert.c +++ b/lib/libv4l2/v4l2convert.c @@ -46,7 +46,6 @@ LIBV4L_PUBLIC int open(const char *file, int oflag, ...) { int fd; - struct v4l2_capability cap; int v4l_device = 0; /* check if we're opening a video4linux2 device */ @@ -76,14 +75,6 @@ LIBV4L_PUBLIC int open(const char *file, int oflag, ...) if (fd == -1 || !v4l_device) return fd; - /* check that this is an v4l2 device, libv4l2 only supports v4l2 devices */ - if (SYS_IOCTL(fd, VIDIOC_QUERYCAP, &cap)) - return fd; - - /* libv4l2 only adds functionality to capture capable devices */ - if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) - return fd; - /* Try to Register with libv4l2 (in case of failure pass the fd to the application as is) */ v4l2_fd_open(fd, 0); diff --git a/lib/libv4lconvert/control/libv4lcontrol-priv.h b/lib/libv4lconvert/control/libv4lcontrol-priv.h index 22cdf34..1259e6b 100644 --- a/lib/libv4lconvert/control/libv4lcontrol-priv.h +++ b/lib/libv4lconvert/control/libv4lcontrol-priv.h @@ -22,6 +22,8 @@ #ifndef __LIBV4LCONTROL_PRIV_H #define __LIBV4LCONTROL_PRIV_H +#include "libv4l2-plugin.h" + #define V4LCONTROL_SHM_SIZE 4096 #define V4LCONTROL_SUPPORTS_NEXT_CTRL 0x01 @@ -37,6 +39,8 @@ struct v4lcontrol_data { unsigned int *shm_values; /* shared memory control value store */ unsigned int old_values[V4LCONTROL_COUNT]; /* for controls_changed() */ const struct v4lcontrol_flags_info *flags_info; + struct libv4l2_dev_ops *dev_ops; + void *dev_ops_priv; }; struct v4lcontrol_flags_info { diff --git a/lib/libv4lconvert/control/libv4lcontrol.c b/lib/libv4lconvert/control/libv4lcontrol.c index 116bef5..24a5600 100644 --- a/lib/libv4lconvert/control/libv4lcontrol.c +++ b/lib/libv4lconvert/control/libv4lcontrol.c @@ -747,7 +747,8 @@ static void v4lcontrol_get_flags_from_db(struct v4lcontrol_data *data, } } -struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) +struct v4lcontrol_data *v4lcontrol_create(int fd, void *dev_ops_priv, + struct libv4l2_dev_ops *dev_ops, int always_needs_conversion) { int shm_fd; int i, rc, got_usb_ids, init = 0; @@ -767,10 +768,12 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) } data->fd = fd; + data->dev_ops = dev_ops; + data->dev_ops_priv = dev_ops_priv; /* Check if the driver has indicated some form of flipping is needed */ - if ((SYS_IOCTL(data->fd, VIDIOC_G_INPUT, &input.index) == 0) && - (SYS_IOCTL(data->fd, VIDIOC_ENUMINPUT, &input) == 0)) { + if ((data->dev_ops->ioctl(data->dev_ops_priv, data->fd, VIDIOC_G_INPUT, &input.index) == 0) && + (data->dev_ops->ioctl(data->dev_ops_priv, data->fd, VIDIOC_ENUMINPUT, &input) == 0)) { if (input.status & V4L2_IN_ST_HFLIP) data->flags |= V4LCONTROL_HFLIPPED; if (input.status & V4L2_IN_ST_VFLIP) @@ -787,7 +790,8 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) data->flags = strtol(s, NULL, 0); ctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL; - if (SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL, &ctrl) == 0) + if (data->dev_ops->ioctl(data->dev_ops_priv, data->fd, + VIDIOC_QUERYCTRL, &ctrl) == 0) data->priv_flags |= V4LCONTROL_SUPPORTS_NEXT_CTRL; /* If the device always needs conversion, we can add fake controls at no cost @@ -795,7 +799,8 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) if (always_needs_conversion || v4lcontrol_needs_conversion(data)) { for (i = 0; i < V4LCONTROL_AUTO_ENABLE_COUNT; i++) { ctrl.id = fake_controls[i].id; - rc = SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL, &ctrl); + rc = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, + VIDIOC_QUERYCTRL, &ctrl); if (rc == -1 || (rc == 0 && (ctrl.flags & V4L2_CTRL_FLAG_DISABLED))) data->controls |= 1 << i; } @@ -807,17 +812,20 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) different sensors with / without autogain or the necessary controls. */ while (data->flags & V4LCONTROL_WANTS_AUTOGAIN) { ctrl.id = V4L2_CID_AUTOGAIN; - rc = SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL, &ctrl); + rc = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, + VIDIOC_QUERYCTRL, &ctrl); if (rc == 0 && !(ctrl.flags & V4L2_CTRL_FLAG_DISABLED)) break; ctrl.id = V4L2_CID_EXPOSURE; - rc = SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL, &ctrl); + rc = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, + VIDIOC_QUERYCTRL, &ctrl); if (rc != 0 || (ctrl.flags & V4L2_CTRL_FLAG_DISABLED)) break; ctrl.id = V4L2_CID_GAIN; - rc = SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL, &ctrl); + rc = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, + VIDIOC_QUERYCTRL, &ctrl); if (rc != 0 || (ctrl.flags & V4L2_CTRL_FLAG_DISABLED)) break; @@ -834,7 +842,7 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) if (data->controls == 0) return data; /* No need to create a shared memory segment */ - if (SYS_IOCTL(fd, VIDIOC_QUERYCAP, &cap)) { + if (data->dev_ops->ioctl(data->dev_ops_priv, fd, VIDIOC_QUERYCAP, &cap)) { perror("libv4lcontrol: error querying device capabilities"); goto error; } @@ -1020,7 +1028,8 @@ int v4lcontrol_vidioc_queryctrl(struct v4lcontrol_data *data, void *arg) } /* find out what the kernel driver would respond. */ - retval = SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL, arg); + retval = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, + VIDIOC_QUERYCTRL, arg); if ((data->priv_flags & V4LCONTROL_SUPPORTS_NEXT_CTRL) && (orig_id & V4L2_CTRL_FLAG_NEXT_CTRL)) { @@ -1057,7 +1066,8 @@ int v4lcontrol_vidioc_g_ctrl(struct v4lcontrol_data *data, void *arg) return 0; } - return SYS_IOCTL(data->fd, VIDIOC_G_CTRL, arg); + return data->dev_ops->ioctl(data->dev_ops_priv, data->fd, + VIDIOC_G_CTRL, arg); } int v4lcontrol_vidioc_s_ctrl(struct v4lcontrol_data *data, void *arg) @@ -1078,7 +1088,8 @@ int v4lcontrol_vidioc_s_ctrl(struct v4lcontrol_data *data, void *arg) return 0; } - return SYS_IOCTL(data->fd, VIDIOC_S_CTRL, arg); + return data->dev_ops->ioctl(data->dev_ops_priv, data->fd, + VIDIOC_S_CTRL, arg); } int v4lcontrol_get_flags(struct v4lcontrol_data *data) diff --git a/lib/libv4lconvert/control/libv4lcontrol.h b/lib/libv4lconvert/control/libv4lcontrol.h index 974e97a..1c09546 100644 --- a/lib/libv4lconvert/control/libv4lcontrol.h +++ b/lib/libv4lconvert/control/libv4lcontrol.h @@ -22,6 +22,8 @@ #ifndef __LIBV4LCONTROL_H #define __LIBV4LCONTROL_H +#include "libv4l2-plugin.h" + /* Flags */ #define V4LCONTROL_HFLIPPED 0x01 #define V4LCONTROL_VFLIPPED 0x02 @@ -47,7 +49,8 @@ enum { struct v4lcontrol_data; -struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion); +struct v4lcontrol_data *v4lcontrol_create(int fd, void *dev_ops_priv, + struct libv4l2_dev_ops *dev_ops, int always_needs_conversion); void v4lcontrol_destroy(struct v4lcontrol_data *data); /* Functions used by v4lprocessing to get the control state */ diff --git a/lib/libv4lconvert/libv4lconvert-priv.h b/lib/libv4lconvert/libv4lconvert-priv.h index 84c706e..9cb6e1c 100644 --- a/lib/libv4lconvert/libv4lconvert-priv.h +++ b/lib/libv4lconvert/libv4lconvert-priv.h @@ -65,6 +65,8 @@ struct v4lconvert_data { unsigned char *convert_pixfmt_buf; struct v4lcontrol_data *control; struct v4lprocessing_data *processing; + struct libv4l2_dev_ops *dev_ops; + void *dev_ops_priv; /* Data for external decompression helpers code */ pid_t decompress_pid; diff --git a/lib/libv4lconvert/libv4lconvert.c b/lib/libv4lconvert/libv4lconvert.c index e4863fd..6861986 100644 --- a/lib/libv4lconvert/libv4lconvert.c +++ b/lib/libv4lconvert/libv4lconvert.c @@ -92,7 +92,8 @@ static const int v4lconvert_crop_res[][2] = { { 176, 144 }, }; -struct v4lconvert_data *v4lconvert_create(int fd) +struct v4lconvert_data *v4lconvert_create(int fd, void *dev_ops_priv, + struct libv4l2_dev_ops *dev_ops) { int i, j; struct v4lconvert_data *data = calloc(1, sizeof(struct v4lconvert_data)); @@ -108,6 +109,8 @@ struct v4lconvert_data *v4lconvert_create(int fd) } data->fd = fd; + data->dev_ops = dev_ops; + data->dev_ops_priv = dev_ops_priv; data->decompress_pid = -1; /* Check supported formats */ @@ -116,7 +119,7 @@ struct v4lconvert_data *v4lconvert_create(int fd) fmt.index = i; - if (SYS_IOCTL(data->fd, VIDIOC_ENUM_FMT, &fmt)) + if (data->dev_ops->ioctl(data->dev_ops_priv, data->fd, VIDIOC_ENUM_FMT, &fmt)) break; for (j = 0; j < ARRAY_SIZE(supported_src_pixfmts); j++) @@ -135,7 +138,8 @@ struct v4lconvert_data *v4lconvert_create(int fd) data->no_formats = i; /* Check if this cam has any special flags */ - if (SYS_IOCTL(data->fd, VIDIOC_QUERYCAP, &cap) == 0) { + if (data->dev_ops->ioctl(data->dev_ops_priv, + data->fd, VIDIOC_QUERYCAP, &cap) == 0) { if (!strcmp((char *)cap.driver, "uvcvideo")) data->flags |= V4LCONVERT_IS_UVC; @@ -143,7 +147,8 @@ struct v4lconvert_data *v4lconvert_create(int fd) always_needs_conversion = 0; } - data->control = v4lcontrol_create(fd, always_needs_conversion); + data->control = v4lcontrol_create(fd, dev_ops_priv, dev_ops, + always_needs_conversion); if (!data->control) { free(data); return NULL; @@ -206,7 +211,8 @@ int v4lconvert_enum_fmt(struct v4lconvert_data *data, struct v4l2_fmtdesc *fmt) if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || (!v4lconvert_supported_dst_fmt_only(data) && fmt->index < data->no_formats)) - return SYS_IOCTL(data->fd, VIDIOC_ENUM_FMT, fmt); + return data->dev_ops->ioctl(data->dev_ops_priv, data->fd, + VIDIOC_ENUM_FMT, fmt); for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) if (v4lconvert_supported_dst_fmt_only(data) || @@ -314,7 +320,8 @@ static int v4lconvert_do_try_format(struct v4lconvert_data *data, try_fmt = *dest_fmt; try_fmt.fmt.pix.pixelformat = supported_src_pixfmts[i].fmt; - if (!SYS_IOCTL(data->fd, VIDIOC_TRY_FMT, &try_fmt)) { + if (!data->dev_ops->ioctl(data->dev_ops_priv, data->fd, + VIDIOC_TRY_FMT, &try_fmt)) { if (try_fmt.fmt.pix.pixelformat == supported_src_pixfmts[i].fmt) { int size_x_diff = abs((int)try_fmt.fmt.pix.width - (int)dest_fmt->fmt.pix.width); @@ -382,7 +389,8 @@ int v4lconvert_try_format(struct v4lconvert_data *data, if (!v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat) || dest_fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || v4lconvert_do_try_format(data, &try_dest, &try_src)) { - result = SYS_IOCTL(data->fd, VIDIOC_TRY_FMT, dest_fmt); + result = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, + VIDIOC_TRY_FMT, dest_fmt); if (src_fmt) *src_fmt = *dest_fmt; return result; @@ -1241,7 +1249,8 @@ static void v4lconvert_get_framesizes(struct v4lconvert_data *data, for (i = 0; ; i++) { frmsize.index = i; - if (SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMESIZES, &frmsize)) + if (data->dev_ops->ioctl(data->dev_ops_priv, data->fd, + VIDIOC_ENUM_FRAMESIZES, &frmsize)) break; /* We got a framesize, check we don't have the same one already */ @@ -1301,7 +1310,8 @@ int v4lconvert_enum_framesizes(struct v4lconvert_data *data, errno = EINVAL; return -1; } - return SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMESIZES, frmsize); + return data->dev_ops->ioctl(data->dev_ops_priv, data->fd, + VIDIOC_ENUM_FRAMESIZES, frmsize); } if (frmsize->index >= data->no_framesizes) { @@ -1337,7 +1347,8 @@ int v4lconvert_enum_frameintervals(struct v4lconvert_data *data, errno = EINVAL; return -1; } - res = SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival); + res = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, + VIDIOC_ENUM_FRAMEINTERVALS, frmival); if (res) V4LCONVERT_ERR("%s\n", strerror(errno)); return res; @@ -1382,7 +1393,8 @@ int v4lconvert_enum_frameintervals(struct v4lconvert_data *data, frmival->pixel_format = src_fmt.fmt.pix.pixelformat; frmival->width = src_fmt.fmt.pix.width; frmival->height = src_fmt.fmt.pix.height; - res = SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival); + res = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, + VIDIOC_ENUM_FRAMEINTERVALS, frmival); if (res) { int dest_pixfmt = dest_fmt.fmt.pix.pixelformat; int src_pixfmt = src_fmt.fmt.pix.pixelformat; diff --git a/utils/qv4l2/qv4l2.cpp b/utils/qv4l2/qv4l2.cpp index 232a318..349d1ca 100644 --- a/utils/qv4l2/qv4l2.cpp +++ b/utils/qv4l2/qv4l2.cpp @@ -47,6 +47,17 @@ #include <sys/mman.h> #include <errno.h> #include <dirent.h> +#include <syscall.h> + +int defIoctl(void *dev_ops_priv, int fd, unsigned long cmd, void *arg) +{ + return syscall(SYS_ioctl, (int)(fd), (unsigned long)(cmd), + (void *)(arg)); +} +ssize_t defRead(void *dev_ops_priv, int fd, void *buf, size_t len) +{ + return syscall(SYS_read, (int)(fd), (void *)(buf), (size_t)(len)); +} ApplicationWindow::ApplicationWindow() : m_capture(NULL), @@ -59,6 +70,10 @@ ApplicationWindow::ApplicationWindow() : m_frameData = NULL; m_nbuffers = 0; m_buffers = NULL; + m_defauldDevOps.init = NULL; + m_defauldDevOps.close = NULL; + m_defauldDevOps.ioctl = &defIoctl; + m_defauldDevOps.read = &defRead; QAction *openAct = new QAction(QIcon(":/fileopen.png"), "&Open device", this); openAct->setStatusTip("Open a v4l device, use libv4l2 wrapper if possible"); @@ -144,7 +159,7 @@ void ApplicationWindow::setDevice(const QString &device, bool rawOpen) } m_tabs->show(); m_tabs->setFocus(); - m_convertData = v4lconvert_create(fd()); + m_convertData = v4lconvert_create(fd(), NULL, &m_defauldDevOps); m_capStartAct->setEnabled(fd() >= 0); } diff --git a/utils/qv4l2/qv4l2.h b/utils/qv4l2/qv4l2.h index 0a3e5ef..d847fe6 100644 --- a/utils/qv4l2/qv4l2.h +++ b/utils/qv4l2/qv4l2.h @@ -91,6 +91,7 @@ private: unsigned char *m_frameData; unsigned m_nbuffers; struct v4lconvert_data *m_convertData; + struct libv4l2_dev_ops m_defauldDevOps; CapMethod m_capMethod; private slots:
A libv4l2 plugin will sit in between libv4l2 itself and the actual /dev/video device node a fd refers to. It will be called each time libv4l2 wants to do an operation (read/write/ioctl) on the actual /dev/video node in question. Signed-off-by: Yordan Kamenov <ykamenov@mm-sol.com> --- lib/include/libv4l2-plugin.h | 36 ++++++ lib/include/libv4lconvert.h | 5 +- lib/libv4l2/Makefile | 6 +- lib/libv4l2/libv4l2-priv.h | 10 ++ lib/libv4l2/libv4l2.c | 88 ++++++++++---- lib/libv4l2/v4l2-plugin.c | 158 ++++++++++++++++++++++++ lib/libv4l2/v4l2convert.c | 9 -- lib/libv4lconvert/control/libv4lcontrol-priv.h | 4 + lib/libv4lconvert/control/libv4lcontrol.c | 35 ++++-- lib/libv4lconvert/control/libv4lcontrol.h | 5 +- lib/libv4lconvert/libv4lconvert-priv.h | 2 + lib/libv4lconvert/libv4lconvert.c | 34 ++++-- utils/qv4l2/qv4l2.cpp | 17 +++- utils/qv4l2/qv4l2.h | 1 + 14 files changed, 347 insertions(+), 63 deletions(-) create mode 100644 lib/include/libv4l2-plugin.h create mode 100644 lib/libv4l2/v4l2-plugin.c