一、前言

视频参数之前在基本参数中,后面越来越多,直接独立了出来,甚至还拆分出来了视频参数1、视频参数2,参数越来越多分组也越来越多的时候,你会发现分组名称都不够用或者不方便命名,不能直观的表示该分组的含义,索性直接用1/2/3来定义,比如BaseConfig1、BaseConfig2、VideoConfig1、VideoConfig2等。用这种命名反而更舒服一些,道理是要讲得通。

视频参数更改立即应用也是近期才实现的,之前做的是需要重启应用,后面发现除了打开了的视频外,其他参数都可以做到立即应用的,于是将这些参数的设置统一封装成了一个函数initCommonVideoWidget用于通用初始化视频控件,因为在各个界面的视频控件指针都可以拿到,于是在视频参数发生变化后,发出信号,接收信号后统一调用该参数重新初始化视频控件即可。当然需要先过滤下已经打开视频的控件,如果视频控件正在播放则不设置,设置会造成问题,需要关闭状态设置。

视频参数说明

  1. 保存视频:开启以后打开视频自动存储录像文件,目录在可执行文件video_normal。
  2. 存储间隔:录像文件按照什么规则存储视频,0分钟表示只存储到单个文件。
  3. 视频边框:视频控件的边框的宽度,值越大边框越粗。
  4. 报警视频:开启以后保存报警视频到可执行文件video_alarm,暂未启用。
  5. 硬件加速:当前视频内核采用何种硬件加速方式,默认none表示不启用硬件加速(常用的所有qsv、dxva2、d3d11va,建议用dxva2或者d3d11va,具体根据电脑是否支持定)。
  6. 通信方式:视频流采用何种通信方式,默认TCP(可靠连接,不会丢包,缺点就是慢),可选UDP(不可靠连接,容易丢包,但是速度快)。
  7. 视频回调:是否采用回调的形式来解码显示视频,比如vlc内核和海康内核都支持回调。
  8. 码流类型:双击摄像机以什么码流地址加载实时视频,默认子码流。
  9. 解码方式:ffmpeg内核有用,可选速度优先、质量优先、均衡处理。
  10. 播放音频:开启以后可以播放声音,有时候不需要声音的时候可以关闭,节省资源。
  11. 图片拉伸:默认开启,通道画面按照填充拉伸显示,不开启的话则按照等比例缩放。
  12. 打开间隔:软件启动后挨个加载打开视频的间隔,默认1秒钟。
  13. 重连间隔:软件多久检测一次摄像机是否掉线,默认10秒钟。
  14. 事件订阅:开启以后会用onvif的机制订阅报警事件。
  15. 自动校时:开启后摄像机上线立即同步本地时间到摄像机。

二、功能特点

(一)软件模块

  1. 视频监控模块,各种停靠小窗体子模块,包括设备列表、图文警情、窗口信息、云台控制、预置位、巡航设置、设备控制、悬浮地图、网页浏览等。
  2. 视频回放模块,包括本地回放、远程回放、设备播放、图片回放、视频上传等。
  3. 电子地图模块,包括图片地图、在线地图、离线地图、路径规划等。
  4. 日志查询模块,包括本地日志、设备日志等。
  5. 系统设置模块,包括系统设置(基本设置、视频参数、数据库设置、地图配置、串口配置等)、录像机管理、摄像机管理、轮询配置、用户管理等。

(二)基础功能

  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. 可保存视频,可选定时存储或者单文件存储,可选存储间隔时间。
  24. 可设置视频流通信方式tcp+udp,可设置视频解码是速度优先、质量优先、均衡等。
  25. 可设置软件中文名称、英文名称、LOGO图标等。
  26. 存储的视频文件支持导出到指定目录,支持批量上传到服务器。

(三)特色功能

  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. 支持xp、win7、win10、linux、mac、各种国产系统(UOS、中标麒麟、银河麒麟等)、嵌入式linux等系统。
  17. 注释完整,项目结构清晰,超级详细完整的使用开发手册,精确到每个代码文件的功能说明,不断持续迭代版本。

