范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

Qt编写视频监控管理平台(支持海康大华宇视华为天地伟业等)

  一、前言
  海康大华等厂家自己的客户端软件,基本上都是支持自家的设备,不支持其他家的摄像机和硬盘录像机,并不是因为技术上做不到,这些大厂要实现支持兼容其他的家的(他们家的服务端或者收费的都是支持其他家的),那都是分分钟的事情,无非就是走通用的标准onvif+rtsp+gb28181,为何目前客户端不兼容其他家的,可能也是由于商业角度考虑,这样可以最大化的绑定自家的硬件一起,毕竟客户端都是免费使用的,仅仅用他们免费的客户端而不用他们的硬件,那就没有太大意义。
  用Qt编写这个视频监控系统,最初的目标就是要实现支持海康/大华/宇视/华为/天地伟业等各个厂家的设备,也一直朝着这个目标前进,好在有onvif+gb28181这种国际标准和国家标准,只要对方的设备支持这两种标准则都可以顺利接入,一般onvif用来搜索和获取设备信息,拿到rtsp地址可以用ffmpeg解码播放,而gb28181主要用来回放视频居多,难易程度上gb28181由于通信复杂更难,onvif相对来说更简单,onvif底层就是用的udp+http,先用udp发组播消息搜索设备,然后用http发送请求拿详细的数据。
  目前市面上绝大部分厂家的设备都是支持onvif和gb28181的,所以这也给专门的软件厂商一个巨大机会,可以将各个硬件厂商的设备集中起来统一管理,除了局域网的设备可以集中管理,广域网的也可以通过各种中转统一管理,甚至推流通过公网管理,只要有权限,想看哪个摄像头哪个设备就调出来查看即可。二、功能特点(一)、软件模块视频监控模块,各种停靠小窗体子模块,包括设备列表、图文警情、窗口信息、云台控制、预置位、巡航设置、设备控制、悬浮地图、网页浏览等。视频回放模块,包括本地回放、远程回放、设备播放、图片回放、视频上传等。电子地图模块,包括图片地图、在线地图、离线地图、路径规划等。日志查询模块,包括本地日志、设备日志等。系统设置模块,包括系统设置(基本设置、视频参数、数据库设置、地图配置、串口配置等)、录像机管理、摄像机管理、轮询配置、录像计划、用户管理等。(二)、基础功能支持各种视频流(rtsp、rtmp、http等)、视频文件(mp4、rmvb、avi等)、本地USB摄像机播放。支持多画面切换,包括1、4、6、8、9、13、16、25、36、64画面切换。支持全屏切换,多种切换方式包括鼠标右键菜单、工具栏按钮、快捷键(alt+enter全屏,esc退出全屏)。支持视频轮询,包括1、4、9、16画面轮询,可设置轮询分组(轮询预案)、轮询间隔、码流类型等。支持onvif协议,包括设备搜索、云台控制、预置位、设备控制(图片参数、校对时间、系统重启,抓拍图片等)。支持权限管理,不同的用户可以对应不同的模块权限,比如删除日志、关闭系统等。数据库支持多种,包括sqlite、mysql、sqlserver、postgresql、oracle、人大金仓等。本地USB摄像机支持设置分辨率、帧率等参数。所有停靠模块都自动生成对应的菜单用来控制显示和隐藏,在标题栏右键可以弹出。支持显示所有模块、隐藏所有模块、复位普通布局、复位全屏布局。双击设备弹出实时预览视频,支持图片地图、在线地图、离线地图等。摄像机节点拖曳到对应窗体播放视频,同时支持拖曳本地文件直接播放。删除视频支持鼠标右键删除、悬浮条关闭删除、拖曳到视频监控面板外删除等多种方式。图片地图上设备按钮可自由拖动,自动保存位置信息。百度地图上可以鼠标单击获取经纬度信息,用来更新设备位置。视频监控面板窗体中任意通道支持拖曳交换,瞬间响应。封装了百度地图,视图切换,运动轨迹,设备点位,鼠标按下获取经纬度等。双击节点、拖曳节点、拖曳窗体交换位置等操作,均自动更新保存最后的播放地址,下次软件打开自动应用。右下角音量条控件,失去焦点自动隐藏,音量条带静音图标。支持视频截图,可指定单个或者对所有通道截图,底部小工具栏也有截图按钮。支持超时自动隐藏鼠标指针、自动全屏机制。支持onvif云台控制,可上下左右移动云台摄像机,包括复位和焦距调整等。支持onvif预置位,可以添加、删除、修改预置位,可以调用起始位。支持onvif图像参数设置,包括明亮度、对比度、饱和度、尖锐度等。支持onvif其他操作,包括抓图、网络设置、校时、重启、事件订阅等。支持任意onvif摄像机,包括但不限于海康、大华、宇视、天地伟业、华为等。可保存视频,可选定时存储或者单文件存储,可选存储间隔时间。可设置视频流通信方式tcp+udp,可设置视频解码是速度优先、质量优先、均衡等。可设置软件中文名称、英文名称、LOGO图标等。存储的视频文件支持导出到指定目录,支持批量上传到服务器。完善的录像计划设置,支持每个通道7乘24小时每半小时设置是否存储录像。(三)、特色功能主界面采用停靠窗体模式,各种组件以小模块的形式加入,可自定义任意模块加入。停靠模块可拖动任意位置嵌入和悬浮,支持最大化全屏,支持多屏幕。双重布局文件存储机制,正常模式、全屏模式都对应不同的布局方案,自动切换和保存,比如全屏模式可以突出几个模块透明显示在指定位置,更具科幻感现代化。原创onvif协议机制,采用底层协议解析(udp广播搜索+http请求执行命令)更轻量易懂易学习拓展,不依赖任何第三方组件比如gsoap。原创数据导入、导出、打印机制,跨平台不依赖任何组件,瞬间导出数据。内置多个原创组件,宇宙超值超级牛逼,包括数据导入导出组件(导出到xls、pdf、打印)、数据库组件(数据库管理线程、自动清理数据线程、万能分页、数据请求等)、地图组件、视频监控组件、文件多线程收发组件、onvif通信组件、通用浏览器内核组件等。自定义信息框+错误框+询问框+右下角提示框(包含多种格式)等。精美换肤,高达17套皮肤样式随意更换,所有样式全部统一,包括菜单等。视频控件悬浮条可以自行增加多个按钮,监控界面底部小工具栏也可自行增加按钮。双击摄像机节点自动播放视频,双击节点自动依次添加视频,会自动跳到下一个,双击父节点自动添加该节点下的所有视频。可选主码流、子码流。录像机管理、摄像机管理,可添加删除修改导入导出打印信息,立即应用新的设备信息生成树状列表,不需重启。可选多种内核自由切换,ffmpeg、vlc、mpv等,均可在pro中设置。推荐用ffmpeg,跨平台最多,默认提供好了linux和mac平台上编译好的库。支持硬解码,可设置硬解码类型(qsv、dxva2、d3d11va等)。默认采用opengl绘制视频,超低的CPU资源占用,支持yuyv和nv12两种格式绘制,很牛逼。高度可定制化,用户可以很方便的在此基础上衍生自己的功能,比如增加自定义模块,增加运行模式、机器人监控、无人机监控、挖掘机监控等。支持xp、win7、win10、win11、linux、mac、各种国产系统(UOS、中标麒麟、银河麒麟等)、嵌入式linux等系统。注释完整,项目结构清晰,超级详细完整的使用开发手册,精确到每个代码文件的功能说明,不断持续迭代版本。三、体验地址体验地址:https://pan.baidu.com/s/1d7TH_GEYl5nOecuNlWJJ7g 提取码:01jf 文件名:bin_video_system.zip。国内站点:https://gitee.com/feiyangqingyun国际站点:https://github.com/feiyangqingyun个人主页:https://blog.csdn.net/feiyangqingyun知乎主页:https://www.zhihu.com/people/feiyangqingyun/在线文档:https://feiyangqingyun.gitee.io/qwidgetdemo/video_system/四、效果图
  五、相关代码#include "deviceonvif.h" #include "quihelper.h" #include "dbquery.h" #include "playwav.h" #include "devicehelper.h" #include "onvifthread.h" #include "videowidgetx.h"  bool DeviceOnvif::checkUrl(const QString &url, OnvifDeviceData &deviceData) {     //不是rtsp开头也不是摄像机,为空也包含在这个判断中     if (!url.startsWith("rtsp")) {         return false;     }      //可能是主码流也可能是子码流     int index1 = DbData::IpcInfo_RtspMain.indexOf(url);     int index2 = DbData::IpcInfo_RtspSub.indexOf(url);     int index = -1;     if (index1 >= 0) {         index = index1;     } else if (index2 >= 0) {         index = index2;     }      //没有码流地址不用继续     if (index < 0) {         return false;     }      //只有onvif地址存在才是onvif设备     QString onvifAddr = DbData::IpcInfo_OnvifAddr.at(index);     if (onvifAddr.isEmpty()) {         return false;     }      //onvif地址中的IP和rtsp地址中的IP必须一致     //为什么会出现这个现象因为用户很可能直接在原来的正确的带有onvif地址的信息中修改了rtsp地址     if (OnvifHelper::getIP(onvifAddr) != OnvifHelper::getIP(url)) {         return false;     }      //对应结构体数据赋值     deviceData.userName = DbData::IpcInfo_UserName.at(index);     deviceData.userPwd = DbData::IpcInfo_UserPwd.at(index);     deviceData.onvifAddr = DbData::IpcInfo_OnvifAddr.at(index);     deviceData.profileToken = DbData::IpcInfo_ProfileToken.at(index);     deviceData.videoSource = DbData::IpcInfo_VideoSource.at(index);     return true; }  bool DeviceOnvif::ptzControl(quint8 type, const QString &url, double x, double y, double z) {     bool result = false;     OnvifDeviceData deviceData;     if (checkUrl(url, deviceData)) {         OnvifDevice *device = OnvifThread::getOnvifDevice(deviceData);         qDebug() << TIMEMS << "执行云台控制" << OnvifHelper::getIP(url);         result = device->ptzControl(type, deviceData.profileToken, x, y, z);     }     return result; }  bool DeviceOnvif::ptzPreset(quint8 type, const QString &url, const QString &presetToken, const QString &presetName) {     bool result = false;     OnvifDeviceData deviceData;     if (checkUrl(url, deviceData)) {         OnvifDevice *device = OnvifThread::getOnvifDevice(deviceData);         qDebug() << TIMEMS << "预置位处理" << OnvifHelper::getIP(url);         result = device->ptzPreset(type, deviceData.profileToken, presetToken, presetName);     }     return result; }  QList DeviceOnvif::getPresets(const QString &url) {     QList presets;     OnvifDeviceData deviceData;     if (checkUrl(url, deviceData)) {         OnvifDevice *device = OnvifThread::getOnvifDevice(deviceData);         qDebug() << TIMEMS << "获取预置位" << OnvifHelper::getIP(url);         presets = device->getPresets(deviceData.profileToken);     }     return presets; }  SINGLETON_IMPL(DeviceOnvif) DeviceOnvif::DeviceOnvif(QObject *parent) : QObject(parent) {     //显示截图的标签     labImage.setWindowFlags(Qt::WindowStaysOnTopHint);     labImage.setFixedSize(QSize(800, 600));     labImage.setWindowTitle("抓拍图片预览");     QUIHelper::setFormInCenter(&labImage);      //关联信号     connect(OnvifThread::Instance(), SIGNAL(receiveImage(QString, QImage)),             this, SLOT(receiveImage(QString, QImage)));     connect(OnvifThread::Instance(), SIGNAL(receiveEvent(QString, OnvifEventInfo)),             this, SLOT(receiveEvent(QString, OnvifEventInfo)));     connect(OnvifThread::Instance(), SIGNAL(receiveResult(QString, QString, QVariant)),             this, SIGNAL(receiveResult(QString, QString, QVariant)));      //启动onvif线程     OnvifThread::Instance()->start();      //启动定时器判断摄像机上下线     QTimer *timerOffline = new QTimer(this);     connect(timerOffline, SIGNAL(timeout()), this, SLOT(checkOffline()));     timerOffline->start(3000); }  void DeviceOnvif::checkOffline() {     for (int i = 0; i < DbData::IpcInfo_Count; ++i) {         QString url = DbData::getRtspAddr(i);         QString ip = OnvifHelper::getIP(url);         int port = OnvifHelper::getPort(url);          //rtsp除外的认为永远存在,可以根据需要自行约定规则         bool online = true;         if (url.startsWith("rtsp")) {             online = QUIHelper::ipLive(ip, port);         }          //过滤下只有当状态变化了才需要         if (online) {             if (!DbData::IpcInfo_IpcOnline.at(i)) {                 DeviceHelper::setVideoIcon2(ip, true);             }         } else {             if (DbData::IpcInfo_IpcOnline.at(i)) {                 DeviceHelper::setVideoIcon2(ip, false);             }         }          DbData::IpcInfo_IpcOnline[i] = online;     } }  void DeviceOnvif::receivePlayStart(int time) {     //轮询阶段不处理     if (AppConfig::Polling) {         //return;     }      //拿到触发信号的控件     VideoWidget *widget = (VideoWidget *)sender();     //先校验当前视频对应的信息是否符合     OnvifDeviceData deviceData;     if (checkUrl(widget->getVideoPara().videoUrl, deviceData)) {         //交给线程执行指令         OnvifThread::Instance()->append(deviceData, "getServices");         if (AppConfig::OnvifNtp) {             OnvifThread::Instance()->append(deviceData, "setDateTime");         }         if (AppConfig::OnvifEvent) {             OnvifThread::Instance()->append(deviceData, "getEvent");         }     } }  void DeviceOnvif::receivePlayFinsh() {     //先校验当前视频对应的信息是否符合     VideoWidget *widget = (VideoWidget *)sender();     OnvifDeviceData deviceData;     if (checkUrl(widget->getVideoPara().videoUrl, deviceData)) {         //交给线程执行指令         OnvifThread::Instance()->append(deviceData, "remove");     } }  void DeviceOnvif::receiveImage(const QString &url, const QImage &image) {     QImage img = image;     if (!img.isNull()) {         //等比例缩放一下         img = img.scaled(labImage.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);         labImage.setPixmap(QPixmap::fromImage(img));         labImage.show();     } }  void DeviceOnvif::receiveEvent(const QString &url, const OnvifEventInfo &event) {     //可能临时关闭了事件订阅     if (!AppConfig::OnvifEvent) {         return;     }      //事件内容存放在结构体数据中     //qDebug() << TIMEMS << event;     QString name = event.dataName;     QVariant value = event.dataValue;     //可能有多种关键字可以自行增加 LogicalState State IsMotion     if (!name.contains("LogicalState") && !name.contains("IsMotion")) {         return;     }      qDebug() << TIMEMS << "收到报警事件" << QUIHelper::getIP(url) << name << value;     //过滤不在本系统中的设备发过来的报警     int index = DbData::IpcInfo_OnvifAddr.indexOf(url);     if (index < 0) {         return;     }      //true false 1 0 字符串转成bool     bool alarm = value.toBool();     QString ipcName = DbData::IpcInfo_IpcName.at(index);     QString info, msg;     if (name.contains("IsMotion")) {         info = (alarm ? "移动侦测" : "移动结束");         msg = QString("%1%2").arg(ipcName).arg(info);         DeviceHelper::addMsg(msg, alarm ? 2 : 0);     } else {         info = (alarm ? "触发报警" : "报警恢复");         msg = QString("%1%2").arg(ipcName).arg(info);         DeviceHelper::addMsg(msg, alarm ? 2 : 0);     }      //播放报警声音     if (alarm) {         DeviceHelper::playAlarm("8.wav");     } else {         DeviceHelper::stopSound();     }      //插入到日志记录数据库     DbQuery::addUserLog("报警日志", msg);     //右下角弹出提示     if (AppConfig::TipInterval != 10000) {         QUIHelper::showTipBox("提示", msg, AppConfig::FullScreen, true, AppConfig::TipInterval);     } }

