使用海康威视的SDK,利用WPF设计一个网络摄像头的显示控制程序(上位机)

目录

一、下载海康威视的SDK

1.1 关于SDK

1.2 关于API

1.3 关于DLL

1.4 下载海康威视的SDK

1.5 关于网络高清摄像机

二、对下载的SDK进行调试

三、利用Visual Studio打开项目的解决方案

3.1 Visual Studio 2022下载

3.2 关于句柄

四、打开WPF进行ui页面设计

4.1 关于WindowsFormsHost

4.2 准备工作

4.2 xaml设计

4.3 C# 后台逻辑代码

4.4 小改动

五、关于延迟


一、下载海康威视的SDK

1.1 关于SDK

软件开发工具包(Software Development Kit,SDK )一般都是一些软件工程师为特定的软件包、软件框架、硬件平台、操作系统等建立应用软件时的开发工具的集合。

软件开发工具广义上指辅助开发某一类软件的相关文档、范例和工具的集合。

软件开发工具包是一些被软件工程师用于为特定的软件包、软件框架、硬件平台、操作系统等创建应用软件的开发工具的集合,一般而言SDK即开发Windows平台下的应用程序所使用的SDK。它通过编译器、调试器、软件框架等来促进应用程序的创建。它可以简单的为某个程序设计语言提供应用程序接口API的一些文件,但也可能包括能与某种嵌入式系统通讯的复杂的硬件。一般的工具包括用于调试和其他用途的实用工具。SDK还经常包括示例代码、支持性的技术注解或者其他的为基本参考资料澄清疑点的支持文档。

1.2 关于API

API(Application Programming Interface,应用编程接口)其实就是操作系统留给应用程序的一个调用接口,应用程序通过调用操作系统的API而使操作系统去执行应用程序的命令(动作)。其实早在DOS时代就有API的概念,只不过那个时候的API是以中断调用的形式(INT 21h)提供的,在DOS下跑的应用程序都直接或间接的通过中断调用来使用操作系统功能,比如将AH置为30h后调用INT 21h就可以得到DOS 操作系统的版本号。而在Windows中,系统API是以函数调用的方式提供的。同样是取得操作系统的版本号,在Windows中你所要做的就是调用GetVersionEx()函数。

可以这么说,DOSAPI是“Thinking in汇编语言”的,而Windows API则是“Thinking in 高级语言”的。

DOSAPI是系统程序的一部分,他们与系统一同被载入内存并且可以通过中断矢量表找到他们的入口,那么什么是Windows API呢?要说明白这个问题就不得不引入下面要介绍得这个概念——DLL。

1.3 关于DLL

DLL,即Dynamic Link Library(动态链接库)。在Windows环境下含有大量.dll格式的文件,这些文件就是动态链接库文件,其实也是一种可执行文件格式。跟.exe文件不同的是,.dll文件不能直接执行,通常由.exe在执行时装入,内含有一些资源以及可执行代码等。其实Windows的三大模块就是以DLL的形式提供的(Kernel32.dll,User32.dll,GDI32.dll),里面就含有了API函数的执行代码。为了使用DLL中的API函数,必须要有API函数的声明(.h)和其导入库(.lib),导入库可以先这样理解,导入库是为了在DLL中找到API的入口点而使用的。

为了使用API函数,我们就要有跟API所对应的.h和.lib文件,而SDK正是提供了一整套开发Windows应用程序所需的相关文件、范例和工具的“工具包”。

SDK包含了使用API的必需资料,所以也常把仅使用API来编写Windows应用程序的开发方式叫做“SDK编程”。而API和SDK是开发Windows应用程序所必需的东西,所以其它编程框架和类库都是建立在它们之上的,比如VCL和MFC,虽然比起“SDK编程”来有着更高的抽象度,但这丝毫不妨碍在需要的时候随时直接调用API函数。

1.4 下载海康威视的SDK

海康威视的SDK下载地址:海康威视下载地址

1.5 关于网络高清摄像机

本次实验用到的是安佳威视的网络摄像机

二、对下载的SDK进行调试

下载完成后获得的文件如下图所示,阅读帮助文档,将要求的DLL配置文件,复制到Demo示例下的bin文件夹下。(可以傻瓜复制,把库文件夹中的内容全部复制过去)

打开Demo示例,找到C#语言开发示例的Demo

 打开2-实时预览示例代码二,找到bin文件下的NVRCsharpDemo.exe,执行查看是否能正常使用

运行结果如下

三、利用Visual Studio打开项目的解决方案

3.1 Visual Studio 2022下载

 打开项目的解决方案,看到海康威视用Winform框架进行ui设计

 3.2 关于句柄

句柄(Handle)是一个用来标识对象或者项目的标识符,可以用来描述窗体、文件等,值得注意的是句柄不能是常量 。

Windows之所以要设立句柄,根本上源于内存管理机制的问题,即虚拟地址。简而言之数据的地址需要变动,变动以后就需要有人来记录、管理变动,因此系统用句柄来记载数据地址的变更。在程序设计中,句柄是一种特殊的智能指针,当一个应用程序要引用其他系统(如数据库、操作系统)所管理的内存块或对象时,就要使用句柄 。

四、打开WPF进行ui页面设计

4.1 关于WindowsFormsHost

WindowFormsHost控件是WPF中与WinForms集成的控件。它允许您将现有的WinForms控件嵌入到WPF应用程序中,以利用它们的功能。WindowFormsHost控件工作原理是将WinForms控件作为其子元素添加到WPF的逻辑树中。在运行时,WinForms控件被呈现在WPF窗口中。

使用WindowFormsHost控件时,首先需要添加对System.Windows.Forms和System.Windows.Forms.Integration命名空间的引用。然后,创建一个WindowFormsHost控件,并将要嵌入的WinForms控件设置为其Child属性。

4.2 准备工作

将下载的SDK中的CHCNetSDK.cs、IPChannelConfig.cs、IPChannelConfig.Designer.cs、IPChannelConfig.resx、PlayCtrl.cs文件复制到你当前项目解决方案的同级目录下。

