* Froe 1678f1f41284ad9665de8717b7b8be117ddf9596 Mon Sep 17 00:00:00 2001
@ 2011-05-03 15:26 Yordan Kamenov
[not found] ` <cover.1304435825.git.ykamenov@mm-sol.com>
0 siblings, 1 reply; 7+ messages in thread
From: Yordan Kamenov @ 2011-05-03 15:26 UTC (permalink / raw)
To: hdegoede; +Cc: linux-media, sakari.ailus
Hi Hans,
here is the fourth version of plugin support for libv4l2.
Changes in v4:
* Make close() callback void
* Move plugin clean up where the actual fd gets closed
* Use SYS_FOO in default device operations instead of syscall()
--------------------------------------------------------------------------
Changes in v3:
* Pass opened fd to the plugin instead of filename
* Plugin private data is returned by init call and is passed as argument
in ioctl/read/close (remove libv4l2_set/get_plugindata functions)
* Plugin do not handle mmap/munmap
--------------------------------------------------------------------------
Changes in v2:
* Remove calls of v4l2_plugin_foo functions in the beginning of coresponding
v4l2_foo functions and instead replace SYS_FOO calls.
* Add to v4l2_dev_info device operation structure which can hold plugin
callbacks or dyrect syscall(SYS_foo, ...) calls.
* Under libv4lconvert also replace SYS_FOO cals with device operations. This
required also to add dev_ops field to v4lconvert_data and v4lcontrol_data.
---------------------------------------------------------------------------
v1:
Here is initial version of plugin support for libv4l, based on your RFC.
It is provided by functions v4l2_plugin_[open,close,etc]. When open() is
called libv4l dlopens files in /usr/lib/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_* functions indicate by their first
argument if plugin was used, and if it was not then v4l2_* functions proceed
Yordan Kamenov (1):
Add plugin support to libv4l
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
--
1.7.3.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v4 1/1] libv4l: Add plugin support to libv4l
[not found] ` <cover.1304435825.git.ykamenov@mm-sol.com>
@ 2011-05-03 15:26 ` Yordan Kamenov
2011-05-05 14:04 ` Hans de Goede
2011-07-17 21:00 ` Hans de Goede
0 siblings, 2 replies; 7+ messages in thread
From: Yordan Kamenov @ 2011-05-03 15:26 UTC (permalink / raw)
To: hdegoede; +Cc: linux-media, sakari.ailus, Yordan Kamenov
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:
--
1.7.3.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v4 1/1] libv4l: Add plugin support to libv4l
2011-05-03 15:26 ` [PATCH v4 1/1] libv4l: Add plugin support to libv4l Yordan Kamenov
@ 2011-05-05 14:04 ` Hans de Goede
2011-07-17 21:00 ` Hans de Goede
1 sibling, 0 replies; 7+ messages in thread
From: Hans de Goede @ 2011-05-05 14:04 UTC (permalink / raw)
To: Yordan Kamenov; +Cc: linux-media, sakari.ailus
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:
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v4 1/1] libv4l: Add plugin support to libv4l
2011-05-03 15:26 ` [PATCH v4 1/1] libv4l: Add plugin support to libv4l Yordan Kamenov
2011-05-05 14:04 ` Hans de Goede
@ 2011-07-17 21:00 ` Hans de Goede
2011-07-22 15:39 ` Yordan Kamenov
1 sibling, 1 reply; 7+ messages in thread
From: Hans de Goede @ 2011-07-17 21:00 UTC (permalink / raw)
To: Yordan Kamenov; +Cc: linux-media, sakari.ailus
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:
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v4 1/1] libv4l: Add plugin support to libv4l
2011-07-17 21:00 ` Hans de Goede
@ 2011-07-22 15:39 ` Yordan Kamenov
2011-07-24 17:36 ` Hans de Goede
0 siblings, 1 reply; 7+ messages in thread
From: Yordan Kamenov @ 2011-07-22 15:39 UTC (permalink / raw)
To: Hans de Goede; +Cc: linux-media, sakari.ailus
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:
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v4 1/1] libv4l: Add plugin support to libv4l
2011-07-22 15:39 ` Yordan Kamenov
@ 2011-07-24 17:36 ` Hans de Goede
2011-07-26 19:05 ` Sakari Ailus
0 siblings, 1 reply; 7+ messages in thread
From: Hans de Goede @ 2011-07-24 17:36 UTC (permalink / raw)
To: Yordan Kamenov; +Cc: linux-media, sakari.ailus
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
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v4 1/1] libv4l: Add plugin support to libv4l
2011-07-24 17:36 ` Hans de Goede
@ 2011-07-26 19:05 ` Sakari Ailus
0 siblings, 0 replies; 7+ messages in thread
From: Sakari Ailus @ 2011-07-26 19:05 UTC (permalink / raw)
To: Hans de Goede; +Cc: Yordan Kamenov, linux-media, sakari.ailus
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! :-)
--
Sakari Ailus
sakari.ailus@iki.fi
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2011-07-26 19:05 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-05-03 15:26 Froe 1678f1f41284ad9665de8717b7b8be117ddf9596 Mon Sep 17 00:00:00 2001 Yordan Kamenov
[not found] ` <cover.1304435825.git.ykamenov@mm-sol.com>
2011-05-03 15:26 ` [PATCH v4 1/1] libv4l: Add plugin support to libv4l Yordan Kamenov
2011-05-05 14:04 ` Hans de Goede
2011-07-17 21:00 ` Hans de Goede
2011-07-22 15:39 ` Yordan Kamenov
2011-07-24 17:36 ` Hans de Goede
2011-07-26 19:05 ` Sakari Ailus
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.