1.以海康摄像头dll为例。(文章转载https://www.cnblogs.com/smartsensor/p/4343744.html)

海康SDK编程指南

目前使用的海康SDK包括IPC_SDK(硬件设备),Plat_SDK(平台),其中两套SDK都需单独调用海康播放库PlayCtrl.dll来解码视频流,返回视频信息和角度信息。本文仅对视频监控常用功能的使用进行说明,其它未实现功能请参看设备网络SDK使用手册播放库编程指南V7.2

IPC_SDK编程指南

(一)    SDK的引用

由于IPC_SDK没有SDK安装程序,所以需手工把下面图表中的DLL放入Debug或者Release文件夹的根目录下供程序调用,或者加入系统环境变量Path下。

名称

版本号

说明

AudioIntercom.dll

1.1.0.5

 

AudioRender.dll

1.0.0.2

 

DsSdk.dll

6.0.10.922

 

gdiplus.dll

 

微软库

HCNetSDK.dll

4.3.0.6

网络功能调用,大量功能调用此库

OpenAL32.dll

 

 

PlayCtrl.dll

7.2.0.0

播放库,定制版本,增加返角回调及数据结构

QosControl.dll

1.0.0.1

 

StreamTransClient.dll

1.1.2.12

 

SuperRender.dll

1.0.1.0

 

SystemTransform.dll

2.4.0.3

设备信息转发,根据播放库修改过

(二)    C#程序调用DLL中的非托管函数方法

1.        调用外部声明方法

首先在C#语言源程序中声明外部方法,其基本形式是:

[DLLImport(“DLL文件”)]

修饰符 extern 返回变量类型 方法名称 (参数列表)

例如:

1
2
3
4
using System.Runtime.InteropServices;
 
[DllImport("HCNetSDK.dll")]
public static extern bool NET_DVR_Init();

注意:

1)        需要在程序声明中使用System.Runtime.InteropServices命名空间。     DllImport只能放置在方法声明上。

2)        DLL文件必须位于程序当前目录或系统定义的查询路径中(即:系统环境变量中Path所设置的路径)。

3)        返回变量类型、方法名称、参数列表一定要与DLL文件中的定义相一致。

4)        若要使用其它函数名,可以使用EntryPoint属性设置,如:[DllImport("user32.dll", EntryPoint="MessageBoxA")]

static extern int MsgBox(int hWnd, string msg, string caption, int type);

5)        其它可选的 DllImportAttribute 属性:

CharSet 指示用在入口点中的字符集,如:CharSet=CharSet.Ansi;

SetLastError 指示方法是否保留 Win32"上一错误",如:SetLastError=true;

ExactSpelling 指示 EntryPoint 是否必须与指示的入口点的拼写完全匹配,

如:ExactSpelling=false;

PreserveSig指示方法的签名应当被保留还是被转换, 如:PreserveSig=true;

CallingConvention指示入口点的调用约定, 如:CallingConvention=CallingConvention.Winapi;

2.        参数数据类型转换

Win32 Types

CLR Type

char,INT8,SBYTE,CHAR

System.SByte

short,short int,INT16,SHORT

System.Int16

int,long,long int,INT32,LONG32,BOOL,INT

System.Int32

_int64,INT64,LONGLONG

System.Int64

unsigned char,UINT8,UCHAR,BYTE

System.Byte

unsigned short,UINT16,USHORT,WORD,ATOM,WCHAR,__wchar_t

System.UInt16

unsigned,unsigned int,UINT32,ULONG32,DWORD32,ULONG,DWORD,UINT

System.UInt32

unsigned __int64,UINT64,DWORDLONG,ULONGLONG

System.UInt64

float,FLOAT

System.Single

double,long double,DOUBLE

System.Double

BSTR

StringBuilder

LPCTSTR

StringBuilder

LPCWSTR

IntPtr

handle

IntPtr

hwnd

IntPtr

char *

string

int *

ref int

int &

ref int

void *

IntPtrs

unsigned char *

ref byte

BOOL ——

bool

DWORD

uint或int

注意:

  1. 指针做参数时在C#中一定要使用ref 或out关键字,尤其是结构体指针,要不会报内存读取错误
  2. 首先声明结构体 [StructLayoutAttribute(LayoutKind.Sequential)]
  3. 重写结构体的时候,之前有指明类型长度或数组长度的地方,也要进行相应的标注,要不也会导致内存错误

3.        重写结构体

例如:[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)],具体长度需参看SDK中改结构体的说明文档

或者

[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 64, ArraySubType = UnmanagedType.I1)]

4.        结构体与指针之间的转换

1)        结构体转换为指针

Hik.NET_DVR_IPPARACFG_V40 ipParaCfgV40 = new Hik.NET_DVR_IPPARACFG_V40();//初始化结构体结构体
Int32 size = Marshal.SizeOf(ipParaCfgV40);//返回结构体字节数
IntPtr ptrIpParaCfgV40 = Marshal.AllocHGlobal(size);//定义指针字节数
Marshal.StructureToPtr(ipParaCfgV40, ptrIpParaCfgV40, false);//将结构体封装到内存指针中
//调用需要指针的方法
Marshal.FreeHGlobal(ptrIpParaCfgV40);//释放指针

2)        指针转换为结构体

Hik.NET_DVR_CAMERAPARAMCFG_EX cameraParamCfg = new Hik.NET_DVR_CAMERAPARAMCFG_EX();//实例化结构体
Int32 size = Marshal.SizeOf(cameraParamCfg );//获取结构体字节数
IntPtr ptrCfg = Marshal.AllocHGlobal(size);//为指针分配空间
//调用获取指针的方法
cameraParamCfg = (Hik.NET_DVR_CAMERAPARAMCFG_EX)Marshal.PtrToStructure(ptrCfg, typeof(Hik.NET_DVR_CAMERAPARAMCFG_EX));//把指针转换为结构体
Marshal.FreeHGlobal(ptrCfg);//释放指针

3)        指针转换为结构体精简写法

Int32 size = Marshal.SizeOf(typeof(Hik.NET_DVR_PTZPOS));
IntPtr ptrPTZ = Marshal.AllocHGlobal(size);
//调用获取指针的方法
Hik.NET_DVR_PTZPOS PTZPos = (Hik.NET_DVR_PTZPOS)Marshal.PtrToStructure(ptrPTZ, typeof(Hik.NET_DVR_PTZPOS));//指针转换为结构体
Marshal.FreeHGlobal(ptrPTZ);//释放指针

对第2点和第3点的说明:当一个方法的参数为一个结构体的指针时,并且执行方法后此指针会返回结构体信息时,可以有两种方式来初始化这个指针,第二种更为简洁些。

