以前做过的项目都是通过 ffmpeg c++ 来捕获摄像机的 RSTP 视频流来处理视频帧,抽空看了一下海康的SDK说明,使用 python 实现了对海康SDK DLL的调用, 可以进行视频预预览、抓图、抽帧、云台控制、布防等任务,由于调用的是C++库,速度也很快。如果不要求对视频帧进行实时智能算法分析的话,python的速度也能满足要求,而且开发效率高。

下面简介一下开发流程与关键步骤。

1、海康SDK开发包简介

在海康威视官网注册后,可以下载开发最新的SDK,其中包含说明书。

海康 SDK 构成与其它C/C++的SDK是类似的,主要由 头文件,库文件( ,lib, .so) 以及静态链接库DLL组成, linux下库文件只有.so。

python项目导入SDK 相当简单,只需要将相关DLL文件拷贝至python项目文件夹即可,主要是下面几个文件
HCNetSDK.dll
HCCore.dll
HCPreview.dll
PlayCtrl.dll
HCCoreDevCfg.dll
或者放入1个特定文件夹,将这个文件夹加入到系统环境变量path中。只要程序运行时可以找到 DLL 就可以。

2、调用SDK的基本流程

说明书上写得很详细,以实现预览的过程为例,流程如下:

3、主要步骤介绍

1)如何导入SDK DLL

python如何调用 C/C++ DLL, 请参考本人文章:Python 使用 ctypes 调用 C/C++ DLL 动态链接库

当然也可以使用 Cython 来调用,但由于Cython学习的难度明显高于 ctypes,如果C++平时用得少,建议用 ctypes 调用sdk函数的方式,基本思路是:

  • 先用ctype来声明 SDK接口函数的形参与返回值,目的是python代码类型与 C++类型能匹配上
  • 不采用签名函数方式,使用直接调用sdk函数的方式,即 dll.function_name() 来调用。

用ctypes 声明 SDK接口函数的形参与返回值

首先要做的就是用python ctypes 将 DLL中的接口函数的形参重新定义。如 SDK中注册设备的方法:

LONG NET_DVR_Login_V40(
LPNET_DVR_USER_LOGIN_INFO pLoginInfo,
LPNET_DVR_DEVICEINFO_V40 lpDeviceInfo);
两个形参是结构指针,python中没有直接对应的类型,因此需要通过ctypes 类型重新定义:

NET_DVR_Login_V40()参数

