前言

最近开始使用python学习海康sdk,进行海康摄像头的开发,很多都需要获取设备能力集,在网上搜索了一圈,发现python端没人写,于是自己写了一下,我会在最后直接给源码的,下面是我思考的过程,本人小白,如果有一些不对的还请指正

ctypes总结

要想学习海康sdk,ctypes肯定少不了,python开发中,都是基于ctypes来使用的.看这篇文章之前,建议先去学习ctypes。下面是我编写过程中总结的一些问题

1.传参问题

func = sdkTest.NET_DVR_GetDeviceAbility  #从动态链接库中导出函数
func.argtypes = (c_int8,c_int8,c_char_p,c_int,c_char_p,c_int32)  #设置函数参数类型()
func.restype = c_bool  # 设置返回值类型为 float

当你要调用动态链接库函数的时候,大多数都会用到这3行代码,这些代码可以确定你传参的类型,但是,这三句其实可以不用写的,你可以单纯根据函数所需要的参数,最后直接带入就可以了,这样可以避免后面你传参时,出现传参数据类型对不上的问题。

2.输入输出指针缓存区

在使用ctypes的时候,海康sdk设备开发手册中最多的就是指针缓存区,下面是我的定义

输入缓存区

#传输的xml数据可根据需求修改
str_byte = bytes(
                 '<?xml version="1.0" encoding="utf-8"?>'
                 '<VcaCtrlAbility  version = "2.0">'
                 '<channelNO>1</channelNO>' 
                 '</VcaCtrlAbility >',encoding="utf-8")
pInBuf = cast(str_byte, c_char_p) 

输出缓存区

M1 = 8 * 1024
pOutBuf = (c_char_p * M1)() #c_char_p类型的指针数组的缓存区

3.数据类型问题

在使用ctypes的时候,调用动态链接库时,数据类型的转换也是一个问题,当你不知道这是什么数据类型的时候,你打开电脑终端(cmd),输入下面代码,就可以看你想看的数据类型啦,非常的方便!

python
from ctypes import *
type(x) 

源码

import os
import platform
from HCNetSDK import *
import ctypes

# 系统环境标识
WINDOWS_FLAG = True

# 获取当前系统环境
def GetPlatform():
    sysstr = platform.system()
    if sysstr != "Windows":
        global WINDOWS_FLAG
        WINDOWS_FLAG = False


# 设置SDK初始化依赖库路径
def SetSDKInitCfg():
    # 设置HCNetSDKCom组件库和SSL库加载路径
    if WINDOWS_FLAG:
        strPath = os.getcwd().encode('gbk')
        sdk_ComPath = NET_DVR_LOCAL_SDK_PATH()
        sdk_ComPath.sPath = strPath
        sdkTest.NET_DVR_SetSDKInitCfg(2, byref(sdk_ComPath))
        sdkTest.NET_DVR_SetSDKInitCfg(3, create_string_buffer(strPath + b'\libcrypto-1_1-x64.dll'))
        sdkTest.NET_DVR_SetSDKInitCfg(4, create_string_buffer(strPath + b'\libssl-1_1-x64.dll'))
    else:
        strPath = os.getcwd().encode('utf-8')
        sdk_ComPath = NET_DVR_LOCAL_SDK_PATH()
        sdk_ComPath.sPath = strPath
        sdkTest.NET_DVR_SetSDKInitCfg(2, byref(sdk_ComPath))
        sdkTest.NET_DVR_SetSDKInitCfg(3, create_string_buffer(strPath + b'/libcrypto.so.1.1'))
        sdkTest.NET_DVR_SetSDKInitCfg(4, create_string_buffer(strPath + b'/libssl.so.1.1'))