4.2 xaml设计

<Window x:Class="project2.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:project2"xmlns:forms="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"mc:Ignorable="d"Title="MainWindow"Height="550"Width="800"><Grid><Grid.ColumnDefinitions><ColumnDefinition Width="250"></ColumnDefinition><ColumnDefinition></ColumnDefinition></Grid.ColumnDefinitions><Grid.RowDefinitions><RowDefinition Height="200"></RowDefinition><RowDefinition></RowDefinition></Grid.RowDefinitions><WrapPanel Background="LightYellow"><Label Height="30"Width="90"HorizontalAlignment="Center"HorizontalContentAlignment="Center"VerticalContentAlignment="Center"Name="Label1"Content="设备IP:"FontFamily="22"Margin="10"></Label><TextBox Height="30"Width="120"HorizontalAlignment="Center"VerticalAlignment="Center"                     Name="TextBoxIP"Text="192.168.1.123"FontSize="14"Margin="10"></TextBox>                        <Label Height=" 30"Width="90"HorizontalContentAlignment="Center"VerticalContentAlignment="Center"Content="端口号:"FontFamily="22"Margin="10"></Label><TextBox Height="30"Width="120"Name="TextBoxPort"Text="8000"FontSize="14"Margin="10"></TextBox><Label Height=" 30"Width="90"HorizontalContentAlignment="Center"VerticalContentAlignment="Center"Content="用户名:"FontFamily="22"Margin="10"></Label><TextBox Height="30"Width="120"Name="TextBoxUserName"Text="admin"FontSize="14"                       Margin="10"></TextBox><Label Height=" 30"Width="90"HorizontalContentAlignment="Center"VerticalContentAlignment="Center"Content="密码:"FontFamily="22"Margin="10"></Label><PasswordBox Height="30"Width="120"Name="TextBoxPassword"FontSize="14"PasswordChar="*"Margin="10"Password="123456"BorderBrush="Black"></PasswordBox></WrapPanel><WrapPanel Grid.Column="0" Grid.Row="1">          <CheckBox Width="130"Height="30"Name="CheckBoxHiDDNS"IsChecked="False"Content="HiDDNS域名登录"                      Click="checkBoxHiDDNS_Checked"Margin="10"></CheckBox><ComboBox Height="30"Width="90"Name="ComboBoxView"><ComboBoxItem Content="直接预览" HorizontalAlignment="Center"VerticalAlignment="Center"HorizontalContentAlignment="Center"VerticalContentAlignment="Center"IsSelected="True"></ComboBoxItem><ComboBoxItem Content="间接预览"HorizontalAlignment="Center"VerticalAlignment="Center"HorizontalContentAlignment="Center"VerticalContentAlignment="Center"></ComboBoxItem></ComboBox><!--<WindowsFormsHost Width="230"Height="150"IsEnabled="True"                              Margin="10"><forms:ListView x:Name="ListViewIPChannel"MouseClick="ListViewIPChannel_MouseClick"View="List"><forms:ListView.Items>                      </forms:ListView.Items></forms:ListView></WindowsFormsHost>--><ListView Height="150"Width="230"x:Name="ListViewIPChannel"MouseDoubleClick="ListViewIPChannel_MouseDoubleClick"Margin="10"SelectedIndex="0"><ListView.View><GridView><GridViewColumn Header="通道"x:Name="ColumnHeader1"Width="110"DisplayMemberBinding="{Binding str1}"></GridViewColumn><GridViewColumn Header="状态"x:Name="ColumnHeader2"Width="110"DisplayMemberBinding="{Binding str2}"></GridViewColumn></GridView></ListView.View></ListView><Button Height="40"Width="100"Content="登录"Name="BtnLogin"Margin="10"Click="BtnLogin_Click"></Button><Button Height="40"Width="100"Content="开始预览"Name="BtnPreview"Click="BtnPreview_Click"Margin="10"></Button>            </WrapPanel><WrapPanel Grid.Column="1" Grid.RowSpan="2"><WindowsFormsHost Width="500"Height="400"IsEnabled="False"Margin="10"><forms:PictureBox x:Name="RealPlayWnd"BorderStyle="None"Dock="Fill" /></WindowsFormsHost><ComboBox Height="30"Width="100"Text="BMP抓图"Name="ScreenshotBoxView"SelectedValuePath="BMP"Margin="10"><ComboBoxItem Content="BMP抓取"IsSelected="True"Tag=""></ComboBoxItem><ComboBoxItem Content="JPG抓取"></ComboBoxItem></ComboBox><Button Height="30"Width="100"Content="抓图"Name="ButtonCatch"Click="ButtonCatch_Click"Margin="10"></Button><Button Height="30"Width="100"Content="刷新"Name="BtnRefresh"Click="BtnRefresh_Click"Margin="10"></Button><Button Height="30"Width="100"Content="Exit"Name="ButtonExit"Click="ButtonExit_Click"Margin="10"></Button></WrapPanel></Grid>
</Window>

 4.3 C# 后台逻辑代码