(三)    SDK的调用

对IPC_SDK的C#封装类见附件Hik.cs,可参考此基础类文件进行程序功能编写。

1.        获取错误码

Hik.NET_DVR_GetLastError();//获取错误码

使用方式:如果每个非托管函数方法返回结果为false,则调用此方法获取错误码。

例如:

ret = Hik.NET_DVR_Init();
if (ret != true)
    throw new HikException(Hik.NET_DVR_GetLastError());//HikException为自定义异常调用类,用来解析错误码抛出异常

2.        登录

1)        用户注册

Hik.NET_DVR_Init();//初始化SDK,多次初始化会抛出错误
Hik.NET_DVR_SetConnectTime(2000, 1);//设置超时时间
Hik.NET_DVR_SetReconnect(10000, 1);//设置重连时间
Hik.NET_DVR_DEVICEINFO_V30 _deviceInfo = new Hik.NET_DVR_DEVICEINFO_V30();//登录参数结构体,可以返回设备信息
String userId = Hik.NET_DVR_Login_V30(IP,Port,UserName,Password,ref _deviceInfo);//登录后,获取用户ID和设备信息供后续方法调用

2)        用户注销

Hik.NET_DVR_StopRealPlay(_realHandle);//如果有预览视频,则根据其播放句柄关闭视频
Hik.NET_DVR_Logout(_userId);//根据用户ID注销用户登录
Hik.NET_DVR_Cleanup();//必须执行的释放IPC_SDK

3.        获取通道号

由于IPC_SDK同时支持IPC与NVR,所以两者获取通道号的方式有所不同。

1)        获取IPC设备通道号

如果Hik.NET_DVR_DEVICEINFO_V30结构体中byChanNum模拟通道数量属性值大于0,则代表登录设备为IPC设备,需要获取其模拟通道号byStartChan属性的值。每组模拟通道号范围为0-32。

for (Int32 i = 0; i < _deviceInfo.byChanNum; i++)//一个IPC设备可以设置多个模拟通道号,默认为一个模拟通道号
{
    Int channelId = _deviceInfo.byStartChan
}

2)        获取NVR设备通道号

如果Hik.NET_DVR_DEVICEINFO_V30结构体中byIPChanNum数字通道数量属性值大于0,则代表登录设备为NVR设备,需要获取其数字通道号,其获取方法要比获取IPC设备通道号复杂。每组数字通道号范围为33-64。

public void InfoIPChannel()
        {
 
            Hik.NET_DVR_IPPARACFG_V40 ipParaCfgV40 = new Hik.NET_DVR_IPPARACFG_V40();
            Int32 size = Marshal.SizeOf(ipParaCfgV40);
 
            IntPtr ptrIpParaCfgV40 = Marshal.AllocHGlobal(size);
            Marshal.StructureToPtr(ipParaCfgV40, ptrIpParaCfgV40, false);
 
            UInt32 result = 0;
            Int32 groupNo = 0;
            Boolean ret = Hik.NET_DVR_GetDVRConfig(_userId, Hik.NET_DVR_GET_IPPARACFG_V40, groupNo, ptrIpParaCfgV40, (UInt32)size, ref result);//获取配置信息
            if (ret)
            {
                ipParaCfgV40 = (Hik.NET_DVR_IPPARACFG_V40)Marshal.PtrToStructure(ptrIpParaCfgV40, typeof(Hik.NET_DVR_IPPARACFG_V40));
 
                byte byStreamType;
                for (Int32 i = 0; i < ipParaCfgV40.dwDChanNum; i++)
                {
 
                    byStreamType = ipParaCfgV40.struStreamMode[i].byGetStreamType;
                    size = Marshal.SizeOf(ipParaCfgV40.struStreamMode[i].uGetStream);
 
                    switch (byStreamType)
                    {
                        //目前NVR仅支持直接从设备取流 NVR supports only the mode: get stream from device directly
                        case 0:
                            IntPtr ptrChanInfo = Marshal.AllocHGlobal(size);
                            Marshal.StructureToPtr(ipParaCfgV40.struStreamMode[i].uGetStream, ptrChanInfo, false);
                            Hik.NET_DVR_IPCHANINFO _struChanInfo = (Hik.NET_DVR_IPCHANINFO)Marshal.PtrToStructure(ptrChanInfo, typeof(Hik.NET_DVR_IPCHANINFO));
                            Int32 deviceId = _struChanInfo.byIPID + _struChanInfo.byIPIDHigh * 256 - groupNo * 64 - 1;
                            if (deviceId == -1)
                                continue;
                            _channelInfoList.Add(new ChannelInfo() { DeviceID = deviceId, ChannelID = i + (Int32)ipParaCfgV40.dwStartDChan, State = (Int32)_struChanInfo.byEnable, IP = ipParaCfgV40.struIPDevInfo[i].struIP.sIpV4 });//获取数字通道信息封装到自定义通道类中
                            Marshal.FreeHGlobal(ptrChanInfo);
                            break;
                        default:
                            break;
                    }
                }
            }
            Marshal.FreeHGlobal(ptrIpParaCfgV40);
        }

4.        预览

1)        初始化预览结构体

Hik.NET_DVR_PREVIEWINFO previewInfo = new Hik.NET_DVR_PREVIEWINFO();
previewInfo.lChannel = channelId;//预览的设备通道 the device channel number
previewInfo.dwStreamType = 0;//码流类型:0-主码流,1-子码流,2-码流3,3-码流4,以此类推
previewInfo.dwLinkMode = 0;//连接方式:0- TCP方式,1- UDP方式,2- 多播方式,3- RTP方式,4-RTP/RTSP,5-RSTP/HTTP 
previewInfo.hPlayWnd = IntPtr.Zero;//预览窗口,如果不使用回调显示视频流,则此处可以设置显示窗口句柄
previewInfo.bBlocked = true; //0- 非阻塞取流,1- 阻塞取流

2)        获取实时视频流和视频句柄

_realHandle = Hik.NET_DVR_RealPlay_V40(UserId, ref previewInfo, realData, IntPtr.Zero);//返回实时流句柄供后续方法调用

参数说明:

UserID为登录后返回的用户句柄,

previewInfo为已实例化的预览结构体

realData为预览实时流回调函数,如果直接在窗口显示实时流而不通过回调方式,则此参数可以设置为null

3)        实时流回调函数的使用

