基于海康SDK实现Python保存海康威视网络摄像头拍摄的视频

基于海康SDK实现Python保存海康威视网络摄像头拍摄的视频

具体环境配置参考上一篇文章:基于海康SDK实现Python调用海康威视网络摄像头

1. 保存视频到本地Python代码实现

  • 需要修改的地方:LoginDev(Objdll) 函数中定义的IP地址登录用户名登录密码
  • 视频保存路径为vedio_path ,这里设置的就是默认的截图保存的路径'../../pic/test.mp4'
# coding=utf-8

import os
import platform
import tkinter
from tkinter import *
from HCNetSDK import *
from PlayCtrl import *
from time import sleep
print("ok")


# 登录的设备信息,在 LoginDev(Objdll) 函数中直接定义了
# DEV_IP = create_string_buffer(b'192.168.100.14') # IP地址
# 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())
    if WINDOWS_FLAG:
        strPath = os.getcwd().encode('gbk')
        sdk_ComPath = NET_DVR_LOCAL_SDK_PATH()
        sdk_ComPath.sPath = strPath
        Objdll.NET_DVR_SetSDKInitCfg(2, byref(sdk_ComPath))
        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:
        strPath = os.getcwd().encode('utf-8')
        sdk_ComPath = NET_DVR_LOCAL_SDK_PATH()
        sdk_ComPath.sPath = strPath
        Objdll.NET_DVR_SetSDKInitCfg(2, byref(sdk_ComPath))
        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))
    device_info = NET_DVR_DEVICEINFO_V40()
    user_info = NET_DVR_USER_LOGIN_INFO() # 实例化,并赋值 
    user_info.sDeviceAddress = create_string_buffer(b'192.168.100.14').raw  # IP地址
    user_info.byUseTransport = 0
    user_info.wPort = 8000  # 端口
    user_info.sUserName = create_string_buffer(b'admin').raw     # 登录用户名
    user_info.sPassword = create_string_buffer(b'abcd1234').raw  # 登录密码

    lUserId = Objdll.NET_DVR_Login_V40(byref(user_info),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:
        print("~~~头数据,进一次~~~")
        print("lPlayHandle: " + str(lPlayHandle))
        print("dwDataType: " + str(dwDataType))
        print("pBuffer: " + str(pBuffer))
        print("dwBufSize: " + str(dwBufSize))
        print("pUser: " + str(pUser))
        # 设置流播放模式
        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:
        # 流数据
        # print("流数据")
        Playctrldll.PlayM4_InputData(PlayCtrl_Port, pBuffer, dwBufSize)
        #vedio_ok = Playctrldll.NET_DVR_SaveRealData(lPlayHandle, './12output.mp4')

    else:
        print (u'其他数据,长度:', dwBufSize)



def OpenPreview(Objdll, lUserId, callbackFun):
    '''
    打开预览
    '''
    preview_info = NET_DVR_PREVIEWINFO()
    preview_info.lChannel = 1  # 通道号 目前设备模拟通道号从1开始
    preview_info.dwStreamType = 0  # 码流类型:0-主码流,1-子码流,2-三码流,3-虚拟码流,以此类推
    preview_info.dwLinkMode = 0  # TCP
    preview_info.hPlayWnd = 0  # 播放窗口的句柄,为NULL表示不解码显示。 
    preview_info.bBlocked = 1  # 阻塞取流

    # 开始预览并且设置回调函数回调获取实时流数据
    lRealPlayHandle = Objdll.NET_DVR_RealPlay_V40(lUserId, byref(preview_info), callbackFun, None)
    # NET_DVR_RealPlay_V40:实时预览(支持多码流)
    
    return lRealPlayHandle, preview_info

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')  # 加载网络库
        Playctrldll = ctypes.CDLL(r'./PlayCtrl.dll')  # 加载播放库
    else:
        os.chdir(r'./lib/linux')
        Objdll = cdll.LoadLibrary(r'./libhcnetsdk.so')
        Playctrldll = cdll.LoadLibrary(r'./libPlayCtrl.so')

    SetSDKInitCfg()  # 设置组件库和SSL库加载路径

    # 初始化DLL
    Objdll.NET_DVR_Init()
    # 启用SDK写日志
    Objdll.NET_DVR_SetLogToFile(3, bytes('./SdkLog_Python/', encoding="utf-8"), False)

    # 获取一个播放句柄
    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,preview_info) = 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()

    # 直接调用保存函数
    vedio_path = ('../../pic/test.mp4') # 详见 ctypes 语法
    vedio_ok = Objdll.NET_DVR_SaveRealData_V30(lRealPlayHandle, 2, c_char_p(vedio_path.encode())) # 详见 ctypes 语法
    print("-----")
    if vedio_ok:
        print("调用保存视频函数成功")
    else:
        print("调用保存视频函数失败")
    print("-----")

    # 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_StopSaveRealData(lRealPlayHandle)
    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()

到底了🤪

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值