using NVRCsharpDemo;
using System;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
using System.IO;
using static NVRCsharpDemo.CHCNetSDK;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
using System.Reflection.Emit;namespace project2
{public class data{public data(string str1,string str2){this.str1 = str1;this.str2 = str2;}public string str1 { get; set; }public string str2 { get; set; }}/// <summary>/// Interaction logic for MainWindow.xaml/// </summary>public partial class MainWindow : System.Windows.Window{private bool m_bInitSDK = false;private bool m_bRecord = false;private uint iLastErr = 0;private Int32 m_lUserID = -1;private Int32 m_lRealHandle = -1;private string str1;private string str2;private Int32 i = 0;private Int32 m_lTree = 0;private string str;private long iSelIndex = 0;private uint dwAChanTotalNum = 0;private uint dwDChanTotalNum = 0;private Int32 m_lPort = -1;private IntPtr m_ptrRealHandle;private int[] iIPDevID = new int[96];private int[] iChannelNum = new int[96];private CHCNetSDK.REALDATACALLBACK RealData = null;public CHCNetSDK.NET_DVR_DEVICEINFO_V30 DeviceInfo;public CHCNetSDK.NET_DVR_IPPARACFG_V40 m_struIpParaCfgV40;public CHCNetSDK.NET_DVR_STREAM_MODE m_struStreamMode;public CHCNetSDK.NET_DVR_IPCHANINFO m_struChanInfo;public CHCNetSDK.NET_DVR_PU_STREAM_URL m_struStreamURL;public CHCNetSDK.NET_DVR_IPCHANINFO_V40 m_struChanInfoV40;private PlayCtrl.DECCBFUN m_fDisplayFun = null;public delegate void MyDebugInfo(string str);public MainWindow(){InitializeComponent();m_bInitSDK = CHCNetSDK.NET_DVR_Init();if (m_bInitSDK == false){System.Windows.MessageBox.Show("NET_DVR_Init error!");return;}else{//保存SDK日志 To save the SDK logCHCNetSDK.NET_DVR_SetLogToFile(3, "C:\\SdkLog\\", true);ComboBoxView.SelectedIndex = 0;for (int i = 0; i < 64; i++){iIPDevID[i] = -1;iChannelNum[i] = -1;}}}public void DebugInfo(string str){if (str.Length > 0){str += "\n";// TextBoxInfo.AppendText(str);System.Windows.MessageBox.Show(str);}}/// <summary>/// 登录/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void BtnLogin_Click(object sender, EventArgs e){if (m_lUserID < 0){string DVRIPAddress = TextBoxIP.Text; //设备IP地址或者域名 Device IPInt16 DVRPortNumber = Int16.Parse(TextBoxPort.Text);//设备服务端口号 Device Portstring DVRUserName = TextBoxUserName.Text;//设备登录用户名 User name to loginstring DVRPassword = TextBoxPassword.Password;//设备登录密码 Password to loginif (CheckBoxHiDDNS.IsChecked == true){byte[] HiDDNSName = System.Text.Encoding.Default.GetBytes(TextBoxIP.Text);byte[] GetIPAddress = new byte[16];uint dwPort = 0;if (!CHCNetSDK.NET_DVR_GetDVRIPByResolveSvr_EX("www.hik-online.com", (ushort)80, HiDDNSName, (ushort)HiDDNSName.Length, null, 0, GetIPAddress, ref dwPort)){iLastErr = CHCNetSDK.NET_DVR_GetLastError();str = "NET_DVR_GetDVRIPByResolveSvr_EX failed, error code= " + iLastErr; //域名解析失败,输出错误号 Failed to login and output the error codeDebugInfo(str);return;}else{DVRIPAddress = System.Text.Encoding.UTF8.GetString(GetIPAddress).TrimEnd('\0');DVRPortNumber = (Int16)dwPort;}}//登录设备 Login the devicem_lUserID = CHCNetSDK.NET_DVR_Login_V30(DVRIPAddress, DVRPortNumber, DVRUserName, DVRPassword, ref DeviceInfo);if (m_lUserID < 0){iLastErr = CHCNetSDK.NET_DVR_GetLastError();str = "NET_DVR_Login_V30 failed, error code= " + iLastErr; //登录失败,输出错误号 Failed to login and output the error codeDebugInfo(str);return;}else{//登录成功DebugInfo("NET_DVR_Login_V30 succ!");BtnLogin.Content = "退出登录";dwAChanTotalNum = (uint)DeviceInfo.byChanNum;dwDChanTotalNum = (uint)DeviceInfo.byIPChanNum + 256 * (uint)DeviceInfo.byHighDChanNum;if (dwDChanTotalNum > 0){InfoIPChannel();}else{for (i = 0; i < dwAChanTotalNum; i++){ListAnalogChannel(i + 1, 1);iChannelNum[i] = i + (int)DeviceInfo.byStartChan;}//ComboBoxView.SelectedItem = 1;//System.Windows.MessageBox.Show("This device has no IP channel!");}}}else{//注销登录 Logout the deviceif (m_lRealHandle >= 0){DebugInfo("Please stop live view firstly"); //登出前先停止预览 Stop live view before logoutreturn;}if (!CHCNetSDK.NET_DVR_Logout(m_lUserID)){iLastErr = CHCNetSDK.NET_DVR_GetLastError();str = "NET_DVR_Logout failed, error code= " + iLastErr;DebugInfo(str);return;}DebugInfo("NET_DVR_Logout succ!");ListViewIPChannel.Items.Clear();//清空通道列表 Clean up the channel listm_lUserID = -1;BtnLogin.Content = "登录";}return;}public void InfoIPChannel(){uint dwSize = (uint)Marshal.SizeOf(m_struIpParaCfgV40);IntPtr ptrIpParaCfgV40 = Marshal.AllocHGlobal((Int32)dwSize);Marshal.StructureToPtr(m_struIpParaCfgV40, ptrIpParaCfgV40, false);uint dwReturn = 0;int iGroupNo = 0;  //该Demo仅获取第一组64个通道,如果设备IP通道大于64路,需要按组号0~i多次调用NET_DVR_GET_IPPARACFG_V40获取if (!CHCNetSDK.NET_DVR_GetDVRConfig(m_lUserID, CHCNetSDK.NET_DVR_GET_IPPARACFG_V40, iGroupNo, ptrIpParaCfgV40, dwSize, ref dwReturn)){iLastErr = CHCNetSDK.NET_DVR_GetLastError();str = "NET_DVR_GET_IPPARACFG_V40 failed, error code= " + iLastErr;//获取IP资源配置信息失败,输出错误号 Failed to get configuration of IP channels and output the error codeDebugInfo(str);}else{DebugInfo("NET_DVR_GET_IPPARACFG_V40 succ!");m_struIpParaCfgV40 = (CHCNetSDK.NET_DVR_IPPARACFG_V40)Marshal.PtrToStructure(ptrIpParaCfgV40, typeof(CHCNetSDK.NET_DVR_IPPARACFG_V40));for (i = 0; i < dwAChanTotalNum; i++){ListAnalogChannel(i + 1, m_struIpParaCfgV40.byAnalogChanEnable[i]);iChannelNum[i] = i + (int)DeviceInfo.byStartChan;}byte byStreamType = 0;uint iDChanNum = 64;if (dwDChanTotalNum < 64){iDChanNum = dwDChanTotalNum; //如果设备IP通道小于64路,按实际路数获取}for (i = 0; i < iDChanNum; i++){iChannelNum[i + dwAChanTotalNum] = i + (int)m_struIpParaCfgV40.dwStartDChan;byStreamType = m_struIpParaCfgV40.struStreamMode[i].byGetStreamType;dwSize = (uint)Marshal.SizeOf(m_struIpParaCfgV40.struStreamMode[i].uGetStream);switch (byStreamType){//目前NVR仅支持直接从设备取流 NVR supports only the mode: get stream from device directlycase 0:IntPtr ptrChanInfo = Marshal.AllocHGlobal((Int32)dwSize);Marshal.StructureToPtr(m_struIpParaCfgV40.struStreamMode[i].uGetStream, ptrChanInfo, false);m_struChanInfo = (CHCNetSDK.NET_DVR_IPCHANINFO)Marshal.PtrToStructure(ptrChanInfo, typeof(CHCNetSDK.NET_DVR_IPCHANINFO));//列出IP通道 List the IP channelListIPChannel(i + 1, m_struChanInfo.byEnable, m_struChanInfo.byIPID);iIPDevID[i] = m_struChanInfo.byIPID + m_struChanInfo.byIPIDHigh * 256 - iGroupNo * 64 - 1;Marshal.FreeHGlobal(ptrChanInfo);break;case 4:IntPtr ptrStreamURL = Marshal.AllocHGlobal((Int32)dwSize);Marshal.StructureToPtr(m_struIpParaCfgV40.struStreamMode[i].uGetStream, ptrStreamURL, false);m_struStreamURL = (CHCNetSDK.NET_DVR_PU_STREAM_URL)Marshal.PtrToStructure(ptrStreamURL, typeof(CHCNetSDK.NET_DVR_PU_STREAM_URL));//列出IP通道 List the IP channelListIPChannel(i + 1, m_struStreamURL.byEnable, m_struStreamURL.wIPID);iIPDevID[i] = m_struStreamURL.wIPID - iGroupNo * 64 - 1;Marshal.FreeHGlobal(ptrStreamURL);break;case 6:IntPtr ptrChanInfoV40 = Marshal.AllocHGlobal((Int32)dwSize);Marshal.StructureToPtr(m_struIpParaCfgV40.struStreamMode[i].uGetStream, ptrChanInfoV40, false);m_struChanInfoV40 = (CHCNetSDK.NET_DVR_IPCHANINFO_V40)Marshal.PtrToStructure(ptrChanInfoV40, typeof(CHCNetSDK.NET_DVR_IPCHANINFO_V40));//列出IP通道 List the IP channelListIPChannel(i + 1, m_struChanInfoV40.byEnable, m_struChanInfoV40.wIPID);iIPDevID[i] = m_struChanInfoV40.wIPID - iGroupNo * 64 - 1;Marshal.FreeHGlobal(ptrChanInfoV40);break;default:break;}}}Marshal.FreeHGlobal(ptrIpParaCfgV40);}public void ListIPChannel(Int32 iChanNo, byte byOnline, int byIPID){str1 = String.Format("IPCamera {0}", iChanNo);m_lTree++;if (byIPID == 0){str2 = "X"; //通道空闲,没有添加前端设备 the channel is idle                  }else{if (byOnline == 0){str2 = "offline"; //通道不在线 the channel is off-line}elsestr2 = "online"; //通道在线 The channel is on-line}ListViewIPChannel.Items.Add(new data(str1,str2));//ListViewIPChannel.Items.Add(new System.Windows.Forms.ListViewItem(new string[] { str1, str2 }));//将通道添加到列表中 add the channel to the list}public void ListAnalogChannel(Int32 iChanNo, byte byEnable){str1 = String.Format("Camera {0}", iChanNo);m_lTree++;if (byEnable == 0){str2 = "Disabled"; //通道已被禁用 This channel has been disabled               }else{str2 = "Enabled"; //通道处于启用状态 This channel has been enabled}ListViewIPChannel.Items.Add(new data(str1,str2));            // ListViewIPChannel.Items.Add(new System.Windows.Forms.ListViewItem(new string[] { str1, str2 }));//将通道添加到列表中 add the channel to the list}/// <summary>/// 判断预览通道/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void listViewIPChannel_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e){if (ListViewIPChannel.SelectedItems.Count > 0){iSelIndex = ListViewIPChannel.SelectedIndex;  //当前选中的行//iSelIndex = ListViewIPChannel.SelectedItems[0].Index;  //当前选中的行}}//解码回调函数private void DecCallbackFUN(int nPort, IntPtr pBuf, int nSize, ref PlayCtrl.FRAME_INFO pFrameInfo, int nReserved1, int nReserved2){// 将pBuf解码后视频输入写入文件中(解码后YUV数据量极大,尤其是高清码流,不建议在回调函数中处理)if (pFrameInfo.nType == 3) //#define T_YV12	3{//    FileStream fs = null;//    BinaryWriter bw = null;//    try//    {//        fs = new FileStream("DecodedVideo.yuv", FileMode.Append);//        bw = new BinaryWriter(fs);//        byte[] byteBuf = new byte[nSize];//        Marshal.Copy(pBuf, byteBuf, 0, nSize);//        bw.Write(byteBuf);//        bw.Flush();//    }//    catch (System.Exception ex)//    {//        MessageBox.Show(ex.ToString());//    }//    finally//    {//        bw.Close();//        fs.Close();//    }}}/// <summary>/// 直接预览/// </summary>/// <param name="lRealHandle"></param>/// <param name="dwDataType"></param>/// <param name="pBuffer"></param>/// <param name="dwBufSize"></param>/// <param name="pUser"></param>public void RealDataCallBack(Int32 lRealHandle, UInt32 dwDataType, IntPtr pBuffer, UInt32 dwBufSize, IntPtr pUser){//下面数据处理建议使用委托的方式MyDebugInfo AlarmInfo = new MyDebugInfo(DebugInfo);switch (dwDataType){case CHCNetSDK.NET_DVR_SYSHEAD:     // sys headif (dwBufSize > 0){if (m_lPort >= 0){return; //同一路码流不需要多次调用开流接口}//获取播放句柄 Get the port to playif (!PlayCtrl.PlayM4_GetPort(ref m_lPort)){iLastErr = PlayCtrl.PlayM4_GetLastError(m_lPort);str = "PlayM4_GetPort failed, error code= " + iLastErr;this.BeginInvoke(AlarmInfo, str);break;}//设置流播放模式 Set the stream mode: real-time stream modeif (!PlayCtrl.PlayM4_SetStreamOpenMode(m_lPort, PlayCtrl.STREAME_REALTIME)){iLastErr = PlayCtrl.PlayM4_GetLastError(m_lPort);str = "Set STREAME_REALTIME mode failed, error code= " + iLastErr;this.BeginInvoke(AlarmInfo, str);}//打开码流,送入头数据 Open streamif (!PlayCtrl.PlayM4_OpenStream(m_lPort, pBuffer, dwBufSize, 2 * 1024 * 1024)){iLastErr = PlayCtrl.PlayM4_GetLastError(m_lPort);str = "PlayM4_OpenStream failed, error code= " + iLastErr;this.BeginInvoke(AlarmInfo, str);break;}//设置显示缓冲区个数 Set the display buffer numberif (!PlayCtrl.PlayM4_SetDisplayBuf(m_lPort, 15)){iLastErr = PlayCtrl.PlayM4_GetLastError(m_lPort);str = "PlayM4_SetDisplayBuf failed, error code= " + iLastErr;this.BeginInvoke(AlarmInfo, str);}//设置显示模式 Set the display modeif (!PlayCtrl.PlayM4_SetOverlayMode(m_lPort, 0, 0/* COLORREF(0)*/)) //play off screen {iLastErr = PlayCtrl.PlayM4_GetLastError(m_lPort);str = "PlayM4_SetOverlayMode failed, error code= " + iLastErr;this.BeginInvoke(AlarmInfo, str);}//设置解码回调函数,获取解码后音视频原始数据 Set callback function of decoded datam_fDisplayFun = new PlayCtrl.DECCBFUN(DecCallbackFUN);if (!PlayCtrl.PlayM4_SetDecCallBackEx(m_lPort, m_fDisplayFun, IntPtr.Zero, 0)){this.BeginInvoke(AlarmInfo, "PlayM4_SetDisplayCallBack fail");}//开始解码 Start to play                       if (!PlayCtrl.PlayM4_Play(m_lPort, m_ptrRealHandle)){iLastErr = PlayCtrl.PlayM4_GetLastError(m_lPort);str = "PlayM4_Play failed, error code= " + iLastErr;this.BeginInvoke(AlarmInfo, str);break;}}break;case CHCNetSDK.NET_DVR_STREAMDATA:     // video stream dataif (dwBufSize > 0 && m_lPort != -1){for (int i = 0; i < 999; i++){//送入码流数据进行解码 Input the stream data to decodeif (!PlayCtrl.PlayM4_InputData(m_lPort, pBuffer, dwBufSize)){iLastErr = PlayCtrl.PlayM4_GetLastError(m_lPort);str = "PlayM4_InputData failed, error code= " + iLastErr;Thread.Sleep(2);}else{break;}}}break;default:if (dwBufSize > 0 && m_lPort != -1){//送入其他数据 Input the other datafor (int i = 0; i < 999; i++){if (!PlayCtrl.PlayM4_InputData(m_lPort, pBuffer, dwBufSize)){iLastErr = PlayCtrl.PlayM4_GetLastError(m_lPort);str = "PlayM4_InputData failed, error code= " + iLastErr;Thread.Sleep(2);}else{break;}}}break;}}/// <summary>/// 显示错误信息/// </summary>/// <param name="alarmInfo"></param>/// <param name="str"></param>/// <exception cref="NotImplementedException"></exception>private void BeginInvoke(MyDebugInfo alarmInfo, string str){throw new NotImplementedException();}/// <summary>/// 预览/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void BtnPreview_Click(object sender, EventArgs e){if (m_lUserID < 0){System.Windows.MessageBox.Show("Please login the device firstly!");return;}if (m_bRecord){System.Windows.MessageBox.Show("Please stop recording firstly!");return;}if (m_lRealHandle < 0){CHCNetSDK.NET_DVR_PREVIEWINFO lpPreviewInfo = new CHCNetSDK.NET_DVR_PREVIEWINFO();lpPreviewInfo.hPlayWnd = RealPlayWnd.Handle;//预览窗口 live view windowlpPreviewInfo.lChannel = iChannelNum[(int)iSelIndex];//预览的设备通道 the device channel numberlpPreviewInfo.dwStreamType = 0;//码流类型:0-主码流,1-子码流,2-码流3,3-码流4,以此类推lpPreviewInfo.dwLinkMode = 0;//连接方式:0- TCP方式,1- UDP方式,2- 多播方式,3- RTP方式,4-RTP/RTSP,5-RSTP/HTTP lpPreviewInfo.bBlocked = true; //0- 非阻塞取流,1- 阻塞取流lpPreviewInfo.dwDisplayBufNum = 15; //播放库显示缓冲区最大帧数IntPtr pUser = IntPtr.Zero;//用户数据 user data if (ComboBoxView.SelectedIndex == 0){//打开预览 Start live view m_lRealHandle = CHCNetSDK.NET_DVR_RealPlay_V40(m_lUserID, ref lpPreviewInfo, null/*RealData*/, pUser);}else{lpPreviewInfo.hPlayWnd = IntPtr.Zero;//预览窗口 live view windowm_ptrRealHandle = RealPlayWnd.Handle;RealData = new CHCNetSDK.REALDATACALLBACK(RealDataCallBack);//预览实时流回调函数 real-time stream callback function m_lRealHandle = CHCNetSDK.NET_DVR_RealPlay_V40(m_lUserID, ref lpPreviewInfo, RealData, pUser);}if (m_lRealHandle < 0){iLastErr = CHCNetSDK.NET_DVR_GetLastError();str = "NET_DVR_RealPlay_V40 failed, error code= " + iLastErr; //预览失败,输出错误号 failed to start live view, and output the error code.DebugInfo(str);return;}else{//预览成功DebugInfo("NET_DVR_RealPlay_V40 succ!");BtnPreview.Content = "停止预览";}}else{//停止预览 Stop live view if (!CHCNetSDK.NET_DVR_StopRealPlay(m_lRealHandle)){iLastErr = CHCNetSDK.NET_DVR_GetLastError();str = "NET_DVR_StopRealPlay failed, error code= " + iLastErr;DebugInfo(str);return;}if ((ComboBoxView.SelectedIndex == 1) && (m_lPort >= 0)){if (!PlayCtrl.PlayM4_Stop(m_lPort)){iLastErr = PlayCtrl.PlayM4_GetLastError(m_lPort);str = "PlayM4_Stop failed, error code= " + iLastErr;DebugInfo(str);}if (!PlayCtrl.PlayM4_CloseStream(m_lPort)){iLastErr = PlayCtrl.PlayM4_GetLastError(m_lPort);str = "PlayM4_CloseStream failed, error code= " + iLastErr;DebugInfo(str);}if (!PlayCtrl.PlayM4_FreePort(m_lPort)){iLastErr = PlayCtrl.PlayM4_GetLastError(m_lPort);str = "PlayM4_FreePort failed, error code= " + iLastErr;DebugInfo(str);}m_lPort = -1;}DebugInfo("NET_DVR_StopRealPlay succ!");m_lRealHandle = -1;BtnPreview.Content = "开始预览";RealPlayWnd.Invalidate();//刷新窗口 refresh the window}return;}/// <summary>/// 抓图/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void ButtonCatch_Click(object sender, RoutedEventArgs e){if (ScreenshotBoxView.SelectedIndex == 0){if (m_lRealHandle < 0){DebugInfo("Please start live view firstly!"); //BMP抓图需要先打开预览return;}string sBmpPicFileName;//图片保存路径和文件名 the path and file name to savesBmpPicFileName = "../image/test.bmp";if (ComboBoxView.SelectedIndex == 0){//BMP抓图 Capture a BMP pictureif (!CHCNetSDK.NET_DVR_CapturePicture(m_lRealHandle, sBmpPicFileName)){iLastErr = CHCNetSDK.NET_DVR_GetLastError();str = "NET_DVR_CapturePicture failed, error code= " + iLastErr;DebugInfo(str);return;}else{str = "NET_DVR_CapturePicture succ and the saved file is " + sBmpPicFileName;DebugInfo(str);}}else{int iWidth = 0, iHeight = 0;uint iActualSize = 0;if (!PlayCtrl.PlayM4_GetPictureSize(m_lPort, ref iWidth, ref iHeight)){iLastErr = PlayCtrl.PlayM4_GetLastError(m_lPort);str = "PlayM4_GetPictureSize failed, error code= " + iLastErr;DebugInfo(str);return;}uint nBufSize = (uint)(iWidth * iHeight) * 5;byte[] pBitmap = new byte[nBufSize];if (!PlayCtrl.PlayM4_GetBMP(m_lPort, pBitmap, nBufSize, ref iActualSize)){iLastErr = PlayCtrl.PlayM4_GetLastError(m_lPort);str = "PlayM4_GetBMP failed, error code= " + iLastErr;DebugInfo(str);}else{FileStream fs = new FileStream(sBmpPicFileName, FileMode.Create);fs.Write(pBitmap, 0, (int)iActualSize);fs.Close();str = "PlayM4_GetBMP succ and the saved file is " + sBmpPicFileName;DebugInfo(str);}}return;}else if (ScreenshotBoxView.SelectedIndex == 1){int lChannel = iChannelNum[(int)iSelIndex]; //通道号 Channel numberCHCNetSDK.NET_DVR_JPEGPARA lpJpegPara = new CHCNetSDK.NET_DVR_JPEGPARA();lpJpegPara.wPicQuality = 0; //图像质量 Image qualitylpJpegPara.wPicSize = 0xff; //抓图分辨率 Picture size: 0xff-Auto(使用当前码流分辨率) //抓图分辨率需要设备支持,更多取值请参考SDK文档//JPEG抓图保存成文件 Capture a JPEG picturestring sJpegPicFileName;sJpegPicFileName = "../image/filetest.jpg";//图片保存路径和文件名 the path and file name to saveif (!CHCNetSDK.NET_DVR_CaptureJPEGPicture(m_lUserID, lChannel, ref lpJpegPara, sJpegPicFileName)){iLastErr = CHCNetSDK.NET_DVR_GetLastError();str = "NET_DVR_CaptureJPEGPicture failed, error code= " + iLastErr;DebugInfo(str);return;}else{str = "NET_DVR_CaptureJPEGPicture succ and the saved file is " + sJpegPicFileName;DebugInfo(str);}//JEPG抓图,数据保存在缓冲区中 Capture a JPEG picture and save in the bufferuint iBuffSize = 400000; //缓冲区大小需要不小于一张图片数据的大小 The buffer size should not be less than the picture sizebyte[] byJpegPicBuffer = new byte[iBuffSize];uint dwSizeReturned = 0;if (!CHCNetSDK.NET_DVR_CaptureJPEGPicture_NEW(m_lUserID, lChannel, ref lpJpegPara, byJpegPicBuffer, iBuffSize, ref dwSizeReturned)){iLastErr = CHCNetSDK.NET_DVR_GetLastError();str = "NET_DVR_CaptureJPEGPicture_NEW failed, error code= " + iLastErr;DebugInfo(str);return;}else{//将缓冲区里的JPEG图片数据写入文件 save the data into a filestring str = "../image/buffertest.jpg";FileStream fs = new FileStream(str, FileMode.Create);int iLen = (int)dwSizeReturned;fs.Write(byJpegPicBuffer, 0, iLen);fs.Close();str = "NET_DVR_CaptureJPEGPicture_NEW succ and save the data in buffer to 'buffertest.jpg'.";DebugInfo(str);}return;}}/// <summary>///  刷新界面/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void BtnRefresh_Click(object sender, EventArgs e){//刷新通道列表ListViewIPChannel.Items.Clear();for (i = 0; i < dwAChanTotalNum; i++){ListAnalogChannel(i + 1, 1);iChannelNum[i] = i + (int)DeviceInfo.byStartChan;}InfoIPChannel();}/// <summary>/// 退出界面/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void ButtonExit_Click(object sender, RoutedEventArgs e){//停止预览if (m_lRealHandle >= 0){CHCNetSDK.NET_DVR_StopRealPlay(m_lRealHandle);m_lRealHandle = -1;}//注销登录if (m_lUserID >= 0){CHCNetSDK.NET_DVR_Logout(m_lUserID);m_lUserID = -1;}CHCNetSDK.NET_DVR_Cleanup();System.Windows.Application.Current.MainWindow.Close();// Application.Exit();}/// <summary>/// 勾选HIDDNS/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void checkBoxHiDDNS_Checked(object sender, RoutedEventArgs e){if (CheckBoxHiDDNS.IsChecked == true){//HiDDNS域名方式访问设备Label1.Content = "HiDDNS域名";TextBoxIP.Text = "a1234test";TextBoxPort.IsEnabled = false;}else{//IP地址或者普通域名方式访问设备Label1.Content = "设备IP/域名";TextBoxIP.Text = "192.168.1.123";TextBoxPort.IsEnabled = true;}}/// <summary>/// 通道配置/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void ListViewIPChannel_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e){if (e.Button == MouseButtons.Right){int iCurChan = iChannelNum[(int)iSelIndex];if (iCurChan >= m_struIpParaCfgV40.dwStartDChan){if (MessageBoxResult.OK == System.Windows.MessageBox.Show("是否配置该IP通道!", "配置提示", MessageBoxButton.OKCancel)){IPChannelConfig dlg = new IPChannelConfig();dlg.m_struIPParaCfgV40 = m_struIpParaCfgV40;dlg.m_lUserID = m_lUserID;int iCurChanIndex = iCurChan - (int)m_struIpParaCfgV40.dwStartDChan; //通道索引int iCurIPDevIndex = iIPDevID[iCurChanIndex]; //设备ID索引dlg.iIPDevIndex = iCurIPDevIndex;dlg.iChanIndex = iCurChanIndex;dlg.ShowDialog();}}else{}}}private void ListViewIPChannel_MouseDoubleClick(object sender, MouseButtonEventArgs e){int iCurChan = iChannelNum[(int)iSelIndex];if (iCurChan >= m_struIpParaCfgV40.dwStartDChan){if (MessageBoxResult.OK == System.Windows.MessageBox.Show("是否配置该IP通道!", "配置提示", MessageBoxButton.OKCancel)){IPChannelConfig dlg = new IPChannelConfig();dlg.m_struIPParaCfgV40 = m_struIpParaCfgV40;dlg.m_lUserID = m_lUserID;int iCurChanIndex = iCurChan - (int)m_struIpParaCfgV40.dwStartDChan; //通道索引int iCurIPDevIndex = iIPDevID[iCurChanIndex]; //设备ID索引dlg.iIPDevIndex = iCurIPDevIndex;dlg.iChanIndex = iCurChanIndex;dlg.ShowDialog();}}else{}}        }
}

