首页 > 学院 > 开发设计 > 正文

海康威视频监控设备Web查看系统(二):服务器篇

2019-11-17 03:06:15
字体:
来源:转载
供稿:网友

海康威视频监控设备Web查看系统(二):服务器篇

声明:本系列文章只提供交流与学习使用。文章中所有涉及到海康威视设备的SDK均可在海康威视官方网站下载得到。文章中所有除官方SDK意外的代码均可随意使用,任何涉及到海康威视公司利益的非正常使用由使用者自己负责,与本人无关。

前言:

上一篇文章《海康威视频监控设备Web查看系统(一):概要篇》笼统的介绍了关于海康视频中转方案的思路,本文将一步步实现方案中的视频中转服务端。文中会涉及到一些.net socket处理和基础的多线程操作。我用的是SDK版本是SDK_Win32_V4.2.8.1 。大家根据自己实际情况想在相应的SDK,页面的说明里有详细的设备型号列表。

分析官方SDK的Demo:

首先来看看官方SDK中的C#版本的Demo,官方Demo分为两个版本,分别是“实时预览示例代码一”和“实时预览示例代码二”,因为有现成的C#版本,所以我们使用示例代码一中的内容。首先关注名为CHCNetSDK的类,这个类封中装了SDK中的所有非托管方法接口,我们需要来把这个类以及SDK中的DLL文件一起引入到我们的项目中,如果有对C#调用C++类库不了解的朋友请自己Google一下,资料非常多,博客园里也有很多作者写过这一类的文章,本文就不就这个内容做深入讨论。

调用SDK没有问题了,接下来看看SDK的使用,根据SDK使用文档,SDK接口的调用需要通过一个标准流程,流程图如下:

按照这个流程,我们第一步要做的是初始化SDK,然后是三个可选回调函数的设置,接着要做用户注册设备即设备登录,紧接着就是核心的部分了,根据上一篇文章中讲的思路,除了预览模块外其他几个模块的调用不在我们要解决的问题范畴,因此不予考虑。最后一步是注销设备,释放SDK资源。所以,最后根据我们的需求,流程简化如下:

虽然标准流程如此,但是我们的服务端程序只有一个单一的任务,所以也没有必要对为托管资源进行释放,因为如果退出程序以后资源就会释放,不退出程序的话,SDK资源就不应该被释放。因此再简化一下流程每个节点都有相应的代码实现如如下所示:

 1 //初始化SDK 2 CHCNetSDK.NET_DVR_Init(); 3  4 //用户登录 5 CHCNetSDK.NET_DVR_DEVICEINFO_V30 DeviceInfo = new CHCNetSDK.NET_DVR_DEVICEINFO_V30(); 6 CHCNetSDK.NET_DVR_Login_V30(设备ip地址, 设备端口, 用户名, 密码, ref DeviceInfo); 7 //说明:关于设备IP、端口、用户名及密码信息请根据自己要访问设备的设置正确填写 8  9 //预览模块10 CHCNetSDK.NET_DVR_CLIENTINFO lpClientInfo = new CHCNetSDK.NET_DVR_CLIENTINFO();11 lpClientInfo.lChannel = channel;12 lpClientInfo.lLinkMode = 0x0000;13 lpClientInfo.sMultiCastIP = "";14 m_fRealData = new CHCNetSDK.REALDATACALLBACK(RealDataCallBack);15 IntPtr pUser = new IntPtr();16 CHCNetSDK.NET_DVR_RealPlay_V30(m_lUserID, ref lpClientInfo, m_fRealData, pUser, 1);17 //说明:这里的NET_DVR_CLIENTINFO类中缺少预览窗口的句柄,需要预览时,要根据自己的项目设置NET_DVR_CLIENTINFO对象的hPlayWnd属性

可能有朋友看到这里已经忍受不了了,说好的视频中转功能在哪呢?别着急,一切的处理都在回调函数RealDataCallBack中,先耐心看一下这个回调函数的签名

void RealDataCallBack(Int32 lRealHandle, UInt32 dwDataType, IntPtr pBuffer, UInt32 dwBufSize, IntPtr pUser)

第一个lRealHandle是预览控件的句柄,第二个参数dwDataType说明回调接收到的数据类型,pBuffer 存放数据的缓冲区指针, dwBufSize 缓冲区大小 ,pUser 用户数据的句柄。我做的这个视频的中转功能其实就是在这个回调函数中实现的。

好了,核心的代码都摘出来了,大家按照SDK提供的Demo照猫画虎就可以把预览功能实现出来了。

服务端设计:

  实现了预览功能,下面看看中转服务的实现。其中包含三个类:Server,Client以及ClientList类。

Server类主要负责从设备读取数据并将数据缓存到服务器上,并且作为Socket监听服务端;ClientList维护一个客户端列表,并在Server获取到设备数据时便利客户端列表发送数据到客户端;Client类主要负责将服务端缓存的数据分发到各个终端请求上。

