Signed-off-by: Zebediah Figura zfigura@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 */
From: Gijs Vermeulen gijsvrm@gmail.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=38011 Signed-off-by: Gijs Vermeulen gijsvrm@gmail.com Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- Resent with some changes I noticed while rebasing:
* pass the right module instance to RegisterClass() and CreateWindow() * don't pass style flags as the extended style parameters * tweak code style a bit
dlls/avicap32/Makefile.in | 1 + dlls/avicap32/avicap32_main.c | 76 +++++++++++++++++++++++++++-------- 2 files changed, 61 insertions(+), 16 deletions(-)
diff --git a/dlls/avicap32/Makefile.in b/dlls/avicap32/Makefile.in index a899a6207b0..b74c4726e8b 100644 --- a/dlls/avicap32/Makefile.in +++ b/dlls/avicap32/Makefile.in @@ -1,5 +1,6 @@ MODULE = avicap32.dll IMPORTLIB = avicap32 +IMPORTS = user32 EXTRALIBS = -Wl,--subsystem,unixlib
EXTRADLLFLAGS = -mno-cygwin diff --git a/dlls/avicap32/avicap32_main.c b/dlls/avicap32/avicap32_main.c index d4608138d8b..3ce9d5240b8 100644 --- a/dlls/avicap32/avicap32_main.c +++ b/dlls/avicap32/avicap32_main.c @@ -30,37 +30,74 @@
WINE_DEFAULT_DEBUG_CHANNEL(avicap);
+static HINSTANCE avicap_instance; static unixlib_handle_t unix_handle;
+static const WCHAR class_name[] = L"wine_avicap_class"; + +static LRESULT CALLBACK avicap_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + switch (msg) + { + default: + if (msg >= WM_CAP_START && msg <= WM_CAP_END) + FIXME("Unhandled message %#x.\n", msg); + return DefWindowProcW(hwnd, msg, wparam, lparam); + } +} + +static void register_class(void) +{ + WNDCLASSEXW class = + { + .cbSize = sizeof(WNDCLASSEXW), + .lpfnWndProc = avicap_wndproc, + .hInstance = avicap_instance, + .hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW), + .hbrBackground = (HBRUSH)(COLOR_BTNFACE+1), + .lpszClassName = class_name, + }; + + if (!RegisterClassExW(&class) && GetLastError() != ERROR_CLASS_ALREADY_EXISTS) + ERR("Failed to register class, error %u.\n", GetLastError()); +} + +static void unregister_class(void) +{ + if (!UnregisterClassW(class_name, avicap_instance) && GetLastError() != ERROR_CLASS_DOES_NOT_EXIST) + ERR("Failed to unregister class, error %u.\n", GetLastError()); +} + /*********************************************************************** * capCreateCaptureWindowW (AVICAP32.@) */ -HWND VFWAPI capCreateCaptureWindowW(LPCWSTR lpszWindowName, DWORD dwStyle, INT x, - INT y, INT nWidth, INT nHeight, HWND hWnd, - INT nID) +HWND VFWAPI capCreateCaptureWindowW(const WCHAR *window_name, DWORD style, + int x, int y, int width, int height, HWND parent, int id) { - FIXME("(%s, %08x, %08x, %08x, %08x, %08x, %p, %08x): stub\n", - debugstr_w(lpszWindowName), dwStyle, x, y, nWidth, nHeight, hWnd, nID); - return 0; + TRACE("window_name %s, style %#x, x %d, y %d, width %d, height %d, parent %p, id %#x.\n", + debugstr_w(window_name), style, x, y, width, height, parent, id); + + return CreateWindowW(class_name, window_name, style, x, y, width, height, parent, NULL, avicap_instance, NULL); }
/*********************************************************************** * capCreateCaptureWindowA (AVICAP32.@) */ -HWND VFWAPI capCreateCaptureWindowA(LPCSTR lpszWindowName, DWORD dwStyle, INT x, - INT y, INT nWidth, INT nHeight, HWND hWnd, - INT nID) -{ UNICODE_STRING nameW; - HWND retW; +HWND VFWAPI capCreateCaptureWindowA(const char *window_name, DWORD style, + int x, int y, int width, int height, HWND parent, int id) +{ + UNICODE_STRING nameW; + HWND window;
- if (lpszWindowName) RtlCreateUnicodeStringFromAsciiz(&nameW, lpszWindowName); - else nameW.Buffer = NULL; + if (window_name) + RtlCreateUnicodeStringFromAsciiz(&nameW, window_name); + else + nameW.Buffer = NULL;
- retW = capCreateCaptureWindowW(nameW.Buffer, dwStyle, x, y, nWidth, nHeight, - hWnd, nID); + window = capCreateCaptureWindowW(nameW.Buffer, style, x, y, width, height, parent, id); RtlFreeUnicodeString(&nameW);
- return retW; + return window; }
/*********************************************************************** @@ -105,6 +142,13 @@ BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) NtQueryVirtualMemory(GetCurrentProcess(), instance, MemoryWineUnixFuncs, &unix_handle, sizeof(unix_handle), NULL); DisableThreadLibraryCalls(instance); + register_class(); + avicap_instance = instance; + break; + + case DLL_PROCESS_DETACH: + if (!reserved) + unregister_class(); break; }