4.4 功能实现

4.4.1 登录

点击登录按钮,提示登陆成功,登录按钮文字变为退出登录。

4.4.2 预览

点击开始预览按钮,提示预览成功,开始预览按钮文字变为停止预览。

 4.4.3 抓图

点击下拉列表,BMP和JPG两种抓图方式,点击抓图按钮,图片保存到Debug上一级文件夹中。

4.4.4 通道配置

双击通道内容,打开配置提示,点击确定进入通道配置

4.4.5 退出

点击Exit按钮,退出界面 。

4.5 小改动

原本的右键点击对通道的配置修改为双击对通道的配置。

原本的抓图是两个单独的按钮,修改为在ComboBox中进行选择不同的抓图方式。

对于海康威视的SDK只实现了部分功能,并不是全部相同。

五、关于延迟

相信大家自己实验过后就会发现,不论是自己写的程序还是SDK中的程序,与给定的程序相比,视频显示会有延迟。用python的Demo实验,延迟少很多。(记得根据帮助文档,将配置文件放入lib文件夹中)

以下是python延迟的实时监测,与原本软件的视频流延迟相差不大。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/32176.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

react笔记-03react-router篇

本文章是react的路由笔记 一、react路由&#xff08;v5版本&#xff09; 1. 什么是路由&#xff08;前端&#xff09;&#xff1f; 一个路由就算一个映射关系&#xff08;key: value)key为路径&#xff0c;value为组件 2. 前端路由的工作原理 根据浏览器历史记录&#xff…

