--- /dev/null
+/*
+* 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
status messages to a file, when NULL errors will get send to stderr */
LIBV4L_PUBLIC extern FILE *v4l2_log_file;
+/* For apps which want to directly use libv4lconvert, but don't want to
+ define their own device ops. Apps which do this call v4lconvert_create
+ with NULL as dev_ops_priv and this as dev_ops parameter */
+LIBV4L_PUBLIC extern const struct libv4l2_dev_ops libv4l2_default_dev_ops;
+
/* Just like your regular open/close/etc, except that format conversion is
done if necessary when capturing. That is if you (try to) set a capture
format which is not supported by the cam, but is supported by libv4lconvert,
#include <linux/videodev2.h>
+#include "libv4l2-plugin.h"
+
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
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, const struct libv4l2_dev_ops *dev_ops);
LIBV4L_PUBLIC void v4lconvert_destroy(struct v4lconvert_data *data);
/* When doing flipping / rotating / video-processing, only supported
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
override CPPFLAGS += -fPIC
endif
+override CPPFLAGS += -DLIBDIR='"$(LIBDIR)"'
+
# This is the soname version
LIB_RELEASE = 0
/* buffer when doing conversion and using read() for read() */
int readbuf_size;
unsigned char *readbuf;
+ /* plugin info */
+ void *plugin_library;
+ void *dev_ops_priv;
+ const struct libv4l2_dev_ops *dev_ops;
};
+/* From v4l2-plugin.c */
+void v4l2_plugin_init(int fd, void **plugin_lib_ret, void **plugin_priv_ret,
+ const struct libv4l2_dev_ops **dev_ops_ret);
+void v4l2_plugin_cleanup(void *plugin_lib, void *plugin_priv,
+ const struct libv4l2_dev_ops *dev_ops);
+
/* From log.c */
void v4l2_log_ioctl(unsigned long int request, void *arg, int result);
#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
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;
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);
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;
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;
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;
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;
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;
}
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;
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));
struct v4l2_format fmt;
struct v4l2_streamparm parm;
struct v4lconvert_data *convert;
+ void *plugin_library;
+ void *dev_ops_priv;
+ const struct libv4l2_dev_ops *dev_ops;
+
+ v4l2_plugin_init(fd, &plugin_library, &dev_ops_priv, &dev_ops);
/* If no log file was set by the app, see if one was specified through the
environment */
}
/* check that this is an v4l2 device */
- if (SYS_IOCTL(fd, VIDIOC_QUERYCAP, &cap)) {
+ if (dev_ops->ioctl(dev_ops_priv, fd, VIDIOC_QUERYCAP, &cap)) {
int saved_err = errno;
-
V4L2_LOG_ERR("getting capabilities: %s\n", strerror(errno));
+ v4l2_plugin_cleanup(plugin_library, dev_ops_priv, dev_ops);
errno = saved_err;
return -1;
}
/* 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_library, dev_ops_priv, 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(dev_ops_priv, fd, VIDIOC_G_FMT, &fmt)) {
int saved_err = errno;
-
V4L2_LOG_ERR("getting pixformat: %s\n", strerror(errno));
+ v4l2_plugin_cleanup(plugin_library, dev_ops_priv, dev_ops);
errno = saved_err;
return -1;
}
/* Check for framerate setting support */
parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- if (SYS_IOCTL(fd, VIDIOC_G_PARM, &parm))
+ if (dev_ops->ioctl(dev_ops_priv, fd, VIDIOC_G_PARM, &parm))
parm.type = 0;
/* init libv4lconvert */
- convert = v4lconvert_create(fd);
- if (!convert)
+ convert = v4lconvert_create(fd, dev_ops_priv, dev_ops);
+ if (!convert) {
+ int saved_err = errno;
+ v4l2_plugin_cleanup(plugin_library, dev_ops_priv, dev_ops);
+ errno = saved_err;
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++)
+ 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 = dev_ops_priv;
+ devices[index].dev_ops = dev_ops;
break;
}
+ }
pthread_mutex_unlock(&v4l2_open_mutex);
if (index == V4L2_MAX_DEVICES) {
V4L2_LOG_ERR("attempting to open more then %d video devices\n",
V4L2_MAX_DEVICES);
+ v4l2_plugin_cleanup(plugin_library, dev_ops_priv, dev_ops);
errno = EBUSY;
return -1;
}
if (index == -1)
return SYS_CLOSE(fd);
- /* Abuse stream_lock to stop 2 closes from racing and trying to free the
- resources twice */
+ /* Abuse stream_lock to stop 2 closes from racing and trying to free
+ the resources twice */
pthread_mutex_lock(&devices[index].stream_lock);
devices[index].open_count--;
result = devices[index].open_count != 0;
if (result)
return 0;
+ v4l2_plugin_cleanup(devices[index].plugin_library,
+ devices[index].dev_ops_priv,
+ devices[index].dev_ops);
+
/* Free resources */
v4l2_unmap_buffers(index);
if (devices[index].convert_mmap_buf != MAP_FAILED) {
}
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;
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,
+ fd, VIDIOC_QUERYCAP, cap);
if (result == 0)
/* We always support read() as we fake it using mmap mode */
cap->capabilities |= V4L2_CAP_READWRITE;
case VIDIOC_TRY_FMT:
if (devices[index].flags & V4L2_DISABLE_CONVERSION) {
- result = SYS_IOCTL(devices[index].fd, VIDIOC_TRY_FMT,
- arg);
+ result = devices[index].dev_ops->ioctl(
+ devices[index].dev_ops_priv,
+ fd, VIDIOC_TRY_FMT, arg);
} else {
result = v4lconvert_try_format(devices[index].convert,
arg, NULL);
}
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,
+ fd, VIDIOC_TRY_FMT, dest_fmt);
src_fmt = *dest_fmt;
} else {
result = v4lconvert_try_format(devices[index].convert, dest_fmt,
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,
+ fd, VIDIOC_S_FMT, &src_fmt);
if (result) {
saved_err = errno;
V4L2_LOG_ERR("setting pixformat: %s\n", strerror(errno));
struct v4l2_streamparm parm = {
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
};
- if (SYS_IOCTL(fd, VIDIOC_G_PARM, &parm) == 0)
- v4l2_update_fps(index, &parm);
+ if (devices[index].dev_ops->ioctl(
+ devices[index].dev_ops_priv,
+ fd, VIDIOC_G_PARM, &parm))
+ break;
+ v4l2_update_fps(index, &parm);
}
break;
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,
+ fd, VIDIOC_REQBUFS, req);
if (result < 0)
break;
result = 0; /* some drivers return the number of buffers on success */
/* 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,
+ fd, VIDIOC_QUERYBUF, buf);
if (result || !v4l2_needs_conversion(index))
break;
break;
}
- result = SYS_IOCTL(devices[index].fd, VIDIOC_QBUF, arg);
+ result = devices[index].dev_ops->ioctl(
+ devices[index].dev_ops_priv,
+ fd, VIDIOC_QBUF, arg);
break;
case VIDIOC_DQBUF: {
}
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,
+ fd, VIDIOC_DQBUF, buf);
if (result) {
int saved_err = errno;
v4l2_adjust_src_fmt_to_fps(index, fps);
}
- result = SYS_IOCTL(devices[index].fd, VIDIOC_S_PARM, parm);
+ result = devices[index].dev_ops->ioctl(
+ devices[index].dev_ops_priv,
+ fd, VIDIOC_S_PARM, parm);
if (result)
break;
}
default:
- result = SYS_IOCTL(fd, request, arg);
+ result = devices[index].dev_ops->ioctl(
+ devices[index].dev_ops_priv,
+ fd, request, arg);
break;
}
return;
req_pix_fmt = src_fmt.fmt.pix;
- if (SYS_IOCTL(devices[index].fd, VIDIOC_S_FMT, &src_fmt))
+ if (devices[index].dev_ops->ioctl(devices[index].dev_ops_priv,
+ devices[index].fd, VIDIOC_S_FMT, &src_fmt))
return;
v4l2_set_src_and_dest_format(index, &src_fmt, &dest_fmt);
src_fmt = orig_src_fmt;
dest_fmt = orig_dest_fmt;
req_pix_fmt = src_fmt.fmt.pix;
- if (SYS_IOCTL(devices[index].fd, VIDIOC_S_FMT, &src_fmt)) {
+ if (devices[index].dev_ops->ioctl(devices[index].dev_ops_priv,
+ devices[index].fd, VIDIOC_S_FMT, &src_fmt)) {
V4L2_LOG_ERR("restoring src fmt: %s\n", strerror(errno));
return;
}
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;
}
--- /dev/null
+/*
+* 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 LIBDIR "/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);
+}
+
+const struct libv4l2_dev_ops libv4l2_default_dev_ops = {
+ .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,
+ const struct libv4l2_dev_ops **dev_ops_ret)
+{
+ char *error;
+ int glob_ret, i;
+ void *plugin_library = NULL;
+ const struct libv4l2_dev_ops *libv4l2_plugin = NULL;
+ glob_t globbuf;
+
+ *dev_ops_ret = &libv4l2_default_dev_ops;
+ *plugin_lib_ret = NULL;
+ *plugin_priv_ret = NULL;
+
+ glob_ret = glob(PLUGINS_PATTERN, 0, NULL, &globbuf);
+
+ if (glob_ret == GLOB_NOSPACE)
+ return;
+
+ if (glob_ret == GLOB_ABORTED || glob_ret == GLOB_NOMATCH)
+ goto leave;
+
+ for (i = 0; i < globbuf.gl_pathc; i++) {
+ V4L2_LOG("PLUGIN: dlopen(%s);\n", globbuf.gl_pathv[i]);
+
+ plugin_library = dlopen(globbuf.gl_pathv[i], 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;
+ }
+
+ if (!libv4l2_plugin->init ||
+ !libv4l2_plugin->close ||
+ !libv4l2_plugin->ioctl ||
+ !libv4l2_plugin->read) {
+ V4L2_LOG("PLUGIN: does not have all functions\n");
+ dlclose(plugin_library);
+ continue;
+ }
+
+ *plugin_priv_ret = libv4l2_plugin->init(fd);
+ if (!*plugin_priv_ret) {
+ V4L2_LOG("PLUGIN: plugin open() returned NULL\n");
+ dlclose(plugin_library);
+ continue;
+ }
+
+ *plugin_lib_ret = plugin_library;
+ *dev_ops_ret = libv4l2_plugin;
+ break;
+ }
+
+leave:
+ globfree(&globbuf);
+}
+
+void v4l2_plugin_cleanup(void *plugin_lib, void *plugin_priv,
+ const struct libv4l2_dev_ops *dev_ops)
+{
+ if (plugin_lib) {
+ dev_ops->close(plugin_priv);
+ dlclose(plugin_lib);
+ }
+}
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 */
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);
#ifndef __LIBV4LCONTROL_PRIV_H
#define __LIBV4LCONTROL_PRIV_H
+#include "libv4l2-plugin.h"
+
#define V4LCONTROL_SHM_SIZE 4096
#define V4LCONTROL_SUPPORTS_NEXT_CTRL 0x01
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;
+ void *dev_ops_priv;
+ const struct libv4l2_dev_ops *dev_ops;
};
struct v4lcontrol_flags_info {
}
}
-struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion)
+struct v4lcontrol_data *v4lcontrol_create(int fd, void *dev_ops_priv,
+ const struct libv4l2_dev_ops *dev_ops, int always_needs_conversion)
{
int shm_fd;
int i, rc, got_usb_info, speed, init = 0;
}
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)
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
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);
- if (rc == -1 || (rc == 0 && (ctrl.flags & V4L2_CTRL_FLAG_DISABLED)))
+ 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;
}
}
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;
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;
}
}
/* 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)) {
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)
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_bandwidth(struct v4lcontrol_data *data)
#ifndef __LIBV4LCONTROL_H
#define __LIBV4LCONTROL_H
+#include "libv4l2-plugin.h"
+
/* Flags */
#define V4LCONTROL_HFLIPPED 0x01
#define V4LCONTROL_VFLIPPED 0x02
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,
+ const struct libv4l2_dev_ops *dev_ops, int always_needs_conversion);
void v4lcontrol_destroy(struct v4lcontrol_data *data);
int v4lcontrol_get_bandwidth(struct v4lcontrol_data *data);
unsigned char *convert_pixfmt_buf;
struct v4lcontrol_data *control;
struct v4lprocessing_data *processing;
+ void *dev_ops_priv;
+ const struct libv4l2_dev_ops *dev_ops;
/* Data for external decompression helpers code */
pid_t decompress_pid;
{ 176, 144 },
};
-struct v4lconvert_data *v4lconvert_create(int fd)
+struct v4lconvert_data *v4lconvert_create(int fd, void *dev_ops_priv,
+ const struct libv4l2_dev_ops *dev_ops)
{
int i, j;
struct v4lconvert_data *data = calloc(1, sizeof(struct v4lconvert_data));
}
data->fd = fd;
+ data->dev_ops = dev_ops;
+ data->dev_ops_priv = dev_ops_priv;
data->decompress_pid = -1;
data->fps = 30;
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++)
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;
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;
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) ||
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))
continue;
if (try_fmt.fmt.pix.pixelformat !=
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;
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 */
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) {
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;
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;
#include <sys/mman.h>
#include <errno.h>
#include <dirent.h>
+#include <libv4l2.h>
ApplicationWindow::ApplicationWindow() :
m_capture(NULL),
}
m_tabs->show();
m_tabs->setFocus();
- m_convertData = v4lconvert_create(fd());
+ m_convertData = v4lconvert_create(fd(), NULL,
+ &libv4l2_default_dev_ops);
m_capStartAct->setEnabled(fd() >= 0);
}