三、体验地址

  1. 体验地址:https://pan.baidu.com/s/1d7TH_GEYl5nOecuNlWJJ7g 提取码:01jf 文件名:bin_video_system.zip。
  2. 国内站点:https://gitee.com/feiyangqingyun
  3. 国际站点:https://github.com/feiyangqingyun
  4. 个人主页:https://blog.csdn.net/feiyangqingyun
  5. 知乎主页:https://www.zhihu.com/people/feiyangqingyun/
  6. 在线文档:https://feiyangqingyun.gitee.io/qwidgetdemo/video_system/

四、效果图



下图纯粹为了劳逸结合!

五、核心代码

void frmConfigSystem::initVideoConfig1()
{
QStringList listImageFlag;
listImageFlag << "速度优先" << "质量优先" << "均衡";
ui->cboxImageFlag->addItems(listImageFlag);
ui->cboxImageFlag->setCurrentIndex(AppConfig::ImageFlag);
connect(ui->cboxImageFlag, SIGNAL(currentIndexChanged(int)), this, SLOT(saveVideoConfig1())); QStringList listHardware;
listHardware << "none";
#ifdef videoffmpeg
listHardware << "qsv" << "cuvid";
#elif videovlc
listHardware << "auto" << "any";
#endif
listHardware << "vaapi" << "vdpau" << "dxva2" << "d3d11va"; ui->cboxHardware->addItems(listHardware);
ui->cboxHardware->setCurrentIndex(ui->cboxHardware->findText(AppConfig::Hardware));
connect(ui->cboxHardware, SIGNAL(currentIndexChanged(int)), this, SLOT(saveVideoConfig1())); QStringList listTransport;
listTransport << "tcp" << "udp";
ui->cboxTransport->addItems(listTransport);
ui->cboxTransport->setCurrentIndex(ui->cboxTransport->findText(AppConfig::Transport));
connect(ui->cboxTransport, SIGNAL(currentIndexChanged(int)), this, SLOT(saveVideoConfig1())); ui->btnCallback->setChecked(AppConfig::Callback);
connect(ui->btnCallback, SIGNAL(checkedChanged(bool)), this, SLOT(saveVideoConfig1())); ui->btnFillImage->setChecked(AppConfig::FillImage);
connect(ui->btnFillImage, SIGNAL(checkedChanged(bool)), this, SLOT(saveVideoConfig1())); ui->btnPlayAudio->setChecked(AppConfig::PlayAudio);
connect(ui->btnPlayAudio, SIGNAL(checkedChanged(bool)), this, SLOT(saveVideoConfig1()));
} void frmConfigSystem::saveVideoConfig1()
{
int imageFlag = ui->cboxImageFlag->currentIndex();
if (AppConfig::ImageFlag != imageFlag) {
AppConfig::ImageFlag = imageFlag;
emit AppEvent::Instance()->slot_changeVideoConfig();
} QString hardware = ui->cboxHardware->currentText();
if (AppConfig::Hardware != hardware) {
AppConfig::Hardware = hardware;
emit AppEvent::Instance()->slot_changeVideoConfig();
} QString transport = ui->cboxTransport->currentText();
if (AppConfig::Transport != transport) {
AppConfig::Transport = transport;
emit AppEvent::Instance()->slot_changeVideoConfig();
} bool callback = ui->btnCallback->getChecked();
if (AppConfig::Callback != callback) {
AppConfig::Callback = callback;
emit AppEvent::Instance()->slot_changeVideoConfig();
} bool fillImage = ui->btnFillImage->getChecked();
if (AppConfig::FillImage != fillImage) {
AppConfig::FillImage = fillImage;
emit AppEvent::Instance()->slot_changeVideoConfig();
} bool playAudio = ui->btnPlayAudio->getChecked();
if (AppConfig::PlayAudio != playAudio) {
AppConfig::PlayAudio = playAudio;
emit AppEvent::Instance()->slot_changeVideoConfig();
} AppConfig::writeConfig();
} void frmConfigSystem::initVideoConfig2()
{
QStringList listVideoRtsp;
listVideoRtsp << "主码流" << "子码流";
ui->cboxVideoRtsp->addItems(listVideoRtsp);
ui->cboxVideoRtsp->setCurrentIndex(AppConfig::VideoRtsp);
connect(ui->cboxVideoRtsp, SIGNAL(currentIndexChanged(int)), this, SLOT(saveVideoConfig2())); QStringList listVideoBorder;
listVideoBorder << "1像素" << "2像素" << "3像素" << "4像素" << "5像素";
ui->cboxVideoBorder->addItems(listVideoBorder);
QString videoBorder = QString("%1像素").arg(AppConfig::VideoBorder);
ui->cboxVideoBorder->setCurrentIndex(ui->cboxVideoBorder->findText(videoBorder));
connect(ui->cboxVideoBorder, SIGNAL(currentIndexChanged(int)), this, SLOT(saveVideoConfig2()));
} void frmConfigSystem::saveVideoConfig2()
{
//自动更新码流类型
int videoRtsp = ui->cboxVideoRtsp->currentIndex();
if (AppConfig::VideoRtsp != videoRtsp) {
AppConfig::VideoRtsp = videoRtsp;
DeviceHelper::initDeviceTree();
DeviceHelper::initVideoIcon();
} QString strVideoBorder = ui->cboxVideoBorder->currentText();
int videoBorder = strVideoBorder.mid(0, strVideoBorder.length() - 2).toInt();
if (AppConfig::VideoBorder != videoBorder) {
AppConfig::VideoBorder = videoBorder;
emit AppEvent::Instance()->slot_changeVideoConfig();
} AppConfig::writeConfig();
} void frmConfigSystem::initVideoConfig3()
{
ui->btnSaveVideoNormal->setChecked(AppConfig::SaveVideoNormal);
connect(ui->btnSaveVideoNormal, SIGNAL(checkedChanged(bool)), this, SLOT(saveVideoConfig3())); ui->btnSaveVideoAlarm->setChecked(AppConfig::SaveVideoAlarm);
connect(ui->btnSaveVideoAlarm, SIGNAL(checkedChanged(bool)), this, SLOT(saveVideoConfig3())); QStringList listSaveVideoInterval;
listSaveVideoInterval << "0分钟" << "1分钟" << "3分钟" << "5分钟" << "10分钟" << "20分钟" << "30分钟" << "60分钟";
ui->cboxSaveVideoInterval->addItems(listSaveVideoInterval);
QString saveVideoInterval = QString("%1分钟").arg(AppConfig::SaveVideoInterval);
ui->cboxSaveVideoInterval->setCurrentIndex(ui->cboxSaveVideoInterval->findText(saveVideoInterval));
connect(ui->cboxSaveVideoInterval, SIGNAL(currentIndexChanged(int)), this, SLOT(saveVideoConfig3())); QStringList listOpenInterval;
listOpenInterval << "0毫秒" << "100毫秒" << "300毫秒" << "500毫秒" << "1000毫秒" << "2000毫秒" << "3000毫秒" << "5000毫秒";
ui->cboxOpenInterval->addItems(listOpenInterval);
QString openInterval = QString("%1毫秒").arg(AppConfig::OpenInterval);
ui->cboxOpenInterval->setCurrentIndex(ui->cboxOpenInterval->findText(openInterval));
connect(ui->cboxOpenInterval, SIGNAL(currentIndexChanged(int)), this, SLOT(saveVideoConfig3())); QStringList listCheckInterval;
listCheckInterval << "5秒钟" << "8秒钟" << "10秒钟" << "30秒钟" << "60秒钟";
ui->cboxCheckInterval->addItems(listCheckInterval);
QString checkInterval = QString("%1秒钟").arg(AppConfig::CheckInterval);
ui->cboxCheckInterval->setCurrentIndex(ui->cboxCheckInterval->findText(checkInterval));
connect(ui->cboxCheckInterval, SIGNAL(currentIndexChanged(int)), this, SLOT(saveVideoConfig3())); QStringList listCheckTime;
listCheckTime << "500毫秒" << "1000毫秒" << "2000毫秒" << "3000毫秒" << "5000毫秒" << "8000毫秒" << "10000毫秒";
ui->cboxCheckTime->addItems(listCheckTime);
QString checkTime = QString("%1毫秒").arg(AppConfig::CheckTime);
ui->cboxCheckTime->setCurrentIndex(ui->cboxCheckTime->findText(checkTime));
connect(ui->cboxCheckTime, SIGNAL(currentIndexChanged(int)), this, SLOT(saveVideoConfig3()));
} void frmConfigSystem::saveVideoConfig3()
{
AppConfig::SaveVideoNormal = ui->btnSaveVideoNormal->getChecked();
AppConfig::SaveVideoAlarm = ui->btnSaveVideoAlarm->getChecked(); QString saveVideoInterval = ui->cboxSaveVideoInterval->currentText();
AppConfig::SaveVideoInterval = saveVideoInterval.mid(0, saveVideoInterval.length() - 2).toInt(); QString openInterval = ui->cboxOpenInterval->currentText();
AppConfig::OpenInterval = openInterval.mid(0, openInterval.length() - 2).toInt(); QString checkInterval = ui->cboxCheckInterval->currentText();
AppConfig::CheckInterval = checkInterval.mid(0, checkInterval.length() - 2).toInt(); QString strCheckTime = ui->cboxCheckTime->currentText();
int checkTime = strCheckTime.mid(0, strCheckTime.length() - 2).toInt();
if (AppConfig::CheckTime != checkTime) {
AppConfig::CheckTime = checkTime;
emit AppEvent::Instance()->slot_changeVideoConfig();
} AppConfig::writeConfig();
}