双例集合(三)——双例集合的实现类之TreeMap容器类

Map接口有两个实现类&#xff0c;一个是HashMap容器类&#xff0c;另一个是TreeMap容器类。TreeMap容器类的使用在API上于HashMap容器类没有太大的区别。它们的区别主要体现在两个方面&#xff0c;一个是底层实现方式上&#xff0c;HashMap是基于Hash算法来实现的吗&#xff0c…

什么是电商大数据?主流电商大数据的采集||关键性技术|电商API接口接入说明

大数据的时代早已到来&#xff0c;然而想要全方位掌握大数据&#xff0c;务必要掌握大数据造成的时代特征&#xff0c;之前大数据被视为废物&#xff0c;如今被视为财产。主流电商大数据的采集&#xff0c;电商API接口的接入在大多数人理解中&#xff0c;是企业用数据来优化自己…

HackTheBox-Linux基础

Linux 结构 历史 许多事件导致了第一个 Linux 内核的创建&#xff0c;并最终创建了 Linux 操作系统 &#xff08;OS&#xff09;&#xff0c;从 1970 年 Ken Thompson 和 Dennis Ritchie&#xff08;当时都在 AT&T 工作&#xff09;发布 Unix 操作系统开始。伯克利软件发行…

微信小程序毕业设计-餐厅点餐系统项目开发实战(附源码+论文)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;微信小程序毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计…