/// <summary>
/// 预览实时流回调函数
/// </summary>
/// <param name="lRealHandle">当前的预览句柄</param>
/// <param name="dwDataType">数据类型:1系统头数据,2流数据(包括复合流或音视频分开的视频流数据),3音频数据</param>
/// <param name="pBuffer">存放数据的缓冲区指针</param>
/// <param name="dwBufSize">缓冲区大小</param>
/// <param name="pUser">用户数据</param>
public delegate void REALDATACALLBACK(Int32 lRealHandle, UInt32 dwDataType, IntPtr pBuffer, UInt32 dwBufSize, IntPtr pUser);

注意:实例化实时流回调函数时,不能在方法内声明并实例化,否则会被回收机制提前释放实例化对象,导致程序错误。需要在最外部调用类中作为字段预先声明。例如:

private Hik.REALDATACALLBACK _callback;//实时流回调,作为字段声明
public override int IncreaseClient()
{
    if (_callback == null)
         _callback = new Hik.REALDATACALLBACK(RealDataCallBack);
         Hik.StartPlay(Hik.ChannelInfoList[0].ChannelID, _callback);//播放实时流视频
}

简易流程描述为实时流回调函数返回实时视频流,然后把实时视频流传入到播放库解码,通过播放库的两个回调函数来返回解析后的视频流和角度。角度回调信息的格式为我公司定制协议,具体内容参看角度信息私有数据格式,59个字节长度的16进制字符串。

private Hik.DECCBFUN _displayCallback;//解码回调
private Hik.ADDITIONDATACBFUN _additionDataDisplayCallback;//角度回调

获取播放库错误码

Int port;
PlayM4_GetPort(ref port);//首先需获取播放句柄
PlayM4_GetLastError(port);//获取播放库错误码

具体回调如下:

int port;播放库端口号 
switch (dwDataType)
{
        case 1:     // sys head 系统头数据
        if (dwBufSize > 0)
        {
           //获取播放句柄 Get the port to play
           PlayM4_GetPort(ref _port);
           //设置流播放模式
           PlayM4_SetStreamOpenMode(_port, 0);
           //打开码流,送入头数据 Open stream
          PlayM4_OpenStream(_port, pBuffer, dwBufSize, 2 * 1024 * 1024);
           //设置显示缓冲区个数 
           PlayM4_SetDisplayBuf(_port, 15);
           //设置解码回调函数,获取解码后音视频原始数据 Set callback function of decoded data
           PlayM4_SetDecCallBackEx(_port, displayFun, IntPtr.Zero, 0);
           //设置角度回调函数,获取解码前角度信息
          PlayM4_SetAdditionDataCallBack(_port, 0x1004, additionDataDisplayFun, IntPtr.Zero);
          //开始解码 Start to play  
          PlayM4_Play(_port, IntPtr.Zero);//最后一个参数表示播放窗体的指针
          }
          break;
          case 2:     // video stream data 视频流数据(包括复合流和音视频分开的视频流数据)
          if (dwBufSize > 0 && _port != -1)
          {
            for (Int32 i = 0; i < 999; i++)
            {
              //送入码流数据进行解码 Input the stream data to decode
             if (!PlayM4_InputData(_port, pBuffer, dwBufSize))
                Thread.Sleep(2);
            else
                 break;  
                      }
            }
           break;
          default:
           if (dwBufSize > 0 && _port != -1)
           {
              //送入其他数据 Input the other data
             for (Int32 i = 0; i < 999; i++)
             {
              if (!PlayM4_InputData(_port, pBuffer, dwBufSize))
                  Thread.Sleep(2);
              else
                  break;
              }
            }
              break;
            }

4)        停止预览

Hik.NET_DVR_StopRealPlay(_realHandle);//_realHandle为播放句柄

5.        云台控制

1)        云台操作命令

            SET_PRESET = 8,// 设置预置点 
            CLE_PRESET = 9,// 清除预置点 
            Up = 21,/* 云台以SS的速度上仰 */
            Down = 22,/* 云台以SS的速度下俯 */
            Left = 23,/* 云台以SS的速度左转 */
            Right = 24,/* 云台以SS的速度右转 */
            UpLeft = 25,/* 云台以SS的速度上仰和左转 */
            UpRight = 26,/* 云台以SS的速度上仰和右转 */
            DownLeft = 27,/* 云台以SS的速度下俯和左转 */
            DownRight = 28,/* 云台以SS的速度下俯和右转 */
            Auto = 29,/* 云台以SS的速度左右自动扫描 */
            ZOOM_IN = 11,/* 焦距以速度SS变大(倍率变大) */
            ZOOM_OUT = 12,/* 焦距以速度SS变小(倍率变小) */
            FOCUS_NEAR = 13,  /* 焦点以速度SS前调 */
            FOCUS_FAR = 14,  /* 焦点以速度SS后调 */
            IRIS_OPEN = 15,  /* 光圈以速度SS扩大 */
            IRIS_CLOSE = 16,  /* 光圈以速度SS缩小 */
            GOTO_PRESET = 39/* 快球转到预置点 */

2)        云台操作方法

根据定制协议,云台控制速度为1-160。但是需保证球机的升级包版本为IPD_R3_STD_5.2.0_141111。

/// <summary>
/// 带速度的云台控制操作(需先启动图像预览)
/// </summary>
/// <param name="lRealHandle">NET_DVR_RealPlay_V40的返回值</param>
/// <param name="dwPTZCommand">云台控制命令</param>
/// <param name="dwStop">云台停止动作或开始动作:0- 开始;1- 停止</param>
/// <param name="dwSpeed">云台控制的速度,用户按不同解码器的速度控制值设置。取值范围[1,160]</param>
/// <returns>TRUE表示成功,FALSE表示失败</returns>
bool NET_DVR_PTZControlWithSpeed(int lRealHandle, uint dwPTZCommand, uint dwStop, uint dwSpeed);

6.        预置位

1)        预置位命令

     SET_PRESET = 8,// 设置预置点 
            CLE_PRESET = 9,// 清除预置点 
            GOTO_PRESET = 39// 转到预置点 

2)        预置位操作

/// <summary>
/// 设置预置位
/// </summary>
/// <param name="lRealHandle">NET_DVR_RealPlay_V40的返回值</param>
/// <param name="dwPTZPresetCmd">预置位控制命令</param>
/// <param name="dwPresetIndex">预置位编号最多支持255个预置点</param>
/// <returns>TRUE表示成功,FALSE表示失败</returns>
bool NET_DVR_PTZPreset(int lRealHandle, uint dwPTZPresetCmd, uint dwPresetIndex);

3)        反向操作

Hik.NET_DVR_PTZPreset(_realHandle, (uint)8, 33);

7.        获取前端参数配置

在设定某些配置时,需预先执行此方法来获取相关配置信息的结构体。

