基于qt的监控(Qt音开发17-海康sdk解码)
基于qt的监控(Qt音开发17-海康sdk解码)5. 调用NET_DVR_RealPlay_V40播放视频。4. 调用NET_DVR_Login_V30登录设备。1. 调用NET_DVR_Init初始化sdk,一个项目中只需要初始化一次。2. 调用NET_DVR_SetConnectTime、NET_DVR_SetReconnect设置连接时间与重连时间。3. 填充NET_DVR_PREVIEWINFO结构体数据用来登录。
## 一、前言在视频监控行业领域,海康当之无愧是老大,稳坐第一的宝座很多年了,近期需要将视频监控系统改成采用海康sdk的内核,于是特意去查阅了sdk的使用手册,sdk相关的文档和文件可以直接官网下载到,而且是经常更新的,目前提供了windows和linux上的,win上的sdk还是更新比较快而且完整的,但是在linux上的就不得不吐槽下了,很旧很旧的版本,不要看打包文件很新,其实里面的内容是很老的,不知道为啥官方不也同步更新linux上的sdk,也许现在linux上的需求还不是很多吧,但是随着国产化的大力推进,估计不久的将来linux上的也会慢慢的完善起来的,说不定官方早就有了此计划,还有一种个人的猜测是linux上的开发包估计官方自己内部用的新的,可能打算自己做linux上的各种客户端吧。
官方的sdk手册做的还是非常详细的,而且还给到了VC/JAVA/C#等语言的demo代码,这点肯定值的表扬的,一个产品持续卖得很好,肯定有他深层次的原因,除了产品本身质量过硬以外,周边的服务也是必须要跟上的。由于本人习惯用Qt来做开发,所以直接编译了VC的demo,一步到位跑起来了,界面相对来说简单丑陋了点,但是要的大部分的功能还是有的,可能很多按钮也没摆摆整齐呢,管他呢,我们要的就是功能,演示如何使用对应的方法函数等,至于界面美化这块,尽量交给专业的UI妹子吧,没有UI妹子那就自己搞点qss样式表弄上去凑合着用吧,界面的美化核心主要就两点:布局 配色。
官方把他们常用的大类设备的sdk都封装到一起了,一个头文件老大了,光HCNetSDK.h这个头文件都47451行,我的乖乖,估计是为了方便用户使用,都放到一个头文件里面了,其实这些sdk不光只是支持摄像机,NVR/CVR等设备也都是支持的,兼容性比价好,用同一个sdk都可以,官方只是对一个大类的都统一起来了,不同大类的硬件产品之间的sdk还是有点区别出入,比如现在流行的人脸识别、红外测温等,那都是新增加的硬件和功能,但是总体接口和使用流程上都大体一致。
解码处理流程:
1. 调用NET_DVR_Init初始化sdk,一个项目中只需要初始化一次。
2. 调用NET_DVR_SetConnectTime、NET_DVR_SetReconnect设置连接时间与重连时间。
3. 填充NET_DVR_PREVIEWINFO结构体数据用来登录。
4. 调用NET_DVR_Login_V30登录设备。
5. 调用NET_DVR_RealPlay_V40播放视频。
6. 调用NET_DVR_StopRealPlay停止播放。
7. 调用NET_DVR_Logout登出设备。
## 二、功能特点1. 支持播放视频流和本地MP4文件。
2. 支持句柄和回调两种模式。
3. 多线程显示图像,不卡主界面。
4. 自动重连网络摄像头。
5. 可设置边框大小即偏移量和边框颜色。
6. 可设置是否绘制OSD标签即标签文本或图片和标签位置。
7. 可设置两种OSD位置和风格。
8. 可设置是否保存到文件以及文件名。
9. 可直接拖曳文件到haikangwidget控件播放。
10. 支持h264/h265视频流。
11. 可暂停播放和继续播放。
12. 支持存储单个视频文件和定时存储视频文件。
13. 自定义顶部悬浮条,发送单击信号通知,可设置是否启用。
14. 可设置画面拉伸填充或者等比例填充。
15. 可设置解码是速度优先、质量优先、均衡处理。
16. 可对视频进行截图(原始图片)和截屏(视频窗体)。
17. 录像文件存储为MP4文件。
18. 支持焦距控制、云台控制。
19. 可定制功能。
## 三、效果图
1. 国内站点:[https://gitee.com/feiyangqingyun/QWidgetDemo](https://gitee.com/feiyangqingyun/QWidgetDemo)
2. 国际站点:[https://github.com/feiyangqingyun/QWidgetDemo](https://github.com/feiyangqingyun/QWidgetDemo)
3. 个人主页:[https://blog.csdn.net/feiyangqingyun](https://blog.csdn.net/feiyangqingyun)
4. 知乎主页:[https://www.zhihu.com/people/feiyangqingyun/](https://www.zhihu.com/people/feiyangqingyun/)
5. 体验地址:[https://blog.csdn.net/feiyangqingyun/article/details/97565652](https://blog.csdn.net/feiyangqingyun/article/details/97565652)
## 五、核心代码bool HaiKangThread::playRtsp()
{
    bool ok = false;
    QString ip  userName  userPwd;
    int port  streamType;
    getInfo(ip  port  streamType  userName  userPwd);
    //登录设备
    NET_DVR_DEVICEINFO_V30 deviceInfo;
    long userid = NET_DVR_Login_V30(ip.toUtf8().data()  port  userName.toUtf8().data()  userPwd.toUtf8().data()  &deviceInfo);
    if (userid >= 0) {
        qDebug() << TIMEMS << "登录海康设备成功" << userid << deviceInfo.sSerialNumber;
        //这里还需要拿到视频流的宽高
        //qDebug() << TIMEMS << url << "videoWidth:" << videoWidth << "videoHeight:" << videoHeight;
        //以下参数具体见对应头文件说明
        NET_DVR_PREVIEWINFO previewInfo;
        previewInfo.lChannel = 1;
        previewInfo.dwStreamType = streamType;
        previewInfo.dwLinkMode = (transport == "tcp" ? 0 : 1);
        previewInfo.bBlocked = 0;
        previewInfo.byProtoType = 1;
        previewInfo.byPreviewMode = 0;
        previewInfo.dwDisplayBufNum = 15;
        //回调则可以拿到音视频数据 否则就直接句柄播放
        if (callback) {
            hand = NET_DVR_RealPlay_V40(userid  &previewInfo  RealDataCallBack  this);
        } else {
            previewInfo.hPlayWnd = (HWND)playWidget->winId();
            hand = NET_DVR_RealPlay_V40(userid  &previewInfo  NULL  NULL);
        }
        if (hand >= 0) {
            ok = true;
            qDebug() << TIMEMS << "打开视频数据成功" << url << "码流" << streamType;
        } else {
            qDebug() << TIMEMS << "打开视频数据失败" << url << NET_DVR_GetLastError();
        }
    } else {
        qDebug() << TIMEMS << "登录海康设备失败" << NET_DVR_GetLastError();
    }
    return ok;
}
bool HaiKangThread::playLocal()
{
    //转码以便支持中文路径
    QTextCodec *codec = QTextCodec::codecForName("gb2312");
    QByteArray data = codec->fromUnicode(url);
    PlayM4_GetPort(&port);
    bool ok = PlayM4_OpenFile(port  data.data());
    if (ok) {
        //设置文件播放完毕回调函数
        PlayM4_SetFileEndCallback(port  FileEndCallback  this);
        //回调则可以拿到音视频数据 否则就直接句柄播放
        if (callback) {
            PlayM4_SetDecCallBackMend(port  DecCallBack  (quser)this);
            PlayM4_Play(port  NULL);
        } else {
            PlayM4_Play(port  (HWND)playWidget->winId());
        }
        //同时播放声音
        PlayM4_PlaySound(port);
        //倒放
        //PlayM4_ReversePlay(port);
        //快进播放 多次调用速度更快
        //PlayM4_Fast(port);
        //PlayM4_Fast(port);
        ok = true;
        qDebug() << TIMEMS << "打开视频文件成功" << url;
    } else {
        qDebug() << TIMEMS << "打开视频文件失败" << url << PlayM4_GetLastError(port);
    }
    return ok;
}
bool HaiKangThread::init()
{
    //判断该摄像机是否能联通
    if (checkConn && isRtsp) {
        if (!checkUrl(url  checkTime)) {
            return false;
        }
    }
    if (playWidget == NULL) {
        return false;
    }
    //视频流和本地文件分别处理
    bool ok = false;
    if (isRtsp) {
        ok = playRtsp();
    } else {
        ok = playLocal();
    }
    if (!ok) {
        return false;
    }
    //设置保存文件
    this->initSave();
    return true;
}
void HaiKangThread::free()
{
    if (isRtsp) {
        //停止播放 登出设备
        NET_DVR_StopRealPlay(hand);
        NET_DVR_Logout(hand);
        hand = -1;
    } else {
        //停止播放 关闭文件 释放端口
        PlayM4_Stop(port);
        PlayM4_StopSound();
        PlayM4_CloseFile(port);
        PlayM4_FreePort(port);
        port = -1;
    }
}          




