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/mmap/munmap) on the
actual /dev/video node in question.

Signed-off-by: Yordan Kamenov <[email protected]>
---
 lib/include/libv4l2-plugin.h |   74 ++++++++
 lib/include/libv4l2.h        |   15 ++
 lib/libv4l2/Makefile         |    4 +-
 lib/libv4l2/libv4l2-priv.h   |    9 +
 lib/libv4l2/libv4l2.c        |   56 ++++++-
 lib/libv4l2/v4l2-plugin.c    |  399 ++++++++++++++++++++++++++++++++++++++++++
 lib/libv4l2/v4l2convert.c    |   20 ++-
 7 files changed, 568 insertions(+), 9 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..881b55d
--- /dev/null
+++ b/lib/include/libv4l2-plugin.h
@@ -0,0 +1,74 @@
+/*
+* Copyright (C) 2010 Nokia Corporation <[email protected]>
+
+* 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>
+
+/* 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/mmap/munmap) on the
+   actual /dev/video node in question. When called the plugin can then choose
+   to do one of the following:
+   1. Pass the call unmodified to the fd, and return the return value unmodifed
+   2. Modify some arguments in the call and pass it through
+   3. Modify the return(ed) value(s) of a passed through call
+   4. Not do any operation on the fd at all but instead completely fake it
+       (which opens the possibility for "fake" v4l devices)
+
+   libv4l2 plugins should *never* use any global variables. All data should be
+   bound to the specific fd to which the plugin is bound. This ensures that for
+   example a plugin for a specific type of usb webcam will also work when 2
+   identical cameras are plugged into a system (and both are used from the same
+   process).
+
+   A libv4l2 plugin can register plugin private data using:
+   void libv4l2_set_plugindata(int fd, void *plugin_data);
+
+   And can get this data out of libv4l2 again inside a callback using:
+   void *libv4l2_get_plugindata(int fd);
+
+   Note that a plugin should call libv4l2_set_plugindata only once per fd !
+   Calling it a second time will overwrite the previous value. The logical
+   place to use libv4l2_set_plugindata is from the plugin's open callback.
+*/
+
+/* Plugin callback function struct */
+struct libv4l2_plugin_data {
+       int (*open)(const char *file, int oflag, ...);
+       int (*close)(int fd);
+       int (*ioctl)(int fd, unsigned long int request, ...);
+       ssize_t (*read)(int fd, void *buffer, size_t n);
+       void *(*mmap)(void *start, size_t length, int prot, int flags,
+                       int fd, int64_t offset);
+       /* Note as munmap has no fd argument, defining a callback for munmap
+               will result in it getting called for *any* call to v4l2_munmap.
+               So if a plugin defines a callback for munmap (because for
+               example it returns fake mmap buffers from its mmap callback).
+               Then it must keep track of the addresses at which these buffers
+               live and their size and check the munmap arguments to see if the
+               munmap call was meant for it. */
+       int (*munmap)(void *_start, size_t length);
+};
+
+/* Plugin utility functions */
+void libv4l2_set_plugindata(int fd, void *plugin_data);
+void *libv4l2_get_plugindata(int fd);
+
+#endif
diff --git a/lib/include/libv4l2.h b/lib/include/libv4l2.h
index cc0ab4a..2123546 100644
--- a/lib/include/libv4l2.h
+++ b/lib/include/libv4l2.h
@@ -22,6 +22,7 @@
 #include <stdio.h>
 #include <unistd.h>
 #include <stdint.h>
+#include "libv4l2-plugin.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -108,6 +109,20 @@ LIBV4L_PUBLIC int v4l2_get_control(int fd, int cid);
    (note the fd is left open in this case). */
 LIBV4L_PUBLIC int v4l2_fd_open(int fd, int v4l2_flags);
 
+
+LIBV4L_PUBLIC int v4l2_plugin_open(int *plugin_used, const char *file,
+                                       int oflag, ...);
+LIBV4L_PUBLIC int v4l2_plugin_close(int *plugin_used, int fd);
+LIBV4L_PUBLIC int v4l2_plugin_ioctl(int *plugin_used, int fd,
+                                       unsigned long int request, ...);
+LIBV4L_PUBLIC ssize_t v4l2_plugin_read(int *plugin_used, int fd, void *dest,
+                                       size_t n);
+LIBV4L_PUBLIC void *v4l2_plugin_mmap(int *plugin_used, void *start,
+                                       size_t length, int prot, int flags,
+                                       int fd, int64_t offset);
+LIBV4L_PUBLIC int v4l2_plugin_munmap(int *plugin_used, void *_start,
+                                       size_t length);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff --git a/lib/libv4l2/Makefile b/lib/libv4l2/Makefile
index d78632f..eb1c019 100644
--- a/lib/libv4l2/Makefile
+++ b/lib/libv4l2/Makefile
@@ -1,8 +1,8 @@
 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