/// <summary>
/// 获取设备的配置信息
/// </summary>
/// <param name="lUserID">NET_DVR_Login_V30的返回值</param>
/// <param name="dwCommand">设备配置命令</param>
/// <param name="lChannel">通道号或者组号,不同的命令对应不同的取值</param>
/// <param name="lpOutBuffer">接收数据的缓冲指针</param>
/// <param name="dwOutBufferSize">接收数据的缓冲长度(以字节为单位),不能为0</param>
/// <param name="lpBytesReturned">实际收到的数据长度指针,不能为NULL</param>
/// <returns></returns>
bool NET_DVR_GetDVRConfig(int lUserID, uint dwCommand, int lChannel, IntPtr lpOutBuffer, uint dwOutBufferSize, ref uint lpBytesReturned);

具体调用见下面操作示例

8.        设置前端参数配置

/// <summary>
/// 设置设备的配置信息
/// </summary>
/// <param name="lUserID">NET_DVR_Login_V30的返回值</param>
/// <param name="dwCommand">设备配置命令</param>
/// <param name="lChannel">通道号或者组号,不同的命令对应不同的取值
<param>
/// <param name="lpInBuffer">输入数据的缓冲指针</param>
/// <param name="dwInBufferSize">输入数据的缓冲长度(以字节为单位)</param>
/// <returns></returns>
bool NET_DVR_SetDVRConfig(int lUserID, uint dwCommand, int lChannel, IntPtr lpInBuffer, uint dwInBufferSize);

具体调用见下面操作示例

9.        日夜切换

1)        设备配置命令

3369; //IPC设置CCD参数配置
3368; //IPC获取CCD参数配置

2)        通道号或者组号

ChannelId//登录IPC设备时获取的通道号

3)        获取配置信息

Hik.NET_DVR_CAMERAPARAMCFG_EX cameraParamCfg = new Hik.NET_DVR_CAMERAPARAMCFG_EX();//实例化前端参数结构体
Int32 nSize = Marshal.SizeOf(cameraParamCfg );//获取结构体空间大小
IntPtr ptrCfg = Marshal.AllocHGlobal(nSize);//设置指针大小
Hik.NET_DVR_GetDVRConfig(_userId,3368, _channelId, ptrCfg, (UInt32)nSize, ref dwReturn);//获取配置信息的指针
cameraParamCfg = (Hik.NET_DVR_CAMERAPARAMCFG_EX)Marshal.PtrToStructure(ptrCfg, typeof(Hik.NET_DVR_CAMERAPARAMCFG_EX));//指针转换为数据结构
Marshal.FreeHGlobal(ptrCfg);//释放指针

4)        日夜切换命令

0白天
1夜晚
2自动

5)        日夜切换结构体

NET_DVR_DAYNIGHT struDayNight;/*日夜转换*/

6)        设置配置信息

Hik.NET_DVR_CAMERAPARAMCFG_EX cameraParamCfg=获取配置信息();
Int32 size = Marshal.SizeOf(cameraParamCfg);//获取结构体大小
IntPtr ptrCfg = Marshal.AllocHGlobal(size);//设置指针空间大小
cameraParamCfg.struDayNight.byDayNightFilterType = (byte)日夜切换命令;
Marshal.StructureToPtr(cameraParamCfg, ptrCfg, false);//结构体转换为指针
Hik.NET_DVR_SetDVRConfig(_userId, 3369, _channelId, ptrCfg, (uint)size);//设置参数
Marshal.FreeHGlobal(ptrCfg);//释放指针

10.    透雾切换

1)        设备配置命令

3369; //IPC设置CCD参数配置
3368; //IPC获取CCD参数配置

2)        通道号或者组号

        ChannelId//登录IPC设备时获取的通道号

3)        获取配置信息

Hik.NET_DVR_CAMERAPARAMCFG_EX cameraParamCfg = new Hik.NET_DVR_CAMERAPARAMCFG_EX();//实例化前端参数结构体
Int32 nSize = Marshal.SizeOf(cameraParamCfg );//获取结构体空间大小
IntPtr ptrCfg = Marshal.AllocHGlobal(nSize);//设置指针大小
Hik.NET_DVR_GetDVRConfig(_userId,3368, _channelId, ptrCfg, (UInt32)nSize, ref dwReturn);//获取配置信息的指针
cameraParamCfg = (Hik.NET_DVR_CAMERAPARAMCFG_EX)Marshal.PtrToStructure(ptrCfg, typeof(Hik.NET_DVR_CAMERAPARAMCFG_EX));//指针转换为数据结构
Marshal.FreeHGlobal(ptrCfg);//释放指针

4)        透雾切换命令

0关闭
2开启

5)        透雾切换结构体

NET_DVR_DEFOGCFG struDefogCfg;//透雾参数

6)        设置配置信息

Hik.NET_DVR_CAMERAPARAMCFG_EX cameraParamCfg=获取配置信息();
Int32 size = Marshal.SizeOf(cameraParamCfg);//获取结构体大小
IntPtr ptrCfg = Marshal.AllocHGlobal(size);//设置指针空间大小
cameraParamCfg.struDefogCfg.byMode = (byte)透雾切换命令;
cameraParamCfg.struDefogCfg.byLevel = (byte)100;//透雾级别
Marshal.StructureToPtr(cameraParamCfg, ptrCfg, false);//结构体转换为指针
Hik.NET_DVR_SetDVRConfig(_userId, 3369, _channelId, ptrCfg, (uint)size);//设置参数
Marshal.FreeHGlobal(ptrCfg);//释放指针

11.    聚焦模式切换

1)        设备配置命令

        3306; //设置快球聚焦模式参数
        3305; //获取快球聚焦模式参数

2)        通道号或者组号

        ChannelId//登录IPC设备时获取的通道号

3)        获取配置信息

Hik.NET_DVR_FOCUSMODE_CFG focusModeCfg = new Hik.NET_DVR_FOCUSMODE_CFG();//实例化聚焦模式结构体
Int32 size = Marshal.SizeOf(focusModeCfg);//获取结构体大小
IntPtr ptrCfg = Marshal.AllocHGlobal(size);//设置指针空间大小
Hik.NET_DVR_GetDVRConfig(_userId, 3305, _channelId, ptrCfg, (UInt32)size, ref dwReturn);//获取聚焦模式信息的指针
focusModeCfg = (Hik.NET_DVR_FOCUSMODE_CFG)Marshal.PtrToStructure(ptrCfg, typeof(Hik.NET_DVR_FOCUSMODE_CFG));//指针转换为聚焦模式结构体
Marshal.FreeHGlobal(ptrCfg);//释放指针

4)        聚焦模式切换命令

