先说一下大华解码器的思路,和天地伟业的解码器思路不一样。天地伟业讲究的是一个物理通道对应一块屏幕,至始至终都是都物理通道的操作,优点是简单明了通俗易懂不花里胡哨。
大华讲究的是开始就把物理通道进行融合,结果就是出来的融合屏必是少于或等于物理屏总数,那么后来的上屏操作都是依托于这个融合屏,融合屏是从物理通道总数开始计起。
开始:首先把大华写的封装类库(NetSDKCS)添加到项目中。
1.项目所需的几个参数
private IntPtr m_LoginHandle = IntPtr.Zero; private NET_DEVICEINFO_Ex m_DeviceInfo; private readonly fDisConnectCallBack m_DisConnectHandle; private string sDeviceIP = "192.168.1.109"; private ushort wDevicePort = 37777; private string sUserName = "admin"; private string sPassword = "admin";
2.SDK的初始化
private void DisConnectCallBack(IntPtr lLoginID, IntPtr pchDVRIP, int nDVRPort, IntPtr dwUser) { Console.WriteLine(Marshal.PtrToStringAnsi(pchDVRIP) + " disConnect"); } m_DisConnectHandle = new fDisConnectCallBack(DisConnectCallBack); NETClient.Init(m_DisConnectHandle, IntPtr.Zero, null);
3.登录解码器
m_LoginHandle = NETClient.Login(sDeviceIP, wDevicePort, sUserName, sPassword, EM_LOGIN_SPAC_CAP_TYPE.TCP, IntPtr.Zero, ref m_DeviceInfo);
4.获取解码器融合通道的窗口信息
public bool GetSplitWindowsInfo(int nChannel)
{ bool bRet = false; NET_SPLIT_CAPS stuCap = new NET_SPLIT_CAPS(); stuCap.dwSize = (uint)Marshal.SizeOf(stuCap); try { bRet = NETClient.GetSplitCaps(m_LoginHandle, nChannel, ref stuCap, 3000); } catch (NETClientExcetion nex) { Console.WriteLine("Failed to get split caps. " + nex.Message); return false; } for (int i = 0; i < stuCap.emSplitMode.Length; i++) { if (stuCap.emSplitMode[i] == EM_SPLIT_MODE.SPLIT_FREE) { NET_IN_SPLIT_GET_WINDOWS stuInGetWhn = new NET_IN_SPLIT_GET_WINDOWS(); stuInGetWhn.nChannel = nChannel; stuInGetWhn.dwSize = (uint)Marshal.SizeOf(stuInGetWhn); NET_OUT_SPLIT_GET_WINDOWS stuOutGetWhn = new NET_OUT_SPLIT_GET_WINDOWS(); stuOutGetWhn.dwSize = (uint)Marshal.SizeOf(stuOutGetWhn); NET_BLOCK_COLLECTION stuBlockColltion = new NET_BLOCK_COLLECTION(); stuBlockColltion.dwSize = (uint)Marshal.SizeOf(stuBlockColltion); object obj = stuBlockColltion; InitStruct(ref obj); stuBlockColltion = (NET_BLOCK_COLLECTION)obj; NET_WINDOW_COLLECTION [] stuWindowColltion = new NET_WINDOW_COLLECTION[128]; for (int x = 0; x < stuWindowColltion.Length; x++) { stuWindowColltion[x].dwSize = (uint)Marshal.SizeOf(stuWindowColltion[x]); } stuBlockColltion.stuWnds = stuWindowColltion; stuOutGetWhn.stuWindows = stuBlockColltion; bRet = NETClient.GetSplitWindowsInfo(m_LoginHandle, ref stuInGetWhn, ref stuOutGetWhn, 3000); for(int x = 0;x < stuOutGetWhn.stuWindows.stuWnds.Length;x ++) { Console.WriteLine("nWindowID:" + stuOutGetWhn.stuWindows.stuWnds[x].nWindowID + "Top:"+stuOutGetWhn.stuWindows.stuWnds[x].stuRect.nTop.ToString()+ "Left:" + stuOutGetWhn.stuWindows.stuWnds[x].stuRect.nLeft.ToString()+ "Right:" + stuOutGetWhn.stuWindows.stuWnds[x].stuRect.nRight.ToString()+ "Bottom:" + stuOutGetWhn.stuWindows.stuWnds[x].stuRect.nBottom.ToString()); } } } return bRet; }
5.获取融合屏通道信息,必须在开窗之前执行此操作
public enum emVideoOutType { ALL = 1, //物理屏和融合屏 COMP = 2, //融合屏 PHY = 3, //物理屏 } private void InitStruct(ref object stu) { IntPtr p_stu = IntPtr.Zero; Type type = stu.GetType(); try { p_stu = Marshal.AllocHGlobal(Marshal.SizeOf(type)); Marshal.StructureToPtr(stu, p_stu, true); stu = Marshal.PtrToStructure(p_stu, type); } finally { Marshal.FreeHGlobal(p_stu); } } public bool GetVideoOutChannelInfo() { bool bRet = false; int nComposite = 30; //拼接屏数量 NET_COMPOSITE_CHANNEL stComChan = new NET_COMPOSITE_CHANNEL(); object obj = stComChan; InitStruct(ref obj); stComChan = (NET_COMPOSITE_CHANNEL)obj; stComChan.dwSize = (uint)Marshal.SizeOf(stComChan.GetType()); object[] oComChans = new object[nComposite]; for (int i = 0; i < nComposite; i++) { oComChans[i] = stComChan; } try { bRet = NETClient.QueryDevState(m_LoginHandle, (int)NETClient.NET_DEVSTATE_COMPOSITE_CHN, ref oComChans, typeof(NET_COMPOSITE_CHANNEL), 3000); if (bRet) { for (int i = 0; i < oComChans.Length; i++) { stComChan = (NET_COMPOSITE_CHANNEL)oComChans[i]; Console.WriteLine("融合屏: {0}", i); Console.WriteLine("name:{0}", stComChan.szMonitorWallName); Console.WriteLine("融合屏ID: {0}", stComChan.szCompositeID); Console.WriteLine("融合屏通道号: {0}", stComChan.nVirtualChannel); } } } catch (NETClientExcetion nex) { Console.WriteLine(nex.Message); return false; } return bRet; }
5.自由开窗,来给视频上墙,返回开窗ID,此ID用来视频上墙
public int ClientSetFreeWindows(int nChannel, int nLeft ,int nTop, int nRight, int nBottom) { if (!GetVideoOutChannelInfo())//打印下当前融合屏情况 { Console.WriteLine("Failed to get channels info;"); } NET_IN_SPLIT_OPEN_WINDOW stOpenWindowIn = new NET_IN_SPLIT_OPEN_WINDOW(); stOpenWindowIn.dwSize = (uint)Marshal.SizeOf(stOpenWindowIn.GetType()); stOpenWindowIn.nChannel = nChannel; stOpenWindowIn.stuRect.nLeft = nLeft; stOpenWindowIn.stuRect.nTop = nTop; stOpenWindowIn.stuRect.nRight = nRight; stOpenWindowIn.stuRect.nBottom = nBottom; NET_OUT_SPLIT_OPEN_WINDOW stOpenWindowOut = new NET_OUT_SPLIT_OPEN_WINDOW(); stOpenWindowOut.dwSize = (uint)Marshal.SizeOf(stOpenWindowOut.GetType()); NET_SPLIT_MODE_INFO stSplitMode = new NET_SPLIT_MODE_INFO(); stSplitMode.dwSize = (uint)Marshal.SizeOf(stSplitMode.GetType()); stSplitMode.emSplitMode = EM_SPLIT_MODE.SPLIT_FREE; try { NETClient.SetSplitMode(m_LoginHandle, stOpenWindowIn.nChannel, ref stSplitMode, 3000);//自由分割 NETClient.OpenSplitWindow(m_LoginHandle, ref stOpenWindowIn, ref stOpenWindowOut, 3000); //开窗 } catch (NETClientExcetion nex) { Console.WriteLine("Failed to open split window, " + nex.Message); } return (int)stOpenWindowOut.nWindowID;
}
6.拉流模式,视频上墙
public bool ClientRealPlay(int nOutChannel,int nWindow,string szIp,string szUserEx,string szPwdEx) { bool bRet = false; int nSrcCount = 1; //视频源个数 NET_SPLIT_SOURCE stSplitSource = new NET_SPLIT_SOURCE(); stSplitSource.dwSize = (uint)Marshal.SizeOf(stSplitSource); stSplitSource.bEnable = true; stSplitSource.szIp = szIp; stSplitSource.szUserEx = szUserEx; stSplitSource.szPwdEx = szPwdEx; stSplitSource.nPort = 37777; stSplitSource.nChannelID = 0; stSplitSource.nStreamType = 0; //主码流 stSplitSource.nVideoChannel = 1;//视频源设备通道总数,在登陆视频源的时候可以获取到。对于IPC设备,视频通道数是1;对于NVR前端,根据NVR型号,有4、8、12、16、32路等。 //设置视频源 try { NET_SPLIT_SOURCE[] splitSrcS = new NET_SPLIT_SOURCE[nSrcCount]; splitSrcS[0] = stSplitSource; bRet = NETClient.SetSplitSource(m_LoginHandle, nOutChannel, nWindow, splitSrcS, 3000); } catch (NETClientExcetion nex) { Console.WriteLine("Failed to set split source" + nex.Message); return false; } return bRet; }
7.删除某一个解码器视频窗口
public bool ClientCloseSplitWindow(int nChannel,int nWindowID) { bool bRet = false; NET_IN_SPLIT_CLOSE_WINDOW stCloseWindowIn = new NET_IN_SPLIT_CLOSE_WINDOW(); stCloseWindowIn.dwSize = (uint)Marshal.SizeOf(stCloseWindowIn.GetType()); stCloseWindowIn.nChannel = nChannel; stCloseWindowIn.nWindowID = nWindowID; NET_OUT_SPLIT_CLOSE_WINDOW stCloseWindowOut = new NET_OUT_SPLIT_CLOSE_WINDOW(); stCloseWindowOut.dwSize = (uint)Marshal.SizeOf(stCloseWindowOut.GetType()); bRet = NETClient.CloseSplitWindow(m_LoginHandle, ref stCloseWindowIn, ref stCloseWindowOut, 3000); return bRet; }
9.退出登录
NETClient.Logout(m_LoginHandle);
10.释放内存
NETClient.Cleanup();