diff --git a/lib/libv4l2/libv4l2-priv.h b/lib/libv4l2/libv4l2-priv.h
index 46d6103..3873b1d 100644
--- a/lib/libv4l2/libv4l2-priv.h
+++ b/lib/libv4l2/libv4l2-priv.h
@@ -87,6 +87,15 @@ struct v4l2_dev_info {
        unsigned char *readbuf;
 };
 
+struct v4l2_plugin_info {
+       int fd;
+       void *plugin_library;
+       struct libv4l2_plugin_data *libv4l2_plugin;
+       unsigned char *frame_pointers[V4L2_MAX_NO_FRAMES];
+       int frame_sizes[V4L2_MAX_NO_FRAMES];
+       void *plugin_data;
+};
+
 /* 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..8696c68 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
@@ -522,7 +523,24 @@ static int v4l2_buffers_mapped(int index)
 
 int v4l2_open(const char *file, int oflag, ...)
 {
-       int fd;
+       int fd, plugin_used;
+
+       if (oflag & O_CREAT) {
+               va_list ap;
+               mode_t mode;
+
+               va_start(ap, oflag);
+               mode = va_arg(ap, mode_t);
+
+               fd = v4l2_plugin_open(&plugin_used, file, oflag, mode);
+
+               va_end(ap);
+       } else {
+               fd = v4l2_plugin_open(&plugin_used, file, oflag, 0);
+       }
+
+       if (plugin_used)
+               return fd;
 
        /* original open code */
        if (oflag & O_CREAT) {
@@ -684,7 +702,12 @@ static int v4l2_get_index(int fd)
 
 int v4l2_close(int fd)
 {
-       int index, result;
+       int index, result, plugin_used;
+
+       result = v4l2_plugin_close(&plugin_used, fd);
+
+       if (plugin_used)
+               return result;
 
        index = v4l2_get_index(fd);
        if (index == -1)
@@ -806,13 +829,18 @@ int v4l2_ioctl(int fd, unsigned long int request, ...)
 {
        void *arg;
        va_list ap;
-       int result, index, saved_err;
+       int result, index, saved_err, plugin_used;
        int is_capture_request = 0, stream_needs_locking = 0;
 
        va_start(ap, request);
        arg = va_arg(ap, void *);
        va_end(ap);
 
+       result = v4l2_plugin_ioctl(&plugin_used, fd, request, arg);
+
+       if (plugin_used)
+               return result;
+
        index = v4l2_get_index(fd);
        if (index == -1)
                return SYS_IOCTL(fd, request, arg);
@@ -1205,9 +1233,14 @@ int v4l2_ioctl(int fd, unsigned long int request, ...)
 ssize_t v4l2_read(int fd, void *dest, size_t n)
 {
        ssize_t result;
-       int saved_errno;
+       int saved_errno, plugin_used;
        int index = v4l2_get_index(fd);
 
+       result = v4l2_plugin_read(&plugin_used, fd, dest, n);
+
+       if (plugin_used)
+               return result;
+
        if (index == -1)
                return SYS_READ(fd, dest, n);
 
@@ -1264,10 +1297,16 @@ leave:
 void *v4l2_mmap(void *start, size_t length, int prot, int flags, int fd,
                int64_t offset)
 {
-       int index;
+       int index, plugin_used;
        unsigned int buffer_index;
        void *result;
 
+       result = v4l2_plugin_mmap(&plugin_used, start, length, prot,
+                                                       flags, fd, offset);
+
+       if (plugin_used)
+               return result;
+
        index = v4l2_get_index(fd);
        if (index == -1 ||
                        /* Check if the mmap data matches our answer to 
QUERY_BUF, if it doesn't
@@ -1329,10 +1368,15 @@ leave:
 
 int v4l2_munmap(void *_start, size_t length)
 {
-       int index;
+       int index, result, plugin_used;
        unsigned int buffer_index;
        unsigned char *start = _start;
 
+       result = v4l2_plugin_munmap(&plugin_used, _start, length);
+
+       if (plugin_used)
+               return result;
+
        /* Is this memory ours? */
        if (start != MAP_FAILED && length == V4L2_FRAME_BUF_SIZE) {
                for (index = 0; index < devices_used; index++)
diff --git a/lib/libv4l2/v4l2-plugin.c b/lib/libv4l2/v4l2-plugin.c
new file mode 100644
index 0000000..3efd533
--- /dev/null
+++ b/lib/libv4l2/v4l2-plugin.c
@@ -0,0 +1,399 @@
+/*
+* Copyright (C) 2010 Nokia Corporation <[email protected]>
+
+* 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 pthread_mutex_t v4l2_plugin_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static struct v4l2_plugin_info plugins[V4L2_MAX_DEVICES];
+
+int v4l2_plugin_open(int *plugin_used, const char *file, int oflag, ...)
+{
+       char *error;
+       int index, fd = -1, glob_ret, plugin_num, i;
+       void *plugin_library = NULL;
+       struct libv4l2_plugin_data *libv4l2_plugin = NULL;
+       glob_t globbuf;
+       static int structs_initialized = 0;
+
+       pthread_mutex_lock(&v4l2_plugin_mutex);
+       if (!structs_initialized) {
+               for (index = 0; index < V4L2_MAX_DEVICES; index++)
+                       plugins[index].fd = -1;
+
+               structs_initialized = 1;
+       }
+
+       /* Check if there is empty slot for plugin */
+       for (index = 0; index < V4L2_MAX_DEVICES; index++)
+               if (plugins[index].fd == -1)
+                       break;
+       pthread_mutex_unlock(&v4l2_plugin_mutex);
+
+       if (index == V4L2_MAX_DEVICES) {
+               V4L2_LOG_ERR("attempting to open more than %d libv4l plugins\n",
+                       V4L2_MAX_DEVICES);
+               *plugin_used = 0;
+               return -1;
+       }
+
+       glob_ret = glob(PLUGINS_PATTERN, 0, NULL, &globbuf);
+
+       if (glob_ret == GLOB_NOSPACE) {
+               *plugin_used = 0;
+               return -1;
+       }
+
+       if (glob_ret == GLOB_ABORTED || glob_ret == GLOB_NOMATCH) {
+               *plugin_used = 0;
+               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_plugin_data *)
+                                       dlsym(plugin_library, "libv4l2_plugin");
+
+               error = dlerror();
+               if (error != NULL)  {
+                       V4L2_LOG_ERR("PLUGIN: dlsym failed: %s\n", error);
+                       dlclose(plugin_library);
+
+                       continue;
+               }
+
+               if (libv4l2_plugin->open == NULL) {
+                       fd = -1;
+               } else {
+                       if (oflag & O_CREAT) {
+                               va_list ap;
+                               mode_t mode;
+
+                               va_start(ap, oflag);
+                               mode = va_arg(ap, mode_t);
+
+                               fd = libv4l2_plugin->open(file, oflag, mode);
+
+                               va_end(ap);
+                       } else {
+                               fd = libv4l2_plugin->open(file, oflag, 0);
+                       }
+               }
+
+               if (fd != -1) {
+                       V4L2_LOG("PLUGIN: plugin open() returned %d\n", fd);
+                       pthread_mutex_lock(&v4l2_plugin_mutex);
+                       /* The plugin may have called libv4l2_set_plugindata()
+                          and there is already reserved slot with that fd */
+                       for (index = 0; index < V4L2_MAX_DEVICES; index++)
+                               if (plugins[index].fd == fd)
+                                       break;
+
+                       /* There is no such fd */
+                       if (index == V4L2_MAX_DEVICES)
+                               for (index = 0; index < V4L2_MAX_DEVICES; 
index++)
+                                       if (plugins[index].fd == -1)
+                                               break;
+
+                       plugins[index].fd = fd;
+                       plugins[index].plugin_library = plugin_library;
+                       plugins[index].libv4l2_plugin = libv4l2_plugin;
+                       for (i = 0; i < V4L2_MAX_NO_FRAMES; i++) {
+                               plugins[index].frame_pointers[i] = MAP_FAILED;
+                               plugins[index].frame_sizes[i] = 0;
+                       }
+                       pthread_mutex_unlock(&v4l2_plugin_mutex);
+                       break;
+               } else {
+                       V4L2_LOG("PLUGIN: plugin open() returned -1\n");
+                       dlclose(plugin_library);
+                       plugin_library = NULL;
+               }
+
+       }
+
+leave:
+       globfree(&globbuf);
+
+       if (fd == -1)
+               *plugin_used = 0;
+       else
+               *plugin_used = 1;
+
+       return fd;
+}
+
+int v4l2_plugin_close(int *plugin_used, int fd)
+{
+       int index, result = -1;
+       void *plugin_library = NULL;
+       struct libv4l2_plugin_data *libv4l2_plugin = NULL;
+
+       pthread_mutex_lock(&v4l2_plugin_mutex);
+       for (index = 0; index < V4L2_MAX_DEVICES; index++)
+               if (plugins[index].fd == fd) {
+                       plugin_library = plugins[index].plugin_library;
+                       libv4l2_plugin = plugins[index].libv4l2_plugin;
+                       break;
+               }
+       pthread_mutex_unlock(&v4l2_plugin_mutex);
+
+       if (index == V4L2_MAX_DEVICES) {
+               *plugin_used = 0;
+       } else {
+               if (libv4l2_plugin->close == NULL) {
+                       *plugin_used = 0;
+               } else {
+                       result = libv4l2_plugin->close(fd);
+                       *plugin_used = 1;
+               }
+
+               dlclose(plugin_library);
+
+               pthread_mutex_lock(&v4l2_plugin_mutex);
+               plugins[index].fd = -1;
+               pthread_mutex_unlock(&v4l2_plugin_mutex);
+       }
+
+       return result;
+}
+
+int v4l2_plugin_ioctl(int *plugin_used, int fd, unsigned long int request, ...)
+{
+       void *arg;
+       va_list ap;
+       int index, result = -1;
+       void *plugin_library = NULL;
+       struct libv4l2_plugin_data *libv4l2_plugin = NULL;
+
+       pthread_mutex_lock(&v4l2_plugin_mutex);
+       for (index = 0; index < V4L2_MAX_DEVICES; index++)
+               if (plugins[index].fd == fd) {
+                       plugin_library = plugins[index].plugin_library;
+                       libv4l2_plugin = plugins[index].libv4l2_plugin;
+                       break;
+               }
+       pthread_mutex_unlock(&v4l2_plugin_mutex);
+
+       if (index == V4L2_MAX_DEVICES || libv4l2_plugin->ioctl == NULL) {
+               *plugin_used = 0;
+       } else {
+               va_start(ap, request);
+               arg = va_arg(ap, void *);
+               va_end(ap);
+
+               result = libv4l2_plugin->ioctl(fd, request, arg);
+               *plugin_used = 1;
+       }
+
+       return result;
+}
+
+ssize_t v4l2_plugin_read(int *plugin_used, int fd, void *dest, size_t n)
+{
+       int index, result = -1;
+       void *plugin_library = NULL;
+       struct libv4l2_plugin_data *libv4l2_plugin = NULL;
+
+       pthread_mutex_lock(&v4l2_plugin_mutex);
+       for (index = 0; index < V4L2_MAX_DEVICES; index++)
+               if (plugins[index].fd == fd) {
+                       plugin_library = plugins[index].plugin_library;
+                       libv4l2_plugin = plugins[index].libv4l2_plugin;
+                       break;
+               }
+       pthread_mutex_unlock(&v4l2_plugin_mutex);
+
+       if (index == V4L2_MAX_DEVICES || libv4l2_plugin->read == NULL) {
+               *plugin_used = 0;
+       } else {
+               result = libv4l2_plugin->read(fd, dest, n);
+               *plugin_used = 1;
+       }
+
+       return result;
+}
+
+void *v4l2_plugin_mmap(int *plugin_used, void *start, size_t length, int prot,
+                                       int flags, int fd, int64_t offset)
+{
+       int index, i;
+       void *result = NULL;
+       void *plugin_library = NULL;
+       struct libv4l2_plugin_data *libv4l2_plugin = NULL;
+
+       pthread_mutex_lock(&v4l2_plugin_mutex);
+       for (index = 0; index < V4L2_MAX_DEVICES; index++)
+               if (plugins[index].fd == fd) {
+                       plugin_library = plugins[index].plugin_library;
+                       libv4l2_plugin = plugins[index].libv4l2_plugin;
+                       break;
+               }
+
+       if (fd == -1 || index == V4L2_MAX_DEVICES
+               || libv4l2_plugin->mmap == NULL) {
+               *plugin_used = 0;
+       } else {
+               for (i = 0; i < V4L2_MAX_NO_FRAMES; i++)
+                       if (plugins[index].frame_pointers[i] == MAP_FAILED)
+                               break;
+
+               if (i == V4L2_MAX_NO_FRAMES) {
+                       *plugin_used = 0;
+                       result = NULL;
+                       goto leave;
+               }
+
+               result = libv4l2_plugin->mmap(start, length, prot,
+                                               flags, fd, offset);
+               if (result) {
+                       plugins[index].frame_pointers[i] = result;
+                       plugins[index].frame_sizes[i] = length;
+                       *plugin_used = 1;
+               } else {
+                       *plugin_used = 0;
+               }
+       }
+
+leave:
+       pthread_mutex_unlock(&v4l2_plugin_mutex);
+
+       return result;
+}
+
+int v4l2_plugin_munmap(int *plugin_used, void *_start, size_t length)
+{
+       int index, map, result = 0;
+       void *plugin_library = NULL;
+       struct libv4l2_plugin_data *libv4l2_plugin = NULL;
+
+       pthread_mutex_lock(&v4l2_plugin_mutex);
+       for (index = 0; index < V4L2_MAX_DEVICES; index++) {
+               for (map = 0; map < V4L2_MAX_NO_FRAMES; map++) {
+                       if (plugins[index].frame_pointers[map] == _start &&
+                               plugins[index].frame_sizes[map] == length) {
+
+                               plugin_library = plugins[index].plugin_library;
+                               libv4l2_plugin = plugins[index].libv4l2_plugin;
+                               plugins[index].frame_pointers[map] = MAP_FAILED;
+                               plugins[index].frame_sizes[map] = 0;
+                               break;
+                       }
+               }
+               if (plugin_library)
+                       break;
+       }
+
+       if (plugin_library) {
+               result = libv4l2_plugin->munmap(_start, length);
+
+               if (result)
+                       *plugin_used = 0;
+               else
+                       *plugin_used = 1;
+
+       } else {
+               *plugin_used = 0;
+       }
+
+       pthread_mutex_unlock(&v4l2_plugin_mutex);
+
+       return result;
+}
+
+LIBV4L_PUBLIC void libv4l2_set_plugindata(int fd, void *plugin_data)
+{
+       int index;
+
+       pthread_mutex_lock(&v4l2_plugin_mutex);
+       for (index = 0; index < V4L2_MAX_DEVICES; index++)
+               if (plugins[index].fd == fd)
+                       break;
+
+       /* We have no info about this fd - reserve an empty slot */
+       if (index == V4L2_MAX_DEVICES) {
+               for (index = 0; index < V4L2_MAX_DEVICES; index++)
+                       if (plugins[index].fd == -1)
+                               break;
+       }
+       pthread_mutex_unlock(&v4l2_plugin_mutex);
+
+       if (index == V4L2_MAX_DEVICES) {
+               V4L2_LOG_ERR("store private data for more than %d plugins\n",
+                       V4L2_MAX_DEVICES);
+               return;
+       }
+
+       pthread_mutex_lock(&v4l2_plugin_mutex);
+       plugins[index].fd = fd;
+       plugins[index].plugin_data = plugin_data;
+       pthread_mutex_unlock(&v4l2_plugin_mutex);
+}
+
+LIBV4L_PUBLIC void *libv4l2_get_plugindata(int fd)
+{
+       int index;
+       void *result = NULL;
+
+       pthread_mutex_lock(&v4l2_plugin_mutex);
+       for (index = 0; index < V4L2_MAX_DEVICES; index++)
+               if (plugins[index].fd == fd) {
+                       result = plugins[index].plugin_data;
+                       break;
+               }
+       pthread_mutex_unlock(&v4l2_plugin_mutex);
+
+       return result;
+}
diff --git a/lib/libv4l2/v4l2convert.c b/lib/libv4l2/v4l2convert.c
index e251085..9f28490 100644
--- a/lib/libv4l2/v4l2convert.c
+++ b/lib/libv4l2/v4l2convert.c
@@ -31,6 +31,7 @@
 #include "../libv4lconvert/libv4lsyscall-priv.h"
 #include <linux/videodev2.h>
 #include <libv4l2.h>
+#include "libv4l2-plugin.h"
 
 /* Check that open/read/mmap is not a define */
 #if defined open || defined read || defined mmap
@@ -45,10 +46,27 @@
 
 LIBV4L_PUBLIC int open(const char *file, int oflag, ...)
 {
-       int fd;
+       int fd, plugin_used;
        struct v4l2_capability cap;
        int v4l_device = 0;
 
+       if (oflag & O_CREAT) {
+               va_list ap;
+               mode_t mode;
+
+               va_start(ap, oflag);
+               mode = va_arg(ap, mode_t);
+
+               fd = v4l2_plugin_open(&plugin_used, file, oflag, mode);
+
+               va_end(ap);
+       } else {
+               fd = v4l2_plugin_open(&plugin_used, file, oflag, 0);
+       }
+
+       if (plugin_used)
+               return fd;
+
        /* check if we're opening a video4linux2 device */
        if (!strncmp(file, "/dev/video", 10) || !strncmp(file, "/dev/v4l/", 9)) 
{
                /* Some apps open the device read only, but we need rw rights 
as the
-- 
1.7.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to