OCC显示渲染结构剖析

1.Display显示 2.Drawer 3.Graphics 4.InteractiveContext 5.Render 6.Selection 7.View

图像分割(四)---(图像显示、灰度直方图和三维灰度图综合分析选取最佳分割方法)

一、引言 对彩色图像进行分割的一种常用方法&#xff0c;是先把彩色图像转灰度图像&#xff0c;然后再选择合适的阈值进行二值分割。但有时彩色图像转灰度图像后不具有典型的双峰特性&#xff0c;二值分割效果不好。本文章提出一种确定彩色图像分割方法的新思路。首先读入一幅彩…

以太坊==给合约转入/查询合约剩余/合约转给某账户/结构体/MAP

转入 必须要定义该函数&#xff0c;或者定义fallback // 接收以太币 receive() external payable {} // Corrected Line // SPDX-License-Identifier: MIT pragma solidity ^0.8.0;contract SimpleStorage {uint256 private storedData;// 事件&#xff0c;用于通知数据变更e…

Java-异常:不恰当的异常转换、不充分的日志记录、过度或不当的异常捕获

Java-异常&#xff1a;不恰当的异常转换、不充分的日志记录、过度或不当的异常捕获 Java-异常&#xff1a;不恰当的异常转换、不充分的日志记录、过度或不当的异常捕获一、前期准备二、案例分析1、不恰当的异常转换2、不充分日志记录3、过度或不当的异常捕获 三、正确处理方式1…

