Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
There's a good chance that we'll want to move v4l handling to a kernel streaming
infrastructure, which is the main reason I hadn't bothered converting avicap32
yet, but I'm not likely to get the time to do that research in the near future.
dlls/avicap32/Makefile.in | 7 +-
dlls/avicap32/avicap32_main.c | 135 +++++++--------------------------
dlls/avicap32/unixlib.h | 33 ++++++++
dlls/avicap32/v4l.c | 137 ++++++++++++++++++++++++++++++++++
4 files changed, 201 insertions(+), 111 deletions(-)
create mode 100644 dlls/avicap32/unixlib.h
create mode 100644 dlls/avicap32/v4l.c
diff --git a/dlls/avicap32/Makefile.in b/dlls/avicap32/Makefile.in
index 8f5a1089d5c..a899a6207b0 100644
--- a/dlls/avicap32/Makefile.in
+++ b/dlls/avicap32/Makefile.in
@@ -1,4 +1,9 @@
MODULE = avicap32.dll
IMPORTLIB = avicap32
+EXTRALIBS = -Wl,--subsystem,unixlib
-C_SRCS = avicap32_main.c
+EXTRADLLFLAGS = -mno-cygwin
+
+C_SRCS = \
+ avicap32_main.c \
+ v4l.c
diff --git a/dlls/avicap32/avicap32_main.c b/dlls/avicap32/avicap32_main.c
index 9e2a99d4c7c..d4608138d8b 100644
--- a/dlls/avicap32/avicap32_main.c
+++ b/dlls/avicap32/avicap32_main.c
@@ -17,45 +17,20 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
-#include "config.h"
-#include "wine/port.h"
-
#include <stdarg.h>
-#include <stdio.h>
-#include <fcntl.h>
-#ifdef HAVE_SYS_IOCTL_H
-# include <sys/ioctl.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
-# include <sys/stat.h>
-#endif
-#include <errno.h>
-#ifdef HAVE_SYS_TIME_H
-# include <sys/time.h>
-#endif
-#ifdef HAVE_ASM_TYPES_H
-# include <asm/types.h>
-#endif
-#ifdef HAVE_LINUX_VIDEODEV2_H
-# include <linux/videodev2.h>
-#endif
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "vfw.h"
-#include "winnls.h"
#include "winternl.h"
#include "wine/debug.h"
-#define CAP_DESC_MAX 32
+#include "unixlib.h"
WINE_DEFAULT_DEBUG_CHANNEL(avicap);
+static unixlib_handle_t unix_handle;
/***********************************************************************
* capCreateCaptureWindowW (AVICAP32.@)
@@ -88,81 +63,6 @@ HWND VFWAPI capCreateCaptureWindowA(LPCSTR lpszWindowName, DWORD dwStyle, INT x,
return retW;
}
-#ifdef HAVE_LINUX_VIDEODEV2_H
-
-static int xioctl(int fd, int request, void * arg)
-{
- int r;
-
- do r = ioctl (fd, request, arg);
- while (-1 == r && EINTR == errno);
-
- return r;
-}
-
-static BOOL query_video_device(int devnum, char *name, int namesize, char *version, int versionsize)
-{
- int fd;
- char device[16];
- struct stat st;
- struct v4l2_capability caps;
-
- snprintf(device, sizeof(device), "/dev/video%i", devnum);
-
- if (stat (device, &st) == -1) {
- /* This is probably because the device does not exist */
- WARN("%s: %s\n", device, strerror(errno));
- return FALSE;
- }
-
- if (!S_ISCHR (st.st_mode)) {
- ERR("%s: Not a device\n", device);
- return FALSE;
- }
-
- fd = open(device, O_RDWR | O_NONBLOCK);
- if (fd == -1) {
- ERR("%s: Failed to open: %s\n", device, strerror(errno));
- return FALSE;
- }
-
- memset(&caps, 0, sizeof(caps));
- if (xioctl(fd, VIDIOC_QUERYCAP, &caps) != -1) {
- BOOL isCaptureDevice;
-#ifdef V4L2_CAP_DEVICE_CAPS
- if (caps.capabilities & V4L2_CAP_DEVICE_CAPS)
- isCaptureDevice = caps.device_caps & V4L2_CAP_VIDEO_CAPTURE;
- else
-#endif
- isCaptureDevice = caps.capabilities & V4L2_CAP_VIDEO_CAPTURE;
- if (isCaptureDevice) {
- lstrcpynA(name, (char *)caps.card, namesize);
- snprintf(version, versionsize, "%s v%u.%u.%u", (char *)caps.driver, (caps.version >> 16) & 0xFF,
- (caps.version >> 8) & 0xFF, caps.version & 0xFF);
- }
- close(fd);
- return isCaptureDevice;
- }
-
- if (errno != EINVAL && errno != 515)
-/* errno 515 is used by some webcam drivers for unknown IOICTL command */
- ERR("%s: Querying failed: %s\n", device, strerror(errno));
- else ERR("%s: Querying failed: Not a V4L compatible device\n", device);
-
- close(fd);
- return FALSE;
-}
-
-#else /* HAVE_LINUX_VIDEODEV2_H */
-
-static BOOL query_video_device(int devnum, char *name, int namesize, char *version, int versionsize)
-{
- ERR("Video 4 Linux support not enabled\n");
- return FALSE;
-}
-
-#endif /* HAVE_LINUX_VIDEODEV2_H */
-
/***********************************************************************
* capGetDriverDescriptionA (AVICAP32.@)
*/
@@ -183,15 +83,30 @@ BOOL VFWAPI capGetDriverDescriptionA(WORD wDriverIndex, LPSTR lpszName,
/***********************************************************************
* capGetDriverDescriptionW (AVICAP32.@)
*/
-BOOL VFWAPI capGetDriverDescriptionW(WORD wDriverIndex, LPWSTR lpszName,
- INT cbName, LPWSTR lpszVer, INT cbVer)
+BOOL VFWAPI capGetDriverDescriptionW(WORD index, WCHAR *name, int name_len, WCHAR *version, int version_len)
{
- char devname[CAP_DESC_MAX], devver[CAP_DESC_MAX];
+ struct get_device_desc_params params;
- if (!query_video_device(wDriverIndex, devname, CAP_DESC_MAX, devver, CAP_DESC_MAX)) return FALSE;
+ params.index = index;
+ if (__wine_unix_call(unix_handle, unix_get_device_desc, ¶ms))
+ return FALSE;
- MultiByteToWideChar(CP_UNIXCP, 0, devname, -1, lpszName, cbName);
- MultiByteToWideChar(CP_UNIXCP, 0, devver, -1, lpszVer, cbVer);
- TRACE("Version: %s - Name: %s\n", debugstr_w(lpszVer), debugstr_w(lpszName));
- return TRUE;
+ TRACE("Found device name %s, version %s.\n", debugstr_w(params.name), debugstr_w(params.version));
+ lstrcpynW(name, params.name, name_len);
+ lstrcpynW(version, params.version, version_len);
+ return TRUE;
+}
+
+BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved)
+{
+ switch (reason)
+ {
+ case DLL_PROCESS_ATTACH:
+ NtQueryVirtualMemory(GetCurrentProcess(), instance,
+ MemoryWineUnixFuncs, &unix_handle, sizeof(unix_handle), NULL);
+ DisableThreadLibraryCalls(instance);
+ break;
+ }
+
+ return TRUE;
}
diff --git a/dlls/avicap32/unixlib.h b/dlls/avicap32/unixlib.h
new file mode 100644
index 00000000000..89ef1cc93f9
--- /dev/null
+++ b/dlls/avicap32/unixlib.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2021 Zebediah Figura for CodeWeavers
+ *
+ * This library 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 library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "wine/unixlib.h"
+
+#define CAP_DESC_MAX 32
+
+struct get_device_desc_params
+{
+ WORD index;
+ WCHAR name[CAP_DESC_MAX];
+ WCHAR version[CAP_DESC_MAX];
+};
+
+enum unix_funcs
+{
+ unix_get_device_desc,
+};
diff --git a/dlls/avicap32/v4l.c b/dlls/avicap32/v4l.c
new file mode 100644
index 00000000000..ab2694ae041
--- /dev/null
+++ b/dlls/avicap32/v4l.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2002 Dmitry Timoshkov for CodeWeavers
+ * Copyright 2005 Maarten Lankhorst
+ *
+ * This library 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 library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#if 0
+#pragma makedep unix
+#endif
+
+#include "config.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <unistd.h>
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef HAVE_LINUX_VIDEODEV2_H
+# include <linux/videodev2.h>
+#endif
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "windef.h"
+#include "winternl.h"
+#include "wine/debug.h"
+
+#include "unixlib.h"
+
+#ifdef HAVE_LINUX_VIDEODEV2_H
+
+WINE_DEFAULT_DEBUG_CHANNEL(avicap);
+
+static int xioctl(int fd, int request, void *arg)
+{
+ int ret;
+
+ do
+ ret = ioctl(fd, request, arg);
+ while (ret < 0 && errno == EINTR);
+
+ return ret;
+}
+
+static void v4l_umbstowcs(const char *src, DWORD srclen, WCHAR *dst, DWORD dstlen)
+{
+ DWORD ret = ntdll_umbstowcs(src, srclen, dst, dstlen - 1);
+
+ dst[ret] = 0;
+}
+
+static NTSTATUS get_device_desc(void *args)
+{
+ struct get_device_desc_params *params = args;
+ struct v4l2_capability caps = {{0}};
+ char device[16];
+ struct stat st;
+ int fd;
+
+ snprintf(device, sizeof(device), "/dev/video%u", params->index);
+
+ if (stat(device, &st) < 0)
+ {
+ /* This is probably because the device does not exist */
+ WARN("Failed to stat %s: %s\n", device, strerror(errno));
+ return STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ if (!S_ISCHR(st.st_mode))
+ {
+ ERR("%s is not a character device.\n", device);
+ return STATUS_OBJECT_TYPE_MISMATCH;
+ }
+
+ if ((fd = open(device, O_RDWR | O_NONBLOCK)) < 0)
+ {
+ ERR("%s: Failed to open: %s\n", device, strerror(errno));
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ if (!xioctl(fd, VIDIOC_QUERYCAP, &caps))
+ {
+ BOOL is_capture_device;
+#ifdef V4L2_CAP_DEVICE_CAPS
+ if (caps.capabilities & V4L2_CAP_DEVICE_CAPS)
+ is_capture_device = caps.device_caps & V4L2_CAP_VIDEO_CAPTURE;
+ else
+#endif
+ is_capture_device = caps.capabilities & V4L2_CAP_VIDEO_CAPTURE;
+ if (is_capture_device)
+ {
+ char version[CAP_DESC_MAX];
+ int ret;
+
+ v4l_umbstowcs((char *)caps.card, strlen((char *)caps.card),
+ params->name, ARRAY_SIZE(params->name));
+
+ ret = snprintf(version, ARRAY_SIZE(version), "%s v%u.%u.%u", (char *)caps.driver,
+ (caps.version >> 16) & 0xff, (caps.version >> 8) & 0xff, caps.version & 0xff);
+ v4l_umbstowcs(version, ret, params->version, ARRAY_SIZE(params->version));
+ }
+ close(fd);
+ return is_capture_device;
+ }
+
+ /* errno 515 is used by some webcam drivers for unknown IOCTL commands. */
+ ERR("Failed to get capabilities for %s: %s\n", device, strerror(errno));
+
+ close(fd);
+ return FALSE;
+}
+
+const unixlib_entry_t __wine_unix_call_funcs[] =
+{
+ get_device_desc,
+};
+
+#endif /* HAVE_LINUX_VIDEODEV_2 */
--
2.33.0