|
@@ -177,13 +177,16 @@ class DahuaSDK:
|
|
|
不同平台/版本的SDK可能缺少部分函数,用可选绑定处理:
|
|
不同平台/版本的SDK可能缺少部分函数,用可选绑定处理:
|
|
|
- 必需函数:缺失则初始化失败
|
|
- 必需函数:缺失则初始化失败
|
|
|
- 可选函数:缺失时设为None,运行时检查可用性
|
|
- 可选函数:缺失时设为None,运行时检查可用性
|
|
|
|
|
+
|
|
|
|
|
+ 注意: 在 Linux 上 BOOL = int (4 bytes),不是 Windows 上的 bool (1 byte)
|
|
|
|
|
+ 所有返回 BOOL 的函数使用 c_int 作为返回值类型
|
|
|
"""
|
|
"""
|
|
|
|
|
|
|
|
# === 必需函数 ===
|
|
# === 必需函数 ===
|
|
|
|
|
|
|
|
- # CLIENT_Init(BOOL (CALLBACK *cbDisConnect), LDWORD)
|
|
|
|
|
|
|
+ # CLIENT_Init(BOOL (CALLBACK *cbDisConnect), LDWORD) -> BOOL
|
|
|
self.sdk.CLIENT_Init.argtypes = [ctypes.c_void_p, c_long]
|
|
self.sdk.CLIENT_Init.argtypes = [ctypes.c_void_p, c_long]
|
|
|
- self.sdk.CLIENT_Init.restype = ctypes.c_bool
|
|
|
|
|
|
|
+ self.sdk.CLIENT_Init.restype = c_int # BOOL = int on Linux
|
|
|
|
|
|
|
|
# CLIENT_Cleanup()
|
|
# CLIENT_Cleanup()
|
|
|
self.sdk.CLIENT_Cleanup.argtypes = []
|
|
self.sdk.CLIENT_Cleanup.argtypes = []
|
|
@@ -196,9 +199,9 @@ class DahuaSDK:
|
|
|
]
|
|
]
|
|
|
self.sdk.CLIENT_LoginWithHighLevelSecurity.restype = c_long
|
|
self.sdk.CLIENT_LoginWithHighLevelSecurity.restype = c_long
|
|
|
|
|
|
|
|
- # CLIENT_Logout(LLONG)
|
|
|
|
|
|
|
+ # CLIENT_Logout(LLONG) -> BOOL
|
|
|
self.sdk.CLIENT_Logout.argtypes = [c_long]
|
|
self.sdk.CLIENT_Logout.argtypes = [c_long]
|
|
|
- self.sdk.CLIENT_Logout.restype = ctypes.c_bool
|
|
|
|
|
|
|
+ self.sdk.CLIENT_Logout.restype = c_int # BOOL = int on Linux
|
|
|
|
|
|
|
|
# CLIENT_RealPlay(LLONG, int, void*) -> LLONG
|
|
# CLIENT_RealPlay(LLONG, int, void*) -> LLONG
|
|
|
self.sdk.CLIENT_RealPlay.argtypes = [c_long, c_int, ctypes.c_void_p]
|
|
self.sdk.CLIENT_RealPlay.argtypes = [c_long, c_int, ctypes.c_void_p]
|
|
@@ -206,17 +209,19 @@ class DahuaSDK:
|
|
|
|
|
|
|
|
# CLIENT_StopRealPlay(LLONG) -> BOOL
|
|
# CLIENT_StopRealPlay(LLONG) -> BOOL
|
|
|
self.sdk.CLIENT_StopRealPlay.argtypes = [c_long]
|
|
self.sdk.CLIENT_StopRealPlay.argtypes = [c_long]
|
|
|
- self.sdk.CLIENT_StopRealPlay.restype = ctypes.c_bool
|
|
|
|
|
|
|
+ self.sdk.CLIENT_StopRealPlay.restype = c_int # BOOL = int on Linux
|
|
|
|
|
|
|
|
- # CLIENT_DHPTZControlEx(LLONG, int, DWORD, LONG, LONG, LONG, BOOL)
|
|
|
|
|
|
|
+ # CLIENT_DHPTZControlEx(LLONG, int, DWORD, LONG, LONG, LONG, BOOL) -> BOOL
|
|
|
|
|
+ # 注意: 在 Linux 上 BOOL = int (4 bytes),不是 Windows 上的 bool
|
|
|
|
|
+ # 使用 c_int 而不是 c_bool 以确保参数大小正确
|
|
|
self.sdk.CLIENT_DHPTZControlEx.argtypes = [
|
|
self.sdk.CLIENT_DHPTZControlEx.argtypes = [
|
|
|
- c_long, c_int, c_uint32, c_int, c_int, c_int, ctypes.c_bool
|
|
|
|
|
|
|
+ c_long, c_int, c_uint32, c_int, c_int, c_int, c_int
|
|
|
]
|
|
]
|
|
|
- self.sdk.CLIENT_DHPTZControlEx.restype = ctypes.c_bool
|
|
|
|
|
|
|
+ self.sdk.CLIENT_DHPTZControlEx.restype = c_int # BOOL = int on Linux
|
|
|
|
|
|
|
|
# CLIENT_SnapPicture(LLONG, SNAP_PARAMS*) -> BOOL
|
|
# CLIENT_SnapPicture(LLONG, SNAP_PARAMS*) -> BOOL
|
|
|
self.sdk.CLIENT_SnapPicture.argtypes = [c_long, POINTER(self.SNAP_PARAMS)]
|
|
self.sdk.CLIENT_SnapPicture.argtypes = [c_long, POINTER(self.SNAP_PARAMS)]
|
|
|
- self.sdk.CLIENT_SnapPicture.restype = ctypes.c_bool
|
|
|
|
|
|
|
+ self.sdk.CLIENT_SnapPicture.restype = c_int # BOOL = int on Linux
|
|
|
|
|
|
|
|
# CLIENT_GetLastError() -> DWORD
|
|
# CLIENT_GetLastError() -> DWORD
|
|
|
self.sdk.CLIENT_GetLastError.argtypes = []
|
|
self.sdk.CLIENT_GetLastError.argtypes = []
|
|
@@ -227,7 +232,7 @@ class DahuaSDK:
|
|
|
|
|
|
|
|
self._bind_optional('CLIENT_SetSnapRevCallBack', [ctypes.c_void_p, c_long], None)
|
|
self._bind_optional('CLIENT_SetSnapRevCallBack', [ctypes.c_void_p, c_long], None)
|
|
|
self._bind_optional('CLIENT_RealPlayEx', [c_long, c_int, ctypes.c_void_p, c_int], c_long)
|
|
self._bind_optional('CLIENT_RealPlayEx', [c_long, c_int, ctypes.c_void_p, c_int], c_long)
|
|
|
- self._bind_optional('CLIENT_StopRealPlayEx', [c_long], ctypes.c_bool)
|
|
|
|
|
|
|
+ self._bind_optional('CLIENT_StopRealPlayEx', [c_long], c_int) # BOOL = int on Linux
|
|
|
self._bind_optional('CLIENT_SetVideoProcCallBack', [ctypes.c_void_p, c_long], None)
|
|
self._bind_optional('CLIENT_SetVideoProcCallBack', [ctypes.c_void_p, c_long], None)
|
|
|
|
|
|
|
|
def _bind_optional(self, name: str, argtypes: list, restype):
|
|
def _bind_optional(self, name: str, argtypes: list, restype):
|
|
@@ -262,13 +267,16 @@ class DahuaSDK:
|
|
|
|
|
|
|
|
if disconnect_callback:
|
|
if disconnect_callback:
|
|
|
# 保存回调引用,防止被垃圾回收
|
|
# 保存回调引用,防止被垃圾回收
|
|
|
|
|
+ # 回调签名: BOOL (CALLBACK *cbDisConnect)(LLONG lLoginID, char *pchDVRIP, LONG nDVRPort, LDWORD dwUser)
|
|
|
|
|
+ # 在 Linux 上 BOOL = int,所以使用 c_int 作为返回值类型
|
|
|
self._disconnect_callback = ctypes.CFUNCTYPE(
|
|
self._disconnect_callback = ctypes.CFUNCTYPE(
|
|
|
- ctypes.c_bool, c_long, c_char_p, c_int, c_long
|
|
|
|
|
|
|
+ c_int, c_long, c_char_p, c_int, c_long
|
|
|
)(disconnect_callback)
|
|
)(disconnect_callback)
|
|
|
|
|
|
|
|
result = self.sdk.CLIENT_Init(self._disconnect_callback, 0)
|
|
result = self.sdk.CLIENT_Init(self._disconnect_callback, 0)
|
|
|
- self.initialized = result
|
|
|
|
|
- return result
|
|
|
|
|
|
|
+ # SDK 返回 TRUE(非0) 表示成功
|
|
|
|
|
+ self.initialized = (result != 0)
|
|
|
|
|
+ return self.initialized
|
|
|
|
|
|
|
|
def cleanup(self):
|
|
def cleanup(self):
|
|
|
"""清理SDK资源"""
|
|
"""清理SDK资源"""
|
|
@@ -314,7 +322,8 @@ class DahuaSDK:
|
|
|
"""登出设备"""
|
|
"""登出设备"""
|
|
|
if not self.sdk or login_handle <= 0:
|
|
if not self.sdk or login_handle <= 0:
|
|
|
return False
|
|
return False
|
|
|
- return self.sdk.CLIENT_Logout(login_handle)
|
|
|
|
|
|
|
+ result = self.sdk.CLIENT_Logout(login_handle)
|
|
|
|
|
+ return result != 0 # SDK 返回 TRUE(非0) 表示成功
|
|
|
|
|
|
|
|
def real_play(self, login_handle: int, channel: int = 0) -> Optional[int]:
|
|
def real_play(self, login_handle: int, channel: int = 0) -> Optional[int]:
|
|
|
"""
|
|
"""
|
|
@@ -374,7 +383,8 @@ class DahuaSDK:
|
|
|
"""停止实时预览"""
|
|
"""停止实时预览"""
|
|
|
if not self.sdk or play_handle <= 0:
|
|
if not self.sdk or play_handle <= 0:
|
|
|
return False
|
|
return False
|
|
|
- return self.sdk.CLIENT_StopRealPlay(play_handle)
|
|
|
|
|
|
|
+ result = self.sdk.CLIENT_StopRealPlay(play_handle)
|
|
|
|
|
+ return result != 0 # SDK 返回 TRUE(非0) 表示成功
|
|
|
|
|
|
|
|
def ptz_control(self, login_handle: int, channel: int,
|
|
def ptz_control(self, login_handle: int, channel: int,
|
|
|
command: int, param1: int, param2: int, param3: int,
|
|
command: int, param1: int, param2: int, param3: int,
|
|
@@ -404,18 +414,24 @@ class DahuaSDK:
|
|
|
}
|
|
}
|
|
|
cmd_name = cmd_names.get(command, f'CMD_{command:#x}')
|
|
cmd_name = cmd_names.get(command, f'CMD_{command:#x}')
|
|
|
|
|
|
|
|
|
|
+ # 将 stop (bool) 转换为 int (TRUE=1, FALSE=0),匹配 Linux SDK 的 BOOL 定义
|
|
|
|
|
+ stop_int = 1 if stop else 0
|
|
|
|
|
+
|
|
|
result = self.sdk.CLIENT_DHPTZControlEx(
|
|
result = self.sdk.CLIENT_DHPTZControlEx(
|
|
|
- login_handle, channel, command, param1, param2, param3, stop
|
|
|
|
|
|
|
+ login_handle, channel, command, param1, param2, param3, stop_int
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
- print(f"[PTZ] {cmd_name}(ch={channel}, p1={param1}, p2={param2}, p3={param3}, stop={stop}) → {'✓' if result else '✗'}")
|
|
|
|
|
|
|
+ # SDK 返回 TRUE(非0) 表示成功,FALSE(0) 表示失败
|
|
|
|
|
+ success = (result != 0)
|
|
|
|
|
+
|
|
|
|
|
+ print(f"[PTZ] {cmd_name}(ch={channel}, p1={param1}, p2={param2}, p3={param3}, stop={stop}) → {'✓' if success else '✗'} (ret={result})")
|
|
|
|
|
|
|
|
- if not result:
|
|
|
|
|
|
|
+ if not success:
|
|
|
# 获取SDK错误码
|
|
# 获取SDK错误码
|
|
|
error = self.sdk.CLIENT_GetLastError() if hasattr(self.sdk, 'CLIENT_GetLastError') else -1
|
|
error = self.sdk.CLIENT_GetLastError() if hasattr(self.sdk, 'CLIENT_GetLastError') else -1
|
|
|
print(f"[PTZ] 错误码: {error}")
|
|
print(f"[PTZ] 错误码: {error}")
|
|
|
|
|
|
|
|
- return result
|
|
|
|
|
|
|
+ return success
|
|
|
|
|
|
|
|
def snap_picture(self, login_handle: int, channel: int = 0,
|
|
def snap_picture(self, login_handle: int, channel: int = 0,
|
|
|
cmd_serial: int = 0) -> bool:
|
|
cmd_serial: int = 0) -> bool:
|
|
@@ -439,7 +455,8 @@ class DahuaSDK:
|
|
|
params.Quality = 1
|
|
params.Quality = 1
|
|
|
params.PicFormat = 0 # BMP
|
|
params.PicFormat = 0 # BMP
|
|
|
|
|
|
|
|
- return self.sdk.CLIENT_SnapPicture(login_handle, byref(params))
|
|
|
|
|
|
|
+ result = self.sdk.CLIENT_SnapPicture(login_handle, byref(params))
|
|
|
|
|
+ return result != 0 # SDK 返回 TRUE(非0) 表示成功
|
|
|
|
|
|
|
|
|
|
|
|
|
# PTZ控制命令常量 (从dhnetsdk.h提取)
|
|
# PTZ控制命令常量 (从dhnetsdk.h提取)
|