Table of contents
Let’s talk about the effect first. I used the real-time stream of AI inference, and the delay dropped from up to 7 seconds to less than 1 second.
If you feel that this delay is still unacceptable, in the next chapter, I will introduce you to a small way to get the best results.
SDK (Software Development Kit) is the abbreviation of Software Development Kit, which is a collection of tools, libraries and documents used to develop specific software or applications. The SDK provides the resources and interfaces required for development to help developers build applications more efficiently.
SDKs typically include the following:
- Tools: The SDK provides a series of development tools, such as compilers, debuggers, IDEs (integrated development environments), etc., for writing, debugging, and testing code.
- Libraries: Libraries in the SDK are pre-compiled, reusable code modules that contain common functions and algorithms. Developers can directly call these libraries to simplify the development process.
- Sample code: The SDK usually comes with some sample code to show how to use the functions and interfaces provided by the SDK to help developers get started quickly and understand the development process.
- Documentation: The SDK provides detailed documentation, including API reference, development guides, sample code explanations, etc., to help developers understand the functions and usage of the SDK.
- Dependencies: The SDK may need to depend on other software or libraries, such as operating systems, third-party libraries, etc. Developers need to meet these dependencies to use the SDK.
The role of the SDK is to simplify the development process, provide the resources and interfaces required for development, and save developers time and energy. By using the SDK, developers can quickly build feature-rich, efficient applications without having to write all the code and functionality from scratch.
1.python sdk use
In the past, python was often used to read USB cameras because its language style is easy to read and quick to get started. At first, when using rtsp stream to read Hikvision's network camera, the video screen will be delayed and stuck. If the real-time requirements are high (at least a frame rate equivalent to the web preview effect), use rtsp stream to read. It seems undesirable. This article adopts the method of calling HikVision’s SDK in python to read the IP camera. In terms of frame rate, the effect is equivalent to the network preview.
1. Download Hikvision SDK
After downloading and decompressing
Enter the following path
Hikvision-HCNetSDKV6.1.9.48_build20230410_win64---Demo example---5- Python development example---1-Preview stream decoding Demo
1. Find the lib path, it should be empty
You need to choose win or linux
2. Return to the main directory, select the library file, copy all the files (actually only part of the library files are required according to the official documentation, but you can package them all in a fool-proof way), and paste them into the win file in the lib folder above
The following are the operating instructions from the official documentation
1. When updating the device network SDK, HCNetSDK.dll, HCCore.dll, HCNetSDKCom folder, libssl-1_1.dll, libcrypto-1_1.dll, hlog.dll, hpr.dll, zlib1 in the SDK development package [library file] .dll, PlayCtrl.dll, SuperRender.dll, AudioRender.dll and other files must be loaded into the program. [HCNetSDKCom folder] (including the functional component dll library file inside) needs to be loaded together with HCNetSDK.dll and HCCore.dll. Place it in the same directory, and the HCNetSDKCom folder name cannot be modified.
2. If the self-developed software cannot properly implement the corresponding functions and the program does not specify the path to the loaded dll library, please try to delete HCNetSDK.dll while the program is running. If it can be deleted, it means that the program may call the dll file in the Windows->System32 directory of the system disk. It is recommended to delete or update the relevant dll files in this directory; if it cannot be deleted, right-click the dll file and select Properties to confirm the SDK library version.
3. If the corresponding function still cannot be implemented after following the above steps, please judge the reason based on the error number returned by NET_DVR_GetLastError.
3. Run test_main.py
Get real-time footage
2.opencv reads sdk stream
Paste the following code into the same directory as test_main.py
Just run
If you have any questions, please leave a message in the comment area
# coding=utf-8
import os
import platform
from HCNetSDK import *
from PlayCtrl import *
import numpy as np
import time
import cv2
class HKCam(object):
def __init__(self,camIP,username,password,devport=8000):
# 登录的设备信息
self.DEV_IP = create_string_buffer(camIP.encode())
self.DEV_PORT =devport
self.DEV_USER_NAME = create_string_buffer(username.encode())
self.DEV_PASSWORD = create_string_buffer(password.encode())
self.WINDOWS_FLAG = False if platform.system() != "Windows" else True
self.funcRealDataCallBack_V30 = None
self.recent_img = None #最新帧
self.n_stamp = None #帧时间戳
self.last_stamp = None #上次时间戳
# 加载库,先加载依赖库 # 1 根据操作系统,加载对应的dll文件
if self.WINDOWS_FLAG:
os.chdir(r'./lib/win')
self.Objdll = ctypes.CDLL(r'./HCNetSDK.dll') # 加载网络库
self.Playctrldll = ctypes.CDLL(r'./PlayCtrl.dll') # 加载播放库
else:
os.chdir(r'./lib/linux')
self.Objdll = cdll.LoadLibrary(r'./libhcnetsdk.so')
self.Playctrldll = cdll.LoadLibrary(r'./libPlayCtrl.so')
# 设置组件库和SSL库加载路径 # 2 设置组件库和SSL库加载路径
self.SetSDKInitCfg()
# 初始化DLL
self.Objdll.NET_DVR_Init() # 3 相机初始化
# 启用SDK写日志
self.Objdll.NET_DVR_SetLogToFile(3, bytes('./SdkLog_Python/', encoding="utf-8"), False)
os.chdir(r'../../') # 切换工作路径到../../
# 登录
(self.lUserId, self.device_info) = self.LoginDev() # 4 登录相机
self.Playctrldll.PlayM4_ResetBuffer(self.lUserId,1)#清空指定缓冲区的剩余数据。这个地方传进来的是self.lUserId,为什么呢?
print(self.lUserId)
if self.lUserId < 0:#登录失败
err = self.Objdll.NET_DVR_GetLastError()
print('Login device fail, error code is: %d' % self.Objdll.NET_DVR_GetLastError())
# 释放资源
self.Objdll.NET_DVR_Cleanup()
exit()
else:
print(f'摄像头[{camIP}]登录成功!!')
self.start_play() # 5 开始播放
time.sleep(1)
def start_play(self,):
#global funcRealDataCallBack_V30
self.PlayCtrl_Port = c_long(-1) # 播放句柄
# 获取一个播放句柄 #wuzh获取未使用的通道号
if not self.Playctrldll.PlayM4_GetPort(byref(self.PlayCtrl_Port)):
print(u'获取播放库句柄失败')
# 定义码流回调函数
self.funcRealDataCallBack_V30 = REALDATACALLBACK(self.RealDataCallBack_V30)
# 开启预览
self.preview_info = NET_DVR_PREVIEWINFO()
self.preview_info.hPlayWnd = 0
self.preview_info.lChannel = 1 # 通道号
self.preview_info.dwStreamType = 0 # 主码流
self.preview_info.dwLinkMode = 0 # TCP
self.preview_info.bBlocked = 1 # 阻塞取流
# 开始预览并且设置回调函数回调获取实时流数据
self.lRealPlayHandle = self.Objdll.NET_DVR_RealPlay_V40(self.lUserId, byref(self.preview_info), self.funcRealDataCallBack_V30, None)
if self.lRealPlayHandle < 0:
print ('Open preview fail, error code is: %d' %self. Objdll.NET_DVR_GetLastError())
# 登出设备
self.Objdll.NET_DVR_Logout(self.lUserId)
# 释放资源
self.Objdll.NET_DVR_Cleanup()
exit()
def SetSDKInitCfg(self,):
# 设置SDK初始化依赖库路径
# 设置HCNetSDKCom组件库和SSL库加载路径
# print(os.getcwd())
if self.WINDOWS_FLAG:
strPath = os.getcwd().encode('gbk')
sdk_ComPath = NET_DVR_LOCAL_SDK_PATH()
sdk_ComPath.sPath = strPath
self.Objdll.NET_DVR_SetSDKInitCfg(2, byref(sdk_ComPath))
self.Objdll.NET_DVR_SetSDKInitCfg(3, create_string_buffer(strPath + b'\libcrypto-1_1-x64.dll'))
self.Objdll.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
self.Objdll.NET_DVR_SetSDKInitCfg(2, byref(sdk_ComPath))
self.Objdll.NET_DVR_SetSDKInitCfg(3, create_string_buffer(strPath + b'/libcrypto.so.1.1'))
self.Objdll.NET_DVR_SetSDKInitCfg(4, create_string_buffer(strPath + b'/libssl.so.1.1'))
def LoginDev(self,):
# 登录注册设备
device_info = NET_DVR_DEVICEINFO_V30()
lUserId = self.Objdll.NET_DVR_Login_V30(self.DEV_IP, self.DEV_PORT, self.DEV_USER_NAME, self.DEV_PASSWORD, byref(device_info))
return (lUserId, device_info)
def read(self,):
while self.n_stamp==self.last_stamp:
continue
self.last_stamp=self.n_stamp
return self.n_stamp,self.recent_img
def DecCBFun(self,nPort, pBuf, nSize, pFrameInfo, nUser, nReserved2):
if pFrameInfo.contents.nType == 3:
t0 = time.time()
# 解码返回视频YUV数据,将YUV数据转成jpg图片保存到本地
# 如果有耗时处理,需要将解码数据拷贝到回调函数外面的其他线程里面处理,避免阻塞回调导致解码丢帧
nWidth = pFrameInfo.contents.nWidth
nHeight = pFrameInfo.contents.nHeight
#nType = pFrameInfo.contents.nType
dwFrameNum = pFrameInfo.contents.dwFrameNum
nStamp = pFrameInfo.contents.nStamp
#print(nWidth, nHeight, nType, dwFrameNum, nStamp, sFileName)
YUV = np.frombuffer(pBuf[:nSize],dtype=np.uint8)
YUV = np.reshape(YUV,[nHeight+nHeight//2,nWidth])
img_rgb = cv2.cvtColor(YUV,cv2.COLOR_YUV2BGR_YV12)
self.recent_img,self.n_stamp = img_rgb,nStamp
def RealDataCallBack_V30(self,lPlayHandle, dwDataType, pBuffer, dwBufSize, pUser):
# 码流回调函数
if dwDataType == NET_DVR_SYSHEAD:
# 设置流播放模式
self.Playctrldll.PlayM4_SetStreamOpenMode(self.PlayCtrl_Port, 0)
# 打开码流,送入40字节系统头数据
if self.Playctrldll.PlayM4_OpenStream(self.PlayCtrl_Port, pBuffer, dwBufSize, 1024*1024):
# 设置解码回调,可以返回解码后YUV视频数据
#global FuncDecCB
self.FuncDecCB = DECCBFUNWIN(self.DecCBFun)
self.Playctrldll.PlayM4_SetDecCallBackExMend(self.PlayCtrl_Port, self.FuncDecCB, None, 0, None)
# 开始解码播放
if self.Playctrldll.PlayM4_Play(self.PlayCtrl_Port, None):
print(u'播放库播放成功')
else:
print(u'播放库播放失败')
else:
print(u'播放库打开流失败')
elif dwDataType == NET_DVR_STREAMDATA:
self.Playctrldll.PlayM4_InputData(self.PlayCtrl_Port, pBuffer, dwBufSize)
else:
print (u'其他数据,长度:', dwBufSize)
def release(self):
self.Objdll.NET_DVR_StopRealPlay(self.lRealPlayHandle)
if self.PlayCtrl_Port.value > -1:
self.Playctrldll.PlayM4_Stop(self.PlayCtrl_Port)
self.Playctrldll.PlayM4_CloseStream( self.PlayCtrl_Port)
self.Playctrldll.PlayM4_FreePort( self.PlayCtrl_Port)
PlayCtrl_Port = c_long(-1)
self.Objdll.NET_DVR_Logout(self.lUserId)
self.Objdll.NET_DVR_Cleanup()
print('释放资源结束')
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.release()
if __name__=="__main__":
camIP ='192.168.1.122'
#camIP ='192.168.3.157'
DEV_PORT = 8000
username ='admin'
password = 'admin'
HIK= HKCam(camIP,username,password)
last_stamp = 0
while True:
t0 =time.time()
n_stamp,img = HIK.read()
last_stamp=n_stamp
'''
TODO
'''
kkk = cv2.waitKey(1)
if kkk ==ord('q'):
break
HIK.release()