demo是在主页面下进行操作代码如下
private void preview(int i)
{
if (_cameraMsg[i].UserID < 0)
{
System.Windows.MessageBox.Show("Please login the device firstly");
return;
}
if (_cameraMsg[i].RealHandle < 0)
{
NET_DVR_PREVIEWINFO lpPreviewInfo = new NET_DVR_PREVIEWINFO();
lpPreviewInfo.hPlayWnd = _pictureBoxes[i].Handle;//预览窗口
lpPreviewInfo.lChannel = Int16.Parse("1");//预te览的设备通道
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 = 1; //播放库播放缓冲区最大缓冲帧数
lpPreviewInfo.byProtoType = 0;
lpPreviewInfo.byPreviewMode = 0;
//if (textBoxID.Text != "")
//{
// lpPreviewInfo.lChannel = -1;
// byte[] byStreamID = Encoding.Default.GetBytes(textBoxID.Text);
// lpPreviewInfo.byStreamID = new byte[32];
// byStreamID.CopyTo(lpPreviewInfo.byStreamID, 0);
//}
if (_realData == null)
{
_realData = RealDataCallBack;//预览实时流回调函数
}
IntPtr pUser = new IntPtr();//用户数据
//打开预览 Start live view
_cameraMsg[i].RealHandle = NET_DVR_RealPlay_V40(_cameraMsg[i].UserID, ref lpPreviewInfo, null/*RealData*/, pUser);
if (_cameraMsg[i].RealHandle < 0)
{
_iLastErr = NET_DVR_GetLastError();
_str = "NET_DVR_RealPlay_V40 failed, error code= " + _iLastErr; //预览失败,输出错误号
System.Windows.MessageBox.Show(_str);
return;
}
else
{
//预览成功
}
}
else
{
//停止预览 Stop live view
if (!NET_DVR_StopRealPlay(_cameraMsg[i].RealHandle))
{
_iLastErr = NET_DVR_GetLastError();
_str = "NET_DVR_StopRealPlay failed, error code= " + _iLastErr;
System.Windows.MessageBox.Show(_str);
return;
}
_cameraMsg[i].RealHandle = -1;
}
return;
}
还有一个回调方法里判断了是不是UI线程
public void cbLoginCallBack(int lUserID, int dwResult, IntPtr lpDeviceInfo, IntPtr pUser)
{
string strLoginCallBack = "登录设备,lUserID:" + lUserID + ",dwResult:" + dwResult;
if (dwResult == 0)
{
uint iErrCode = NET_DVR_GetLastError();
strLoginCallBack = strLoginCallBack + ",错误号:" + iErrCode;
}
//下面代码注释掉也会崩溃
if (Dispatcher.CheckAccess())
{
object[] paras = new object[2];
paras[0] = strLoginCallBack;
paras[1] = lpDeviceInfo;
}
else
{
}
}
现在我给这个Preview提取到了一个工具类里,然后把这个回调参数改为了
private void OnLoginResult(int lUserID, int dwResult, IntPtr lpDeviceInfo, IntPtr pUser)
{
string strLoginCallBack = "登录设备,lUserID:" + lUserID + ",dwResult:" + dwResult;
if (dwResult == 0)
{
uint iErrCode = NET_DVR_GetLastError();
strLoginCallBack = strLoginCallBack + ",错误号:" + iErrCode;
}
//下面代码注释掉也会崩溃
if (_dispatcher.CheckAccess())
{
object[] paras = new object[2];
paras[0] = strLoginCallBack;
paras[1] = lpDeviceInfo;
}
else
{
_dispatcher.Invoke(() => {
object[] paras = new object[2];
paras[0] = strLoginCallBack;
paras[1] = lpDeviceInfo;
});
}
}
不知道这样可行不可行
不会报错,你的markdown 有点乱,我没看
我们C#项目里用过他们的sdk,而且我们也是自己封装自己
用
参考官网demo,引用sdk后随便自己怎么折腾都没问题
在您给出的代码中,您已经将与海康威视摄像头 SDK 相关的 preview
方法以及回调方法提取到一个工具类中。这种做法是合理的,可以有效地实现代码的重用和组织。不过,改动的实现和使用的方式可能会影响到程序的正确性,特别是在多线程环境中如何处理 UI 更新和 SDK 的异步调用。
在您的 OnLoginResult
方法里,您对是否在 UI 线程中的判断是正确的。使用 Dispatcher.CheckAccess()
检查当前线程是否为 UI 线程是很重要的,确保对 UI 组件的任何操作都在 UI 线程上执行。
确认是否存在多线程问题:
确保 SDK 的回调方法(如登录回调和实时视频回调)能在适当的线程中工作,尤其是在你抽象为工具方法后,确保该方法能够处理多线程访问。
使用安全的方式访问共享资源:
如果在其他线程中使用 _cameraMsg
或其他共享资源,确保使用锁机制(例如 lock
关键字)来防止并发访问冲突。
确保 Dispatcher 处理:
在 OnLoginResult
方法中,确保您在 Dispatcher.Invoke 中的代码执行是安全的。要确保所有涉及 UI 的调用都是通过 Dispatcher 进行的。
抽象的影响:
将 preview
方法提取到了工具类后,确保调用这些新方法时,传递的参数仍然能够被正确地处理。如果你在多个地方调用这个新方法,请确保每个调用都是安全且符合原本设计意图的。
错误处理:
在您所有 SDK 方法的调用中,确保有适当的错误处理机制。在 preview
和回调方法中均要捕获并处理异常,以防止因 SDK 的调用失败而导致的崩溃。
基于您的原始代码,下面是对抽象后的 Preview
方法和 OnLoginResult
方法的一些调整建议:
// 抽象后的 Preview 方法
public void StartPreview(int deviceIndex)
{
if (_cameraMsg[deviceIndex].UserID < 0)
{
ShowMessageBox("Please login the device firstly");
return;
}
if (_cameraMsg[deviceIndex].RealHandle < 0)
{
NET_DVR_PREVIEWINFO lpPreviewInfo = new NET_DVR_PREVIEWINFO();
lpPreviewInfo.hPlayWnd = _pictureBoxes[deviceIndex].Handle; // 预览窗口
lpPreviewInfo.lChannel = 1; // 设备通道
lpPreviewInfo.dwStreamType = 0; // 主码流
lpPreviewInfo.dwLinkMode = 0; // TCP连接
lpPreviewInfo.bBlocked = true; // 阻塞取流
lpPreviewInfo.dwDisplayBufNum = 1;
// 设置回调
if (_realData == null)
{
_realData = RealDataCallBack; // 回调函数
}
IntPtr pUser = IntPtr.Zero;
_cameraMsg[deviceIndex].RealHandle = NET_DVR_RealPlay_V40(_cameraMsg[deviceIndex].UserID, ref lpPreviewInfo, null, pUser);
if (_cameraMsg[deviceIndex].RealHandle < 0)
{
uint errorCode = NET_DVR_GetLastError();
ShowMessageBox($"NET_DVR_RealPlay_V40 failed, error code = {errorCode}");
}
else
{
// 预览成功
}
}
else
{
StopPreview(deviceIndex);
}
}
private void StopPreview(int deviceIndex)
{
if (!NET_DVR_StopRealPlay(_cameraMsg[deviceIndex].RealHandle))
{
uint errorCode = NET_DVR_GetLastError();
ShowMessageBox($"NET_DVR_StopRealPlay failed, error code = {errorCode}");
}
_cameraMsg[deviceIndex].RealHandle = -1;
}
// 优化后的回调方法
private void OnLoginResult(int lUserID, int dwResult, IntPtr lpDeviceInfo, IntPtr pUser)
{
string resultMessage = $"登录设备,lUserID:{lUserID},dwResult:{dwResult}";
if (dwResult == 0)
{
uint errorCode = NET_DVR_GetLastError();
resultMessage += $",错误号: {errorCode}";
}
// 确保在 UI 线程中更新 UI
if (_dispatcher.CheckAccess())
{
ShowMessageBox(resultMessage);
}
else
{
_dispatcher.Invoke(() => ShowMessageBox(resultMessage));
}
}
// 简化弹窗显示逻辑
private void ShowMessageBox(string message)
{
System.Windows.MessageBox.Show(message);
}
通过将行为封装在方法中,并确保你在合适的线程上下文中执行 UI 交互,可以减少崩溃和其他潜在问题的风险。确保所有与 SDK 交互的部分都有适当的错误处理并且线程安全。如果在实施这些更改后仍然遇到问题,请分享具体的错误信息或崩溃点,以便进一步分析和解决。
感谢回复,现在设备还没有到,等到了我去尝试一下