Open WebUI – 本地化部署大模型仿照 ChatGPT用户界面

Open WebUI介绍&#xff1a; Open WebUI 是一个仿照 ChatGPT 界面&#xff0c;为本地大语言模型提供图形化界面的开源项目&#xff0c;可以非常方便的调试、调用本地模型。你能用它连接你在本地的大语言模型&#xff08;包括 Ollama 和 OpenAI 兼容的 API&#xff09;&#xf…

emqx5.6.1 数据、配置备份与迁移

EMQX 支持导入和导出的数据包括&#xff1a; EMQX 配置重写的内容&#xff1a; 认证与授权配置规则、连接器与 Sink/Source监听器、网关配置其他 EMQX 配置内置数据库 (Mnesia) 的数据 Dashboard 用户和 REST API 密钥客户端认证凭证&#xff08;内置数据库密码认证、增强认证…

公共网络IP地址不正确?别担心,这里有解决方案

在数字化时代&#xff0c;公共网络IP地址的正确性对于我们的在线体验至关重要。它不仅是网络连接的标识&#xff0c;更是确保我们正常访问互联网资源、享受网络服务的基础。然而&#xff0c;有时我们可能会遇到公共网络IP地址不正确的情况&#xff0c;这不仅会影响我们的网络速…

【已解决】SpringBoot图片更新需重启服务器才能显示

