使用 Python 的 ctypes 库中的 Windows 本机 API 进行网络摄像头捕获的代码未按预期工作

问题描述 投票:0回答:1

所以我尝试在Python中捕获网络摄像头快照ctypes,这是代码:

import ctypes
from ctypes import wintypes

def CaptureWebcam(index: int, filePath: str) -> bool:
    avicap32 = ctypes.windll.avicap32
    WS_CHILD = 0x40000000
    WM_CAP_DRIVER_CONNECT = 0x0400 + 10
    WM_CAP_DRIVER_DISCONNECT = 0x0402
    WM_CAP_FILE_SAVEDIB = 0x0400 + 100 + 25

    hcam = avicap32.capCreateCaptureWindowW(
        wintypes.LPWSTR("Blank"),
        WS_CHILD,
        0, 0, 0, 0,
        ctypes.windll.user32.GetDesktopWindow(), 0
    )

    result = False

    if hcam:
        if ctypes.windll.user32.SendMessageA(hcam, WM_CAP_DRIVER_CONNECT, index, 0):
            if ctypes.windll.user32.SendMessageA(hcam, WM_CAP_FILE_SAVEDIB, 0, wintypes.LPWSTR(filePath)):
                result = True
            ctypes.windll.user32.SendMessageA(hcam, WM_CAP_DRIVER_DISCONNECT, 0, 0)
        ctypes.windll.user32.DestroyWindow(hcam)
    
    return result

然而,当我跑到这里时,正在发生的事情;

我的网络摄像头的 LED 指示灯亮起,这意味着脚本正在访问我的网络摄像头,但它正在将一个空文件(0 字节)保存到磁盘中,并且该函数返回 False。

python c ctypes
1个回答
0
投票

最佳实践是为每个函数完全定义

.argtypes
.restype
,并且不要混合 A 和 W 版本的 API。

请注意,HWND 在 64 位系统上是 64 位值。

.restype
默认为
c_int
,因此较大的值可能会被截断。

我没有网络摄像头,但下面是我通过挖掘 Windows SDK 标头并完全遵循定义而使用的(未经测试)。 尝试一下吧。

import ctypes as ct
import ctypes.wintypes as w

WS_CHILD = 0x40000000
WM_USER = 0x400
WM_CAP_START = WM_USER
WM_CAP_DRIVER_CONNECT = WM_CAP_START + 10
WM_CAP_DRIVER_DISCONNECT = WM_CAP_START + 11
WM_CAP_UNICODE_START = WM_USER + 100
WM_CAP_FILE_SAVEDIBW = WM_CAP_UNICODE_START + 25

LRESULT = LONG_PTR = ct.c_ssize_t

avicap32 = ct.WinDLL('avicap32', use_last_error=True)
capCreateCaptureWindowW = avicap32.capCreateCaptureWindowW
capCreateCaptureWindowW.argtypes = w.LPCWSTR, w.DWORD, ct.c_int, ct.c_int, ct.c_int, ct.c_int, w.HWND, ct.c_int
capCreateCaptureWindowW.restype = w.HWND

user32 = ct.WinDLL('user32')
GetDesktopWindow = user32.GetDesktopWindow
GetDesktopWindow.argtypes = ()
GetDesktopWindow.restype = w.HWND
SendMessageW = user32.SendMessageW
SendMessageW.argtypes = w.HWND, w.UINT, w.WPARAM, w.LPARAM
SendMessageW.restype = LRESULT
DestroyWindow = user32.DestroyWindow
DestroyWindow.argtypes = w.HWND,
DestroyWindow.restype = w.BOOL
IsWindow = user32.IsWindow
IsWindow.argtypes = w.HWND,
IsWindow.restype = w.BOOL

def AVICapSM(hwnd, m, w, l):
    return SendMessageW(hwnd, m, w, l) if IsWindow(hwnd) else 0

def capFileSaveDIB(hwnd, szName):
    return AVICapSM(hwnd, WM_CAP_FILE_SAVEDIBW, 0, szName)

def capDriverConnect(hwnd, i):
    return AVICapSM(hwnd, WM_CAP_DRIVER_CONNECT, i, 0)

def capDriverDisconnect(hwnd):
    return AVICapSM(hwnd, WM_CAP_DRIVER_DISCONNECT, 0, 0)

def CaptureWebcam(index, filePath):
    hcam = capCreateCaptureWindowW('Blank', WS_CHILD, 0, 0, 0, 0, GetDesktopWindow(), 0)
    result = False
    if hcam:
        if capDriverConnect(hwnd, 0):
            result = capFileSaveDIB(filePath)
            capDriveDisconnect(hwnd)
        DestroyWindow(hcam)
    return result
© www.soinside.com 2019 - 2024. All rights reserved.