使用海康威视的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"
                     Block.TextAlignment="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"
                      d:ItemsSource="{d:SampleData ItemCount=5}">
                <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 log
                CHCNetSDK.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 IP
                Int16 DVRPortNumber = Int16.Parse(TextBoxPort.Text);//设备服务端口号 Device Port
                string DVRUserName = TextBoxUserName.Text;//设备登录用户名 User name to login
                string DVRPassword = TextBoxPassword.Password;//设备登录密码 Password to login

                
                if (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 code
                        DebugInfo(str);
                        return;
                    }
                    else
                    {
                        DVRIPAddress = System.Text.Encoding.UTF8.GetString(GetIPAddress).TrimEnd('\0');
                        DVRPortNumber = (Int16)dwPort;
                    }
                }

                //登录设备 Login the device
                m_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 code
                    DebugInfo(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 device
                if (m_lRealHandle >= 0)
                {
                    DebugInfo("Please stop live view firstly"); //登出前先停止预览 Stop live view before logout
                    return;
                }

                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 list
                m_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 code
                DebugInfo(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 directly
                        case 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 channel
                            ListIPChannel(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 channel
                            ListIPChannel(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 channel
                            ListIPChannel(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
                }
                else
                    str2 = "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 head
                    if (dwBufSize > 0)
                    {
                        if (m_lPort >= 0)
                        {
                            return; //同一路码流不需要多次调用开流接口
                        }

                        //获取播放句柄 Get the port to play
                        if (!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 mode
                        if (!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 stream
                        if (!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 number
                        if (!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 mode
                        if (!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 data
                        m_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 data
                    if (dwBufSize > 0 && m_lPort != -1)
                    {
                        for (int i = 0; i < 999; i++)
                        {
                            //送入码流数据进行解码 Input the stream data to decode
                            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;
                default:
                    if (dwBufSize > 0 && m_lPort != -1)
                    {
                        //送入其他数据 Input the other data
                        for (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 window
                lpPreviewInfo.lChannel = iChannelNum[(int)iSelIndex];//预览的设备通道 the device channel number
                lpPreviewInfo.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 window
                    m_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 save
                sBmpPicFileName = "../image/test.bmp";

                if (ComboBoxView.SelectedIndex == 0)
                {
                    //BMP抓图 Capture a BMP picture
                    if (!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 number

                CHCNetSDK.NET_DVR_JPEGPARA lpJpegPara = new CHCNetSDK.NET_DVR_JPEGPARA();
                lpJpegPara.wPicQuality = 0; //图像质量 Image quality
                lpJpegPara.wPicSize = 0xff; //抓图分辨率 Picture size: 0xff-Auto(使用当前码流分辨率) 
                                            //抓图分辨率需要设备支持,更多取值请参考SDK文档

                //JPEG抓图保存成文件 Capture a JPEG picture
                string sJpegPicFileName;
                sJpegPicFileName = "../image/filetest.jpg";//图片保存路径和文件名 the path and file name to save

                if (!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 buffer
                uint iBuffSize = 400000; //缓冲区大小需要不小于一张图片数据的大小 The buffer size should not be less than the picture size
                byte[] 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 file
                    string 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 小改动

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

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

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

五、关于延迟

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

以下是python延迟的实时监测

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

《现代通信原理与技术》模拟调制与解调—FM 调制实验报告

摘要 本实验旨在通过 MATLAB 软件进行模拟调制与解调的实践&#xff0c; 加深对频率调制&#xff08;Frequency Modulation, FM&#xff09;原理的理解&#xff0c;并掌 握 FM 调制与解调的实现方法。 关键词&#xff1a;MATLAB 引言 在现代通信系统中&#xff0c;调制技术是…

MySQL 创建数据表

创建MySQL数据表需要以下信息&#xff1a; 表名表字段名定义每个表字段 语法 以下为创建MySQL数据表的SQL通用语法&#xff1a; CREATE TABLE table_name (column_name column_type); 以下例子中我们将在 W3CSCHOOL 数据库中创建数据表w3cschool_tbl&#xff1a; CREAT…

win11 之下载安装 allure

1. 下载 https://repo.maven.apache.org/maven2/io/qameta/allure/allure-commandline/2.25.0/allure-commandline-2.25.0.zip 2. 配置系统变量 path 下添加解压后的bin目录 3. 验证是否安装成功 输入 allure

malloc和new的本质区别

目录 一、结论 二、示例 1.实现类T 2.用malloc分配类T的内存空间 3.用new分配类T的内存空间 一、结论 malloc 和 new 都是用于在运行时动态分配内存的机制。但它们之间存在一些本质的区别&#xff0c;主要是在使用方面&#xff0c;现在我们直接说结论&#xff0c;然后在通过…

docker拉取镜像的时候超时

问题描述&#xff1a; 有时候我们在使用docker拉取镜像的时候会遇到超时的情况迟迟拉取不下来&#xff0c;如下面 这时候我们需要设置成国内源&#xff1b; 操作步骤&#xff1a; 首先&#xff1a;创建docker目录 sudo mkdir -p /etc/docker其次&#xff1a;创建daemon文件…

MacOS - command not found: brew

问题描述 command not found: brew 原因分析 没有安装 Homebrew&#xff0c;安装后即可使用~ 解决方案 打开终端&#xff0c;输入&#xff1a;/bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"&#xff0c;点击回车 在弹出…

[C#]winform基于opencvsharp实现黑白图像上色

【算法简介】 技术有时会提高艺术&#xff0c;但有时也会破坏艺术。着色黑白电影是一个可以追溯到1902年的古老想法。几十年来&#xff0c;许多电影创作者反对将黑白电影着色的想法&#xff0c;并将其视为对艺术的破坏。但今天它被接受为艺术形式的增强。该技术本身已经从艰苦…

2024最新IDEA插件开发+发布全流程 SelectCamelWords[选中驼峰单词](idea源代码)

2024最新IDEA插件开发&#xff08;发布&#xff09;-SelectCamelWords[选中驼峰单词]&#xff08;idea源代码&#xff09; 参考文档 Jetbrains Idea插件开发文档: https://plugins.jetbrains.com/docs/intellij/welcome.html代码地址&#xff1a;https://github.com/yangfeng…

超大场景的三维模型(3D)轻量化的主要技术方法

超大场景的三维模型&#xff08;3D&#xff09;轻量化的主要技术方法 超大场景的三维模型在虚拟现实、游戏开发和可视化应用等领域具有重要的价值和应用前景。然而&#xff0c;由于其庞大的数据量和复杂的几何结构&#xff0c;给数据存储、传输和渲染带来了挑战。为了提高超大场…

搭建PHP开发环境:Linux篇

目录 一、引言 二、环境准备 三、安装Web服务器&#xff08;Apache&#xff09; Ubuntu/Debian系统&#xff1a; CentOS/Red Hat系统&#xff1a; 四、安装PHP解释器 Ubuntu/Debian系统&#xff1a; CentOS/Red Hat系统&#xff1a; 五、配置Apache以支持PHP Ubuntu/…

Hive期末总结

hive的概念&#xff0c;谁开发的 Apache Hive 是一个Apache 软件基金会维护的开源项目 Facebook贡献 hive是一个基于hadoop的数据仓库工具&#xff08;对数据汇总查询和分析的工具&#xff09; hive执行原理 Hive通过给用户提供的一系列交互接口&#xff0c;接收到用户的指令…

【x264】整体框架汇总

【x264】整体框架汇总 1. x264整体框架图2. 思考 参考&#xff1a; x264源代码简单分析&#xff1a;概述 参数分析&#xff1a; 【x264】x264编码器参数配置 流程分析&#xff1a; 【x264】x264编码主流程简单分析 【x264】编码核心函数&#xff08;x264_encoder_encode&…

创建型设计模式

1.设计模式是什么&#xff1f; 设计模式是指在软件开发过程中&#xff0c;经过验证的&#xff0c;用于解决在特定环境下&#xff0c;重复出现的&#xff0c;特定问题的解决方案。 软件设计过程中&#xff0c;解决问题的固定套路。 慎用设计模式。 2.设计模式是怎么来的&…

数据库实战(一)(关系数据库设计)

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;数据库 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 前言 练习题 题型一&#xff1a;判断关系…

“首秀”欧洲杯,海信冰箱欧洲市占率居国产品牌首位

随着欧洲杯的火热开赛&#xff0c;挑灯夜战、观看球赛的时刻已经来临。此时&#xff0c;你需要何物相伴&#xff1f;是打开冰箱&#xff0c;取出真空腌制的食材&#xff0c;亲手烹饪一场观赛盛宴&#xff1f;还是取出极致保鲜的荔枝、樱桃&#xff0c;一边观赛一边品味&#xf…

如何避免接口重复请求(axios推荐使用AbortController)

前言&#xff1a; 我们日常开发中&#xff0c;经常会遇到点击一个按钮或者进行搜索时&#xff0c;请求接口的需求。 如果我们不做优化&#xff0c;连续点击按钮或者进行搜索&#xff0c;接口会重复请求。 以axios为例&#xff0c;我们一般以以下几种方法为主&#xff1a; 1…

【文献阅读】Partially Adaptive Array Techniques

Abstract 文章研究了在多窄带干扰环境下&#xff0c;辅助阵元的选择&#xff0c;为部分自适应天线阵&#xff0c;以达到性能优化的目的。推导了双干扰问题的显式解。这个案例足以说明多个干扰的相互作用&#xff0c;同时也为更复杂的问题提供了一定程度的理解。本文还提出并讨…

如何实现ElementUI动态表头?

可能看到这个标题,有些小伙伴会有些疑惑,动态表头是个什么东西,怎么没听说过? 其实动态表头在企业的项目中用途还是非常广泛的,比如erp系统什么的 那么动态表头是什么呢?说简单点就是让ElementUI的Table表格可以实现自定义表头展示+表头拖拽排序的一个功能 这个东西我…

本地运行大语言模型(LLMs)

用例 像PrivateGPT、llama.cpp、Ollama、GPT4All、llamafile 等项目的流行度凸显了本地&#xff08;在您自己的设备上&#xff09;运行大型语言模型&#xff08;LLMs&#xff09;的需求。 这至少有两个重要的好处&#xff1a; 1.隐私&#xff1a;您的数据不会发送给第三方&a…

Mars3d实现汽车尾气粒子效果从汽车屁股开始发射效果

本身的汽车尾气粒子效果&#xff1a;在汽车模型的中间发射的↓↓↓↓↓↓↓↓↓↓↓ Mars3d实例中是使用transY偏移值实现汽车尾气粒子效果从汽车屁股开始发射效果&#xff1a; // 动态运行车辆的尾气粒子效果 function addDemoGraphic4(graphicLayer) {const fixedRoute new…