三个类的关系及主要成员请看下图:

Server类:

  1 class Server  2     {  3         int m_lUserID = -1;  4         //头数据  5         byte[] headStream;  6   7         ClientList clientList = ClientList.GetClientList();  8         CHCNetSDK.REALDATACALLBACK m_fRealData;  9         Socket listenSocket; 10         Semaphore m_maxNumberAcceptedClients; 11         /// <summary> 12         /// Server构造函数,启动服务端Socket及海康SDK获取设备数据 13         /// </summary> 14         /// <param name="ipPoint">服务端IP配置</param> 15         /// <param name="numConnections">最大客户端连接数</param> 16         /// <param name="channel">设备监听通道</param> 17         public Server(IPEndPoint ipPoint, int numConnections, int channel) 18         { 19             if (!InitHK()) 20             { 21                 return; 22             } 23             RunGetStream(channel); 24  25             listenSocket = new Socket(ipPoint.AddressFamily, SocketType.Stream, PRotocolType.Tcp); 26             listenSocket.Bind(ipPoint); 27             m_maxNumberAcceptedClients = new Semaphore(numConnections, numConnections); 28             listenSocket.Listen(100); 29             Console.WriteLine("开始监听客户端连接......"); 30             StartAccept(null); 31         } 32  33         #region HKSDK 34  35         private void RunGetStream(int channel) 36         { 37             if (m_lUserID != -1)//初始化成功 38             { 39                 CHCNetSDK.NET_DVR_CLIENTINFO lpClientInfo = new CHCNetSDK.NET_DVR_CLIENTINFO(); 40                 lpClientInfo.lChannel = channel; 41                 lpClientInfo.lLinkMode = 0x0000; 42                 lpClientInfo.sMultiCastIP = ""; 43                 m_fRealData = new CHCNetSDK.REALDATACALLBACK(RealDataCallBack); 44                 IntPtr pUser = new IntPtr(); 45                 int m_lRealHandle = CHCNetSDK.NET_DVR_RealPlay_V30(m_lUserID, ref lpClientInfo, m_fRealData, pUser, 1); 46                 Console.WriteLine("开始获取视频数据......"); 47             } 48             else//初始化 失败,因为已经初始化了 49             { 50                 Console.WriteLine("视频数据获取失败......"); 51             } 52         } 53  54         private bool InitHK() 55         { 56             bool m_bInitSDK = CHCNetSDK.NET_DVR_Init(); 57             if (m_bInitSDK == false) 58             { 59                 return false; 60             } 61             else 62             { 63                 Console.WriteLine("设备SDK初始化成功......."); 64                 CHCNetSDK.NET_DVR_DEVICEINFO_V30 DeviceInfo = new CHCNetSDK.NET_DVR_DEVICEINFO_V30(); 65                 m_lUserID = CHCNetSDK.NET_DVR_Login_V30("设备IP", 连接端口, "连接用户名", "连接密码", ref DeviceInfo); 66                 if (m_lUserID != -1) 67                 { 68                     Console.WriteLine("监控设备登录成功......."); 69                     return true; 70                 } 71                 else 72                 { 73                     Console.WriteLine("监控设备登录失败,稍后再试......."); 74                     return false; 75                 } 76             } 77         } 78  79         private void RealDataCallBack(Int32 lRealHandle, UInt32 dwDataType, IntPtr pBuffer, UInt32 dwBufSize, IntPtr pUser) 80         { 81             byte[] data = new byte[dwBufSize]; 82             Marshal.Copy(pBuffer, data, 0, (int)dwBufSize); 83             Console.WriteLine("监控设备连接正常......"); 84             if (dwDataType == CHCNetSDK.NET_DVR_SYSHEAD) 85             { 86                 headStream = data; 87             } 88             clientList.SetSendData(data); 89             return; 90         } 91  92         #endregion 93  94         #region Socket 95         /// <summary> 96         /// 监听客户端 97         /// </summary> 98         /// <param name="acceptEventArg"></param> 99         private void StartAccept(SocketAsyncEventArgs acceptEventArg)100         {101             if (acceptEventArg == null)102             {103                 acceptEventArg = new SocketAsyncEventArgs();104                 acceptEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed);105             }106             else107             {108                 acceptEventArg.AcceptSocket = null;109             }110 111             m_maxNumberAcceptedClients.WaitOne();112             bool willRaiseEvent = listenSocket.AcceptAsync(acceptEventArg);113             if (!willRaiseEvent)114             {115                 ProcessAccept(acceptEventArg);116             }117         }118         /// <summary>119         /// 增加客户端列表120         /// </summary>121         /// <param name="e"></param>122         private void ProcessAccept(SocketAsyncEventArgs e)123         {124             clientList.AddClient(new Client(e.AcceptSocket, headStream));125             StartAccept(e);126         }127 128         /// <summary>129         /// Socket回调函数130         /// </summary>131         /// <param name="
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表