[vlc-devel] [PATCH] Support for alternative libv4l2 library (userspace drivers)
Rémi Denis-Courmont
remi at remlab.net
Fri Aug 1 17:30:02 CEST 2014
Lo,
Le 2014-07-31 22:01, Markus Rechberger a écrit :
> Attached patch adds support to access our userspace USB TV Tuner
> drivers (the analogTV part - S-Video / Composite and AnalogTV)
> directly via our interface library.
> That way VLC would also be able to access our driver interface on
> MacOSX, FreeBSD and Solaris.
Hmm? FreeBSD perhaps, but I don't think VLC has the V4L plugin on MacOS
nor Solaris.
> It is fully compatible with the official V4L2 API, the patch will
> have
> no effect on existing V4L2 devices.
If it were fully compatible, then it would intrinscally not need such a
patch, so that is a bit misleading statement. In fact, I do not surmise
why your library is not hooked as a proper libv4l2 plugin, which would
*then* be fully compatible.
Further...
diff --git a/modules/access/v4l2/lib.c b/modules/access/v4l2/lib.c
index cf2b480..46057c5 100644
--- a/modules/access/v4l2/lib.c
+++ b/modules/access/v4l2/lib.c
@@ -25,6 +25,8 @@
#include <pthread.h>
#include <dlfcn.h>
#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
@@ -34,6 +36,7 @@
static void *v4l2_handle = NULL;
static int (*v4l2_fd_open_) (int, int);
+static int (*v4l2_open_direct) (__const char *__file, int __oflag,
...);
Identifiers with leading underscore are reserved.
int (*v4l2_close) (int);
int (*v4l2_ioctl) (int, unsigned long int, ...);
ssize_t (*v4l2_read) (int, void *, size_t);
@@ -46,6 +49,87 @@ static int fd_open (int fd, int flags)
return fd;
}
+static int v4l2_check_socket() {
Incomplete prototype. This is not C++.
+ int fd;
+ char *buf=NULL;
+ int buflen=0;
+ int nread;
+ char rbuf[10240];
+ int rv;
+ struct stat statbuf;
+
+ const char *sockpath="@/de/sundtek/mediasocket";
+
+ /* FreeBSD, Solaris, MacOSX */
+ rv = stat("/tmp/.mediasocket", &statbuf);
+ if (rv == 0)
+ return 0;
Looks very much like a TOCTOU race.
Ditto for the procfs check.
+
+ fd = open("/proc/net/unix", O_RDONLY);
Missing close-on-exec.
+ if (fd >= 0) {
+ while ((nread=read(fd, rbuf, 10240))>0) {
+ buf = (char*)realloc(buf, buflen+nread+1);
Unchecked NULL return.
+ memcpy(&buf[buflen], rbuf, nread);
+ buflen+=nread;
+ }
+ buf[buflen]=0;
+ if (strstr(buf, sockpath)) {
Reinventing the square wheel. There are fopen() and getline() for this.
+ free(buf);
+ close(fd);
+ return 0;
+ }
+ close(fd);
+ free(buf);
+ }
+ return -1;
+}
+
+static int v4l2_net_open (char *path) {
+ void *h;
+ int fd;
+
+ h = dlopen ("libmcsimple.so", RTLD_LAZY | RTLD_LOCAL);
+ if (h == NULL) {
+ /* this is the default driver location */
+ h = dlopen("/opt/lib/libmcsimple.so", RTLD_LAZY | RTLD_LOCAL);
From a quick glance, that library is not reentrant.
+ if (h == NULL)
+ goto fallback;
+ }
+ /* no need for that one */
+ v4l2_open_direct = dlsym (h, "net_open");
+ v4l2_close = dlsym (h, "net_close");
+ v4l2_ioctl = dlsym (h, "net_ioctl");
+ v4l2_read = dlsym (h, "__net_read");
+ v4l2_mmap = dlsym (h, "net_mmap");
+ v4l2_munmap = dlsym (h, "net_munmap");
This breaks reentrancy and the memory model.
The reast of the assumes that the back-end library is constant
throughout the lifetime of the process.
+
+ if (v4l2_open_direct != NULL && v4l2_close != NULL && v4l2_ioctl
!= NULL
+ && v4l2_read != NULL && v4l2_mmap != NULL && v4l2_munmap != NULL)
+ {
+ v4l2_handle = h;
+ fd = v4l2_open_direct(path, O_RDWR);
+ if (fd == -1) {
+ v4l2_handle = NULL;
+ dlclose(h);
+ return -1;
+ } else {
+ return fd;
+ }
+ }
+
+ dlclose (h);
+fallback:
+ return -1;
+}
+
+int v4l2_check_device(char *path) {
+ int sk;
+ sk = v4l2_check_socket();
+ if (sk == 0)
+ return v4l2_net_open (path);
+ return -1;
+}
+
static void v4l2_lib_load (void)
{
void *h = dlopen ("libv4l2.so.0", RTLD_LAZY | RTLD_LOCAL);
diff --git a/modules/access/v4l2/v4l2.c b/modules/access/v4l2/v4l2.c
index 7807a8a..beb95d9 100644
--- a/modules/access/v4l2/v4l2.c
+++ b/modules/access/v4l2/v4l2.c
@@ -466,21 +466,29 @@ int OpenDevice (vlc_object_t *obj, const char
*path, uint32_t *restrict caps)
{
msg_Dbg (obj, "opening device '%s'", path);
- int rawfd = vlc_open (path, O_RDWR);
- if (rawfd == -1)
- {
- msg_Err (obj, "cannot open device '%s': %s", path,
- vlc_strerror_c(errno));
- return -1;
- }
-
- int fd = v4l2_fd_open (rawfd, 0);
- if (fd == -1)
- {
- msg_Warn (obj, "cannot initialize user-space library: %s",
- vlc_strerror_c(errno));
- /* fallback to direct kernel mode anyway */
- fd = rawfd;
+ int rawfd;
+ int fd;
+
+ fd = v4l2_check_device(path);
I don't really get why this should override even the normal existing
V4L devices.
+
+ if (fd == -1) {
+
+ rawfd = vlc_open (path, O_RDWR);
+ if (rawfd == -1)
+ {
+ msg_Err (obj, "cannot open device '%s': %s", path,
+ vlc_strerror_c(errno));
+ return -1;
+ }
+
+ fd = v4l2_fd_open (rawfd, 0);
+ if (fd == -1)
+ {
+ msg_Warn (obj, "cannot initialize user-space library: %s",
+ vlc_strerror_c(errno));
+ /* fallback to direct kernel mode anyway */
+ fd = rawfd;
+ }
}
/* Get device capabilites */
diff --git a/modules/access/v4l2/v4l2.h b/modules/access/v4l2/v4l2.h
index 9888785..da28519 100644
--- a/modules/access/v4l2/v4l2.h
+++ b/modules/access/v4l2/v4l2.h
@@ -22,6 +22,7 @@
/* libv4l2 functions */
extern int v4l2_fd_open (int, int);
+extern int v4l2_check_device(char *path);
extern int (*v4l2_close) (int);
extern int (*v4l2_ioctl) (int, unsigned long int, ...);
extern ssize_t (*v4l2_read) (int, void *, size_t);
--
Rémi Denis-Courmont
More information about the vlc-devel
mailing list