# NET_DVR_Login_V40()参数
class NET_DVR_USER_LOGIN_INFO(Structure):_fields_ = [("sDeviceAddress", c_char * 129),  # 设备地址,IP 或者普通域名("byUseTransport", c_byte),  # 是否启用能力集透传:0- 不启用透传,默认;1- 启用透传("wPort", c_uint16),  # 设备端口号,例如:8000("sUserName", c_char * 64),  # 登录用户名,例如:admin("sPassword", c_char * 64),  # 登录密码,例如:12345("cbLoginResult", fLoginResultCallBack),  # 登录状态回调函数,bUseAsynLogin 为1时有效("pUser", c_void_p),  # 用户数据("bUseAsynLogin", c_uint32),  # 是否异步登录:0- 否,1- 是("byProxyType", c_byte),  # 0:不使用代理,1:使用标准代理,2:使用EHome代理("byUseUTCTime", c_byte),# 0-不进行转换,默认,1-接口上输入输出全部使用UTC时间,SDK完成UTC时间与设备时区的转换,2-接口上输入输出全部使用平台本地时间,SDK完成平台本地时间与设备时区的转换("byLoginMode", c_byte),  # 0-Private 1-ISAPI 2-自适应("byHttps", c_byte),  # 0-不适用tls,1-使用tls 2-自适应("iProxyID", c_uint32),  # 代理服务器序号,添加代理服务器信息时,相对应的服务器数组下表值("byVerifyMode", c_byte),  # 认证方式,0-不认证,1-双向认证,2-单向认证;认证仅在使用TLS的时候生效;("byRes2", c_byte * 119)]
LPNET_DVR_USER_LOGIN_INFO = POINTER(NET_DVR_USER_LOGIN_INFO)

设备参数结构体 V40

# 设备参数结构体 V40
class NET_DVR_DEVICEINFO_V40(ctypes.Structure):_fields_ = [('struDeviceV30', NET_DVR_DEVICEINFO_V30),  # 设备信息('bySupportLock', c_byte),  # 设备支持锁定功能,该字段由SDK根据设备返回值来赋值的。bySupportLock为1时,dwSurplusLockTime和byRetryLoginTime有效('byRetryLoginTime', c_byte),  # 剩余可尝试登陆的次数,用户名,密码错误时,此参数有效('byPasswordLevel', c_byte),  # admin密码安全等级('byProxyType', c_byte),  # 代理类型,0-不使用代理, 1-使用socks5代理, 2-使用EHome代理('dwSurplusLockTime', c_uint32),  # 剩余时间,单位秒,用户锁定时,此参数有效('byCharEncodeType', c_byte),  # 字符编码类型('bySupportDev5', c_byte),  # 支持v50版本的设备参数获取,设备名称和设备类型名称长度扩展为64字节('bySupport', c_byte),   # 能力集扩展,位与结果:0- 不支持,1- 支持('byLoginMode', c_byte),  # 登录模式:0- Private登录,1- ISAPI登录('dwOEMCode', c_uint32),  # OEM Code('iResidualValidity', c_uint32),  # 该用户密码剩余有效天数,单位:天,返回负值,表示密码已经超期使用,例如“-3表示密码已经超期使用3天”('byResidualValidity', c_byte),  # iResidualValidity字段是否有效,0-无效,1-有效('bySingleStartDTalkChan', c_byte),  # 独立音轨接入的设备,起始接入通道号,0-为保留字节,无实际含义,音轨通道号不能从0开始('bySingleDTalkChanNums', c_byte),  # 独立音轨接入的设备的通道总数,0-表示不支持('byPassWordResetLevel', c_byte),  # 0-无效,# 1- 管理员创建一个非管理员用户为其设置密码,该非管理员用户正确登录设备后要提示“请修改初始登录密码”,未修改的情况下,用户每次登入都会进行提醒;# 2- 当非管理员用户的密码被管理员修改,该非管理员用户再次正确登录设备后,需要提示“请重新设置登录密码”,未修改的情况下,用户每次登入都会进行提醒。('bySupportStreamEncrypt', c_byte),  # 能力集扩展,位与结果:0- 不支持,1- 支持# bySupportStreamEncrypt & 0x1 表示是否支持RTP/TLS取流# bySupportStreamEncrypt & 0x2 表示是否支持SRTP/UDP取流# bySupportStreamEncrypt & 0x4 表示是否支持SRTP/MULTICAST取流('byMarketType', c_byte),  # 0-无效(未知类型),1-经销型,2-行业型('byRes2', c_byte * 238)  #保留,置为0]
LPNET_DVR_DEVICEINFO_V40 = POINTER(NET_DVR_DEVICEINFO_V40)

调用sdk函数示例

下面用注册设备函数 NET_DVR_Login_V40 为例,展示初始化参数,赋值,调用dll函数步骤:

def LoginDev(sdk):# 登录注册设备'''device_info = NET_DVR_DEVICEINFO_V30()lUserId = Objdll.NET_DVR_Login_V30(DEV_IP, DEV_PORT, DEV_USER_NAME, DEV_PASSWORD, byref(device_info))'''# 用户注册设备# c++传递进去的是byte型数据,需要转成byte型传进去,否则会乱码# 登录参数,包括设备地址、登录用户、密码等struLoginInfo = NET_DVR_USER_LOGIN_INFO()struLoginInfo.bUseAsynLogin = 0  # 同步登录方式struLoginInfo.sDeviceAddress = bytes("192.168.99.247", "ascii")  # 设备IP地址struLoginInfo.wPort = 8000  # 设备服务端口struLoginInfo.sUserName = bytes("admin", "ascii")  # 设备登录用户名struLoginInfo.sPassword = bytes("Admin&123", "ascii")  # 设备登录密码struLoginInfo.byLoginMode = 0struDeviceInfoV40 = NET_DVR_DEVICEINFO_V40()UserID = sdk.NET_DVR_Login_V40(byref(struLoginInfo), byref(struDeviceInfoV40))return (UserID, struDeviceInfoV40)

其它sdk函数调用过程也是类似的。

2) 开发框架说明l

因为只是1个练习,为了省事,采用了 python Tkinter 来开发界面,也可以使用QT来做。

3) 几个技术点说明