0自动
1手动
2半自动

5)        聚焦模式切换结构体

NET_DVR_FOCUSMODE_CFG

6)        设置配置信息

Hik.NET_DVR_FOCUSMODE_CFG focusModeCfg = 获取配置信息();
Int32 size = Marshal.SizeOf(focusModeCfg);//获取结构体大小
IntPtr ptrCfg = Marshal.AllocHGlobal(size);//设置指针空间大小
focusModeCfg.byFocusMode = (byte)聚焦模式命令;
Marshal.StructureToPtr(focusModeCfg, ptrCfg, false);//结构体转换为指针
Hik.NET_DVR_SetDVRConfig(_userId, Hik.NET_DVR_SET_FOCUSMODECFG, _channelId, ptrCfg, (uint)size);//设置聚焦模式
Marshal.FreeHGlobal(ptrCfg);//释放指针

12.    OSD字符设置

1)        设备配置命令

1030;//获取叠加字符操作命令
1031;//设置叠加字符操作命令

2)        通道号或者组号

ChannelId//登录IPC设备时获取的通道号

3)        获取配置信息

Hik.NET_DVR_SHOWSTRING_V30 struShowStrCfg = new Hik.NET_DVR_SHOWSTRING_V30();//初始化叠加字符结构体
Int32 size = Marshal.SizeOf(struShowStrCfg);//获取结构体空间大小
IntPtr ptr = Marshal.AllocHGlobal(size);//设置指针大小
Hik.NET_DVR_GetDVRConfig(_userId, 1030, _channelId, ptr, (UInt32)size, ref dwReturn);//获取配置信息
struShowStrCfg = (Hik.NET_DVR_SHOWSTRING_V30)Marshal.PtrToStructure(ptr, typeof(Hik.NET_DVR_SHOWSTRING_V30));//指针转换为结构体
Marshal.FreeHGlobal(ptr);//释放指针

4)        叠加字符结构体

NET_DVR_SHOWSTRINGINFO struStringInfo;/* 要显示的字符内容 */

说明:设置叠加字符需要为其属性赋值。

5)        设置配置信息

Hik.NET_DVR_SHOWSTRING_V30 struShowStrCfg =获取叠加字符配置信息();
Int32 size = Marshal.SizeOf(struShowStrCfg);//获取结构体空间大小
IntPtr ptr = Marshal.AllocHGlobal(size);//设置指针空间大小
String osd = "海康智能监控视频一";
struShowStrCfg.struStringInfo[0].wShowString = 1;//1为显示,0为不显示
struShowStrCfg.struStringInfo[0].sString = osd;//叠加的字符串
struShowStrCfg.struStringInfo[0].wStringSize = (ushort)(osd.Length * 2);//字符串大小
struShowStrCfg.struStringInfo[0].wShowStringTopLeftX = 0;//坐标
struShowStrCfg.struStringInfo[0].wShowStringTopLeftY = 0;//坐标
Marshal.StructureToPtr(struShowStrCfg, ptr, false);//街头体转换为指针
Hik.NET_DVR_SetDVRConfig(_userId, 1031, _channelId, ptr, (UInt32)size);//设置配置信息
Marshal.FreeHGlobal(ptr);//释放指针

说明:可以叠加显示多个字符串。

13.    球机定位速度设置

1)        设备配置命令

3270;//获取PTZ基本参数信息
3271;//设置PTZ基本参数信息

2)        通道号或者组号

ChannelId//登录IPC设备时获取的通道号

3)        获取配置信息

Hik.NET_DVR_PTZ_BASICPARAMCFG basicParamCfg = new Hik.NET_DVR_PTZ_BASICPARAMCFG();//初始化PTZ基本参数结构体
Int32 size = Marshal.SizeOf(basicParamCfg);//获取结构体空间大小
IntPtr ptr = Marshal.AllocHGlobal(size);//设置指针大小
Hik.NET_DVR_GetDVRConfig(userId, 3270, _channelId, ptr, (UInt32)size, ref bytesReturned);//获取配置参数指针
basicParamCfg = (Hik.NET_DVR_PTZ_BASICPARAMCFG)Marshal.PtrToStructure(ptr, typeof(Hik.NET_DVR_PTZ_BASICPARAMCFG));//指针转换为结构体
Marshal.FreeHGlobal(ptr);//释放指针

4)        球机定位速度命令

1-8

5)        球机定位速度结构体

Hik.NET_DVR_PTZ_BASICPARAMCFG basicParamCfg

6)        设置配置信息

Hik.NET_DVR_PTZ_BASICPARAMCFG basicParamCfg = 获取配置信息();
Int32 size = Marshal.SizeOf(basicParamCfg);//获取结构体空间大小
IntPtr ptr = Marshal.AllocHGlobal(size);//设置指针空间大小
basicParamCfg.byPresetSpeed = (byte)速度值;
Marshal.StructureToPtr(basicParamCfg, ptr, false);//结构体转换为指针
Hik.NET_DVR_SetDVRConfig(userId, 3271, _channelId, ptr, size);//设置配置信息
Marshal.FreeHGlobal(ptr);//释放指针

14.    获取球机转动范围

1)        设备配置命令

294;//云台获取PTZ范围

2)        通道号或者组号

ChannelId//登录IPC设备时获取的通道号

3)        获取配置信息

Hik.NET_DVR_PTZSCOPE PTZScope = new Hik.NET_DVR_PTZSCOPE();//初始化球机范围信息结构体
Int32 size = Marshal.SizeOf(PTZScope);//获取结构体空间大小
IntPtr ptrScope = Marshal.AllocHGlobal(size);//设置指针空间大小
Hik.NET_DVR_GetDVRConfig(_userId, 294, _channelId, ptrScope, (UInt32)size, ref result);//获取配置信息
PTZScope = (Hik.NET_DVR_PTZSCOPE)Marshal.PtrToStructure(ptrScope, typeof(Hik.NET_DVR_PTZSCOPE));//指针转换为结构体
Marshal.FreeHGlobal(ptrScope);//释放指针

4)        球机转动范围结构体

Hik.NET_DVR_PTZSCOPE PTZScope

15.    球机定位

使用球机定位功能前,需先设置球机定位速度和获取球机转动范围,再根据球机转动范围信息来操作球机定位功能。

1)        设备配置命令

292;//云台设置PTZ位置
293;//云台获取PTZ位置

2)        通道号或者组号

ChannelId//登录IPC设备时获取的通道号

3)        获取配置信息

