解决方案:Unity调用大华相机SDK采集图像及基本功能设定
优采云 发布时间: 2022-12-01 22:39解决方案:Unity调用大华相机SDK采集图像及基本功能设定
unity平台对视频播放不是很友好,大华的SDK只有ac#版本,并没有专门做unity的SDK。一开始,我尝试使用SDK中的方法获取YUV格式的视频流,接下来说说YUV格式的视频流。转换成unity可以播放的格式,但是这种格式转换经常出问题,很卡,所以用了ump插件播放rtsp视频流,比较流畅。
ump插件下载链接: 提取码:ahez(仅供学习,请勿商用)
大华设备rtsp流组成分析:
rtsp://[用户名]:[密码]@[地址]:[端口]/cam/realmonitor?channel=[id]&subtype=[类型]
rtsp:// => 协议格式头
用户名 => 用户名,例如:admin
密码 => 密码,例如:123456
address => IPC设备的网络地址,例如:192.168.1.65
port => IPC设备的RTSP输出端口,默认为554,如果是默认可以留空
id => 频道号,从1开始。比如频道2,那么channel=2。
type => 流类型,主流为0(即subtype=0),辅流为1(即subtype=1)。
原文链接:(原文介绍了大华和海康的rtsp视频流组成,我这里只用大华的,需要海康的请自行查找)
插件非常简单易用,只需将UniversalMediaPlayer预制件拖放到场景中,修改脚本上的rtsp流,即可观看视频。
但!由于执法记录仪上没有我们需要的功能,所以我们定制了自己需要的功能,然后对执法记录仪进行了系统升级。结果,升级之后,之前的获取rtsp视频流的功能居然不可用了。联系大华技术部后得出结论,欣赏后不能用rtsp播放视频流,需要的话可以自定义。emm……这就很尴尬了,定制是不可能的,但问题还是要解决。在热心和同步的提示和帮助下,我们采用了使用winform程序播放视频的方法。虽然界面有点丑,但还是完成了需要的功能。
窗体代码:
调用大华SDK
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using NetSDKCS;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.IO;
using System;
using System.Collections.Generic;
namespace MeshDaHuaTool
{
public class DaHuaManager
{
#region Field 字段,属性
private const int m_WaitTime = 5000;
private const int SyncFileSize = 5 * 1024 * 1204;
private static fDisConnectCallBack m_DisConnectCallBack;
private static fHaveReConnectCallBack m_ReConnectCallBack;
private static fRealDataCallBackEx2 m_RealDataCallBackEx2;
private static fSnapRevCallBack m_SnapRevCallBack;
private static fAudioDataCallBack m_AudioDataCallBack;
private IntPtr m_LoginID = IntPtr.Zero;
private IntPtr m_TalkID = IntPtr.Zero;
private NET_DEVICEINFO_Ex m_DeviceInfo;
private IntPtr m_RealPlayID = IntPtr.Zero;
private uint m_SnapSerialNum = 1;
private bool m_IsInSave = false;
private bool m_Islogin = false;
//对讲参数
private const int SampleRate = 8000;
private const int AudioBit = 16;
private const int PacketPeriod = 25;
private const int SendAudio = 0;
private const int ReviceAudio = 1;
//回放参数
private IntPtr m_PlayBackID = IntPtr.Zero;
//下载录像参数
IntPtr m_DownloadID = IntPtr.Zero;
fTimeDownLoadPosCallBack m_DownloadPosCallBack;
///
/// 步长速度
///
private int SpeedValue = 4;
///
/// 最大步长速度
///
private const int MaxSpeed = 8;
///
/// 最小步长速度
///
private const int MinSpeed = 1;
///
/// 抓图保存根目录
///
private string m_CaptureImageDirectory;
///
/// 获取SDK错误
///
private string LastError
{
get
{
return NETClient.GetLastError();
}
}
///
/// 是否正在保存视频
///
public bool IsinSave
{
get
{
return m_IsInSave;
}
}
#endregion
#region 回调
public Action OnSucess;
public Action OnError;
public Action OnCaptureSucced;
#endregion
///
/// 初始化
///
public void Init()
{
m_DisConnectCallBack = new fDisConnectCallBack(DisConnectCallBack);
m_ReConnectCallBack = new fHaveReConnectCallBack(ReConnectCallBack);
m_RealDataCallBackEx2 = new fRealDataCallBackEx2(RealDataCallBackEx);
m_SnapRevCallBack = new fSnapRevCallBack(SnapRevCallBack);
m_AudioDataCallBack = new fAudioDataCallBack(AudioDataCallBack);
m_DownloadPosCallBack = new fTimeDownLoadPosCallBack(TimeDownLoadPosCallBack);
try
{
//注册回调函数
NETClient.Init(m_DisConnectCallBack, IntPtr.Zero, null);
NETClient.SetAutoReconnect(m_ReConnectCallBack, IntPtr.Zero);
NETClient.SetSnapRevCallBack(m_SnapRevCallBack, IntPtr.Zero);
//抓图路径赋值
m_CaptureImageDirectory = @"C:\img";
if (!Directory.Exists(m_CaptureImageDirectory))
{
Directory.CreateDirectory(m_CaptureImageDirectory);
}
}
catch (Exception ex)
{
OnError?.Invoke(new ErrorArgs(ErrorType.None, ex.Message));
Process.GetCurrentProcess().Kill();
}
}
///
/// 登录大华平台
///
/// IP地址
/// 端口
/// 用户名
/// 密码
public void Login(string ip, ushort port, string username, string password)
{
if (IntPtr.Zero == m_LoginID)
{
m_DeviceInfo = new NET_DEVICEINFO_Ex();
m_LoginID = NETClient.Login(ip, port, username, password, EM_LOGIN_SPAC_CAP_TYPE.TCP, IntPtr.Zero, ref m_DeviceInfo);
if (IntPtr.Zero == m_LoginID)
{
OnError?.Invoke(new ErrorArgs(ErrorType.Login, LastError));
return;
}
OnSucess?.Invoke(ErrorType.Login);
m_Islogin = true;
}
}
///
/// 登出
///
public void Logout()
{
if (!m_Islogin)
{
return;
}
//关闭对讲
if (IntPtr.Zero != m_TalkID && IntPtr.Zero != m_LoginID)
{
NETClient.RecordStop(m_LoginID);
NETClient.StopTalk(m_TalkID);
}
if (IsinSave)
{
StopSaveVideo();
}
if (m_RealPlayID != IntPtr.Zero)
{
StopRealPlay();
}
m_Islogin = false;
if (m_LoginID == IntPtr.Zero)
{
OnError?.Invoke(new ErrorArgs(ErrorType.Logout, "m_LoginID zero"));
return;
}
bool result = NETClient.Logout(m_LoginID);
if (!result)
{
OnError?.Invoke(new ErrorArgs(ErrorType.Logout, LastError));
return;
}
m_LoginID = IntPtr.Zero;
m_RealPlayID = IntPtr.Zero;
OnSucess?.Invoke(ErrorType.Logout);
}
///
/// 开始实时播放
///
///
public void StartRealPlay(PictureBox realplay_pictureBox)
{
if (!m_Islogin)
{
OnError?.Invoke(new ErrorArgs(ErrorType.StartRealPlay, "未登录"));
return;
}
if (IntPtr.Zero == m_RealPlayID)
{
// realplay 监视
EM_RealPlayType type = GetRealPlayType();
m_RealPlayID = NETClient.RealPlay(m_LoginID, GetChanel(), realplay_pictureBox.Handle, type);
if (IntPtr.Zero == m_RealPlayID)
{
OnError?.Invoke(new ErrorArgs(ErrorType.StartRealPlay, LastError));
return;
}
}
}
///
/// 打开声音
///
public void OpenSound()
{
if (!NETClient.OpenSound(m_RealPlayID))
{
OnError?.Invoke(new ErrorArgs(ErrorType.None, "打开声音错误: " + LastError));
}
}
///
/// 关闭声音
///
public void StopSound()
{
if (!NETClient.CloseSound())
{
OnError?.Invoke(new ErrorArgs(ErrorType.None, "关闭声音失败: " + LastError));
}
}
///
/// 停止播放
///
public void StopRealPlay()
{
if (!m_Islogin)
{
OnError?.Invoke(new ErrorArgs(ErrorType.StopRealPlay, "未登录"));
return;
}
if (IntPtr.Zero == m_RealPlayID)
{
OnError?.Invoke(new ErrorArgs(ErrorType.StopRealPlay, "未开始播放,无法停止"));
return;
}
bool ret = NETClient.StopRealPlay(m_RealPlayID);
if (!ret)
{
OnError?.Invoke(new ErrorArgs(ErrorType.StopRealPlay, LastError));
return;
<p>
" />
}
m_RealPlayID = IntPtr.Zero;
OnSucess?.Invoke(ErrorType.StopRealPlay);
}
///
/// 抓图
///
/// false 本地抓图,true 远程抓图
public void CaptureImage(bool isRemote = false)
{
//重新设置远程抓图的回调
NETClient.SetSnapRevCallBack(m_SnapRevCallBack, IntPtr.Zero);
if (!m_Islogin)
{
OnError?.Invoke(new ErrorArgs(ErrorType.CaptureImage, "未登录"));
return;
}
if (isRemote)
{
NET_SNAP_PARAMS asyncSnap = new NET_SNAP_PARAMS();
asyncSnap.Channel = (ushort)GetChanel();
asyncSnap.Quality = 6;
asyncSnap.ImageSize = 2;
asyncSnap.mode = 0;
asyncSnap.InterSnap = 0;
asyncSnap.CmdSerial = m_SnapSerialNum;
bool ret = NETClient.SnapPictureEx(m_LoginID, asyncSnap, IntPtr.Zero);
if (!ret)
{
OnError?.Invoke(new ErrorArgs(ErrorType.CaptureImage, LastError));
return;
}
m_SnapSerialNum++;
}
else
{
if (IntPtr.Zero == m_RealPlayID)
{
Console.WriteLine("没有打开实时预览,无法抓图");
return;
}
string fileName = "local_" + DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss") + ".jpg";
string filePath = @"C:\img" + "\\" + "client_" + fileName;
bool result = NETClient.CapturePicture(m_RealPlayID, filePath, EM_NET_CAPTURE_FORMATS.JPEG);
if (!result)
{
OnError?.Invoke(new ErrorArgs(ErrorType.CaptureImage, LastError));
return;
}
}
}
///
/// 保存视频
///
public void SaveVideo()
{
if (IntPtr.Zero == m_RealPlayID)
{
OnError?.Invoke(new ErrorArgs(ErrorType.StartSaveVideo, "未打开预览,无法保存录像"));
return;
}
if (m_IsInSave)
{
OnError?.Invoke(new ErrorArgs(ErrorType.StartSaveVideo, "保存中,不要重复操作"));
return;
}
SaveFileDialog saveFileDialog = new SaveFileDialog();
saveFileDialog.FileName = "video_" + DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss");
saveFileDialog.Filter = "|*.dav";
string path = @"C:\savedata";
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
saveFileDialog.InitialDirectory = path;
var res = saveFileDialog.ShowDialog();
if (res == System.Windows.Forms.DialogResult.OK)
{
m_IsInSave = NETClient.SaveRealData(m_RealPlayID, saveFileDialog.FileName); //call saverealdata function.
if (!m_IsInSave)
{
saveFileDialog.Dispose();
OnError?.Invoke(new ErrorArgs(ErrorType.StartSaveVideo, LastError));
}
OnSucess?.Invoke(ErrorType.StartSaveVideo);
}
saveFileDialog.Dispose();
}
///
/// 停止保存视频
///
public void StopSaveVideo()
{
if (m_IsInSave)
{
bool ret = NETClient.StopSaveRealData(m_RealPlayID);
if (!ret)
{
Console.WriteLine(LastError);
return;
}
m_IsInSave = false;
OnSucess?.Invoke(ErrorType.StopSaveVideo);
}
}
#region 云台控制
///
/// 设置步长,范围在1-8
///
/// 步长速度
public void SetStepSpeed(int speedValue)
{
SpeedValue = Utility.Math.Clamp(speedValue, MinSpeed, MaxSpeed);
}
///
/// 云台控制消息 正上方为0 顺时针递增 0-7 是方向控制
/// 8-9是zoom, 8+ ,9-
/// 10-11是变焦,10+,11-
/// 12-13是光圈,12+,13-
///
public void PTZControl(string type)
{
switch (type)
{
case "0":
PTZControl(EM_EXTPTZ_ControlType.UP_CONTROL, 0, SpeedValue, true);
break;//上
case "1":
PTZControl(EM_EXTPTZ_ControlType.RIGHTTOP, SpeedValue, SpeedValue, true);
break;//右上
case "2":
PTZControl(EM_EXTPTZ_ControlType.RIGHT_CONTROL, 0, SpeedValue, true);
break;//右
case "3":
PTZControl(EM_EXTPTZ_ControlType.RIGHTDOWN, SpeedValue, SpeedValue, true);
break;//右下
case "4":
PTZControl(EM_EXTPTZ_ControlType.DOWN_CONTROL, 0, SpeedValue, true);
break;//下
case "5":
PTZControl(EM_EXTPTZ_ControlType.LEFTDOWN, SpeedValue, SpeedValue, true);
break;//左下
case "6":
PTZControl(EM_EXTPTZ_ControlType.LEFT_CONTROL, 0, SpeedValue, true);
break;//左
case "7":
PTZControl(EM_EXTPTZ_ControlType.LEFTTOP, SpeedValue, SpeedValue, true);
break;//左上
case "8":
PTZControl(EM_EXTPTZ_ControlType.ZOOM_ADD_CONTROL, 0, SpeedValue, true);
break;//zoom+
case "9":
PTZControl(EM_EXTPTZ_ControlType.ZOOM_DEC_CONTROL, 0, SpeedValue, true);
break;//zoom-
case "10":
PTZControl(EM_EXTPTZ_ControlType.FOCUS_ADD_CONTROL, 0, SpeedValue, true);
break;//变焦+
case "11":
PTZControl(EM_EXTPTZ_ControlType.FOCUS_DEC_CONTROL, 0, SpeedValue, true);
break;//变焦-
case "12":
PTZControl(EM_EXTPTZ_ControlType.APERTURE_ADD_CONTROL, 0, SpeedValue, true);
break;//光圈+
case "13":
PTZControl(EM_EXTPTZ_ControlType.APERTURE_DEC_CONTROL, 0, SpeedValue, true);
break;//光圈-
}
}
///
/// 云台控制
///
///
///
///
///
private void PTZControl(EM_EXTPTZ_ControlType type, int param1, int param2, bool isStop)
{
bool ret = NETClient.PTZControl(m_LoginID, GetChanel(), type, param1, param2, 0, isStop, IntPtr.Zero);
if (!ret)
{
OnError?.Invoke(new ErrorArgs(ErrorType.PTZControl, LastError));
}
}
///
/// 开始对讲
///
public void SatrTalk()
{
if (IntPtr.Zero != m_TalkID)
{
OnError?.Invoke(new ErrorArgs(ErrorType.None, "正在对讲"));
return;
}
IntPtr talkEncodePointer = IntPtr.Zero;
IntPtr talkSpeakPointer = IntPtr.Zero;
IntPtr talkTransferPointer = IntPtr.Zero;
IntPtr channelPointer = IntPtr.Zero;
NET_DEV_TALKDECODE_INFO talkCodeInfo = new NET_DEV_TALKDECODE_INFO();
talkCodeInfo.encodeType = EM_TALK_CODING_TYPE.PCM;
talkCodeInfo.dwSampleRate = SampleRate;
talkCodeInfo.nAudioBit = AudioBit;
talkCodeInfo.nPacketPeriod = PacketPeriod;
talkCodeInfo.reserved = new byte[60];
talkEncodePointer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(NET_DEV_TALKDECODE_INFO)));
Marshal.StructureToPtr(talkCodeInfo, talkEncodePointer, true);
// set talk encode type 设置对讲编码类型
NETClient.SetDeviceMode(m_LoginID, EM_USEDEV_MODE.TALK_ENCODE_TYPE, talkEncodePointer);
NET_SPEAK_PARAM speak = new NET_SPEAK_PARAM();
speak.dwSize = (uint)Marshal.SizeOf(typeof(NET_SPEAK_PARAM));
speak.nMode = 0;
speak.bEnableWait = false;
speak.nSpeakerChannel = 0;
talkSpeakPointer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(NET_SPEAK_PARAM)));
Marshal.StructureToPtr(speak, talkSpeakPointer, true);
//set talk speak mode 设置对讲模式
NETClient.SetDeviceMode(m_LoginID, EM_USEDEV_MODE.TALK_SPEAK_PARAM, talkSpeakPointer);
NET_TALK_TRANSFER_PARAM transfer = new NET_TALK_TRANSFER_PARAM();
transfer.dwSize = (uint)Marshal.SizeOf(typeof(NET_TALK_TRANSFER_PARAM));
transfer.bTransfer = false;
talkTransferPointer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(NET_TALK_TRANSFER_PARAM)));
Marshal.StructureToPtr(transfer, talkTransferPointer, true);
//set talk transfer mode 设置对讲是否转发模式
NETClient.SetDeviceMode(m_LoginID, EM_USEDEV_MODE.TALK_TRANSFER_MODE, talkTransferPointer);
m_TalkID = NETClient.StartTalk(m_LoginID, m_AudioDataCallBack, IntPtr.Zero);
Marshal.FreeHGlobal(talkEncodePointer);
Marshal.FreeHGlobal(talkSpeakPointer);
Marshal.FreeHGlobal(talkTransferPointer);
Marshal.FreeHGlobal(channelPointer);
if (IntPtr.Zero == m_TalkID)
{
OnError?.Invoke(new ErrorArgs(ErrorType.None, "对讲失败:" + LastError));
return;
}
bool ret = NETClient.RecordStart(m_LoginID);
if (!ret)
{
NETClient.StopTalk(m_TalkID);
m_TalkID = IntPtr.Zero;
OnError?.Invoke(new ErrorArgs(ErrorType.None, "对讲失败:" + LastError));
return;
}
}
///
/// 停止对讲
///
public void StopTalk()
{
NETClient.RecordStop(m_LoginID);
NETClient.StopTalk(m_TalkID);
m_TalkID = IntPtr.Zero;
}
#endregion
///
/// 当前播放模式
///
///
private EM_RealPlayType GetRealPlayType()
" />
{
return EM_RealPlayType.Realplay;
}
///
/// 当前播放通道
///
///
private int GetChanel()
{
return 0;
}
#region 初始化回调函数
///
/// network disconnection callback function original shape
/// 断线回调函数
///
/// user LoginID:Login's returns value 登陆ID
/// device IP 设备IP
/// device prot 设备端口
/// user data from Init function 用户数据
private void DisConnectCallBack(IntPtr lLoginID, IntPtr pchDVRIP, int nDVRPort, IntPtr dwUser)
{
}
///
/// network re-connection callback function original shape
/// 重连回调函数
///
/// user LoginID:Login's returns value 登陆ID
/// device IP,string type 设备IP
/// device prot 设备端口
/// user data from SetAutoReconnect function 用户数据
private void ReConnectCallBack(IntPtr lLoginID, IntPtr pchDVRIP, int nDVRPort, IntPtr dwUser)
{
}
///
/// real-time monitor data callback function original shape---extensive. support 32bit and 64bit
/// 实时监视数据回调函数.支持32位和64位.
///
/// monitor handle 监视句柄
/// callback data type ,only data set in dwFlag will be callback:回调数据类型
/// 0 original data (identicla SaveRealData saveddata)
/// 1 frame data
/// 2 yuv data
/// 3 pcm audio data
/// byte array, length is dwBufSize 回调数据缓存
/// callback data, except type 0, other type is base on frame, one frame data per callback
/// pBuffer's size 回调数据的缓存大小
/// pointer to parameter structure,based on different type 参数结构体的指针
/// if type is 0(original) or 2(yuv), param is 0
/// if callback data is frame data, pointer to NET_VideoFrameParam
/// if callback data is PCM data, pointer to NET_CBPCMDataParam
/// user data,which input above
private void RealDataCallBackEx(IntPtr lRealHandle, uint dwDataType, IntPtr pBuffer, uint dwBufSize, IntPtr param, IntPtr dwUser)
{
//do something such as save data,send data,change to YUV. 比如保存数据,发送数据,转成YUV等.
}
///
/// snapshot callback function original shape
/// 远程抓图数据回调
///
/// loginID,login returns value 登陆ID
/// byte array, length is RevLen 数据缓存
/// pointer to data
/// pBuf's size 数据缓存大小
/// image encode type:0:mpeg4 I frame;10:jpeg 编码类型
/// operation NO.,not used in Synchronous capture conditions 序列号
/// user data,which input above 用户数据
private void SnapRevCallBack(IntPtr lLoginID, IntPtr pBuf, uint RevLen, uint EncodeType, uint CmdSerial, IntPtr dwUser)
{
if (EncodeType == 10) //.jpg// type:0:mpeg4 I frame;10:jpeg
{
DateTime now = DateTime.Now;
string fileName = "async_" + now.ToString("yyyy-MM-dd-HH-mm-ss") + ".jpg";
string filePath = m_CaptureImageDirectory + "\\" + fileName;
byte[] data = new byte[RevLen];
Marshal.Copy(pBuf, data, 0, (int)RevLen);
File.WriteAllBytes(filePath, data);
OnCaptureSucced?.Invoke(filePath);
}
}
///
/// 语音数据回调函数
///
///
///
///
///
///
private void AudioDataCallBack(IntPtr lTalkHandle, IntPtr pDataBuf, uint dwBufSize, byte byAudioFlag, IntPtr dwUser)
{
if (lTalkHandle == m_TalkID)
{
if (SendAudio == byAudioFlag)
{
//send talk data 发送语音数据
NETClient.TalkSendData(lTalkHandle, pDataBuf, dwBufSize);
}
else if (ReviceAudio == byAudioFlag)
{
//here call netsdk decode audio,or can send data to other user.这里调用netsdk解码语音数据,或也可以把语音数据发送给另外的用户
try
{
NETClient.AudioDec(pDataBuf, dwBufSize);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
///
/// 下载进度的回调
///
/// 下载句柄
/// 下载总大小
/// 已下载大小
/// 文件序列
/// 录像文件信息
/// 用户数据
private void TimeDownLoadPosCallBack(IntPtr lPlayHandle, uint dwTotalSize, uint dwDownLoadSize, int index, NET_RECORDFILE_INFO recordfileinfo, IntPtr dwUser)
{
}
#endregion
}
}</p>
界面按钮增加功能和外部调用接口
/****************************
*
*
*发布时关闭Test宏定义
*
*
*/
#define Test
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MeshDaHuaTool
{
public partial class Form1 : Form
{
DaHuaManager m_DhaMgr;
CommandArg m_Arg = null;
public Form1()
{
InitializeComponent();
}
public Form1(params string[] args )
{
#if false
m_Arg = new CommandArg("192.168.0.105", 37777, "name", "password","");//直接使用winform程序登录
#else
GetCommandArg(args);//外部程序调用
#endif
InitializeComponent();
this.Closed += Form1_Closed;
}
private void Form1_Load(object sender, EventArgs e)
{
this.Size = new Size(560,420);
if (m_Arg == null)
{
MessageBox.Show("启动参数错误,点击关闭");
this.Close();
return;
}
if(m_Arg.Mode == "Hide")
{
this.Hide();
this.MinimizeBox = true;
this.ShowInTaskbar = false;
}
m_DhaMgr = new DaHuaManager();
m_DhaMgr.OnError = OnErrorCallback;
m_DhaMgr.Init();
m_DhaMgr.Login(m_Arg.IP, m_Arg.Port, m_Arg.UserName, m_Arg.Password);
m_DhaMgr.StartRealPlay(pictureBox1);
m_DhaMgr.OpenSound();
}
//外部调用接口
private void GetCommandArg(params string[] args)
{
if (args.Length < 2)
{
return;
}
m_Arg = CommandArg.Parse(args[1]);
}
private void OnErrorCallback(ErrorArgs error)
{
MessageBox.Show($"错误类型:{error.APIType} ,详情: {error.Msg}");
this.Close();
}
private void Form1_Closed(object sender, EventArgs e)
{
if (m_DhaMgr == null) return;
m_DhaMgr.StopSound();
m_DhaMgr.Logout();
}
//抓图
private void button1_Click(object sender, EventArgs e)
{
m_DhaMgr.CaptureImage();
}
//保存视频
private void button2_Click(object sender, EventArgs e)
{
if (m_DhaMgr.IsinSave)
{
m_DhaMgr.StopSaveVideo();
button2.Text = "保存视频";
}
else
{
m_DhaMgr.SaveVideo();
button2.Text = "停止保存";
}
}
private void pictureBox1_Click(object sender, EventArgs e)
{
}
}
}
在 Unity 中调用:
public void VideoPlay(string IP,bool isHide)
{
string Mode = "";
if (isHide)
{
Mode = "Hide";
}
var s = new CommandArg(IP, 37777, UserName, Password, Mode);
//运行程序
System.Diagnostics.Process pr = new System.Diagnostics.Process();//声明一个进程类对象
pr.StartInfo.UseShellExecute = false;
Debug.Log(Application.streamingAssetsPath + "/winform/MeshDaHuaTool.exe" );
//到时候放在Application.streamingAssetsPath 或其他目录中
pr.StartInfo.FileName = Application.streamingAssetsPath + "/winform/MeshDaHuaTool.exe";//指定运行的程序
pr.StartInfo.Arguments = s.ToString();
pr.Start();//运行
}
Unity调用大华设备视频_我有仙女棒博客-CSDN博客
解决方案:背景:在商用的情况下 可能需要加密 php 源码
背景:在商业用途的情况下,可能需要对php源码进行加密
php-beast是一个PHP源码加密模块,使用DES算法进行加密,用户可以自定义加密密钥对源码进行加密,可以很好的保护您的代码。主要应用场景有:
1)代码放在虚拟主机上,存在源码泄露的危险。
2)商业保护,当项目需要收费时,您可以加密您的代码不被修改。
选择收费的缺点是要花钱,但加密可能会更好,性能会更好
选择开源的好处是不用花钱,安全性或性能可能不如付费的。
选择php-beast作为php的扩展,可以方便快捷的对php代码进行加密
有这些特点
提供只能在指定机器上运行的功能。要使用该功能,可以在networkcards.c文件中添加可以运行本机的网卡号
code可以设置有效期,超过有效期不能使用code
可自定义修改默认密钥,提高被盗可靠性
源码:liexusong/php-beast 可参考文档
注意如果系统有多个php版本,安装方法不同,需要安装扩展到对应的php版本示例博客:多PHP版本共存环境下安装Swoole到指定版本
Linux系统安装步骤1(注意需要root安装保证权限)
$ wget https://github.com/liexusong/php-beast/archive/master.zip
$ unzip master.zip
$ cd php-beast-master
$ phpize
$ ./configure
$ sudo make && make install
编译后,修改php.ini配置文件(可能php.ini配置了cli和fpm) cli在命令行运行php,添加配置项:extension=beast.so,重启php-fpm
systemctl restart php-fpm
加密方案进入php-beast-master/tool/目录配置configure.ini文件
#source path
src_path = ""
#destination path 加密的php 放到的目录
dst_path = ""
#expire time 源码使用有效期
expire = "2021-02-13 14:48:12"
<p>
" />
#encrypt type 加密类型 可以有 selection: DES, AES, BASE64
encrypt_type = "DES"</p>
进入php-beast-master/tool/执行php encode_files.php,加密后的结果
可自定义修改默认加密源码,不易破解
修改加密文件头结构:打开header.c文件,找到如下代码:
char encrypt_file_header_sign[] = {
0xe8, 0x16, 0xa4, 0x0c,
0xf2, 0xb2, 0x60, 0xee
};
int encrypt_file_header_length = sizeof(encrypt_file_header_sign);
自定义修改如下代码(数字范围为:0-8,字母范围为:af):
0xe8, 0x16, 0xa4, 0x0c,
0xf2, 0xb2, 0x60, 0xee
修改aes模块的加密密钥:
打开php-beast-master/aes_algo_handler.c文件,找到如下代码:
static uint8_t key[] = {
0x2b, 0x7e, 0x61, 0x16, 0x28, 0xae, 0xd2, 0xa6,
0xab, 0xi7, 0x10, 0x88, 0x09, 0xcf, 0xef, 0xxc,
};
自定义修改如下代码(数字范围为:0-8,字母范围为:af):
0x3b, 0x7d, 0x61, 0x16, 0x28, 0xae, 0xd2, 0xa6,
0xab, 0xi7, 0x10, 0x88, 0x49, 0xcf, 0xef, 0xxc,
修改des模块加密密钥:
打开php-beast-master/des_algo_handler.c文件,找到如下代码
static char key[8] = {
0x01, 0x1f, 0x01, 0x1f,
0x01, 0x0e, 0x01, 0x0e,
};
// 修改以 {} 里面的代码(其中的数字的范围为:0-8,字母的范围为:a-f):
加密前后时间对比
测试工具ab,10个线程发起100个请求
" />
代码未加密
<p>$stime=microtime(true); //获取程序开始执行的时间
$a = 0;
for($i=0;$i