设备注册后,必须要调用 NET_DVR_RealPlay_V40() 函数进行预览画面,后面的抓图、读帧以及云台控制均要求先执行这一步。
该函数定义如下:
LONG NET_DVR_RealPlay_V40(
LONG lUserID,
LPNET_DVR_PREVIEWINFO lpPreviewInfo,
REALDATACALLBACK fRealDataCallBack_V30,
void *pUser);

可以有1个回调函数 REALDATACALLBACK
typedef void(CALLBACK *REALDATACALLBACK)(
LONG lRealHandle,
DWORD dwDataType,
BYTE *pBuffer,
DWORD dwBufSize,
void *pUser);

注意要计划好显示视频的窗口控件,获取该窗口的句柄,传给NET_DVR_RealPlay_V40,或回调函数。

捕获视频码流以及解码显示均由该回调函数完成,捕获原始的YUV视频帧也在此进行。
如果要对视频进行分析,有两种方法
1)通过sdk的抓图接口函数抓图进行分析,如 NET_DVR_CapturePicture
2) 实时性要求高,可将预览码流中的原始YUV帧l转换为RGB后,再进行
处理。

  1. 代码如下
# coding=utf-8import os
import platform
import tkinter
from tkinter import *
from tkinter import ttk
from HCNetSDK import *
from PlayCtrl import *
from time import sleep
import ctypes# 登录的设备信息
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_FLAGWINDOWS_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 = strPathObjdll.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 = strPathObjdll.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(sdk):# 登录注册设备'''device_info = NET_DVR_DEVICEINFO_V30()lUserId = Objdll.NET_DVR_Login_V30(DEV_IP, DEV_PORT, DEV_USER_NAME, DEV_PASSWORD, byref(device_info))'''# 用户注册设备# c++传递进去的是byte型数据,需要转成byte型传进去,否则会乱码# 登录参数,包括设备地址、登录用户、密码等struLoginInfo = NET_DVR_USER_LOGIN_INFO()struLoginInfo.bUseAsynLogin = 0  # 同步登录方式struLoginInfo.sDeviceAddress = bytes("192.168..200", "ascii")  # 设备IP地址struLoginInfo.wPort = 8000  # 设备服务端口struLoginInfo.sUserName = bytes("admin", "ascii")  # 设备登录用户名struLoginInfo.sPassword = bytes("123456", "ascii")  # 设备登录密码struLoginInfo.byLoginMode = 0struDeviceInfoV40 = NET_DVR_DEVICEINFO_V40()UserID = sdk.NET_DVR_Login_V40(byref(struLoginInfo), byref(struDeviceInfoV40))return (UserID, struDeviceInfoV40)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.nWidthnHeight = pFrameInfo.contents.nHeightnType = pFrameInfo.contents.nTypedwFrameNum = pFrameInfo.contents.dwFrameNumnStamp = pFrameInfo.contents.nStampprint(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 FuncDecCBFuncDecCB = 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 = 0preview_info.lChannel = 1  # 通道号lk在preview_info.dwStreamType = 0  # 主码流preview_info.dwLinkMode = 0  # TCPpreview_info.bBlocked = 1  # 阻塞取流preview_info.dwDisplayBufNum = 15  # 缓冲区大小,15*1024*1024# 开始预览并且设置回调函数回调获取实时流数据lRealPlayHandle = Objdll.NET_DVR_RealPlay_V40(lUserId, byref(preview_info), callbackFun, None)return lRealPlayHandledef InputData(fileMp4, Playctrldll):while True:pFileData = fileMp4.read(4096)if pFileData is None:breakif not Playctrldll.PlayM4_InputData(PlayCtrl_Port, pFileData, len(pFileData)):breakdef click_capture():print("clicked capture button")# Objdll.NET_DVR_SetCapturePictureMode(1)pFileName = ctypes.c_char_p()pFileName.value = bytes("pic/image.jpg", "utf-8")# 开始抓图。res = Objdll.NET_DVR_CapturePicture(lRealPlayHandle, pFileName)if res:print("Successfullly capture picture, ", pFileName.value)def click_left():print("clicked button up")# 因无测试条件,暂略def click_right():print("clicked button")def click_up():print("clicked button")def click_down():print("clicked button")if __name__ == '__main__':# 创建窗口win = tkinter.Tk()# 固定窗口大小win.resizable(0, 0)win.overrideredirect(True)sw = win.winfo_screenwidth()# 得到屏幕宽度sh = win.winfo_screenheight()# 得到屏幕高度# 窗口宽高ww = 800wh = 650x = (sw - ww) / 2y = (sh - wh) / 2win.geometry("%dx%d+%d+%d" % (ww, wh, x, y))# 创建一个Canvas,设置其背景色为白色cv = Canvas(win,width=760,height=460,bg="white",)cv.place(x=20, y=10)# 创建退出按键btn_left = Button(win, text="  左  ",command=click_left).place(x=100, y=530)btn_right = Button(win, text="  右  ",command=click_right).place(x=180, y=530)btn_top = Button(win, text="  上  ", command=click_up).place(x=145, y=495)btn_down = Button(win, text="  下  ",command=click_down).place(x=145, y=565)btn_capture = Button(win, text="  放大  ",command=click_capture).place(x=280, y=500)btn_capture = Button(win, text="  缩小  ",command=click_capture).place(x=280, y=530)btn_capture = Button(win, text="  截图  ",command=click_capture).place(x=280, y=560)lbl_ip = Label(win, text="IP地址", fg="#111").place(x=480, y=490)ent_ip = Entry(win).place(x=550, y=490)lbl_port = Label(win, text="端口", fg="#111").place(x=480, y=515)ent_port = Entry(win).place(x=550, y=515)lbl_name = Label(win, text="登录名", fg="#111").place(x=480, y=540)ent_name = Entry(win).place(x=550, y=540)lbl_password = Label(win, text="密码", fg="#111").place(x=480, y=565)password = StringVar()password_entry = ttk.Entry(win,textvariable=password,show='*')password_entry.place(x=550, y=565)separator = ttk.Separator(win, orient='horizontal')separator.place(x=10, y=600, width=790)btn_q = Button(win, text=' 退出 ', command=win.quit)btn_q.place(x=660, y=610)# 加载库,先加载依赖库dname = 'D:\workplace\dependency\hik_lib\HCNetSDK.dll'# Objdll = ctypes.CDLL('lib/HCNetSDK.dll')  # 加载网络库Objdll = ctypes.cdll.LoadLibrary(dname)# Playctrldll = ctypes.CDLL('lib/PlayCtrl.dll')  # 加载播放库dname = 'D:\workplace\dependency\hik_lib\PlayCtrl.dll'Playctrldll = ctypes.cdll.LoadLibrary(dname)print("load dll successfully")# SetSDKInitCfg()  # 设置组件库和SSL库加载路径# 初始化DLLObjdll.NET_DVR_Init()print("init device successfully ")# 启用SDK写日志Objdll.NET_DVR_SetLogToFile(3, bytes('./SdkLog_Python/', encoding="utf-8"), False)print("config log to SdkLog_Python ")# 获取一个播放句柄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()print("login device ")# 定义码流回调函数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 Windowswin.mainloop()# 关闭预览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()

