From 04f586ebb9bcd4d70ff11492ddf66f5548e88980 Mon Sep 17 00:00:00 2001 From: feiyangqingyun Date: Tue, 9 May 2023 21:04:57 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- control/lightbutton/lightbutton.cpp | 25 ++++++++++++------------- control/lightbutton/lightbutton.h | 7 +++++++ docs/video_system/index.html | 6 +++--- docs/video_system/snap/12-3-11.jpg | Bin 0 -> 75672 bytes 4 files changed, 22 insertions(+), 16 deletions(-) create mode 100644 docs/video_system/snap/12-3-11.jpg diff --git a/control/lightbutton/lightbutton.cpp b/control/lightbutton/lightbutton.cpp index 50a537e..9c149d2 100644 --- a/control/lightbutton/lightbutton.cpp +++ b/control/lightbutton/lightbutton.cpp @@ -27,6 +27,7 @@ LightButton::LightButton(QWidget *parent) : QWidget(parent) overlayColor = QColor(255, 255, 255); canMove = false; + pressed = false; this->installEventFilter(this); isAlarm = false; @@ -37,23 +38,21 @@ LightButton::LightButton(QWidget *parent) : QWidget(parent) bool LightButton::eventFilter(QObject *watched, QEvent *event) { - if (canMove) { - static QPoint lastPoint; - static bool pressed = false; - QMouseEvent *mouseEvent = static_cast(event); - - if (mouseEvent->type() == QEvent::MouseButtonPress) { - if (this->rect().contains(mouseEvent->pos()) && (mouseEvent->button() == Qt::LeftButton)) { - lastPoint = mouseEvent->pos(); - pressed = true; - } - } else if (mouseEvent->type() == QEvent::MouseMove && pressed) { + QMouseEvent *mouseEvent = (QMouseEvent *)event; + if (mouseEvent->type() == QEvent::MouseButtonPress) { + if (this->rect().contains(mouseEvent->pos()) && (mouseEvent->button() == Qt::LeftButton)) { + lastPoint = mouseEvent->pos(); + pressed = true; + } + } else if (mouseEvent->type() == QEvent::MouseMove && pressed) { + if (canMove) { int dx = mouseEvent->pos().x() - lastPoint.x(); int dy = mouseEvent->pos().y() - lastPoint.y(); this->move(this->x() + dx, this->y() + dy); - } else if (mouseEvent->type() == QEvent::MouseButtonRelease && pressed) { - pressed = false; } + } else if (mouseEvent->type() == QEvent::MouseButtonRelease && pressed) { + pressed = false; + emit clicked(); } return QWidget::eventFilter(watched, event); diff --git a/control/lightbutton/lightbutton.h b/control/lightbutton/lightbutton.h index 6609955..ea0051f 100644 --- a/control/lightbutton/lightbutton.h +++ b/control/lightbutton/lightbutton.h @@ -71,6 +71,9 @@ private: bool showOverlay; //是否显示遮罩层 QColor overlayColor; //遮罩层颜色 + bool pressed; //鼠标是否按下 + QPoint lastPoint; //鼠标最后按下坐标 + bool isAlarm; //是否报警 QTimer *timerAlarm; //定时器切换颜色 @@ -147,6 +150,10 @@ public Q_SLOTS: void startAlarm(); void stopAlarm(); void alarm(); + +Q_SIGNALS: + //单击信号 + void clicked(); }; #endif // LIGHTBUTTON_H diff --git a/docs/video_system/index.html b/docs/video_system/index.html index c94a83e..ec7b332 100644 --- a/docs/video_system/index.html +++ b/docs/video_system/index.html @@ -675,8 +675,8 @@ header, .context-menu, .megamenu-content, footer{ 视频监控系统开发及使用手册
-
  • 0 前言说明

    0.1 系统说明

    1. 本视频监控系统做的是通用的系统,主要偏重整体框架和UI交互等。

    2. 主要功能包括摄像机管理,实时视频显示,视频轮询、视频存储、设备地图显示,各种画面切换,各种悬停子模块、onvif搜索设备和云台控制及预置位,通用的NVR视频流播放(比如海康的NVR支持直接取流回放),录像计划、用户管理等功能。

    3. 如果是依赖SDK去实现的功能(雨刷、去雾等)都没有做,那个破坏了兼容性,无法通用其他摄像机设备以及其他操作系统。

    4. 每个厂家SDK和定制的功能都不一样,如果有这方面的需要都是买过去自己加上SDK的功能和自己定制需要的功能。

    5. 整个项目源代码行数大概30W行(项目代码本身除去第三方库以后约7W行,就是自己写的部分),其中代码13.5W行(占比45%),注释12.7W行(占比42%),空行3.5W行。分层设计注释详细。

    6. 本程序会一直持续迭代更新,包括项目源码、整体框架、使用说明等,一次购买终生售后。

    0.2 特别说明

    1. 程序本身是个客户端(直接从摄像机或者NVR等设备取rtsp视频流)并不是服务器程序。

    2. 摄像机管理没有限制摄像机的数量,理论上10000路肯定没有问题,就是个数据库记录。

    3. 实时显示具体能支持多少路,和具体的电脑配置有关(亲测1.8G主频8G内存I5子码流64路,总之比海康大华客户端要更优秀)。

    4. 程序实时显示界面最大可以到64路,每个通道都是打开的时候才会去建立连接取视频流,而不是一开始就建立了连接。

    5. 系统采用onvif协议+rtsp视频流机制,并不限定支持哪家的摄像机,只要符合这两种协议的都支持,市面上99%的网络摄像机都支持这两种基础协议,包括但不限于海康、大华、宇视、天地伟业、华为等各种安防厂家的摄像机。

    6. 本系统没有内置人脸识别等任何相关算法,提供的是相关的接口,比如自己的算法识别到人脸区域后,将区域坐标传入视频控件自动绘制。

    7. 系统采用纯QtWidget(非qml)编写,解码采用ffmpeg,搜索采用onvif协议,视频播放采用rtsp协议,所有源码开放,没有封装的库。

    8. 同时集成了数据库、多线程、串口通信、网络通信、音视频解码/同步/存储、网页地图、界面美化、UI布局等众多知识点。

    9. 未经本人许可不可将本项目源码扩散,如有发现本人将追究法律责任,谢谢配合。

    0.3 相关站点

    1. 国内站点:https://gitee.com/feiyangqingyun

    2. 国际站点:https://github.com/feiyangqingyun

    3. 个人主页:https://blog.csdn.net/feiyangqingyun

    4. 知乎主页:https://www.zhihu.com/people/feiyangqingyun

    5. 产品主页:https://blog.csdn.net/feiyangqingyun/article/details/97565652

    6. 在线文档:https://feiyangqingyun.gitee.io/qwidgetdemo/video_system/

    7. 体验地址:https://pan.baidu.com/s/1d7TH_GEYl5nOecuNlWJJ7g 提取码:01jf 文件名:bin_video_system.zip。

    8. 文章导航:https://qtchina.blog.csdn.net/article/details/121327495

    0.4 功能特点

    0.4.1 软件模块

    1. 视频监控模块,各种停靠小窗体子模块,包括设备列表、图文警情、窗口信息、云台控制、预置位、巡航设置、设备控制、悬浮地图、网页浏览等。

    2. 视频回放模块,包括本地回放、远程回放、设备播放、图片回放、视频上传等。

    3. 电子地图模块,包括图片地图、在线地图、离线地图、路径规划等。

    4. 日志查询模块,包括本地日志、设备日志等。

    5. 系统设置模块,包括系统设置(基本设置、视频参数、数据库设置、地图配置、串口配置等)、录像机管理、摄像机管理、轮询配置、录像计划、用户管理等。

    0.4.2 基础功能

    1. 支持各种视频流(rtsp、rtmp、http等)、视频文件(mp4、rmvb、avi等)、本地USB摄像机播放。

    2. 支持多画面切换,包括1、4、6、8、9、13、16、25、36、64画面切换。

    3. 支持全屏切换,多种切换方式包括鼠标右键菜单、工具栏按钮、快捷键(alt+enter全屏,esc退出全屏)。

    4. 支持视频轮询,包括1、4、9、16画面轮询,可设置轮询分组(轮询预案)、轮询间隔、码流类型等。

    5. 支持onvif协议,包括设备搜索、云台控制、预置位、设备控制(图片参数、校对时间、系统重启,抓拍图片等)。

    6. 支持权限管理,不同的用户可以对应不同的模块权限,比如删除日志、关闭系统等。

    7. 数据库支持多种,包括sqlite、mysql、sqlserver、postgresql、oracle、人大金仓等。

    8. 本地USB摄像机支持设置分辨率、帧率等参数。

    9. 所有停靠模块都自动生成对应的菜单用来控制显示和隐藏,在标题栏右键可以弹出。

    10. 支持显示所有模块、隐藏所有模块、复位普通布局、复位全屏布局。

    11. 双击设备弹出实时预览视频,支持图片地图、在线地图、离线地图等。

    12. 摄像机节点拖曳到对应窗体播放视频,同时支持拖曳本地文件直接播放。

    13. 删除视频支持鼠标右键删除、悬浮条关闭删除、拖曳到视频监控面板外删除等多种方式。

    14. 图片地图上设备按钮可自由拖动,自动保存位置信息。百度地图上可以鼠标单击获取经纬度信息,用来更新设备位置。

    15. 视频监控面板窗体中任意通道支持拖曳交换,瞬间响应。

    16. 封装了百度地图,视图切换,运动轨迹,设备点位,鼠标按下获取经纬度等。

    17. 双击节点、拖曳节点、拖曳窗体交换位置等操作,均自动更新保存最后的播放地址,下次软件打开自动应用。

    18. 右下角音量条控件,失去焦点自动隐藏,音量条带静音图标。

    19. 支持视频截图,可指定单个或者对所有通道截图,底部小工具栏也有截图按钮。

    20. 支持超时自动隐藏鼠标指针、自动全屏机制。

    21. 支持onvif云台控制,可上下左右移动云台摄像机,包括复位和焦距调整等。

    22. 支持onvif预置位,可以添加、删除、修改预置位,可以调用起始位。

    23. 支持onvif图像参数设置,包括明亮度、对比度、饱和度、尖锐度等。

    24. 支持onvif其他操作,包括抓图、网络设置、校时、重启、事件订阅等。

    25. 支持任意onvif摄像机,包括但不限于海康、大华、宇视、天地伟业、华为等。

    26. 可保存视频,可选定时存储或者单文件存储,可选存储间隔时间。

    27. 可设置视频流通信方式tcp+udp,可设置视频解码是速度优先、质量优先、均衡等。

    28. 可设置软件中文名称、英文名称、LOGO图标等。

    29. 存储的视频文件支持导出到指定目录,支持批量上传到服务器。

    30. 完善的录像计划设置,支持每个通道7 * 24小时每半小时设置是否存储录像。

    0.4.3 特色功能

    1. 主界面采用停靠窗体模式,各种组件以小模块的形式加入,可自定义任意模块加入。

    2. 停靠模块可拖动任意位置嵌入和悬浮,支持最大化全屏,支持多屏幕。

    3. 双重布局文件存储机制,正常模式、全屏模式都对应不同的布局方案,自动切换和保存,比如全屏模式可以突出几个模块透明显示在指定位置,更具科幻感现代化。

    4. 原创onvif协议机制,采用底层协议解析(udp广播搜索+http请求执行命令)更轻量易懂易学习拓展,不依赖任何第三方组件比如gsoap。

    5. 原创数据导入、导出、打印机制,跨平台不依赖任何组件,瞬间导出数据。

    6. 内置多个原创组件,宇宙超值超级牛逼,包括数据导入导出组件(导出到xls、pdf、打印)、数据库组件(数据库管理线程、自动清理数据线程、万能分页、数据请求等)、地图组件、视频监控组件、文件多线程收发组件、onvif通信组件、通用浏览器内核组件等。

    7. 自定义信息框+错误框+询问框+右下角提示框(包含多种格式)等。

    8. 精美换肤,高达17套皮肤样式随意更换,所有样式全部统一,包括菜单等。

    9. 视频控件悬浮条可以自行增加多个按钮,监控界面底部小工具栏也可自行增加按钮。

    10. 双击摄像机节点自动播放视频,双击节点自动依次添加视频,会自动跳到下一个,双击父节点自动添加该节点下的所有视频。可选主码流、子码流。

    11. 录像机管理、摄像机管理,可添加删除修改导入导出打印信息,立即应用新的设备信息生成树状列表,不需重启。

    12. 可选多种内核自由切换,ffmpeg、vlc、mpv等,均可在pro中设置。推荐用ffmpeg,跨平台最多,默认提供好了linux和mac平台上编译好的库。

    13. 支持硬解码,可设置硬解码类型(qsv、dxva2、d3d11va等)。

    14. 默认采用opengl绘制视频,超低的CPU资源占用,支持yuyv和nv12两种格式绘制,性能爆表。

    15. 标签和图形信息支持三种绘制方式,绘制到遮罩层、绘制到图片、源头绘制(对应信息可以存储到文件)。

    16. 高度可定制化,用户可以很方便的在此基础上衍生自己的功能,比如增加自定义模块,增加运行模式、机器人监控、无人机监控、挖掘机监控等。

    17. 支持xp、win7、win10、win11、linux、mac、各种国产系统(UOS、中标麒麟、银河麒麟等)、嵌入式linux等系统。

    18. 注释完整,项目结构清晰,超级详细完整的使用开发手册,精确到每个代码文件的功能说明,不断持续迭代版本。

    0.5 目录说明

    1. 本源码项目文件中对编译生成的临时文件和可执行文件做了重定向,可执行文件并不在build开头的目录下,而是在源码同级目录的bin目录下。

    2. config目录放的是软件的配置文件、地图模块需要的图片资源等。

    3. db目录一般有三个文件,key.db是秘钥文件、video_system.db是对应sqlite的数据库文件、video_system.sql是对应数据库脚本(可以在系统设置中数据库管理部分执行脚本用来切换到mysql等其他数据库)。

    4. logo目录存放的各种左上角软件LOGO图片,可以在系统设置中下拉选择。

    5. map目录存放的图片地图模块所用的地图图片文件,可以手动拷贝到此。

    6. sound目录存放的本系统所用的声音文件。

    7. layout目录存放的不同工作模式不同界面对应的布局方案配置文件。

    0.6 编译说明

    0.6.1 特别提示

    1. 本系统没有说基于哪个Qt版本,由于系统中电子地图模块用到了浏览器模块,所以理论上要求你电脑的Qt版本也有浏览器模块才行

    2. 如果没有则电子地图模块不可用,但是其余功能全部可用没有任何影响。

    3. 本人亲测Qt4.7到Qt6.4之间的所有版本(理论上支持后续所有版本),亲测msvc、mingw、gcc、clang、armgcc各种编译器,亲测xp、win7、win10、linux、mac、树莓派、香橙派、全志H3、cotex-A9、imx6等。

    4. 2021-1-6开始集成了miniblink浏览器内核,意味着mingw版本的qt5.6以上版本也全部支持,这样就所有系统都有浏览器模块不需要担心没有电子地图的问题。

    5. 部分构建套件可能不支持预编译头,预编译头仅仅是为了加快编译速度,和程序本身无关。比如在win+Qt5.5 5.6就发现不支持,也可能是支持的不够全面,如果编译发生错误可以试着打开pro文件注释掉PRECOMPILED_HEADER = head.h 这行。

    6. Qt6.2的mingw版本的multimedia模块不可用,msvc版本的正常。

    7. 开启视频存储后默认存储的MP4格式的文件,如果想要调整体积大小,可以找到core/core_videoffmpeg/ffmpegsave.cpp videoCodecCtx->bit_rate = FFmpegHelper::getBitRate(videoWidth, videoHeight); 将这个码率调小即可,比如 videoCodecCtx->bit_rate = FFmpegHelper::getBitRate(videoWidth, videoHeight)/2; 可以将体积减少一半,相应的画质也会差一些。

    8. 推荐用64位的Qt搭配64位的ffmpeg,目前绝大部分系统都是64位的,能获得最大性能提升,本人亲自对比测试32位和64位,64位无论资源占用和操作响应等体验都更优。尤其是开启硬解码后,如果64个通道都需要硬解码,32位的测试下来貌似资源不够用。

    0.6.2 注意事项

    1. 可执行文件在源码同级目录的bin目录下。

    2. 编译完成后记得将源码下的file目录下(切记是file目录下而不是file目录)的所有文件复制到可执行文件同一目录。

    3. 如果开启了视频监控(默认开启),则记得将对应的动态库文件复制到可执行文件同一目录。比如采用ffmpeg内核(默认就是ffmpeg)的话,则将下载到的dll_ffmpeg4下的所有文件复制到可执行文件同一目录。

    4. 各个操作系统的ffmpeg和vlc编译好的动态库以及miniblink的动态库下载地址。 -https://pan.baidu.com/s/13LDRu6mXC6gaADtrGprNVA  提取码: ujm7。

    5. 如果是64位的qt则对应的dll时候拷贝dll_ffmpeg4_64目录下的。

    6. 如果使用的ffmpeg3则对应dll目录就是dll_ffmpeg3,在core_videoffmpeg.pri文件中可以看到具体启用的是ffmpeg3(支持XP)还是ffmpeg4(不支持XP),默认是ffmpeg4。

    7. 如果编译运行提示miniblink文件不存在请先拷贝,则说明你当前用的Qt版本没有浏览器模块,要么没安装,要么不支持,你也不用担心啥,此时自动切换用的miniblink浏览器内核,你还需要将ffmpeg库下载的网盘的地方找到dll_miniblink.zip下载解压到可执行文件同一目录即可。

    8. 系统中所有的图标,都采用的图形字体,对照表在doc目录下的FontAwesome.png、FontAliBaBa.png,对应图形字体类IconHelper中加载的图形字体,后期如果还有增加的其他图形字体也是放在这里,一个类支持多种图形字体,通过不同的值范围自动设置。

    9. 如果发现地图打不开或者提示秘钥文件丢失,请先确认file目录下的所有文件有没有拷贝过去。

    10. 如果是用vs+qt可能报错 error LNK2026,解决办法详细见本文档中13其他说明/13.5环境使用qt+vs。

    11. 默认用户名admin 密码admin。

    12. 系统配置参数在加载的时候会对节点值进行过滤判断,如果为空会自动用初始值生成新的配置文件,如果不想要显示版权所有公司,可以填xxx而不是删掉整个值。

    13. 如果是用vlc推流的rtsp地址,比如 rtsp://:8554/aabb,由于vlc推流默认写死的采用的udp协议,所以监控系统也必须在系统设置中通信方式选择udp才行(默认tcp)。

    0.6.3 离线地图

    1. 离线地图可以用网上的瓦片地图下载器下载百度的离线地图放到对应目录即可。

    2. 也可以直接下载网盘中已经下载好的上海市的离线地图。

    3. 下载地址:https://pan.baidu.com/s/1ZxG-oyUKe286LPMPxOrO2A 提取码:o05q 文件名称:bin_map_tiles.tar.xz

    使用说明

    1. 将压缩包下的两个文件夹复制到对应可执行文件下的config文件夹下,和map.js文件同一级目录。

    2. tiles文件夹是街道图,tiles_hybrid文件夹是卫星图,tiles_self是路网图,路网图和卫星图合并就是混合图。

    3. 默认提供的是上海市徐汇区的瓦片地图,如果自己用万能地图下载器下载的百度地图的瓦片文件,也可以对应替换就行。

    4. 要注意的是格式,默认是jpg,如果下载的瓦片地图格式是png则需要打开config文件夹下的map_load.js文件,将.jpg改成.png保存即可。

    0.7 视频格式

    0.7.1 USB摄像头

    1. 下面假定USB摄像头的设备名为 USB2.0 PC CAMERA。

    2. win系统如何查看设备名见本文档中13其他说明/13.7打开USB摄像头。

    3. linux系统查看设备名直接执行命令 ls /dev/video * 即可,一般对应的设备名是 /dev/video0。

    4. 写法1:video=USB2.0 PC CAMERA,这种写法默认按照640x480分辨率打开摄像头。

    5. 写法2:video=USB2.0 PC CAMERA|1280x720|30,这种写法按照指定的分辨率1280x720以及采集帧率30来打开摄像头。

    6. 写法3:video=/dev/video0,这种是对应linux系统,程序内部会自动过滤和调整填入的地址。

    7. 如果指定了分辨率和帧率则需要硬件支持才行,比如摄像头的最大分辨率是640x480,而指定了1280x720则会打开失败。

    0.7.2 中央卫视

    1. 中央卫视1:rtmp://58.200.131.2:1935/livetv/cctv1

    2. 中央卫视2:rtmp://58.200.131.2:1935/livetv/cctv2

    3. 中央卫视3:rtmp://58.200.131.2:1935/livetv/cctv3

    4. 中央卫视4:rtmp://58.200.131.2:1935/livetv/cctv4

    5. 中央卫视5:rtmp://58.200.131.2:1935/livetv/cctv5

    6. 中央卫视6:rtmp://58.200.131.2:1935/livetv/cctv6

    7. 中央卫视7:rtmp://58.200.131.2:1935/livetv/cctv7

    8. 中央卫视8:rtmp://58.200.131.2:1935/livetv/cctv8

    9. 中央卫视9:rtmp://58.200.131.2:1935/livetv/cctv9

    10. 中央卫视10:rtmp://58.200.131.2:1935/livetv/cctv10

    0.7.3 视频文件

    万能办法,用谷歌或者谷歌内核的浏览器,打开时光网 http://www.mtime.com/ ,随便打开个视频,这里一般是预告片,按F12切换到审查元素,顶部切换到网络,选中媒体,刷新网页,按照尺寸排列,最大的那个MP4文件就是,鼠标右键复制地址,这个地址就是完整的网络地址。

    1. http://vfx.mtime.cn/Video/2021/11/16/mp4/211116131456748178.mp4

    2. http://vfx.mtime.cn/Video/2019/03/19/mp4/190319212559089721.mp4

    3. http://vfx.mtime.cn/Video/2019/03/17/mp4/190317150237409904.mp4

    4. http://vfx.mtime.cn/Video/2019/03/14/mp4/190314223540373995.mp4

    5. http://vfx.mtime.cn/Video/2023/03/09/mp4/230309152143524121.mp4

    6. http://vfx.mtime.cn/Video/2023/03/07/mp4/230307085324679124.mp4

    7. http://vfx.mtime.cn/Video/2022/07/18/mp4/220718132929585151.mp4

    8. http://vfx.mtime.cn/Video/2022/12/17/mp4/221217153424902164.mp4

    9. http://vfx.mtime.cn/Video/2022/07/04/mp4/220704110656040153.mp4

    10. http://vfx.mtime.cn/Video/2021/02/08/mp4/210208150307073134.mp4

    11. http://vfx.mtime.cn/Video/2021/05/11/mp4/210511114524329144.mp4

    12. http://vfx.mtime.cn/Video/2021/04/20/mp4/210420113022586184.mp4

    13. http://vfx.mtime.cn/Video/2021/03/13/mp4/210313111010421158.mp4

    14. http://vfx.mtime.cn/Video/2020/01/15/mp4/200115125943120574.mp4

    15. http://vfx.mtime.cn/Video/2019/09/19/mp4/190919093845618674.mp4

    0.7.4 网友提供

    1. rtmp://live.yihtc.com:10935/hls/stream_3

    2. rtmp://live.yihtc.com:10935/hls/stream_13

    3. rtmp://218.3.205.46/live/ggpd_sd

    4. rtmp://hls.hsrtv.cn/hls/hstv2

    5. rtmp://hls.hsrtv.cn/hls/hstv1

    6. rtmp://222.173.22.119:1935/live/jnyd_sd

    7. rtmp://222.173.22.119:1935/live/xwhd_hd

    8. rtmp://livetv.dhtv.cn:1935/live/peoples

    9. rtmp://livetv.dhtv.cn:1935/live/citylife

    10. rtmp://livetv.dhtv.cn:1935/live/financial

    11. rtmp://livetv.dhtv.cn:1935/live/news

    0.7.5 监控设备

    下面列出的是一些常用厂家的格式,不同厂家格式不一样,具体什么格式请咨询厂家索要对应的视频流格式,或者设备支持onvif的话,通过onvif工具搜索可以拿到视频流格式。

    0.7.5.1 海康
    • 实时预览格式:rtsp://admin:12345@192.168.1.128:554/Streaming/Channels/101?transportmode=unicast

    • 视频回放格式:rtsp://admin:12345@192.168.1.128:554/Streaming/tracks/101?starttime=20120802t063812z&endtime=20120802t064816z

    • 流媒体视频流:rtsp://172.6.24.15:554/Devicehc8://172.6.22.106:8000:0:0?username=admin&password=12345

    • 日期时间格式:ISO 8601 表示Zulu(GMT) 时间 YYYYMMDD”T”HHmmSS.fraction”Z”,

    • 单播多播说明:unicast表示单播,multicast表示多播,默认单播,可以省略。

    • 通道码流说明:101,1是通道号,01是通道的码流编号,也可以是02、03,第2通道主码流=201,第16通道子码流=1602,依次类推。

    0.7.5.2 大华
    • 实时预览格式:rtsp://192.168.1.128:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif

    • 视频回放格式:rtsp://admin:12345@192.168.1.128:554/cam/playback?channel=1&subtype=0&starttime=2021_03_18_11_36_01&endtime=2021_03_18_12_05_01

    • 格式内容说明:channel表示通道,subtype表示码流编号,日期时间字符串非常明确。

    0.7.5.3 常规
    • 实时预览格式:rtsp://admin:12345@192.168.1.128:554/live?channel=1&stream=1

    • 视频回放格式:rtsp://admin:12345@192.168.1.128:554/file?channel=1&start=1494485280&stop=1494485480

    • 其他通用格式:rtsp://admin:12345@192.168.1.128:554/0 0-主码流 1-子码流

    • 日期时间说明:先转换时间戳,1970年到该时间经过的秒数。

    0.8 版本说明

    0.8.1 精益求精

    后期规划

    1. 摄像机信息表的用户信息字段用起来,视频流地址不带用户信息,主动加入用户信息构建最终地址应用。

    2. 用户密码密文存储,防止泄露。

    V20230416

    1. 新增桌面录屏的支持,包括ffmpeg、vlc、qtav、easyplayer等内核。

    2. 桌面录屏可指定录屏区域位置。

    3. 完善easyplayer内核对各种视频流的支持。

    4. 重新优化视频类型的判断,http开头的地址可能是文件也可能是视频流,以最终时长作为判断依据。

    5. 增加了H264裸流视频文件倍速播放。

    6. 内核ffmpeg增加发送packet帧信号,一般用于推流的同时保存视频文件需要。

    7. 模块onvif增加osd相关处理,可以获取所有osd,并执行添加、删除、修改操作。

    8. 增加OSD管理悬停模块,可以增删改查OSD相关信息。

    V20230323

    1. onvif模块增加获取mac地址。

    2. 所有监控内核增加矫正视频类型,比如http开头的有文件长度的则强制设置为filehttp类型,方便后期其他判断处理。

    3. 新增主动设置文件时长和播放进度的函数,以便事件回调那边主动设置。

    4. 修复ffmpeg内核部分视频文件当分辨率不是常规分辨率时(比如分辨率426x240)回调取出图片不正确的BUG,转换需要做字节对齐设置,现在约定统一用4字节对齐,这样兼容了所有可能的分辨率。

    5. 修复ffmpeg内核在高倍速比如5倍速播放情况下,如果解码来不及导致播放进度计算不正确的BUG。

    6. 增加对http开头的地址对应视频类型的判断,有些是视频文件(有时长并且可以切换播放进度),有些是实时视频,尽管地址格式都是 http://xxxxxx/xx.m3u8 这种。

    V20230201

    1. 新增天气预报模块开关。

    2. 海康内核增加手动指定端口解析。

    3. 更新onvif相关处理,支持内网摄像头通过路由器端口映射公开到外网,以外网的IP地址形式访问。

    4. 设备搜索模块在单播的时候增加厂家为空则先获取设备信息获取到制造商名称并自动填入。

    5. 内核vlc增加图片和文字水印功能,从源头处理。

    6. 内核mpv增加文字水印功能。

    7. 内核ffmpeg增加网络访问视频文件头部消息user_agent=Mozilla,有些视频网站根据这个头部消息过滤不让ffmpeg访问。

    8. onvif单播搜索增加指定地址不存在的过滤。

    9. 增加对显卡禁用环境的识别,自动切换采用Qt::AA_UseOpenGLES,否则在禁用显卡环境中无法正常使用opengl。

    10. 增加当处于OpenGLES绘制下自动将硬解码改成none,防止无法正常显示视频画面。

    11. onvif组件搜索功能增加错误提示,比如绑定组播失败、单播地址不通等提示。

    12. 无人机移动演示模块增加过滤,还没有初始化好就不触发js交互。

    13. 增加对虚拟机环境的识别,自动切换采用Qt::AA_UseOpenGLES,否则在虚拟机中硬解码下无法使用AA_UseDesktopOpenGL。

    14. 录像计划批量按钮增加先清空再批量,否则通道数不一致。

    15. 本地回放等界面增加全选、全不选按钮,用于对查询出来的视频文件全部选中和不选中。

    16. 打包文件增加了wenquanyi.ttf字体文件,由于ffmpeg用到了滤镜,为了支持中文正确显示,依赖指定的中文字体文件,放到可执行文件同一目录即可。

    V20230108

    1. 内核ffmpeg实现了各种OSD标签和图形直接绘制到帧上,保存也带了对应的标签信息,之前是绘制在遮罩层上。

    2. 内核ffmpeg带旋转角度的视频旋转采用滤镜实现,之前是通过算法转换。

    3. 修复图文警情在清空后重新添加警情的时候最底部一个item可能高度不对的BUG。

    4. 批量添加NVR通道改进编号和摄像头名称策略,编号为NVR地址的后两个网段的值加上3位通道字符串,名称为通道001/通道002依次下去。这样符合现场跨网段的场景,一般现场有N多摄像机和NVR,很多都是跨网段的场景。

    5. 地图上设备单击弹出视频预览增加过滤,限制双击只允许单击。

    6. 增加配置参数控制设备树是否显示主码流子码流节点。

    7. 增加配置参数双击打开分组最大数量,0-最大通道数量 1-当前通道数量 2-自动调整数量。

    8. 增加配置参数记录最后展开的设备节点,下次打开自动应用。

    V20221212

    1. 改进实时监测设备在线情况逻辑,之前是一次性所有的处理,改成了排队处理,每次间隔0.1s,同时处理完一个来回后休息5s,这样在设备数据很多的时候尤其有效。

    2. 视频参数设置中新增离线检测开关和报警视频存储时间下拉框选择。

    3. 设备播放模块增加添加完一个通道后自动切换到下一个通道。

    4. 将批量添加单独做成窗体,通用于轮询管理和摄像机管理,可以很方便的批量添加摄像机,录像机通道递增等各种智能规则。

    5. 打开弹窗视频增加在线判断,没有开启在线检测则先检测再判断是否需要弹窗。

    6. 纠正图片参数调节中饱和度和对比度界面上名称标识写反了的BUG。

    V20221207

    1. 报警事件抓图后添加到图文警情,改成线程排队处理,之前在主线程处理,如果有多个同时,很可能卡主界面,而且还要等待抓图的文件生成才能正确显示图片。

    2. 新增警情字典表config/event.txt,格式 1,IsMotion,移动报警,移动结束 ,分别表示 事件等级/唯一标识/报警字样/解除字样 ,这样大大增强灵活性,每个不同厂家的设备可能有不同的关键字表示不同的警情,用户只需要在字典表中编辑好即可。

    3. 内核vlc彻底解决回调模式下视频流需要手动指定的问题,改成了在播放后拿到分辨率后去设置回调数据,完美解决。

    4. 修复内核vlc中打开视频流后多次触发读取媒体信息的BUG,包括中途视频流发生变化也会多次触发。

    5. 修复悬停模块透明度值应用不及时的BUG。

    6. 图文警情双击显示原图增加自适应图片大小策略,并限定最大分辨率。

    7. 增加了左右通道音频振幅分别计算,之前混在一起计算。单通道的则左右一样。

    8. 视频预览窗体增加自适应视频大小策略,并限定最大分辨率。

    9. 新增将选择的软件图标作为全局的左上角图标,选择后立即应用。

    10. 修复在共享解码线程中再次打开弹出的视频窗体声音大小和静音状态不一致的BUG,改成了和原共享解码线程一致。

    11. 弹出窗体自适应最大尺寸,如果视频尺寸超过了最大尺寸则等比例缩放到合适尺寸。

    12. 报警事件抓图按照日期文件夹存放,之前存放在image_alarm目录下挤在一起,多了就很难看。

    13. 新增每个视频控件都有共享解码属性,每个控件都可以控制是否需要共享解码,之前是统一全局的属性,有时候需要单独弹出的报警视频独立处理以及存储录像,此时就需要指定该控件不共享解码,极大的增加了自由度。

    14. 修复清空录像机信息后,设备列表无法正常加载的BUG,改成了自动生成一个默认的分组。

    15. 新增半透明轮询分组提示标签窗体,在轮询启动后显示停止轮询后隐藏,可以拖动到合适位置,自动记忆最后的位置。方便在全屏轮询阶段告知用户当前轮询到哪里。

    16. 增加开关量报警弹出报警视频,并录像存储,可在视频回放中查询对应的报警视频并回放。

    17. 报警视频弹窗窗体标题栏,如果指定了存储报警录像,则显示关闭倒计时字样。

    18. 修复在打开了未连接的视频通道,通道处于不断重连中,单击轮询崩溃的BUG。

    19. onvif组件增加唯一标识,打印信息更清晰,带上唯一标识和设备IP地址。

    V20221125

    1. onvif搜索增加超时时间参数,经过大量的现场应用反馈,少部分厂家的设备,在极端的网络环境中,返回的数据要慢,需要把之前写死在代码中的超时时间放出来作为参数设置可调节。

    2. 视频参数增加悬浮工具栏位置参数,可以设置视频控件的悬浮条位置在顶部、底部、左侧、右侧四个位置。

    3. 解决Qt6.4及以后版本比如Qt6.5上minibink和opengl冲突导致opengl黑屏的bug,此问题找了很久发现原来是和miniblink冲突了,改成了异步加载miniblink浏览器控件即可,代码 QMetaObject::invokeMethod(this, "initWebView", Qt::QueuedConnection);

    4. 对不启用任何解码内核增加过滤,没有指定内核则不用启动解码线程。

    5. 测试发现Qt6.4.1版本音频播放有问题,会打印 qt.multimedia.audiooutput: Failed to setup resampler ,确认过是官方新增的bug(https://forum.qt.io/topic/140523/qt-6-x-error-message-qt-multimedia-audiooutput-failed-to-setup-resampler/5),用最新的6.5版本即可,总之不要用6.4.1。

    6. 使用示例增加音频频谱示例。

    7. 使用示例增加拖曳播放示例。

    8. 系统设置增加音频振幅开关,开启后视频右侧都会显示左右通道额音量条。

    9. 初始化结构体参数增加过滤机制,地址为空的不处理。

    10. 新增了视频通道拖动配置参数,可控是否允许拖动交换通道,防止误操作。

    11. 增加根据视频控件的高度自动调整音量条格子数量,比如4通道60个格子,64通道20个格子,保证音量条自适应。

    12. 音量条的圆角角度、格子高度、边距、间距等参数可自由设置。

    13. 静音状态约定只是声音不发送给音频输出设备播放,音频数据正常解析,包括音频频谱正常显示。

    14. 增加根据视频控件的宽度自动调整音量条的宽度,比如4通道的时候音量条可以宽一些,64通道音量条可以窄一些。以便留出更多的空间给视频显示而不会显得很拥挤。

    15. 增加根据视频控件的宽度自动设置悬浮条提示信息是否需要显示,宽度不够则不显示,比如悬浮条设定显示在左侧右侧由于宽度不够也不显示提示文字信息。

    16. 增加报警事件抓图显示在图文警情中。

    17. 增加udp://开头的视频流强制采用udp协议解析。

    18. 修复重连后默认的音量大小以及静音状态不正确的BUG。

    V20221121

    1. 新增图形字体文件可编辑,可以根据需要添加自己的图标到iconfont.ttf字体文件,需要借助fontcreator工具。

    2. 新增部分图标,把底部通道1-通道64的图标换成了数字模样的,整齐统一容易拓展。

    3. 修复ffmpeg内核声音播放的时候遇到标题栏或者UI按下卡住停顿0.5s的BUG,改成了线程中播放音频,无论UI如何卡丝毫不影响。

    4. 视频回放增加手动停止按钮以及静音切换按钮。

    5. 增加ffmpeg内核声音解码过滤,部分摄像机的音频流如果是48000采样会导致转换失败,增加过滤处理。

    6. 修复应用最后的音量大小和静音状态时候在ffmpeg内核下有时候不成功的BUG。

    7. 实时检测摄像机是否在线,增加其他端口的识别,默认554端口,也可能有其他端口。

    8. 改进默认音量大小和静音状态设置逻辑,如果采用QAudioOutput播放音频则初始化的时候传入对应参数,如果是内核自带声音静音接口的则在打开成功以后主动去设置默认的音量大小和静音状态。

    9. 本地回放增加停止播放和静音切换图标按钮,并优化对应的处理逻辑。

    10. 修复qmedia内核静音切换对应标志位没有改变的BUG。

    11. 对视频监控控件新增获取是否暂停状态、音量大小、静音状态等函数。

    12. 本地回放新增当用户按下播放按钮右侧又选择了对应的文件则自动触发双击播放。

    13. 修复本地回放中停止播放后当还不是末尾一个视频文件时还会自动播放下一个的BUG,因为有自动播放机制,需要增加标志位判断,只要按下过停止按钮则无需自动播放。

    14. 修复ffmpeg内核在快速拖动进度条期间切换播放进度后小概率出现播放暂停的BUG。之前复用的暂停标志位,由于很多地方用到并且可能修改了暂停标志位导致恰时间点的不正确,新增了切换进度标志位,专用于切换进度判断,完美解决。

    15. 增加onvif指令过滤重复机制,当队列中有相同的onvif地址和指令的时候,不需要加入队列。

    16. 内核ffmpeg增加了实时码率的计算,统计的一个周期内(帧率25就统计25个包)所有视频数据包的总大小。

    17. 重新更新全部说明书,包括截图和文字说明。

    V20221116

    1. 每个视频控件都可以手动开启和停止录像,开启的时候传入文件名即可。

    2. 修正视频控件边框大小计算当尺寸为奇数的时候不准确的情况,增加了偏移1个像素处理非常完美。

    3. 修复ffmpeg内核打开视频流中途分辨率变化后计算不正确的BUG,中途分辨率调整后策略改成重新打开。

    4. 修复ffmpeg内核在暂停阶段切换播放进度后会继续播放的BUG,应该是要继续处于暂停播放。

    5. 解码线程基类、保存线程基类都增加全局静态变量控制是否打印消息,由于解码线程等类中要打印的信息特别多,可以在需要的时候开启,几乎每一个重要的步骤或者可能出错的地方都会有对应打印信息,方便跟踪查找问题。有时候想关注其他地方的打印信息,为了避免给解码线程的打印信息冲掉,尤其是通道数量多的时候,信息类似涌过来,此时可以关闭解码线程的打印信息,专注于其他打印信息。

    6. 视频配置参数这块很多参数的设置改成了立即应用,比如边框大小、图片显示策略等,不能立即应用的也可以通过主界面中的停靠窗体设备控制单击刷新通道来应用。

    7. 录像计划改成了立即应用,添加、删除、修改后都会立即更新录像计划到视频管理线程类。

    8. 视频回放中的日期选择范围,改成了精确到分,无需精确到秒。

    9. 视频回放增加了倍速选项,可选0.5/1.0/2.0/4.0/8.0等倍速。设置完立即应用,下一个自动播放的也会立即应用该倍速。

    10. 视频管理线程类对切换保存文件的时间的精准度做了调整,比如30分钟一个文件,文件的时间是12:00:00到12:29:59,12:30:00到12:59:59,整半点开始,59秒结束。

    11. 目前的视频存储策略是中间存储的保证是30分钟的一个文件,头部和尾部,因为开启录像或者结束录像的时间未必是整半点,所以可能产生的录像文件的时间不一定的30分钟一个。

    12. 经过详细测试对比,如果是视频流,开启了变码流则视频大小未必一样,如果是定码流则几乎一样,变码流则文件大小相差比较大,视频中动静变化比较大或者颜色比较多的文件体积更大。

    13. 同样分辨率的视频流,用H265编码生成的视频文件体积比H264小很多(同一个摄像头同样主码流分辨率切换到H265存储体积大概是普通H264的40%,还有其他H264H/H264B之类的没有具体对比测试),本系统中的策略是源头是H264的就采用H264编码,源头是H265的就用H265编码存储。这样可以不用转码大大减轻CPU运算压力。

    14. 录像文件存储以本地时间为准,如果设备的时间和本地时间不一致,可能会看到摄像头视频文件上显示的时间和要求的时间不一致,在开启了onvif校时的情况下,大概会有3s左右的偏差,也就是说录像文件上显示的时间可能是走到10:30:03才结束,如果时间完全一致则应该是10:29:59。

    15. 增加目标秒数核对以便尽量保持录像时间以59秒结束,可以自行更改该目标秒数值保持一致。

    16. 所有下拉框中的通道字符串为了整齐统一改成了两位字符串比如 通道01、通道05、通道16,除了主界面通道文字是 通道1、通道5、通道16字样,其余全部两位。

    V20221111

    1. 新增录像计划,增加录像任务计划控件,支持星期一到星期日每天24小时勾选是否录像,精确到30分钟间隔。

    2. 任务策略表格支持直接右键菜单全部选中、反向选中、清空选中操作。

    3. 新增录像计划表RecordInfo,对应字段RecordCh表示通道0-64,RecordWeek1-RecordWeek7表示星期一到星期日的录像计划字符串表示,通过占位符表示该30分钟时间内是否录像,每天有48个小格式。

    4. 通道唯一标识统一ch01到ch64字样,录像文件以及截图都按照这个作为文件的前缀,方便查找。

    5. 调整了一个设备多路通道(比如NVR或者部分相机)搜索的结果组合的策略,以便配置成多个不同的通道。大部分厂家的规则是每个通道一路主码流一路子码流,依次顺序存放。

    6. 录像计划新增批量一键添加64通道7 * 24小时录像,绝大部分时候都是这个情况所以可以一键添加,添加好以后有特殊的可以自行调整。

    7. 演示示例demo新增了配置参数保存对应选择的视频地址。

    8. 视频参数设置做了重大调整,按照新的解码内核来设计,更合理更贴切,把一些不需要的删除了。

    V20220918

    构思和编码及测试花了一年时间,将所有视频监控内核重新架构重写,抽象视频解码线程类和视频窗体展示类,着重解决了视频解码线程复用。具体可参见文档中的内核模块说明。

    视频复用技术难点

    • 通道1打开视频流A,通道2也打开视频流A,通道3也打开视频流A,此时通道1负责打开视频流A,其他两个通道公用通道1的视频流数据。

    • 通道1关闭视频流A(仅仅是关闭映射,不能关闭视频流),通道2关闭视频流A(仅仅是关闭映射,不能关闭视频流),通道3关闭视频流A(关闭映射+关闭视频流)。

    • 首次打开视频流地址的通道负责打开视频流。

    • 末次关闭视频流地址的通道负责关闭视频流。

    主要改进功能点

    1. 共享解码线程,相同地址的已经打开过的,直接复用,大大减轻网络流量和推流设备的压力。

    2. 动态内核挂载,解码和展示分离,通过基类的公共接口设计,视频控件可以任意动态挂载任意的解码内核,在打开的时候指定即可,内部会根据指定的内核自动实例化对应解码线程解码。

    3. 悬浮工具栏控件,各种颜色设置,包括透明度,位置可以上下左右,内容可以自定义。单击事件发信号,常用的录像、抓图、静音、关闭等按钮内置了实现,其余自定义按钮可以自行拿到信号做处理。空白处显示对应通道的分辨率、录像状态等信息,提供接口设置对应提示信息。

    4. 自定义标签OSD,任意多个,有多种类型和属性参数。

    5. 自定义图形,任意多个,直接绘制到原图上,有多种类型和属性参数。

    6. 视频控件基类,参数极其丰富,包括边框大小、边框颜色、焦点颜色、背景颜色、文字颜色、填充颜色、背景文字、背景图片、是否拷贝图片、缩放显示模式、视频显示模式等。

    7. 解码线程基类,参数极其丰富,包括解析内核、视频地址、缓存分辨率、解码策略、硬件加速、通信协议、缓存时间、循环播放、读取超时时间、连接超时时间等。

    8. 除了常规的视频文件、网络文件、视频流,还支持本地摄像头、旋转了90度的手机视频文件、非H264的文件自动转码显示。

    9. 对ffmpeg内核做了极度优化,支持音频视频文件保存,之前只支持rtsp视频流,而且生成的文件不标准没有文件属性分辨率信息等。

    10. 统一的打印格式,完整的信号通知,友好的接口设计。

    0.8.2 破茧成蝶

    V20220625

    1. 在之前支持NVR所有通道批量添加基础上,增加自动添加NVR信息到表,这样每个NVR都会自动添加,如果有手动添加好的则取添加好的,以IP地址为准。

    2. 修复设备在线状态处理,在同一个NVR下IP地址相同的不同通道视频,不会处理在线状态的BUG。

    3. 修复在postgresql数据库和oracle数据库下,QSqlTableModel对应setTable设置表名严格区分大小写的BUG。

    4. 测试发现有些很老的设备支持的是onvif1.0,云台地址需要用getCapabilities才能拿到,改进这个处理,兼容任意版本。

    V20220612

    1. 修复qss中分组框QGroupBox标题位移的BUG,在linux系统表现不统一。

    2. 改进同样的内容导出到pdf和打印显示效果不一致的情况,统一设置分辨率为96。

    3. 摄像机管理增加多选删除,删除的时候除了删除摄像机表中对应记录,也同时删除轮询信息表中的记录。

    4. 初始化数据库按钮增加弹框确认,由于这个操作安全级别非常高,增加弹框确认很有必要。

    5. 所有QTableView+QSqlTableModel对应的保存按钮代码增加主动设置焦点,避免mac系统中当单元格处于编辑状态,再去单击保存按钮,数据依然是之前的数据的BUG。

    6. 样式表全局颜色增加悬停背景颜色QUIConfig::HoverBgColor和选中背景颜色QUIConfig::SelectBgColor用于自定义委托。

    7. 对于加深的样式,重新设置单元格等item选中和悬停颜色 默认悬停-DarkColorEnd 选中-NormalColorEnd,加深颜色设置为相反。

    8. 增加全局参数控制是悬停颜色覆盖选中颜色还是选中颜色优先,默认选中颜色优先,这样选中的item鼠标移上去不会改变掉颜色。

    9. 增加过滤同名的NVR,之前会重复加载,现在限定同名的只加载一个,要求整个系统中NVR的名字必须唯一。

    10. 轮询管理中增加摄像机表的过滤条件,启用了的才显示在表格中。

    11. 增加播放记录开关,用于软件启动后,是否从播放记录url.txt读取历史记录进行播放。

    12. 增加播放记录url.txt过滤机制,只有摄像机表中存在且启用过的才可以播放。也可以改成只对rtsp开头的进行过滤。

    13. 增加选择列表通道的时候自动选中视频通道,高亮显示,这样很明确知道选择的哪个,同理,选中视频通道也高亮选中列表通道。相当于通道选中和列表选中联动。

    14. 增加设备列表在线离线不同图标显示,目前只对rtsp地址开头的进行实时监测上线离线状态,其他全部永远当做在线。离线图标颜色取系统设置中的报警图标颜色。

    15. 增加设备在线状态字段列表,实时监测设备状态期间先判断状态是否发生变化,只有发生变化了才需要去调用对应函数处理,大大减少无效的多余的处理。

    16. 修复设备列表双击空白处崩溃的BUG,需要过滤空节点item。

    17. 增加表格策略,单选按下编辑、多选双击编辑,有些用户需要多选摄像机列表删除。

    V20220515

    1. 将用户退出中的退出系统权限验证去掉,理论上对退出系统这个限制没啥意义,还可以通过任务管理器强制关闭进程。

    2. 将退出系统的权限名称改成调整布局,没有调整布局权限则不能调整拖动停靠窗体位置等。

    3. 视频面板窗体对象指针放到了全局静态变量,这样很多地方可以直接使用,比如声音控制、布局调整、视频轮询等。这样就不用繁琐的信号槽切换,可以省略很多不必要的代码,性能更高。

    4. 修复静音状态下调整音量可能不正确的BUG,静音状态下只改变音量值变量而不是正常改变音量。

    5. 实现右下角音量面板静音切换、音量值调整,全局视频控件应用。

    6. 改进默认地图算法,取第一个有背景地图的设备的图片作为默认图片,可能默认图片不存在则取图片列表中的第一张。

    7. 修复ffmpeg内核回调模式自动重连崩溃的BUG,此时图片不存在应该置为空。

    8. 增加识别秘钥有限制后限定标题栏带试用字样。

    9. 重写通用的视频地址类videourl,将通道改成0开始,分隔符改成英文逗号,视频地址集合通过指定枚举值选择不同类型添加。

    10. 增加自动插入临时消息到数据库用户操作记录,增加参数控制是否需要显示临时消息的时候插入。

    V20220413

    1. 修复视频控件设置自定义背景颜色的时候,没有考虑边框的范围问题。

    2. 选项卡样式去掉悬停样式,经过观察对比Qt自带的样式都是没有悬停样式,直接是选中样式。

    3. 修复自定义委托复选框不居中的问题,之前计算不准确会有细微偏差。

    4. 自定义委托增加悬停颜色。

    5. 重写自定义委托禁用列,支持文字颜色、背景颜色、字体等特性。

    6. 修复用户登录、用户退出界面标题栏字体被放大的BUG,因为样式冲突了。

    7. 将NvrInfo和IpcInfo中的地址字段改名为mark备注字段,涵盖内容更广。

    8. 地图模块默认卫星图增加了叠加层,更符合实际需求,对应地图综合应用示例做了极大升级改善,比如下载离线地图改成了最新的地址,可以下载到和在线地图一样的瓦片图片文件,离线地图下载改成了多线程,速度提升10倍以上。

    9. 自定义委托增加quistyle标记,有该标记则自动代码内部引用换肤全局颜色变量,这样删除了大量的设置自定义委托背景颜色的代码。

    10. 修复Qt6中msvc编译器下,强制指定miniblink浏览器内核的时候编译通不过的BUG,其实这个操作有点吃饱了撑着,因为msvc下有webengine浏览器内核。但是就是因为有极个别人有这个需求,客户就是上帝。

    11. 增加用户管理权限。

    12. 将用户权限和用户信息相关类合并到通用的类userhelper中,做成通用的权限组件。

    13. 修复Qt6中自定义复选框委托,在设置了全局样式的情况下,会不断切换选中的BUG。

    14. 效果图重新截图,用最新的运行界面。

    15. 组件示例增加4通道视频同时播放,进度条控制。

    V20220106

    1. 彻底修复全屏模式+webengine同时存在的情况下鼠标右键菜单无法弹出以及视频可能黑屏的BUG,这是Qt的BUG。

    2. 同时测试多屏幕下正常状态和全屏状态的情况,多屏幕不同分辨率。

    3. 增加其他设置界面,将串口设置、网络设置等移动到其他设置。随着功能越来越多,也很有必要单独拆分设置。

    4. 修复打印预览看不到文字的BUG,原来是设置了QGraphicsView的前景色导致的,把前景色和背景色设置成一样的了,其实是有文字的,鬼想得到QPrintPreviewDialog里面的预览原来用的是QGraphicsView绘制的。

    5. 修复qchart图表控件鼠标按下松开后会跟随窗体移动的BUG,因为qchart鼠标按下是UngrabMouse事件而不是MouseButtonRelease。

    6. 修复表格行按下后自定义委托颜色在部分样式方案下设置不正确的BUG。

    7. 增加视频弹窗按钮,封装的统一的视频弹窗静态函数,直接传入url地址即可。

    8. 修复鼠标按下视频预览底部工具栏也能拖曳视频的BUG。

    9. 海康内核解析增加对通道的解析,比如可能是一个摄像机有多个通道,或者NVR多个通道。同时完善主码流子码流的解析,可以解析多个码流,之前只能解析主码流子码流两个。

    10. 海康内核句柄模式下增加等比例缩放自适应。

    11. onvif模块修复部分厂家摄像机比如天地伟业,搜索返回的媒体地址等一系列请求地址,没有加onvif节点的BUG。

    V20211220

    1. 重新梳理整个onvif模块,调整对应的结构,删除多余的变量和设置等,对应云台控制等操作需要指定profile,通过参数传入。

    2. 对应图片参数操作需要指定videosource,通过参数传入。

    3. 去除数据库字段mediaurl、ptzurl,因为这两个数据每次都是更新重新获取的,通过getServices获取,这两个字段改成了videosource、profiletoken,用来从数据库读取出来,每次使用的时候自动下发。

    4. 预置位表格中的按钮样式调整,去掉圆角,增加边距,效果更完美。

    5. 新增nvr多个通道onvif支持,改动onvif模块代码和数据库结构。

    • 搜索设备后判断是否多个videosource,多个表示有多个视频源,一般是NVR,也有部分IPC自带多个视频源。

    • 有多个则根据不同厂家不同规则,找出对应的每个通道的videosource、profiletoken、rtspmain、rtspsub用分隔符 | 插入到临时表格中。

    • 摄像机管理界面接收到添加设备的时候,在addDevice槽函数中,判断发过来的数据,带了 | 要分别取出来作为通道添加到数据库中。

    1. 重新定义搜索的摄像机设备命名规则,按照摄像机#ip地址末尾数字的方式。

    2. 如果是NVR过来的摄像机,增加自动查找NVR的名称插入数据库。

    3. 获取预置位增加立即清空所有行,之前是先清空内容再根据读取到的预置位个数设置行数。

    4. 增加双击打开NVR(也叫分组)对应策略 0-最后空白通道 1-从头清空通道。

    5. 增加双击打开IPC(也叫设备)对应策略 0-最后空白通道 1-最后按下通道。

    6. 改进在分辨率不同缩放比例保持一致的UI体验,不受缩放比例的影响。

    7. 修正异或加密,增加对@String开头的密文进行过滤,防止高版本产生的配置文件到低版本的Qt程序不能正确解析的BUG。

    8. 如果打开视频流出错提示 Server returned 5XX Server Error reply 表示摄像机的码流满了,可能多个地方在拉取码流导致摄像机输出的视频流被占满,已经没有更多资源。

    V20211205

    1. 地图内核增加了海量点接口。

    2. 路径规划模块彻底重写,支持重新绘制、沿线移动等模式,数据表格显示。

    3. 设备轨迹模块改成从gps点集合文本文件加载进行循环动态模拟移动,默认飞机图标,以便转动角度。

    4. 设备播放增加保存视频开关配置参数,可以直接在界面上开启,开启后,通过rtsp从nvr取流比如回放视频,可以将回放的视频保存MP4文件到本地。

    5. 修正Qt6通过属性设置标签labtip不能居中对齐的BUG。

    6. 封装通用的设置一堆按钮比如添加、删除、保存、导入、导出等按钮图形字体的函数,直接传入父面板即可,自动查找对应的objname设置图标,省去一堆重复代码。

    7. 新增飞行轨迹模块frmDeviceGps2,之前的frmDeviceGps作为通过外部函数调用移动。

    8. 样式统一整理规范,分类6大类:normal、black、light、dark、flat、other。

    10.1 windows-7

    10.2 windows-11

    10.3 linux-ubuntu

    10.4 linux-fedora

    10.5 linux-centos

    10.6 linux-uos

    10.7 linux-kylin

    10.8 linux-neokylin

    10.9 linux-newstart

    10.10 linux-debian

    10.11 unix-mac

    11 程序框架说明

    备注:下面的截图和说明未必是最新的,但是大部分是一致的,整体的框架不会改变,可能会有新增加子模块和代码,或者部分类文件有调整或者删除,具体以最新的代码为准。

    11.1 整体代码结构

    本系统采用模块化的设备,有用到第三方开源类库比如串口通信qextserialport,全部放在3rd下面,有用到很多自己封装完善的通用类库比如ffmpeg视频监控,全部放在core下面,设备通信和辅助处理全部放在class下面,所有界面全部放在ui下面,相当于一个个小的组件合起来,最终形成了整个监控系统的完整代码。

    11.2 主模块说明

    名称说明
    3rd一些第三方开源的类库,比如串口通信qextserialport。
    class存放系统初始化、样式控制、自定义控件、设备通信等。
    core本人一直持续更新完善的通用的类库,比如ffmpeg视频监控。
    ui所有的界面都分门别类放在这里。

    11.3 子模块说明

    11.3.1 第三方类库

    这里放的全部是第三方开源的轮子,感谢开源、感谢github、gitee等开源社区。

    名称说明
    3rd_qextserialport第三方串口通信qextserialport,这个类比较稳定可靠,经过了几十个项目持续数十年运行的考验,不用Qt自带的串口类。

    具体代码不做过多说明。

    11.3.2 通信及辅助类

    这里放的都是一些系统初始化、设备通信相关的类。

    名称说明
    api存放数据库表映射成对应的全局队列数据、通用的辅助函数类。
    app全局配置参数管理类、秘钥管理类、通用函数。
    devicecustom用户自定义设备通信管理,比如机器人通信、无人机通信等。
    devicevideo视频监控相关处理类,包括设备地图、表格消息、线程UI通信、人工智能处理等。
    usercontrol当前系统的自定义控件全部放在这里,其中包括云台仪表盘、天气面板等控件。
    11.3.2.1 模块-api
    名称说明
    dbdata将数据库表映射到全局变量数据队列,比如将摄像机表ipcinfo转成QStringList存放一行行数据,这样在程序中运算比较速度极快,直接内存比较,不用每次都去读取数据库。
    dbquery所有的数据库查询插入更新等操作都在这里,比如查询摄像机表、插入日志记录等。
    11.3.2.2 模块-app
    名称说明
    appconfig配置参数类,整个系统的配置参数存放在ini文件中,跨平台,所有参数都对应一个变量,读取配置参数的时候将值赋值给变量,写入的时候将变量值写入到配置文件。
    appdata全局变量类,系统中无可避免需要一些全局变量方便处理,都放在此类,比如版本号、录像机类型、摄像机类型、当前用户信息、地图宽度高度、左侧右侧顶部底部宽高等。
    appevent全局事件转发类,系统越复杂信号需要传递的层级越多,所以需要一个全局事件转发类,用来中转这些事件,这样永远只需要两层就可以收到信号进行处理,而且整个系统看起来干净整洁,不会说一个信号传递到了N个地方乱七八糟,建议需要跨层级传递的信号都放在这里中转。比如软件退出信号,可能多个界面需要收到退出信号进行保存和其他处理,如果从关闭界面发出信号传递给需要的界面,那不知道要中间层层传递多少次,有了这个全局事件转发类,你只需要将事件传给appevent,需要接收事件的地方关联这个信号就行,appevent为全局单例类,整个系统唯一。通用的一些信号有软件退出、全局样式改变、主窗体变化(0-最小化 1-最大化 2-恢复 3-关闭 4-移动 5-尺寸变化)等。
    appinit程序初始化类,在main函数中,会先执行这个初始化的类,比如初始化皮肤、字体、数据库、样式等操作,这些都是要优先在窗体加载前执行的,执行完毕以后再打开窗体主界面。
    appstyle全局样式管理类,整个系统的样式全部放在这里,一般加载流程是先读取样式表文件,然后将本系统独特的样式(比如开关按钮、视频监控、云台仪表盘)内容追加到后面,最后统一设置全局样式,在main函数中加载,和appinit类一样放在最前面执行。
    appurl视频监控系统中常用的默认的视频地址集合。
    11.3.2.3 模块-devicecustom
    名称说明
    devicerobot机器人串口通信管理类。
    devicerobot2机器人串口通信管理类2,有串口数据转发功能。
    deviceuavsserver无人机后端服务类,当前为空,用户自己添加。
    deviceuavsvideo无人机视频监控类,将视频控件设置过来,然后就可以将自己人工智能算法处理后的图片传过来进行绘制,类似于实时视频效果。
    11.3.2.4 模块-devicevideo
    名称说明
    devicehelper整个系统设备管理辅助类,比如插入窗口消息、加载设备列表、加载图片地图、加载设备按钮、初始化视频控件等。
    devicemap设备图片地图管理类,相当于一次性加载所有图片到内存,当要切换或者显示的时候,直接从内存取出来设置即可,速度极快,瞬间相应,纯粹是为了加快相应速度以及可能在图片上进行绘制增加的功能,比从文件系统读取图片文件显示快N倍。
    deviceonvif设备onvif通信管理类,比如获取当前选中通道的onvif地址、开启事件订阅、校对时间、重启设备、获取视频参数、设置视频参数、云台控制等,这里是具体的需要和摄像机信息表及视频通道关联的处理,所以不能放到通用的onvif模块中。
    devicethreadui演示线程通知UI更新,包括每隔一段时间插入消息、异步调用添加表格消息和图文警情、设备GPS移动、报警闪烁、指定通道编号设置视频和通道交换等。
    devicevideosmart人工智能处理类,最常见的应用就是设置一个视频控件,然后在视频控件上绘制人脸框、文字信息等,比如设备的实时运行状态。
    11.3.2.5 模块-usercontrol
    名称说明
    gaugecloud云台仪表盘控件。
    cityhelper省市县联动类,通过从json文件读取省市县信息。
    weather城市天气类,最后显示在标题栏上,实时显示设置的城市的最近几天的天气。
    widgetsound声音面板控件,主界面右下角单击弹出音量条。

    11.3.3 核心通用类库

    这里放的全部是个人一直持续更新完善的独创的轮子,所有的项目都公用这些轮子,用到哪个就包含哪个进来,更新只需要更新轮子代码就行。

    视频监控系统包含的轮子超级丰富给力,物超所值,涵盖了数据导出模块、数据库应用、音频播放和录制、视频播放和录制、ONVIF通信、TCP文件传输、地图应用、通用浏览器内核等。

    名称说明
    core_audio音频播放和录制,包括音频输入输出管理、音频曲线、音频播放、音频录制、音频振幅控件等。
    core_common通用函数,包括通用秘钥、通用导航、通用样式、声音播放、日志记录、运行时间记录等。
    core_control通用自定义控件,很多系统经常用到的控件全部放在这里,比如开关按钮、设备容器、设备按钮、颜色下拉框等。
    core_dataout数据导入导出到xls/pdf和打印类库,极速、跨平台、无依赖。
    core_db数据库通用类库比如数据库线程管理、数据清理、数据采集等。
    core_form通用的用户登录、用户退出、用户管理、数据库配置界面类等。
    core_map地图综合应用类库,百度地图(支持在线离线)和echart封装类等。
    core_onvifonvif功能封装类,包括设备搜索、云台控制、设备参数设置等。
    core_qui通用的辅助类,包括自定义对话框,全局辅助函数,图形字体等。
    core_tcpfile文件多线程收发类,支持多个并发。
    core_video视频播放核心类,包括了监控画面切换控件、视频回放控件、视频播放组件结构体、视频播放辅助函数、视频解码线程类、视频显示控件类等。
    core_videobase视频相关基类,包括音视频文件保存基类、视频解码基类、视频控件基类、视频悬浮工具栏、视频控件结构体等。
    core_videoffmpeg视频监控内核ffmpeg版本,本系统默认采用的内核。
    core_videoopenglopengl封装类,支持打开yuv/nv12文件,绘制yuv/nv12帧数据,一般搭配ffmpeg视频内核显示视频,直接走GPU绘制。
    core_videosave音视频保存组件,包括音频保存类、视频保存类、保存相关辅助函数类。
    core_webview通用浏览器控件类,同时支持webkit、wenengine、miniblink三种内核,打通了所有的Qt版本。
    11.3.3.1 模块-core_audio
    名称说明
    audiohelper音频相关辅助函数,比如获取音频输入输出设备、根据设备名称查找设备对象、初始化音频格式、获取对应音频格式最大振幅、获取对应音频格式音频数据的振幅级别等。
    audiolevel音频振幅控件,根据传入的音频振幅大小绘制振幅,可设置颜色。
    audioplayer音频播放类,可以设置声音大小和静音状态,支持带参数打开音频输入和输出设备,自动关联音频输入输出设备形成话筒和音响联动。
    audioplot音频曲线类,包括初始化图表、添加振幅数据、添加音频数据等。
    audiorecorder音频录制类,可以设置音频录制的参数,包括采样大小、比特率、通道数、质量级别、编码模式等。
    11.3.3.2 模块-core_common
    名称说明
    base64helper图片及文字和base64编码之间转换的类。
    commonkey通用秘钥管理类,指定校验秘钥文件,可设置运行时间、设备数量等限制,支持根据硬件指纹特征生成机器码文件等。
    commonnav通用菜单导航管理类,用来控制和显示顶部导航栏、左侧导航栏的样式。很多子界面需要用到,所以封装成一个专门管理这个的类。
    commonstyle通用样式管理类,比如Qt自带类窗体样式、自定义控件样式、分页导航样式、导航按钮样式、开关按钮样式等。相当于将多个项目常用的自定义样式封装一起做成通用。
    framelesswidget2无边框窗体拉伸类,边框四周八个方位都可以自由拉伸,可设置是否允许拖动和拉伸。
    playwav声音文件播放类,通用Qt456,自动识别当前Qt版本使用对应的类,Qt4采用QSound,Qt5以上采用QSoundEffect,嵌入式采用对应的命令行aplay、mpv来播放。
    savelog日志钩子类,将系统中所有的打印信息转为日志存储或者输出到网络等,可以开启用来打印输出日志信息。
    saveruntime保存运行时间类,用来存储系统启动后每隔一段时间就输出一条记录用来记录启动后软件运行了多久,方便分析问题。
    11.3.3.3 模块-core_control
    名称说明
    bottomwidget通用底部状态栏控件,可以设置软件名称、版本号、运行时间等。
    colorcombobox颜色下拉框控件,在系统设置中有。
    cpumemorylabelCPU和内存使用情况标签控件,主界面右上角显示。
    customtitlebar停靠窗体自定义标题栏控件。
    devicebutton设备按钮控件,比如图片地图模块中用到,可设置不同的图标样式和状态等,双击发出信号进行相应处理比如弹出对应窗体等。
    lcddatetime软件右上角显示时间的控件。
    panelwidget面板容器控件,主界面子模块表格消息,就用到此控件,用于将一堆widget放到此容器进行管理,自动形成滚动条等。
    switchbutton开关按钮控件,在系统设置中存在大量该控件。
    xslider滑动条控件,在原有滑动条基础上增加了鼠标按下立即定位等。
    11.3.3.4 模块-core_dataout
    名称说明
    datacreat通用数据报表内容创建类,比如生成表格格式的html内容,然后赋值给dataprint直接打印,里面举例了图文混排的报告内容,后期会不断增加其他模板,也可以自行增加其他模板数据。
    datacsv导入导出数据,csv格式,可设置分隔符。拓展名。过滤条件等。
    datahead当前组件通用头文件。
    datahelper辅助类,比如校验规则函数,通用数据导出+打印函数。
    dataprint数据打印到pdf及纸张,支持多线程。
    dataxls数据导出到xls类,支持多线程导出。
    11.3.3.5 模块-core_db
    名称说明
    dbcleanthread自动清理数据线程类。
    dbconnthread数据库通信管理线程类。
    dbdelegate自定义委托全家桶,包括复选框、下拉框、密码框、按钮等。
    dbhead当前组件通用头文件。
    dbhelper各种数据库应用函数封装,比如初始化数据库、执行sql语句等。
    dbhttpthread网络请求数据采集类。
    dbpage数据库通用翻页类。
    dbpagemodel数据库翻页类数据模型。
    navpage分页导航控件。
    11.3.3.6 模块-core_form
    名称说明
    formhelper封装的导入导出、导出数据到xls/pdf和打印数据、自动备份数据、保存最后打开的文件夹等。
    frmconfigdb通用数据库管理界面类,可选不同的数据库类型,填入用户信息,执行检测连接和初始化数据操作。
    frmconfiguser通用用户管理界面类,可添加、删除、修改用户信息,包括权限分配等,可导入导出打印用户信息。
    frmlogin通用用户登录界面类,包括自动登录和记住密码复选框,多次密码错误校验,记住当前用户信息等。三次错误关闭,下拉可选用户,内置超级密码。
    frmlogout通用用户退出界面类,三次错误关闭,下拉可选用户,内置超级密码。
    userhelper通用用户权限管理类,内置7种类型权限,对应权限名称可自定义,一般在用户切换对应界面或者单击了对应功能按钮的时候触发。
    11.3.3.7 模块-core_map
    名称说明
    echartjsechart模块中用到的json文件转js文件,获取js文件中的名字和经纬度等处理。
    echartsechart封装类,可加载仪表盘、闪烁点图、迁徙图、世界地图、区域地图等,每个点可自定义颜色和提示信息等。
    mapbaidu百度地图封装类,支持在线和离线两种模式。
    11.3.3.8 模块-core_onvif
    名称说明
    onvifbase基础类,用于获取设备信息、服务文件地址、能力文件地址、媒体文件地址、视频流地址等。
    onvifdevice设备类,核心处理及管理,包括设置用户信息请求onvif地址、获取设备信息、云台控制、事件订阅、抓拍图片等。
    onvifevent事件订阅具体实现类,可设置请求超时时间等。
    onvifhead当前组件通用头文件。
    onvifhelper辅助类,比如获取UUID用于请求、判断IP合法、获取本机IP地址集合、管理系统中所有onvif设备对象等。
    onvifmedia获取媒体文件具体解析类。
    onvifother其他处理类,比如系统重启、NTP校时、获取和设置网络信息、获取和设备时间、获取和设置图片参数等。
    onvifptz云台控制实现类,包括绝对移动、相对移动等。
    onvifquery数据查询类,用于将接收到的xml数据解析,并赋值字符串比如命名空间、设备地址、媒体地址、事件地址等。
    onvifrequest网络请求类,包括设置用户信息、获取用户token数据、获取xml头部数据等,通用的请求数据返回结果函数。
    onvifsearch设备搜索类,支持广播搜索、指定地址搜索,可获取设备信息集合、获取设备地址集合。
    onvifservices服务类,用于获取媒体地址、云台地址等。
    onvifsnap图片抓拍实现类,包括获取抓图地址、抓拍图片等。
    11.3.3.9 模块-core_qui

    本组件涵盖的功能较多,所以采用了分层管理代码结构。

    名称说明
    iconhelper万能图形字体类,可传入多种图形字体文件,一个类通用所有图形字体。
    quiconfig存储当前组件的配置参数信息,比如全局的字体名称、字号、无边框窗体的最小化最大化关闭等图标、样式表的颜色值。
    quihead当前组件通用头文件。
    quistyle当前组件通用样式设置管理类,可以指定枚举类型样式、传入样式内容设置、获取样式表文件对应的颜色值等。当前组件样式相关的处理函数都放在这里,统一管理。
    名称说明
    quiabout关于系统对话框,可传入软件标题、版本、版权、网址等信息。
    quidateselect自定义日期范围选择对话框。
    quiinputbox自定义输入框窗体,可指定不同的输入类型比如文本框、下拉框等。
    quimessagebox自定义信息消息框窗体,可设置关闭倒计时,不同的类型比如信息框、询问框、错误框等。
    quisplash自定义弹出提示信息,提示完自动消息关闭。
    quitipbox自定义右下角信息对话框,可设置对齐方式、关闭倒计时等。
    quiwidget自定义无边框窗体,可设置标题,各种图标等。
    名称说明
    quihelper项目通用辅助类,各种常用函数的封装,比如获取当前屏幕分辨率、设置字体、设置编码、加载翻译文件、各种进制数据转换、弹出各种对话框、设置延时时间等。
    quihelpercore获取当前桌面分辨率,设置编码、字体、翻译文件等。
    quihelperdata16进制、2进制、10进制互相转换,16进制字符串、字节数组互相转换,字节数组转int和short,CRC校验等。
    quihelperfile选择文件、保存文件、选择目录等对话框,复制文件、删除文件等。
    quihelperform设置无边框窗体、边框阴影,弹出信息框、错误框、询问框、日期选择框、关于对话框、中间提示框等。
    quihelperimage获取等比例缩放图片,通用设置logo图片,支持资源文件、本地图片、图形字体、svg自动变色等多种形式。
    quihelpernet获取本机IP地址集合,获取外网IP地址,判断IP、MAC等是否合法,下载网络文件,IP地址字符串与整型互相转换。
    quihelperother初始化数据库文件,设置系统时间、开机启动,设置图标到按钮,写入临时消息的文本文件等。
    11.3.3.10 模块-core_tcpfile
    名称说明
    tcpfilehead当前组件通用头文件。
    tcpfilehelper辅助类,包括将字节转为MB单位、初始化表格控件、生成表格行、数据加密解密、解压文件、重启系统等。
    tcpreceivefileserver接收文件服务类,管理多个接收文件线程,支持监听端口被动接收文件和主动连接服务器接收文件。
    tcpreceivefilethread接收文件线程类,根据发送的文件名、包编号、块大小、挨个接收数据最终形成文件,可设置保存文件夹等。
    tcpsearchfileserver搜索文件服务类,目前没用,用于接收请求搜索文件是否存在。
    tcpsendfilethread发送文件线程类,按照 文件开始符+文件大小+文件内容+文件结束符 逐个分包发送,可对文件的每个包进行加密传输。
    11.3.3.11 模块-core_video

    视频组件继承和依赖关系说明:

    1. videobase是基类组件,video是视频播放组件,依赖基类组件,videoffmpeg是具体的内核实现组件,依赖视频播放组件,videosave是视频保存组件,依赖基类组件。

    2. video组件中的videothread解码线程类继承自videobase基类组件中的abstractvideothread。

    3. video组件中的videowidgetx视频显示类继承自videobase基类组件中的abstractvideowidget。

    4. videosave组件中的saveaudio和savevideo继承自videobase组件中的abstractsavethread。

    5. videoffmpeg组件中的ffmpegthread继承自video组件中的videothread。

    6. videoffmpeg组件中的ffmpegsave继承自videobase组件中的abstractsavethread。

    7. 按照此规则还有其他内核比如vlc组件中的vlcthread也是继承自videothread,mpv组件中的mpvthread也是继承自videothread。这样新增一种内核只要具体实现部分处理函数即可应用整个视频框架。

    8. 通过多层基类继承关系,使得动态挂载任意解码内核极为方便。

    9. 为何在video视频组件的基础上还要提炼一个videobase基类组件?因为该基类组件还可以提供给QCamera本地摄像头采集组件使用,基类中的变量、函数、处理逻辑几乎一致,但是又有特殊性,所以需要分开再提炼出videobase基类。

    名称说明
    videobox监控画面切换控件,将所有通道切换处理全部集中到一个类,通用异形布局切换函数,可以参考进行自定义异形布局,通道布局切换发出信号通知,支持自定义子菜单布局内容。
    videohelper视频播放内核辅助函数,比如根据url地址取出ip地址、校验网络地址是否可达、检查地址是否正常、加载解析内核到下拉框、根据地址获取本地摄像头参数、创建视频采集类、对采集线程设置参数等。
    videomanage视频线程管理类,全局单例,将所有视频控件发给此类管理,负责挨个打开视频、应用录像计划等。
    videoplayback视频回放控件,支持多个通道,显示每个通道对应的视频段。
    videostruct视频播放组件结构体定义类,包括解析内核枚举值、视频类型枚举值、解码策略枚举值、视频采集参数结构体。
    videotask视频任务线程类,全局单例,可以随时插入一些视频相关的任务进行处理,比如vlc录制视频后需要重命名文件,mpv内核关闭视频后鼠标指针打圈圈需要复位。
    videothread视频解码线程类,内置了共享解码线程处理逻辑,可以打开视频、关闭视频、设置视频宽高比例、获取文件总时长、获取媒体信息、获取和设置播放位置、获取和设置播放速度、获取和设置音量大小、获取和设置静音状态等。
    videourl视频地址相关静态函数,可以读取和写入地址到文本文件,用作历史记录,内置了各种类型(rtsp、http、音频文件、视频文件、网络文件、本地USB摄像头)的测试音视频地址集合。
    videowidgetx视频播放控件,一个控件对应一个解码线程,提供播放成功、播放结束、收到截图、工具栏按钮单击等处理,提供开始播放、停止播放、暂停播放、继续播放、抓拍截图、开始录制、暂停录制、停止录制等接口。
    11.3.3.12 模块-core_videobase
    名称说明
    abstractsavethread音视频存储基类,可以设置需要保存的音视频文件类型,比如音频文件类型有pcm、wav、aac,视频文件类型有yuv、h264、mp4,提供开始保存、暂停保存、停止保存等接口。
    abstractvideosurface视频回调基类,用于Qt中的QCamera和QMedia类播放后拿到回调视频数据,这样可以取到一张张图片。
    abstractvideothread视频解码线程基类,摄像头采集线程和视频采集线程都继承自此类,将各种公用的变量、函数、接口、信号槽全部放在基类,包括了停止线程标志位、打开是否成功标志位、暂停采集标志位、开始截图标志位、正在录制标志位,提供了虚函数开始播放、停止播放、暂停播放、继续播放、抓拍截图、截图完成、开始录制、暂停录制、停止录制等,提供写入视频数据到文件、写入音频数据到文件槽函数。
    abstractvideowidget视频显示控件基类,
    audioplayer音频播放类,空的,纯粹为了在没有Qt音频播放类QAudioOutput的时候使用,有些Qt版本或者嵌入式板子环境未必有这个类,但是又不能影响整个组件的运行,于是定义了空的类,函数正常调用但是不做任何处理。
    bannerwidget悬浮工具栏控件,可以设置各种颜色、按钮图标集合、按钮名称集合、按钮提示信息集合等,悬浮条位置支持上下左右四个方位。
    imagelabel图片标签控件,多线程绘制传入的图片,性能比setpixmap更优。
    widgethelper窗体相关辅助函数,包括传入图片尺寸和窗体区域及边框大小返回居中区域(scaleMode: 0-自动调整 1-等比缩放 2-拉伸填充)、绘制矩形区域比如人脸框、绘制点集合多边形路径比如三角形、绘制路径集合、显示截图预览等。
    11.3.3.13 模块-core_videoffmpeg
    名称说明
    ffmpeghelper相关辅助函数,包括打印输出各种信息、打印设备列表和参数、格式枚举值转字符串、视频帧旋转、通用硬解码、通用软解码、通用软编码、释放数据帧数据包、超时回调(包括打开超时和读取超时)等。
    ffmpegrun执行ffmpeg命令,包括yuv420p文件转mp4文件、mp4文件转yuv420p文件、wav文件转aac文件、合并aac以及h264文件或者mp4文件到带声音的mp4文件、转换视频文件到mp4文件等。
    ffmpegrunthread执行ffmpeg命令行线程,可以设置执行完成是否删除转换前的文件、可执行文件路径,传入需要执行的指令即可。
    ffmpegsave视频存储类,用于保存h264和mp4文件。
    ffmpegsync音视频同步线程类,解码后的音视频数据发给本类进行时间同步处理,采用的外部时钟同步策略。音视频播放的进度也在本类中。
    ffmpegthread视频解码线程核心,从打开地址、分配解码器、初始化参数、取出音视频数据解码、关闭并释放资源等都在本类实现。
    11.3.3.14 模块-core_videoopengl
    名称说明
    openglinclude当前组件头文件。
    nv12glwidget空类,用于没有opengl的Qt版本中保证程序能够继续运行。
    nv12openglwidget继承自QOpenGLWidget的NV12格式OPENGL绘制窗体。
    yuvglwidget空类,用于没有opengl的Qt版本中保证程序能够继续运行。
    yuvopenglwidget继承自QOpenGLWidget的YUV格式OPENGL绘制窗体。
    11.3.3.15 模块-core_videosave
    名称说明
    saveaudio音频保存类,继承自videobase组件中的abstractsavethread,可以设置音频文件类型、采样率、通道数等,支持pcm、wav、aac三种格式。
    savevideo视频保存类,继承自videobase组件中的abstractsavethread,可以设置视频文件类型、宽度、高度、帧率,支持yuv原始数据格式。
    savehelper音视频保存相关辅助函数,包括pcm文件转wav文件、aac文件采样率下标、aac文件添加adts头等。
    11.3.3.16 模块-core_webview
    名称说明
    webcore.pri通用的根据不同的Qt版本、不同的编译器环境、不同的操作系统,加载对应的浏览器内核模块和定义不同的变量。
    miniblinkminiblink封装处理类。
    webhelper经纬度转换、获取小数点经纬度值等常用处理函数。
    webjsdata通用的浏览器控件和Qt程序交互数据中转类。
    webview通用浏览器控件,支持webkit、webengine、miniblink。

    11.3.4 界面UI

    界面说明

    1. 这里分门别类存放的各种功能集合的界面类。

    2. 每个类都一个ui文件、一个h头文件、一个cpp实现文件。

    3. 可以方便快速查找对应功能的界面,也方便拓展增加界面。

    4. 不仅分文件夹存放的,而且命名也尽量按照对应功能打头,比如系统设置模块中的都用frmconfig打头。

    5. 外层文件夹是整齐的,内部代码也是整齐的。

    名称说明
    frmconfig系统设置模块,包括基本设置、录像机管理、摄像机管理、轮询管理、用户管理、视频上传等。
    frmdata日志查询模块,包括本地日志、设备日志等。
    frmdemo演示demo示例,用于演示具体控件或者功能的使用,方便学习参考,比如视频图片、视频控件、视频存储都单独的使用demo。
    frmipc存放摄像机处理相关的模块,比如设备控制,云台控制、预置位、巡航设置等。之前放在frmmodule模块中,后面独立出来管理更方便。
    frmmain主界面模块,包括登录登出界面、主界面、右上角时间组件、欢迎组件等。
    frmmap地图模块,包括通用地图内核界面、图片地图、在线地图、离线地图、路径规划等。
    frmmodule停靠子窗体模块,包括停靠窗体管理核心类、设备列表、窗口信息、图文警情、设备轨迹、网页浏览等模块。将摄像机、机器人、无人机相关的模块放到了对应的模块文件夹,这里放的是系统通用的模块。
    frmrobot无人机模块,包括图像增强、飞行监控等模块。
    frmuavs无人机模块,包括图像增强、飞行监控等模块。
    frmvideo视频监控模块,所有视频监控相关的都放在这里,包括主界面的视频监控布局窗体、视频回放、远程回放、图片回放等。
    11.3.4.1 模块-frmconfig
    名称说明
    frmconfig系统设置模块主界面,采用堆栈窗体形式,加载多个子界面比如摄像机管理、轮询管理等。
    frmconfigipc摄像机管理,可以增加、删除、修改、清空、导入、导出、打印摄像机信息。
    frmconfigipcsearchonvif设备搜索,独立出来的窗体,可以搜索局域网内的所有onvif摄像机信息,搜索完以后获取摄像机的视频流地址等,最后可以单个添加或者批量选中添加到摄像机信息表格中。
    frmconfignvr录像机管理,可以增加、删除、修改、清空、导入、导出、打印录像机信息。
    frmconfigpoll轮询管理,可以增加、删除、修改、清空、导入、导出、打印轮询点信息。可以按照设定规则批量生成轮询点信息。
    frmconfigpollplus将轮询管理中的轮询参数配置、分组管理、批量添加等独立出来的界面,方便管理和拓展。
    frmconfigsave录像计划,可以对每个通道每周每天每半小时时间段设置是否存储录像。
    frmconfigsystem系统设置,包括基本设置、视频参数、数据库设置、地图配置、功能激活、颜色配置、串口配置、网络配置等。
    11.3.4.2 模块-frmdata
    名称说明
    frmdata日志查询模块主界面,采用堆栈窗体形式,加载多个子界面包括本地日志、设备日志等。
    frmdatadevice设备日志,通过私有协议从NVR取对应设备日志信息。
    frmdatauser本地地址,用户操作的日志信息,可查询和导出打印数据记录。
    11.3.4.3 模块-frmdemo
    名称说明
    frmdemo单独的功能演示示例主窗体,加载多个子界面比如视频控件等。
    frmdemoqui通用辅助示例,主要演示qui通用组件中封装的函数如何使用,比如各种消息框、提示框等。
    frmdemovideoimage视频图片示例,从图片文件夹读取图片集合,定时器绘制取出图片发给视频控件绘制。
    frmdemovideoplus视频叠加示例,多个视频控件叠加在一起同时播放,可以设置在四个角落位置。
    frmdemovideosave视频保存示例,演示如何对视频控件进行视频保存,可动态保存。
    frmdemovideowidget视频控件示例,演示视频控件如何使用。
    11.3.4.4 模块-frmipc
    名称说明
    frmipccontrol设备控制模块,可对选中设备进行图片参数调节、NTP校时、设备重启、抓拍图片(ONVIF抓图)等。
    frmipcnavigate巡航管理模块,暂未实现,后期完善。
    frmipcreset预置位管理模块,暂未实现,后期完善。
    frmipcptz云台控制模块,可对选中的摄像机进行云台控制。
    11.3.4.5 模块-frmmain
    名称说明
    frmmain系统主界面,采用堆栈窗体,加载各个子模块。
    frmmain1备用模块1界面,根据参数设置决定是否启用。
    frmtimecpu右上角日期时间+CPU内存显示。
    frmwelcome右上角欢迎信息界面。
    11.3.4.6 模块-frmmap
    名称说明
    frmmap地图管理主界面,采用堆栈窗体形式,加载各个子界面比如图片地图、在线地图、离线地图、路径规划等。
    frmmapcore通用百度地图内核界面,用来加载百度地图,可设置在线、离线模式,有很多个窗体用到类似功能特意封装到一个类,重复利用,比如悬浮地图、飞行轨迹、路径规划等模块都用到了此内核。
    frmmapdevice通用的设备地图界面,在线地图和离线地图界面公用这个界面,唯一区别就是设置下地图的模式是在线还是离线。
    frmmapimage图片地图界面,设备作为一个个按钮点显示在对应地图上,可以拖动,双击弹出预览实时视频。
    frmmaplocal离线地图界面,可更新经纬度值、模拟运动轨迹等。
    frmmapweb在线地图界面,可更新经纬度值、模拟运动轨迹等。
    frmmaproute路径规划界面,可查询路线得到路线的经纬度坐标集合。
    11.3.4.7 模块-frmmodule
    名称说明
    frmdevicegps设备轨迹模块,对设定的设备随机模拟轨迹,也可传入经纬度坐标值自动移动并绘制轨迹线条,不同设备可以不同颜色。
    frmdevicetree设备列表模块,读取设备信息加载形成树状列表,双击或者拖动到视频监控窗体直接播放视频,提供右键菜单作为演示如何使用。
    frmmodule主界面中心部分窗体,采用QMainWindow类,中间加载的视频监控面板,其余new出来每个子模块,子模块可停靠和悬浮拖动等。不同工作模式下的各种子模块都在此加载。同时负责管理模块的显示隐藏菜单。
    frmmsglist图文警情模块,也叫消息列表模块,带有右键菜单添加、删除、清空列表中的消息,双击可以弹出大图预览。
    frmmsglistitem图文警情模块子类,都是由一个个item组成放到panelwidget面板控件中,自动形成滚动条。
    frmmsgtable窗口消息模块,也叫表格消息模块,表格形式显示打印信息,不同的内容可以不同颜色区分。
    frmwebview网页浏览模块,传入一个url地址打开对应的网页,比如打开一个3D的网页。
    11.3.4.8 模块-frmrobot
    名称说明
    frmrobotdata仿真数据模块,启动机器人通信服务,接收数据解析显示。
    frmrobotdebug数据调试模块,可模拟发送轨迹数据测试解析类。
    frmrobotdebug2新数据调试模块,打印多个串口数据,不同颜色显示。
    frmrobotemulate运动仿真模块,预留给用户实现,一般放个3D效果。
    frmrobotlog机器人实时数据模块,预留给用户实现。
    11.3.4.9 模块-frmvideo
    名称说明
    frmvideo视频回放模块主界面,堆栈窗体形式,加载多个子界面比如本地回放、远程回放、设备播放等。
    frmvideopanel视频监控面板,主界面中间部分,这是核心,管理多个通道,通道可移除删除,拖曳打开,拖曳交换等。
    frmvideopaneltool视频监控底部工具栏,独立出来一个类专门管理。
    frmvideoplayimage图片回放模块,按照规则查询图片目录,然后可设定播放速度进行图片序列播放。
    frmvideoplaylocal本地回放模块,查询对应通道的本地存储的视频文件,双击播放,可暂停和拖动进度条位置。
    frmvideoplaynvr设备播放模块,通过RTSP视频流的形式从远程设备取视频进行播放,支持摄像机和录像机,手动填入地址也行。
    frmvideoplayweb远程回放模块,需要用厂家sdk去实现,从NVR回放录像。
    frmvideopreview视频预览窗体,比如图片或者地图上双击设备弹出的视频预览,可以多个,关闭的时候自动释放资源。
    frmvideoupload视频上传,将本地存储的视频文件上传到服务器。

    12 二次开发说明

    12.1 通用开发环境搭建

    1. 第一步:安装系统,推荐用vmware虚拟机。

    2. 第二步:安装qt环境,可以直接用官方下载的run安装包安装,有些要求用命令行安装。

    3. 第三步:写个空白窗体程序测试下是否环境正常。

    4. 第四步:编译ffmpeg,生成对应的动态库或者静态库。

    5. 第五步:打开video_system.pro项目进行编译。

    6. 第六步:打包发布,为了发布方便,推荐用静态编译的Qt+静态编译的ffmpeg,这样打包发布很清爽,就一个可执行文件。

    12.2 不同系统注意事项

    12.3 监控系统组件示例

    本系统功能比较多,封装了多个控件,尤其是核心的视频监控控件,所以特意安排了独立的使用示例演示如何使用,可以在main函数找到 AppConfig::IndexStart = 0; 改成AppConfig::IndexStart = 1;即可,这样编译运行的是监控系统组件示例。

    12.3.1 通用辅助

    演示通用组件比如qui封装的类的使用。

    1. 弹出信息框

    2. 弹出错误框

    3. 弹出询问框

    4. 带自动关闭倒计时

    5. 弹出右下角信息框

    6. 隐藏右下角信息框

    7. 弹出时间选择框

    8. 弹出中间提示信息

    9. 弹出关于对话框

    12.3.2 视频图片

    演示加载图片文件夹,进行图片序列的播放。

    12.3.3 视频控件

    演示通用视频控件如何使用,包括打开、关闭、暂停、继续、截图、自动抓拍等功能。

    12.3.4 视频存储

    演示视频控件如何存储视频文件到本地,单击开始按钮开始存储视频,单击关闭则关闭存储。

    12.3.5 视频叠加

    演示如何用多个视频控件做视频叠加播放,可以设置叠加的位置在四个角落。

    12.3.6 同步播放

    演示如何同步播放多个视频,切换进度条自动全部切换播放进度。

    12.3.7 音频频谱

    演示如何关联视频声音左右通道频谱信号,界面中音量控件实时显示当前的左右通道音量值。

    12.3.8 拖曳播放

    演示关联拖曳文件信号,识别本地文件拖曳到视频控件中播放。

    12.3.9 视频切换

    演示如何无缝切换打开不同视频,避免关闭后打开中间产生的空白缝隙。

    12.3.10 标签图形

    演示如何添加各种osd标签信息和各种图形信息,osd标签信息可以设置字体、颜色、位置等,图形信息可以是矩形、三角形、多边形、圆形等。都支持批量多个添加。

    12.3.11 文字水印

    演示视频控件文字水印功能,可以添加日期时间水印、自定义文字水印、实时码率帧率水印,提供按钮主动更新自定义文字水印。

    12.4 人工智能集成

    13 其他说明

    13.1 海康onvif设置

    新版的海康的摄像机,默认onvif是关闭的,需要手动开启,开启以后记得添加onvif用户,并重启摄像机应用。提示:海康旗下的萤石目前暂时不支持onvif协议。

    13.2 大华onvif设置

    大华摄像机,需要在用户管理中添加onvif用户,添加好以后建议重启摄像机应用。

    13.3 国际onvif工具

    工具的名字叫ONVIF Device Manager,可以自行搜索下载,此工具位国际官方工具,如果此工具搜索不到摄像机,则说明该摄像机不是真正的onvif摄像机,不是标准的摄像机,目前市面上的绝大部分网络摄像机都支持onvif。具体用法可以参考 https://www.cnblogs.com/lsdb/p/9157302.html

    现在大部分厂家的NVR也逐渐支持onvif,并将每个通道都可以单独列出来。

    切换到ptz页面可以进行云台控制和预置位管理。

    13.4 报警输入设置

    操作说明

    1. 默认摄像机IO输入或者开关量输入是关闭的,需要手动开启。

    2. 一般都是登录到摄像机的web页面找到开关量的地方,可能描述不一样但是大致的意思差不多。

    3. 一般摄像机会有两组开关量输入,而且开关量报警有常开常闭两种,都需要自己手动选择。

    4. 如果是常开的话意味着闭合是属于报警,反之亦然。

    5. 找两个导线接在对应口子(详见摄像机厂家的说明书,摄像机背面板也会有对应字样标识一般叫 in)。

    6. 短接或者扒开,都会有反应,onvif工具都能接收到信息(前提是单击过订阅事件按钮,而且顺利返回了订阅地址才行)。

    7. 会收到LogicalState关键字的信息,true或者1表示报警,false或者0表示正常。

    8. 可能每个厂家会有所区别,需要自己拿到数据后做特殊处理,但是大部分厂家都是相似的,实在不行无非搞个contains方法判断好了。

    13.5 环境使用qt+vs

    打开项目:QT VS TOOLS – Open Qt Project File 选择 video_system.pro,然后等待项目加载完毕。 diff --git a/docs/video_system/snap/12-3-11.jpg b/docs/video_system/snap/12-3-11.jpg new file mode 100644 index 0000000000000000000000000000000000000000..22d36060da742cfd2078315ffc3c1cedcdfabb9b GIT binary patch literal 75672 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