def LoginDev():
    # 设备登录信息
    struLoginInfo = NET_DVR_USER_LOGIN_INFO()
    struLoginInfo.bUseAsynLogin = 0  # 同步登录方式
    struLoginInfo.sDeviceAddress = bytes("192.168.1.64", "ascii")  # 设备IP地址
    struLoginInfo.wPort = 8000  # 设备服务端口
    struLoginInfo.sUserName = bytes("admin", "ascii")  # 设备登录用户名
    struLoginInfo.sPassword = bytes("gac13579", "ascii")  # 设备登录密码

    # 设备信息, 输出参数
    struDeviceInfoV40 = NET_DVR_DEVICEINFO_V40()

    # 登录设备
    iUserID = sdkTest.NET_DVR_Login_V40(byref(struLoginInfo), byref(struDeviceInfoV40))
    if iUserID < 0:
        print('登录失败, 错误码: %d' % sdkTest.NET_DVR_GetLastError())
    else:
        print('登录成功,设备序列号:%s' % str(struDeviceInfoV40.struDeviceV30.sSerialNumber, encoding="utf8").rstrip('\x00'))
    return iUserID


# 登出设备
def logoutDev(lUserID):
    if lUserID >= 0:
        # 注销用户
        sdkTest.NET_DVR_Logout(lUserID)
        # 释放SDK资源
        sdkTest.NET_DVR_Cleanup()


def Get_ability(iUserID):
    #func = sdkTest.NET_DVR_GetDeviceAbility  #从动态链接库中导出函数
    #func.argtypes = (c_int8,c_int8,c_char_p,c_int,c_char_p,c_int32)  #设置函数参数类型()
    #func.restype = c_bool  # 设置返回值类型为 float

# 声明参数

    dwAbilityType = 0x011

    dwOutLength = c_int32(8 * 1024)



    # 参数赋值
    '''
    < ?xmlversion = "1.0"encoding = "utf-8"? >
    < !--req, 获取智能通道分析能力时pInBuf参数描述 -->
    < VcaChanAbility version = "2.0" >
    < channelNO > 1 < / channelNO >
    < !--req, 通道号 -->
    < / VcaChanAbility >
    '''

    str_byte = bytes(
                     '<?xml version="1.0" encoding="utf-8"?>'
                     '<VcaCtrlAbility  version = "2.0">'
                     '<channelNO>1</channelNO>' 
                     '</VcaCtrlAbility >',encoding="utf-8")


    dwInLength = len(str_byte)
    pInBuf = cast(str_byte, c_char_p) #数据类型为c_char_p指针
    #byref(pInBuf)  #数据类型为_ctypes.CArgObject

    M1 = 8 * 1024
    pOutBuf = (c_char_p * M1)()



    ret =                     sdkTest.NET_DVR_GetDeviceAbility(iUserID,dwAbilityType,pInBuf,dwInLength,byref(pOutBuf),dwOutLength)
    
    if ret == 1:
        print('---获取成功---')
        # 获取成功,输出结果
        Bbytes_Out = string_at(pOutBuf, dwOutLength.value)
        strOutput = str(Bbytes_Out, 'UTF-8')
        print(strOutput.replace("\x00", ""))
    else:
        print('NET_DVR_STDXMLConfig接口调用失败,错误码:%d,登录句柄:%d' % (sdkTest.NET_DVR_GetLastError(), iUserID))




if __name__ == '__main__':
    # 获取系统平台
    GetPlatform()

    # 加载库,先加载依赖库
    if WINDOWS_FLAG:
        os.chdir(r'./lib')
        sdkTest = ctypes.CDLL(r'./HCNetSDK.dll')
    else:
        os.chdir(r'./lib')
        sdkTest = cdll.LoadLibrary(r'./libhcnetsdk.so')

    SetSDKInitCfg()  # 设置组件库和SSL库加载路径
    # 初始化
    sdkTest.NET_DVR_Init()
    # 启用SDK写日志
    sdkTest.NET_DVR_SetLogToFile(3, bytes('../SdkLog_Python/', encoding="utf-8"), False)

    # 注册登录设备
    iUserID = LoginDev()
    print('userid = %d' %iUserID)
    if iUserID < 0:
        print('登录失败,退出')
    else:
        Get_ability(iUserID)

    # 退出程序前,登出设备,释放sdk资源
    logoutDev(iUserID)

结语

谢谢大家观看完这篇文章,因为第一次搞海康sdk和python,前前后后也是花费了几天(报错改了2天哈哈哈哈),最后希望这个篇文章对大家有帮助。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