Qt编写安防视频监控系统48-视频参数的更多相关文章

  1. Qt编写安防视频监控系统(界面很漂亮)

    一.前言 视频监控系统在整个安防领域,已经做到了烂大街的程序,全国起码几百家公司做过类似的系统,当然这一方面的需求量也是非常旺盛的,各种定制化的需求越来越多,尤其是这几年借着人脸识别的东风,发展更加迅 ...

  2. Qt编写安防视频监控系统11-动态换肤

    一.前言 Qt中的动态换肤技术是非常一流的,直接调用qApp->setStyleSheet(qss);就可以对整个应用程序进行换肤,如果样式表内容不多,或者对应的贴图不对,效率还是蛮好的,不过据 ...

  3. Qt编写安防视频监控系统18-云台控制

    一.前言 云台控制是视频监控系统中必备的一个功能,对球机进行上下左右的移动,还有焦距的控制,其实核心就是控制XYZ三个坐标轴,为了开发这个模块,特意研究了各种云台控制的方法和开源库比如soap,有些厂 ...

  4. Qt编写安防视频监控系统12-异形布局

    一.前言 视频监控系统中,除了常规的1画面.4画面.9画面.16画面以外,还有几个布局比较另类,比如6画面.8画面.13画面,有些通道需要占据不同的行列,4画面.9画面.16画面都是非常对称的布局,行 ...

  5. Qt编写安防视频监控系统9-自动隐藏光标

    一.前言 这个效果的灵感来自于大屏电子看板系统,在很多系统中尤其是上了大屏的时候,其实在用户不在操作的时候,是很不希望看到那个鼠标箭头指针的,只有当用户操作的时候才显示出来,这个就需要开个定时器定时计 ...

  6. Qt编写安防视频监控系统8-双击节点

    一.前言 在所有的视频监控系统中,双击摄像机的节点,对应摄像机加载到当前焦点通道显示,这个都是必须具备的功能,还有一些厂家会做双击NVR节点,自动加载该NVR下的所有摄像机全部显示,从通道1开始到通道 ...

  7. Qt编写安防视频监控系统7-全屏切换

    一.前言 全屏切换这个功能点属于简单的,一般会做到右键菜单中,也提供了快捷键比如alt+enter来触发,恢复全屏则按esc即可,全屏处理基本上都是隐藏通道面板以外的窗体,保持最大化展示,由于采用了模 ...

  8. Qt编写安防视频监控系统5-视频回放

    一.前言 一般视频回放都会采用GB28181国标来处理,这样可以保证兼容国内各大厂家的NVR,毕竟在同一的国家标准下,大家都会统一支持国标的,就不需要根据各个厂家的SDK来做兼容处理,烦得很,厂家越来 ...

  9. Qt编写安防视频监控系统3-通道交换

    一.前言 最开始写通道交换的功能的时候,走了很多弯路,比如最开始用最初级的办法,触发交换的时候,先关闭视频,然后设置新的url重新打开视频,这样处理非常低级而且耗内存还卡还很慢,毕竟重新打开视频都需要 ...

  10. Qt编写安防视频监控系统1-通道切换

    一.前言 通道切换在视频监控系统中是最基础的必备功能,一般都会提供1通道+4通道+6通道+8通道+9通道+16通道这几个通道切换,可能做得比较好的还会提供24通道+32通道的,这个可能对电脑的配置就有 ...