//用精简方式实现
Int32 size = Marshal.SizeOf(typeof(Hik.NET_DVR_PTZPOS));//获取球机位置信息结构体大小
IntPtr ptrPTZ = Marshal.AllocHGlobal(size);//设置指针空间大小
Hik.NET_DVR_GetDVRConfig(_userId, 293, _channelId, ptrPTZ, (UInt32)size, ref result);//获取球机位置配置信息
Hik.NET_DVR_PTZPOS PTZPos = (Hik.NET_DVR_PTZPOS)Marshal.PtrToStructure(ptrPTZ, typeof(Hik.NET_DVR_PTZPOS));//指针转换为结构体
Marshal.FreeHGlobal(ptrPTZ);//释放指针

4)        透雾切换结构体

Hik.NET_DVR_PTZPOS PTZPos

5)        设置配置信息

Hik.NET_DVR_PTZPOS PTZPos = 获取球机位置信息();
Int32 size = Marshal.SizeOf(PTZPos);//获取结构体空间大小
IntPtr ptr = Marshal.AllocHGlobal(size);//设置指针空间大小
PTZPos.wAction = 1;//-表示定位PTZ参数
//本结构体中的wAction参数是设置时的操作类型,因此获取时该参数无效。实际显示的PTZ值是获取到的十六进制值的十分之一,如获取的水平参数P的值是0x1750,实际显示的P值为175度;获取到的垂直参数T的值是0x0789,实际显示的T值为78.9度;获取到的变倍参数Z的值是0x1100,实际显示的Z值为110度。
String temp = "0x" + Convert.ToString(horAngle * 10);//实际显示的PTZ值是获取到的十六进制值的十分之一,所以需要把输入的数值乘以10再拼成十六进制字符串
PTZPos.wPanPos = Convert.ToUInt16(temp, 16);//转换为16进制水平角度
if (pitAngle >= 0)//判断俯仰角度的正负。由于零方位角的设置不同,会导致出现负的俯仰角度,所以处理方式不同
   PTZPos.wTiltPos = Convert.ToUInt16("0x" + Convert.ToString(pitAngle * 10), 16);
else
   PTZPos.wTiltPos = Convert.ToUInt16("0x" + Convert.ToString((pitAngle + 360) * 10), 16);
PTZPos.wZoomPos = Convert.ToUInt16("0x" + Convert.ToString(viewAngle * 10), 16);
Marshal.StructureToPtr(PTZPos, ptr, false);//结构体转换为指针
Hik.NET_DVR_SetDVRConfig(_userId, 292, _channelId, ptr, (uint)size);//设置配置
Marshal.FreeHGlobal(ptr);//释放指针

16.    零方位角控制

1)        设备配置命令

3283;// 零方位角控制

2)        通道号或者组号

ChannelId//登录IPC设备时获取的通道号

3)        零方位角控制命令

SET = 0,//设置
GOTO = 1,//调用
CLE = 2//清除

4)        零方位角控制结构体

Hik.NET_DVR_INITIALPOSITIONCTRL initialPositionCtrl

5)        设置控制信息

Hik.NET_DVR_INITIALPOSITIONCTRL initialPositionCtrl = new Hik.NET_DVR_INITIALPOSITIONCTRL();//初始化零方位角控制结构体
Int32 size = Marshal.SizeOf(initialPositionCtrl);//获取结构体空间大小
IntPtr ptr = Marshal.AllocHGlobal(size);//设置指针大小
initialPositionCtrl.dwSize = (uint)size;//结构体大小
initialPositionCtrl.dwChan = (uint)_channelId;//播放通道号
initialPositionCtrl.byWorkMode = (byte)command;//零方位角控制命令
Marshal.StructureToPtr(initialPositionCtrl, ptr, false);//结构体转换为指针
Hik.NET_DVR_RemoteControl(_userId, (uint)3283, ptr, (uint)size);//零方位角控制
Marshal.FreeHGlobal(ptr);//释放指针

17.    录像回放

此功能需要硬盘录像机支持。需要先登录NVR设备。在登录和获取数字通道号后,根据设备所对应的通道号操作相关IPC设备的一些基础功能。

1)        设备配置命令

1;//开始播放
2;//停止播放
3;//暂停播放
4;//恢复播放
5;//快放
6;//慢放
7;//正常速度
8;//单帧放
9;//打开声音
10;//关闭声音
11;//调节音量
12;//改变文件回放的进度
13;//获取文件回放的进度
14;//获取当前已经播放的时间(按文件回放的时候有效)
15;//获取当前已经播放的帧数(按文件回放的时候有效)
16;//获取当前播放文件总的帧数(按文件回放的时候有效)
17;//获取当前播放文件总的时间(按文件回放的时候有效)
20;//丢B帧
24;//设置码流速度
25;//保持与设备的心跳(如果回调阻塞,建议2秒发送一次)
26;//按绝对时间定位
27;//获取按时间回放对应时间段内的所有文件的总长度
29;//倒放切换为正放
30;//正放切换为倒放
32;//设置转封装类型
33;//正放切换为倒放

2)        初始化录像回放结构体

Hik.NET_DVR_VOD_PARA struVodPara = new Hik.NET_DVR_VOD_PARA();//初始化录像回放结构体
struVodPara.dwSize = (uint)Marshal.SizeOf(struVodPara);//获取结构体空间大小
struVodPara.struIDInfo.dwChannel = (uint)_ipChannelId; //数字通道号 Channel number,海康设备数字通道号从33开始  
//struVodPara.hWnd = this.pictureBoxVideo.Handle;//不使用回调获取回放视频时,使用此属性设置回放窗口句柄
 struVodPara.hWnd = IntPtr.Zero;//使用回调获取回放视频时,需如此设置回放窗口句柄
//设置回放的开始时间 Set the starting time to search video files
struVodPara.struBeginTime.dwYear = (uint)dateTimeStart.Value.Year;
struVodPara.struBeginTime.dwMonth = (uint)dateTimeStart.Value.Month;
struVodPara.struBeginTime.dwDay = (uint)dateTimeStart.Value.Day;
struVodPara.struBeginTime.dwHour = (uint)dateTimeStart.Value.Hour;
struVodPara.struBeginTime.dwMinute = (uint)dateTimeStart.Value.Minute;
struVodPara.struBeginTime.dwSecond = (uint)dateTimeStart.Value.Second;
//设置回放的结束时间 Set the stopping time to search video files
struVodPara.struEndTime.dwYear = (uint)dateTimeEnd.Value.Year;
struVodPara.struEndTime.dwMonth = (uint)dateTimeEnd.Value.Month;
struVodPara.struEndTime.dwDay = (uint)dateTimeEnd.Value.Day;
struVodPara.struEndTime.dwHour = (uint)dateTimeEnd.Value.Hour;
struVodPara.struEndTime.dwMinute = (uint)dateTimeEnd.Value.Minute;
struVodPara.struEndTime.dwSecond = (uint)dateTimeEnd.Value.Second;