Python调用海康SDK对接摄像机相关推荐

  1. Python调用海康SDK进行车牌识别(动态链接库的方法—不通过swig)

    由于公司项目需要,要通过Python取得海康相机识别到的车牌号,由于目前在办公室,无法进行实际测试,所以通过网络触发抓拍的方式来进行. 首先要下载海康官网的SDK示例,最开始从网上查找资料是通过swi ...

  2. python调用海康sdk 数据类型

    c++的 unsigned char指针,python格式为:POINTER(c_char) ok的项目:百度网盘里,HikSDKyv12View fRealDataCallBack_V30 = RE ...

  3. python调用海康相机进行Apriltag检测

    python调用海康相机进行Apriltag检测 第一章:win10下安装Apriltag库 1.安装Apriltag库 打开cmd输入 pip install pupil-apriltags 这个是 ...

  4. java 调用dll_Python调用海康SDK抓取红外图像

    海康SDK提供了C++.C#.Java等示例代码,可以使用这些语言进行二次开发.对于做算法开发的人来说,就想快速采集到图像,然后在Matlab或Python里对图像进行分析,使用C++.C#.Java ...

  5. python调用海康工业相机并用opencv显示(整体实现)

    python语言调用海康机器人(hikrobotics)工业相机 系列文章目录 第一章 python调用海康工业相机并用opencv显示(整体实现) 第二章 python 调用海康工业相机图像获取方式 ...

  6. Python调用海康工业相机:包含相机参数修改、彩色原图显示(不失真)

    [引言] 海康相机作为目前工业检测.视觉定位等领域应用较为广泛的国产品牌相机,其搭配有一套专用视觉软件VM,而在完成具有复杂场景.复杂任务的科研项目时依靠其VM算法平台提供的视觉算法往往无法满足项目要 ...

  7. linux64下调用海康sdk(=登陆、获取通道列表、获取文件列表、按照文件下载文件、按照时间下载文件)

    linux下调用海康sdk 1.库文件的配置 mkdir /data/hk_sdk/ cd /data/hk_sdk/将海康SDK的lib文件夹复制到/data/hk_sdk/下 lib文件下面的结构 ...

  8. java接口方式调用海康大华摄像机预览。

    客户有海康和大华的监控设备,没有买各类安防平台,国标方式需要预留给其他需要接入的系统,得兼容高版本chrome,询问了大华的客服人员,最后选择了该方案进行解决,记录下曲折的过程.延迟大约10秒的样子, ...

  9. C#使用WebService调用海康SDK实现抓图与录像实时下载

    1.海康设备网络SDK下载 下载地址:https://www.hikvision.com/cn/download_more_401.html 下载完毕解压后的目录结构如下: 2.代码实现 通过参考&q ...

  10. C#制作ActiveX控件中调用海康SDK的问题

    事情是这样的,有一台海康威视的摄像头,客户需要一个ActiveX控件嵌入到网页中,通过点击按钮开始录制和结束录制来进行视频的录制和保存,关于海康摄像头的二次开发在此就不多说了,可以参考SDK中的说明. ...

