首页 新闻 会员 周边 捐助

有没有大佬用过海康威视的摄像头SDK,想将调用SDK的Preview的方法等抽象出去不知道会不会报错

0
悬赏园豆:200 [待解决问题]

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;
            });
        }
    }

不知道这样可行不可行

ShallowYP的主页 ShallowYP | 初学一级 | 园豆:2
提问于:2024-11-23 17:35
< >
分享
所有回答(3)
0

不会报错,你的markdown 有点乱,我没看

echo_lovely | 园豆:1584 (小虾三级) | 2024-11-23 23:36

我们C#项目里用过他们的sdk,而且我们也是自己封装自己

支持(0) 反对(0) echo_lovely | 园豆:1584 (小虾三级) | 2024-11-23 23:40

支持(0) 反对(0) echo_lovely | 园豆:1584 (小虾三级) | 2024-11-23 23:40
0

参考官网demo,引用sdk后随便自己怎么折腾都没问题

茂茂 | 园豆:2902 (老鸟四级) | 2024-11-25 16:26
0

在您给出的代码中,您已经将与海康威视摄像头 SDK 相关的 preview 方法以及回调方法提取到一个工具类中。这种做法是合理的,可以有效地实现代码的重用和组织。不过,改动的实现和使用的方式可能会影响到程序的正确性,特别是在多线程环境中如何处理 UI 更新和 SDK 的异步调用。

错误处理和多线程环境

在您的 OnLoginResult 方法里,您对是否在 UI 线程中的判断是正确的。使用 Dispatcher.CheckAccess() 检查当前线程是否为 UI 线程是很重要的,确保对 UI 组件的任何操作都在 UI 线程上执行。

优化建议

  1. 确认是否存在多线程问题:
    确保 SDK 的回调方法(如登录回调和实时视频回调)能在适当的线程中工作,尤其是在你抽象为工具方法后,确保该方法能够处理多线程访问。

  2. 使用安全的方式访问共享资源:
    如果在其他线程中使用 _cameraMsg 或其他共享资源,确保使用锁机制(例如 lock 关键字)来防止并发访问冲突。

  3. 确保 Dispatcher 处理:
    OnLoginResult 方法中,确保您在 Dispatcher.Invoke 中的代码执行是安全的。要确保所有涉及 UI 的调用都是通过 Dispatcher 进行的。

  4. 抽象的影响:
    preview 方法提取到了工具类后,确保调用这些新方法时,传递的参数仍然能够被正确地处理。如果你在多个地方调用这个新方法,请确保每个调用都是安全且符合原本设计意图的。

  5. 错误处理:
    在您所有 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 交互的部分都有适当的错误处理并且线程安全。如果在实施这些更改后仍然遇到问题,请分享具体的错误信息或崩溃点,以便进一步分析和解决。

Technologyforgood | 园豆:7775 (大侠五级) | 2024-11-27 16:01

感谢回复,现在设备还没有到,等到了我去尝试一下

支持(0) 反对(0) ShallowYP | 园豆:2 (初学一级) | 2024-11-27 16:20
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册