3)        获取录像回放播放句柄

目前根据需求只实现根据录像起止时间范围播放录像视频,其他功能请参考SDK功能说明文档。

//按时间回放 Playback by time
_realHandle = Hik.NET_DVR_PlayBackByTime_V40(_NVRUserId, ref struVodPara);// struVodPara为录像回放结构体

4)        录像数据回调函数的使用

/// <summary>
/// 录像数据回调函数 
/// </summary>
/// <param name="lPlayHandle">当前的录像播放句柄</param>
/// <param name="dwDataType">数据类型</param>
/// <param name="pBuffer">存放数据的缓冲区指针</param>
/// <param name="dwBufSize">缓冲区大小</param>
/// <param name="pUser">用户数据</param>
public delegate void PlayDataCallBack_V40(Int32 lPlayHandle, UInt32 dwDataType, IntPtr pBuffer, UInt32 dwBufSize, IntPtr pUser);

此回调函数的使用方式与实时流回调函数的操作方式类似,都是获取视频流后,用播放库解码,返回角度信息和解码后的视频流。

Hik.NET_DVR_PlayBackControl_V40(_realHandle, 1, IntPtr.Zero, 0, IntPtr.Zero, ref iOutValue);//播放录像回放视频

5)        停止录像回放

Hik.NET_DVR_StopPlayBack(_realHandle)

18.    录像下载

1)        初始化录像下载结构体

Hik.NET_DVR_PLAYCOND struDownPara = new Hik.NET_DVR_PLAYCOND();//初始化录像下载结构体
struDownPara.dwChannel = (uint)_ipChannelId; //数字通道号 Channel number  
//设置下载的开始时间 Set the starting time
struDownPara.struStartTime.dwYear = (uint)dateTimeStart.Value.Year;
struDownPara.struStartTime.dwMonth = (uint)dateTimeStart.Value.Month;
struDownPara.struStartTime.dwDay = (uint)dateTimeStart.Value.Day;
struDownPara.struStartTime.dwHour = (uint)dateTimeStart.Value.Hour;
struDownPara.struStartTime.dwMinute = (uint)dateTimeStart.Value.Minute;
struDownPara.struStartTime.dwSecond = (uint)dateTimeStart.Value.Second;
//设置下载的结束时间 Set the stopping time
struDownPara.struStopTime.dwYear = (uint)dateTimeEnd.Value.Year;
struDownPara.struStopTime.dwMonth = (uint)dateTimeEnd.Value.Month;
struDownPara.struStopTime.dwDay = (uint)dateTimeEnd.Value.Day;
struDownPara.struStopTime.dwHour = (uint)dateTimeEnd.Value.Hour;
struDownPara.struStopTime.dwMinute = (uint)dateTimeEnd.Value.Minute;
struDownPara.struStopTime.dwSecond = (uint)dateTimeEnd.Value.Second;

2)        录像下载结构体

Hik.NET_DVR_PLAYCOND  struDownPara

3)        录像下载

录像下载后默认保存格式为mp4。

_realHandle = Hik.NET_DVR_GetFileByTime_V40(_NVRUserId, sVideoFileName, ref struDownPara);

Plat_SDK编程指南

海康平台可以挂载多个NVR设备,调用NVR下挂载的IPC设备时,只需要在海康平台的设备设置中找到其摄像头ID即可。

(一)    SDK的引用

具体引用方式,参见IPC_SDK的引用。由于海康平台技术人员提供的DLL文件过于繁杂,就不一一列出DLL的说明,详情参见IVMS_SDK文件夹目录。

(二)    C#程序调用DLL中的非托管函数方法

详情参见C#程序调用DLL中的非托管函数方法

(三)    SDK的调用

根据海康视频设备及平台使用的方案设计,只应用海康平台SDK的视频回调显示功能,其它功能暂不使用。对Plat_SDK的C#封装类见附件HikIVMS.cs,可参考此基础类文件进行程序功能编写。

1.        获取错误码

Plat_GetLastError(_userId);//获取错误码,userId为登录后获得的用户ID

使用方式:如果每个非托管函数方法返回结果不为0(正确),则调用此方法获取错误码。

例如:

Int32 ret = Plat_Init();
if (ret != 0)
   throw new HikIVMSException(Plat_GetLastError(_userId));// HikIVMSException为自定义异常调用类,用来解析错误码抛出异常

2.        登录

1)        用户注册

Int32 ret;
ret = Plat_Init();//platformSDK初始化
if (ret != 0)
   throw new HikIVMSException(Plat_GetLastError(_userId));
IntPtr ptrIP = Marshal.StringToHGlobalAnsi(uri.Host);//IP
IntPtr ptrUserName = Marshal.StringToHGlobalAnsi(a[0]);//用户名
IntPtr ptrPassword = Marshal.StringToHGlobalAnsi(a[1]);//密码
IntPtr ptrPort = Marshal.StringToHGlobalAnsi(uri.Port.ToString());//端口号
_userId = Plat_LoginCMS(ptrIP, ptrUserName, ptrPassword, ptrPort, 0);//登录
//释放指针
Marshal.FreeHGlobal(ptrIP);
Marshal.FreeHGlobal(ptrUserName);
Marshal.FreeHGlobal(ptrPassword);
Marshal.FreeHGlobal(ptrPort);

2)        用户注销

//如果存在播放的视频,也就是_streamHandle播放句柄>0,则先停止播放视频
Plat_StopVideo(_streamHandle);
Plat_LogoutCMS(_userId);//注销用户
Plat_Free();//释放SDK,必须执行

3.        预览

1)        播放预览

/// <summary>
/// 播放实时视频(开始预览/回放)
/// </summary>
/// <param name="url">预览或回放的播放路径,由Plat_QueryRealStreamURL或Plat_QueryRecordFile</param>
/// <param name="hWnd">播放窗口句柄,如果为空,则不播放</param>
/// <param name="userHandle">用户ID</param>
/// <param name="streamCallback">视频码流接收回调函数指针,如果回调函数为NULL则不给码流</param>
/// <returns>>=0成功,返回实时视频句柄,错误时返回-1</returns>
Int32 Plat_PlayVideo(String url, IntPtr hWnd, Int32 userHandle, fStreamCallback streamCallback, IntPtr user);

例如:

_streamHandle = Plat_PlayVideo(cameraId, IntPtr.Zero, _userId, callback, IntPtr.Zero);