随机推荐

  1. 经典排序算法(C语言、Java版)

    排序 比较 分类 比较排序的时间复杂度的下界O(nlogn) 对于n个待排序元素,在未比较时,可能的正确结果有n!种.在经过一次比较后,其中两个元素的顺序被确定,所以可能的正确结果剩余n!/2种(确定 ...

  2. 为什么会有unknown模块

    当一个模块在free后,他的线程仍然在运行时,会导致GetModuleName失败,返回unknown

  3. MaekLogic笔记 _001 _CURD_20210826

    MaekLogic笔记 _001 _CURD _20210826 1.插入文档 API xdmp:document-insert( $uri as xs:string, $root as node() ...

  4. 管中窥豹----从String Intern中观察.NET Core到.NET 8 托管堆的变迁

    简介 https://www.cnblogs.com/lmy5215006/p/18494483 在此文中,研究.NET String底层结构时,我所观察到的情况与<.NET Core底层入门& ...

  5. java可变参数案例学习

    /* ** 可变参数案例 */ public class changeVar { public static void main(String[] args) { printMax(34, 3, 2, ...

  6. register at least one qt version using“qt vs tools“->“qt options“问题描述及解决方法

    问题描述:在安装了Qt 5.9.8,vs 2022, QT VS Tool 2022并配置好环境变量之后创建Qt项目时无法创建,提示至少需要注册一个Qt版本到Qt VS Tools的Qt Option ...

  7. git 暂存区问题

    如果需要合别人的代码进来 需要暂时把自己的代码stash一下,用 git stash 放入暂存 如果需要释放出来用 git stash pop 当暂存用的越来越多,问题出现了需要清理暂存区队列,使用代 ...

  8. Hook框架之Frida

    Frida是一款轻量级HOOK框架,可用于多平台上,例如android.windows.ios等.    frida分为两部分,服务端运行在目标机上,通过注入进程的方式来实现劫持应用函数,另一部分运行 ...

  9. python3安装与使用(Linux)

    之前写过有关Windows下的python3的安装与使用,这次看一下Linux下的python3 1. 安装依赖环境 yum -y install zlib-devel bzip2-devel ope ...

  10. AtCoder Beginner Contest 296

    Transition Game 给定序列\(a\),\(1<=a_i<=n\),一场游戏有\(n\)个回合,第\(i\)回合时,第一个人先指定一个任意数\(k\),第二个人任意选定一个\( ...