问题描述 1、更新头像&#xff0c;并跳转回列表页&#xff0c;发现显示不出来 2、但是前端获取用户头像的信息是在加载页面就会被调用的&#xff0c;同时前端也不存在所谓的缓存问题&#xff0c;因为没有动这部分代码。 但查看响应是能获得正确的信息&#xff08;前端打印图片…

数据结构--单链表(图文)

单链表的概念 在单链表中&#xff0c;每个元素&#xff08;称为节点&#xff09;包含两部分&#xff1a;一部分是存储数据的数据域&#xff0c;另一部分是存储下一个节点地址的指针域。这里的“单”指的是每个节点只有一个指向下一个节点的指针。 节点&#xff1a;链表中的基…

Apple - Secure Coding Guide

本文翻译整理自&#xff1a;Secure Coding Guide https://developer.apple.com/library/archive/documentation/Security/Conceptual/SecureCodingGuide/Introduction.html#//apple_ref/doc/uid/TP40002477-SW1 文章目录 一、安全编码指南简介1、概览黑客和攻击者没有平台是免疫…

【办公类-50-01】20240620自主游戏观察记录表19周内容打乱

背景需求&#xff1a; 又到了期末&#xff0c;各种班级资料需要提交。 有一份自主游戏观察记录需要写19周&#xff08;每周2次&#xff09;的观察记录&#xff0c;并根据参考书填写一级、三级、五级的评价指标。 去年中六班的时候&#xff0c;我很认真的手写了21周的户外游戏…

具有 Hudi、MinIO 和 HMS 的现代数据湖

Apache Hudi 已成为管理现代数据湖的领先开放表格式之一&#xff0c;直接在现代数据湖中提供核心仓库和数据库功能。这在很大程度上要归功于 Hudi 提供了表、事务、更新/删除、高级索引、流式摄取服务、数据聚类/压缩优化和并发控制等高级功能。 我们已经探讨了 MinIO 和 Hudi…

Vue3 - 在项目中使用vue-i18n不生效的问题

检查和配置 Vue I18n 确保你已经正确安装了Vue I18n并且配置了组合API模式。 安装 Vue I18n npm install vue-i18nnext配置 i18n.js import { createI18n } from vue-i18n; import messages from ./messages;const i18n createI18n({legacy: false, // 使用组合 API 模式l…

Linux检查端口nmap

yum install -y nmap # 查看本机在运行的服务的端口号 nmap 127.0.0.1 补充&#xff1a;netstat netstat -tunlp | grep 3306

读《文明之光》第2册总结

《文明之光》系列大致按照从地球诞生到近现代的顺序讲述了人类文明进程的各个阶段&#xff0c;每个章节相对独立&#xff0c;全景式地展现了人类文明发展历程中的多样性。《文明之光》系列第二册讲述了从近代科学兴起&#xff0c;到工业革命时代&#xff0c;以及原子能应用这一…