注意:此函数的第一个参数,在应用中只需要传入摄像机ID即可。

2)        实时流回调函数的使用

/// <summary>
/// 实时流回调
/// </summary>
/// <param name="handle">Plat_PlayVideo返回的句柄</param>
/// <param name="data">接收视频码流数据缓冲区指针</param>
/// <param name="size">接收视频码流数据字节数</param>
/// <param name="user">用户数据</param>
public delegate void fStreamCallback(Int32 handle, IntPtr data, UInt32 size, IntPtr user, UInt32 dataType);

其调用方式与IPC_SDK中回调实时视频流的方式相同,都是调用播放库解码,然后返回角度信息和解码后的视频。详情参见IPC_SDK预览功能说明

示例如下:

private HikIVMS.fStreamCallback _callback;
private HikIVMS.DECCBFUN _displayCallback;//解码回调
private HikIVMS.ADDITIONDATACBFUN _additionDataDisplayCallback;//角度回调
 
if (_callback == null)
_callback = new HikIVMS.fStreamCallback(StreamCallback);
if (_displayCallback == null)
 _displayCallback = new HikIVMS.DECCBFUN(DecCallbackFUN);
if (_additionDataDisplayCallback == null)
 _additionDataDisplayCallback = new HikIVMS.ADDITIONDATACBFUN(AdditionDataCallBackFUN);
Hik.Play(cameraCode, _callback);

注意:Plat的回调函数与IPC回调函数中唯一的区别在于数据类型的定义不同,IPC的系统头数据类型为1,视频流数据类型为2;Plat系统头数据类型为0,视频流数据类型为1,仅此区别,其它相同。

c# 调取 c++ dll____c#调用dll的更多相关文章

  1. python调取C/C++的dll生成方法

    本文针对Windows平台下,python调取C/C++的dll文件. 1.如果使用C语言,代码如下,文件名为test.c. __declspec(dllexport) int sum(int a,i ...

  2. (转)python调取C/C++的dll生成方法

    本文针对Windows平台下,python调取C/C++的dll文件. 1.如果使用C语言,代码如下,文件名为test.c. __declspec(dllexport) int sum(int a,i ...

  3. Windows平台Go调用DLL的坑

    最近的项目中,使用了GO来开发一些服务中转程序.业务比较简单,但是有一些业务需要复用原有C++开发的代码.而在WINDOWS,用CGO方式来集成C/C++代码并不是太方便.所以用DLL把C++的代码封 ...

  4. Java 调用 C++ (Java 调用 dll)康哥手把手教你

    摘要: 本文原创,转载请注明地址 http://www.cnblogs.com/baokang/p/4979243.html 因为要做点图形处理的项目,需要在Java中调用dll库,所以开发的第一步是 ...

  5. 【转】C#调用DLL

    C#中如何调用动态链接库DLL(转)     每种编程语言调用DLL的方法都不尽相同,在此只对用C#调用DLL的方法进行介绍.首先,您需要了解什么是托管,什么是非托管.一般可以认为:非托管代码主要是基 ...

  6. C#程序实现动态调用DLL的研究(转)

    摘 要:在<csdn开发高手>2004年第03期中的<化功大法——将DLL嵌入EXE>一文,介绍了如何把一个动态链接库作为一个资源嵌入到可执行文件,在可执行文件运行时,自动从资 ...

  7. 外壳exe通过反射调用dll时

    外壳exe通过反射调用dll时,dll是 4.0的框架,外壳exe也需要编译成4.0的框架,如果dll本身有调用32位的dll,那么外壳exe也需要编译成32位. 调试时报的那个错,直接继续运行,不影 ...

  8. C++ exe调用dll文件

    生成dll程序 extern "C"_declspec(dllexport) void maopao(int *p,int count);void maopao(int *p,in ...

  9. 卸载AppDomain动态调用DLL异步线程执行失败

    应用场景 动态调用DLL中的类,执行类的方法实现业务插件功能 使用Assembly 来实现 但是会出现逻辑线程数异常的问题 使用AppDomain 实现动态调用,并卸载. 发现问题某个插件中开启异步线 ...

随机推荐

  1. Linux 学习第四天

    Linux学习第四天 一.常用命令 1.tar  (压缩.解压) A.添加压缩包  tar czvf 压缩包名称.tar.gz 源文件 B.添加压缩包  tar cjvf 压缩包名称.tar.bz2 ...

  2. PHP程序员面试中经常被提问的问题【转载】

    1. Include 与 require的区别,require和require_once的效率哪个高? Php在遇到include时就解释一次,如果页面中出现10次include,php就解释10次, ...

  3. Java实现“睡排序”——线程池Executors的使用

    前提 之前在知乎上看见一个有意思的排序算法——睡排序. 睡排序最早好像是4chan上一个用户用shell脚本实现的: 算法思想简洁明了:利用进程的sleep来实现 越大的数字越迟输出. 虽然像2L说的 ...

  4. js 中~~是什么意思?

    其实是一种利用符号进行的类型转换,转换成数字类型 ~~true == 1~~false == 0~~"" == 0~~[] == 0 ~~undefined ==0~~!undef ...

  5. mysql8.0.11的坑早知道

    1.plugin caching_sha2_password could not be loaded 我在mac上用Sequel Pro连数据库的时候,会报出以上错误,这是应为8.0.11把身份认证插 ...

  6. 网络文件系统nfs在ubuntu16.04的安装

    1.搜索nfs-sudo apt-cache search nfs- 2.安装sudo apt-get install nfs-kernel-server 3.配置:/etc/exports /hom ...

  7. Codeforces Round #482 (Div. 2) :B - Treasure Hunt

    题目链接:http://codeforces.com/contest/979/problem/B 解题心得: 这个题题意就是三个人玩游戏,每个人都有一个相同长度的字符串,一共有n轮游戏,每一轮三个人必 ...

  8. SpaceVim 语言模块 elixir

    原文连接: https://spacevim.org/cn/layers/lang/elixir/ 模块简介 功能特性 启用模块 快捷键 语言专属快捷键 交互式编程 运行当前脚本 模块简介 这一模块为 ...

  9. 使用OpenLayers发布地图

    OpenLayers是用于制作交互式Web地图的开源客户端JavaScript类库,制作的地图几乎可以在所有的浏览器中查看.因为是客户端类库,它不需要特殊的服务器端软件或配置,甚至不用下载任何东西就可 ...

  10. day 6 老王开枪打人

    1.图示 2 程序 1)版本1:框架的搭建 def main(): '''用来控制这个程序的流程''' pass #1.创建alex对象 #2.创建1个枪对象 #3.创建1个弹夹对象 #4.创建子弹对 ...