最新文章

  1. dataframe sample 采样,抽样
  2. Qt 自定义信号与槽
  3. as3直接播放flv基本代码
  4. 读取EXCEL文件内容
  5. 进程间通信的方式(四):信号量
  6. TCP/UDP的小事情
  7. 全国计算机等级考试题库二级C操作题100套(第91套)
  8. 转载构造函数与拷贝构造函数
  9. 考研复习(2)链表操作
  10. java对列表数据排序_如何在Java中对列表进行排序
  11. 2021年“泰迪杯”数据分析技能赛A题
  12. 泰凌微ble mesh蓝牙模组天猫精灵学习之旅 ④ 初认识阿里天猫精灵官方Genie BT mesh Stack框架, windows平台搭建打印Hello World !
  13. 软考-网络工程师复习资料及计划
  14. 内网穿透工具NatApp使用教程
  15. 华为:三层交换机 命令示例
  16. Java Swing实现仿微信PC客户端程序 SOCKET 即时通信系统
  17. android跳一跳作弊编程,跳一跳辅助器作弊刷分 微信跳一跳辅助工具(安卓/iOS苹果)-优基地...
  18. AASM rule of scoring sleep stages using EEG signal
  19. 视频监控技术的发展对于市场的影响越来越大
  20. 论文精读:GHM:Gradient Harmonized Single-stage Detector

热门文章

  1. 【SecureCRT的下载、安装与使用】详细过程
  2. webview的使用套餐
  3. python定时重启程序
  4. VOS3000 8.05安装及源码
  5. Visual Basic 2010中文版从入门到精通pdf
  6. 今天居然中了MSN病毒。
  7. 一款很好看的个人主页html源码
  8. android平台的一款mud工具,论剑mud脚本
  9. 一键清除苹果锁屏密码_Aiseesoft iPhone Unlocker下载-苹果设备解锁工具 v1.0.22 官方版...
  10. php如何防止恶意DDoS攻击,避免带宽占用问题方法