漫游西南200天(day14)2021年10月15日汉中96公里,小雨成大事以小心一生谨慎仰流风于遗象万古清高勉县武侯祠建于公元263年,比成都武侯祠早建约50年,堪称中华第一武侯祠。诸葛亮于公元234年病逝后共同奋斗,不断实现人民对美好生活的向往!二十大报告勾勒的美好民生蓝图点燃会场内外热切期盼江山就是人民,人民就是江山。中国共产党领导人民打江山守江山,守的是人民的心。二十大报告中的这句话,深深戳中人心。报告明确提出,必须坚持在发展中保障和改善民生,鼓励共同奋斗创造美好生东航国际航班量翻倍,小步快跑持续10月30日冬春航季即将开启,东航计划每周客运国际航线增至42条108班,航班量环比10月中旬(25条54班)翻倍,国际线小步快跑持续。2022年冬春新航季,东航国际计划航班量将恢将群众的每件小事当作大事办畅谈心声看到党的二十大报告提出全方位夯实粮食安全根基,牢牢守住十八亿亩耕地红线,我感到由衷振奋。今年是我在皖北农村基层工作的第11个年头,这里是全国重要的商品粮生产基地。11年来,基金募集回暖市场筑底时如何逆向布局回顾2022年前三季度,A股走势持续震荡,市场情绪也随之起伏。在震荡市中寻找攻守有道的基金产品,成为不少投资者的目标。这种情况下,近期中银基金正在发行的由涂海强担任基金经理的新基金盘点五大险企前三季度保费收入寿险增速分化财险持续向好近日,A股五大上市险企前9个月原保费收入已悉数出炉。据南都湾财社记者统计,中国人寿中国人保中国平安中国太保和新华保险五大A股上市险企前9个月合计实现保费收入约2。12万亿元,同比增9位老牌港星定居内地有人52岁找内地女友,有人在农村住别墅上世纪的香港是亚洲四小龙之一,不少内地人都选择南下香港打拼生活,后来还在当地生了孩子,逐渐成了香港人。这些孩子长大后有不少都成了明星,他们从小受到父母的教育,知道自己的根在哪里。这港媒热议二十大报告为香港施政指明方向据香港信报网站10月19日报道,香港特区行政长官李家超19日在立法会发表任内首份施政报告。他18日形容中共二十大报告是港府未来工作的行动指南,也是推动香港发展的定海神针。李家超表示又一上市券商迎重要人事变动作者丨雷晨实习生黎雨辰编辑丨巫燕玲图源丨图虫中泰证券(600918。SH)迎重要人事变动。10月20日,中泰证券相关负责人在接受21世纪经济报道记者采访时表示,王洪已正式担任中泰证如果要保持平安快乐,请记住最后两大原则平安快乐的第十二大原则凡事尽力而为,然后撑起伞,避开责难之雨。一件事,我们尽力了,也就不后悔了。做自己该做的,尽自己最大的努力,人生就无怨无悔。可有时候,还是管不住流言蜚语,那就撑在相遇的地方等你我在偶遇的地方仰望等待相遇的奇迹再次出现思念一泻千里爱情像洒满的阳光我找不到更好的方法治疗我无尽的相思我一遍遍呼唤着李杜怎样才能把诗写深写明怎样把爱情抒写得多彩绚丽我忘记了曾经的我
在非洲安哥拉,这家餐厅的烤虾绝了在海外的时间,是单调的,除了完成每日的工作,下班后要么约同事一起打网球,壁球,跑步,或者一个人在宿舍练习瑜伽。有时候不想吃食堂的饭菜了,就会组局到外面吃,在非洲吃中餐是非常贵的(改元宵夜的万绿园人潮沉浸在五彩斑斓的光影世界里共享热闹新海南客户端南海网南国都市报2月5日消息(记者王康景文图)疫情发生三年来,我第一次看到万绿园里的元宵节如此热闹非凡,大家就像积蓄了很久的力量,一下子就迸发出来了。2月5日元宵夜,市30年老车队发布最新款F1赛车,周冠宇今年要为阿尔法罗密欧拿更多积分因为有了首位中国F1车手周冠宇,今年迎来参加F1大奖赛30周年的阿尔法罗密欧无疑是中国车迷在新赛季最关心的车队。这支1993年第一次上F1赛道历史比赛总场次仅次于法拉利迈凯伦和威廉外媒北京国安希望以50万欧元租借引进罗马尼亚前锋斯托伊卡直播吧2月10日讯据罗马尼亚媒体Digisport报道,国安希望租借引进20岁的罗马尼亚前锋亚尼斯斯托伊卡。斯托伊卡的所有权属于布加勒斯特星,本赛季租借至克卢日大学。斯托伊卡已经成金碧辉煌的布达拉宫究竟有多壕?传说世界一半的黄金都在这里布达拉宫,是个让众多朝圣者向往的地方。一提起西藏,人们就会想起布达拉宫。这里风景如画,文化气息浓厚,有强大的宗教力量在此支撑。一提起净化心灵,许多人都会想到这个纯净的地方。当年,干纽约特色床边服务,结束后顾客满血复活,柜台小姐帮助睡眠如今我们国家的发展十分的迅速,百姓的生活也是水涨船高,闲暇之余,人们都希望能好好的享受生活,让自己过上更舒适的生活方式,而很多人的选择就是外出旅游。(此处已添加小程序,请到今日头条2015我的爬山元年2015年是我开始爬山的第一年。在2015年之前,我也爬过一些山,多是为了游玩赏景,没有登顶的决心,也没有规划登山路线的雅致。只是到了景区沿着人最多或者最宽阔的那条路开始爬,爬累了小营街道元宵佳节共欢腾特色民俗齐闹春大众网海报新闻记者刘建波见习记者尹唯一通讯员韩红艳李玉玲滨州报道锣鼓声声辞旧岁,喜庆洋洋闹元宵。新春伊始,浓浓的年味儿还没散去,又迎来了传统的正月十五元宵节。为进一步弘扬中华传统文儋州中和古镇舞龙舞狮闹元宵敲锣打鼓度佳节新海南客户端南海网南国都市报2月5日消息(记者梁振文)狮子舞龙吉祥兔仙鹤马转亭2月5日上午9时,在儋州市中和古镇关帝庙前的广场上,来自镇上各个片区的舞狮舞龙表演队伍齐聚一堂,锣鼓喧打卡人民公园沙滩!这里成了欢乐的海洋驻马店网讯(记者刘金霞)给娃一片沙池,再来一个铲子一个桶,配上几个简单的模具,孩子就能挖呀挖,挖出一个新世界来。你根本想象不到他们的创造力有多强,一玩就是一下午。2月5日下午2时许中国足球一地鸡毛陈某源给自己打九分是虚假新闻中国足球真是一地鸡毛,陈某源给自己打九分是虚假新闻,足协辟谣了。图片来源网络,侵删中国足球真是会辟谣啊!选的时机是恰到好处,不然陈某源会被骂的体无完肤,这一辟谣,很好的保护了陈某源