import os import platform import tkinter from tkinter import * from HCNetSDK import * from PlayCtrl import * from time import sleep # 登录的设备信息 DEV_IP = create_string_buffer(b'10.17.35.231') DEV_PORT = 8000 DEV_USER_NAME = create_string_buffer(b'admin') DEV_PASSWORD = create_string_buffer(b'abcd1234') WINDOWS_FLAG = True win = None # 预览窗口 funcRealDataCallBack_V30 = None # 实时预览回调函数,需要定义为全局的 PlayCtrl_Port = c_long(-1) # 播放句柄 Playctrldll = None # 播放库 FuncDecCB = None # 播放库解码回调函数,需要定义为全局的 # 获取当前系统环境 def GetPlatform(): sysstr = platform.system() print('' + sysstr) if sysstr != "Windows": global WINDOWS_FLAG WINDOWS_FLAG = False # 设置SDK初始化依赖库路径 def SetSDKInitCfg(): # 设置HCNetSDKCom组件库和SSL库加载路径 # print(os.getcwd()) strPath = os.getcwd().encode('gbk') sdk_ComPath = NET_DVR_LOCAL_SDK_PATH() sdk_ComPath.sPath = strPath Objdll.NET_DVR_SetSDKInitCfg(2, byref(sdk_ComPath)) if WINDOWS_FLAG: Objdll.NET_DVR_SetSDKInitCfg(3, create_string_buffer(strPath + b'\libcrypto-1_1-x64.dll')) Objdll.NET_DVR_SetSDKInitCfg(4, create_string_buffer(strPath + b'\libssl-1_1-x64.dll')) else: Objdll.NET_DVR_SetSDKInitCfg(3, create_string_buffer(strPath + b'\libcrypto.so.1.1')) Objdll.NET_DVR_SetSDKInitCfg(4, create_string_buffer(strPath + b'\libssl.so.1.1')) def LoginDev(Objdll): # 登录注册设备 device_info = NET_DVR_DEVICEINFO_V30() lUserId = Objdll.NET_DVR_Login_V30(DEV_IP, DEV_PORT, DEV_USER_NAME, DEV_PASSWORD, byref(device_info)) return (lUserId, device_info) def DecCBFun(nPort, pBuf, nSize, pFrameInfo, nUser, nReserved2): # 解码回调函数 if pFrameInfo.contents.nType == 3: # 解码返回视频YUV数据,将YUV数据转成jpg图片保存到本地 # 如果有耗时处理,需要将解码数据拷贝到回调函数外面的其他线程里面处理,避免阻塞回调导致解码丢帧 sFileName = ('../../pic/test_stamp[%d].jpg'% pFrameInfo.contents.nStamp) 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) lRet = Playctrldll.PlayM4_ConvertToJpegFile(pBuf, nSize, nWidth, nHeight, nType, c_char_p(sFileName.encode())) if lRet == 0: print('PlayM4_ConvertToJpegFile fail, error code is:', Playctrldll.PlayM4_GetLastError(nPort)) else: print('PlayM4_ConvertToJpegFile success') def RealDataCallBack_V30(lPlayHandle, dwDataType, pBuffer, dwBufSize, pUser): # 码流回调函数 if dwDataType == NET_DVR_SYSHEAD: # 设置流播放模式 Playctrldll.PlayM4_SetStreamOpenMode(PlayCtrl_Port, 0) # 打开码流,送入40字节系统头数据 if Playctrldll.PlayM4_OpenStream(PlayCtrl_Port, pBuffer, dwBufSize, 1024*1024): # 设置解码回调,可以返回解码后YUV视频数据 global FuncDecCB FuncDecCB = DECCBFUNWIN(DecCBFun) Playctrldll.PlayM4_SetDecCallBackExMend(PlayCtrl_Port, FuncDecCB, None, 0, None) # 开始解码播放 if Playctrldll.PlayM4_Play(PlayCtrl_Port, cv.winfo_id()): print(u'播放库播放成功') else: print(u'播放库播放失败') else: print(u'播放库打开流失败') elif dwDataType == NET_DVR_STREAMDATA: Playctrldll.PlayM4_InputData(PlayCtrl_Port, pBuffer, dwBufSize) else: print (u'其他数据,长度:', dwBufSize) def OpenPreview(Objdll, lUserId, callbackFun): ''' 打开预览 ''' preview_info = NET_DVR_PREVIEWINFO() preview_info.hPlayWnd = None preview_info.lChannel = 1 # 通道号 preview_info.dwStreamType = 0 # 主码流 preview_info.dwLinkMode = 0 # TCP preview_info.bBlocked = 1 # 阻塞取流 # 开始预览并且设置回调函数回调获取实时流数据 lRealPlayHandle = Objdll.NET_DVR_RealPlay_V40(lUserId, byref(preview_info), callbackFun, None) return lRealPlayHandle def InputData(fileMp4, Playctrldll): while True: pFileData = fileMp4.read(4096) if pFileData is None: break if not Playctrldll.PlayM4_InputData(PlayCtrl_Port, pFileData, len(pFileData)): break if __name__ == '__main__': # 创建窗口 win = tkinter.Tk() #固定窗口大小 win.resizable(0, 0) win.overrideredirect(True) sw = win.winfo_screenwidth() # 得到屏幕宽度 sh = win.winfo_screenheight() # 得到屏幕高度 # 窗口宽高 ww = 512 wh = 384 x = (sw - ww) / 2 y = (sh - wh) / 2 win.geometry("%dx%d+%d+%d" % (ww, wh, x, y)) # 创建退出按键 b = Button(win, text='退出', command=win.quit) b.pack() # 创建一个Canvas,设置其背景色为白色 cv = tkinter.Canvas(win, bg='white', width=ww, height=wh) cv.pack() # 获取系统平台 GetPlatform() # 加载库,先加载依赖库 if WINDOWS_FLAG: os.chdir(r'./lib/win') Objdll = ctypes.CDLL(r'./HCNetSDK.dll') else: os.chdir(r'./lib/linux') Objdll = cdll.LoadLibrary(r'./libhcnetsdk.so') SetSDKInitCfg() # 设置组件库和SSL库加载路径 # 初始化DLL Objdll.NET_DVR_Init() # 启用SDK写日志 Objdll.NET_DVR_SetLogToFile(3, bytes('C:\\SdkLog_Python\\', encoding="gbk"), False) # 加载播放库 Playctrldll = ctypes.CDLL(r'./PlayCtrl.dll') # 获取一个播放句柄 if not Playctrldll.PlayM4_GetPort(byref(PlayCtrl_Port)): print(u'获取播放库句柄失败') # 登录设备 (lUserId, device_info) = LoginDev(Objdll) if lUserId < 0: err = Objdll.NET_DVR_GetLastError() print('Login device fail, error code is: %d' % Objdll.NET_DVR_GetLastError()) # 释放资源 Objdll.NET_DVR_Cleanup() exit() # 定义码流回调函数 funcRealDataCallBack_V30 = REALDATACALLBACK(RealDataCallBack_V30) # 开启预览 lRealPlayHandle = OpenPreview(Objdll, lUserId, funcRealDataCallBack_V30) if lRealPlayHandle < 0: print ('Open preview fail, error code is: %d' % Objdll.NET_DVR_GetLastError()) # 登出设备 Objdll.NET_DVR_Logout(lUserId) # 释放资源 Objdll.NET_DVR_Cleanup() exit() #show Windows win.mainloop() # 开始云台控制 lRet = Objdll.NET_DVR_PTZControl(lRealPlayHandle, PAN_LEFT, 0) if lRet == 0: print ('Start ptz control fail, error code is: %d' % Objdll.NET_DVR_GetLastError()) else: print ('Start ptz control success') # 转动一秒 sleep(1) # 停止云台控制 lRet = Objdll.NET_DVR_PTZControl(lRealPlayHandle, PAN_LEFT, 1) if lRet == 0: print('Stop ptz control fail, error code is: %d' % Objdll.NET_DVR_GetLastError()) else: print('Stop ptz control success') # 关闭预览 Objdll.NET_DVR_StopRealPlay(lRealPlayHandle) # 停止解码,释放播放库资源 if PlayCtrl_Port.value > -1: Playctrldll.PlayM4_Stop(PlayCtrl_Port) Playctrldll.PlayM4_CloseStream(PlayCtrl_Port) Playctrldll.PlayM4_FreePort(PlayCtrl_Port) PlayCtrl_Port = c_long(-1) # 登出设备 Objdll.NET_DVR_Logout(lUserId) # 释放资源 Objdll.NET_DVR_Cleanup()