一、前言

设备播放模块是后面增加的,核心就是通过组合rtsp视频流地址来播放实时视频和历史视频,目前市面上很多厂家比如排第一的海康都是支持直接rtsp通过NVR来播放某个通道视频流和回放某个通道的视频流,这些格式在网上都可以搜索到的,每个厂家的第一可能有点不一样,但是大致的信息都一样,比如要播放实时视频流,需要提供的信息有用户名、密码、NVR地址、对应的通道、码流类型(主码流/子码流),如果要播放历史视频流即回放视频,需要提供的信息除了上面的以外还有时间范围,需要限定一个时间范围才能拿到对应的视频流文件,这个时间戳有些厂家是1970年经过的秒数计算,有些是时间时间等,都需要按照具体厂家的格式约定来。

设备播放的原理流程其实就是厂家重新将拿到的视频流文件或者存储的视频文件打包再发出来,有些厂家用自己的算法,有些用live555之类的。整体来说可能多多少少都会参照一些开源的推流库,咨询过很多同行的朋友,基本上都会参考ffmpeg、live555之类的开源库,其实ffmpeg养活了国内不少的厂家,甚至不乏一些大厂,再放大点说github养活了N多的公司,尤其是AI人工智能企业,业内有段话说:如果github不能允许访问了,国内的AI水平倒退5年。

通用视频控件开源:https://gitee.com/feiyangqingyun/QWidgetDemo https://github.com/feiyangqingyun/QWidgetDemo

文件名称:videowidget

体验地址:https://gitee.com/feiyangqingyun/QWidgetExe https://github.com/feiyangqingyun/QWidgetExe

文件名称:bin_video_system.zip

二、功能特点

  1. 支持16画面切换,全屏切换等,包括1+4+6+8+9+13+16画面切换。
  2. 支持alt+enter全屏,esc退出全屏。
  3. 自定义信息框+错误框+询问框+右下角提示框。
  4. 17套皮肤样式随意更换,所有样式全部统一,包括菜单等。
  5. 云台仪表盘鼠标移上去高亮,八个方位精准识别。
  6. 底部画面工具栏(画面分割切换+截图声音等设置)移上去高亮。
  7. 可在配置文件更改左上角logo+中文软件名称+英文软件名称。
  8. 封装了百度地图,三维切换,设备点位,鼠标按下获取经纬度等。
  9. 堆栈窗体,每个窗体都是个单独的qwidget,方便编写自己的代码。
  10. 顶部鼠标右键菜单,可动态控制时间CPU+左上角面板+左下角面板+右上角面板+右下角面板的显示和隐藏,支持恢复默认布局。
  11. 工具栏可以放置多个小图标和关闭图标。
  12. 左侧右侧可拖动拉伸,并自动记忆宽高位置,重启后恢复。
  13. 双击摄像机节点自动播放视频,双击节点自动依次添加视频,会自动跳到下一个,双击父节点自动添加该节点下的所有视频。
  14. 摄像机节点拖曳到对应窗体播放视频,同时支持拖曳本地文件直接播放。
  15. 视频画面窗体支持拖曳交换,瞬间响应。
  16. 双击节点+拖曳节点+拖曳窗体交换位置,均自动更新url.txt。
  17. 支持从url.txt中加载16通道视频播放,自动记忆最后通道对应的视频,软件启动后自动打开播放。
  18. 右下角音量条控件,失去焦点自动隐藏,音量条带静音图标。
  19. 集成百度地图,可以添加设备对应位置,自动生成地图,支持缩放和三维地图,提供地图风格选择,共12种风格。
  20. 视频拖动到通道窗体外自动删除视频。
  21. 鼠标右键可删除当前+所有视频,截图当前+所有视频。
  22. 录像机管理、摄像机管理,可添加删除修改导入导出打印信息,立即应用新的设备信息生成树状列表,不需重启。
  23. 在pro文件中可以自由开启是否加载地图。
  24. 视频播放可选四种内核自由切换,vlc+ffmpeg+easyplayer+海康sdk,均可在pro中设置。
  25. 可设置1+4+9+16画面轮询,可设置轮询间隔以及轮询码流类型等,直接在主界面底部工具栏右侧单击启动轮询按钮即可,再次单击停止轮询。
  26. 默认超过10秒钟未操作自动隐藏鼠标指针。
  27. 支持onvif搜素设备,支持任意onvif摄像机,包括但不限于海康大华宇视天地伟业华为等,支持onvif云台控制。
  28. 高度可定制化,用户可以很方便的在此基础上衍生自己的功能,支持linux系统。

三、效果图

四、核心代码

#include "frmvideoplaynvr.h"
#include "ui_frmvideoplaynvr.h"
#include "quiwidget.h"
#include "iconfont.h"
#include "videowidget.h" #ifdef videovlc
#include "vlc.h"
#elif videoffmpeg
#include "ffmpeg.h"
#elif easyplayer
#include "easyplayer.h"
#endif frmVideoPlayNvr::frmVideoPlayNvr(QWidget *parent) : QWidget(parent), ui(new Ui::frmVideoPlayNvr)
{
ui->setupUi(this);
this->initForm();
this->initIcon();
this->initAddr();
this->initVideo();
} frmVideoPlayNvr::~frmVideoPlayNvr()
{
delete ui;
} bool frmVideoPlayNvr::eventFilter(QObject *watched, QEvent *event)
{
if (event->type() == QEvent::MouseButtonPress) {
if (watched->inherits("QWidget")) {
QWidget *widget = (QWidget *) watched;
videoIndex = widget->property("index").toInt();
ui->labTip->setText(QString("当前选中 %1").arg(widgets.at(videoIndex)->getBgText()));
}
} else if (event->type() == QEvent::MouseButtonDblClick) {
if (watched->inherits("QWidget")) {
QWidget *widget = (QWidget *) watched;
if (!videoMax) {
for (int i = 0; i < videoCount; i++) {
widgets.at(i)->setVisible(false);
} videoMax = true;
widget->setVisible(true);
} else {
for (int i = 0; i < videoCount; i++) {
widgets.at(i)->setVisible(true);
} videoMax = false;
} widget->setFocus();
}
} return QWidget::eventFilter(watched, event);
} void frmVideoPlayNvr::initForm()
{
ui->cboxCompany->addItems(DBData::NvrTypes);
ui->cboxCompany->setCurrentIndex(ui->cboxCompany->findText("深广")); ui->cboxType->addItem("实时视频");
ui->cboxType->addItem("回放视频"); for (int i = 1; i <= 16; i++) {
ui->cboxCh->addItem(QString("通道%1").arg(i));
} ui->cboxRtsp->addItem("主码流");
ui->cboxRtsp->addItem("子码流"); ui->dateTimeStart->calendarWidget()->setLocale(QLocale::Chinese);
ui->dateTimeEnd->calendarWidget()->setLocale(QLocale::Chinese);
ui->dateTimeStart->setDate(QDate::currentDate().addDays(-1));
ui->dateTimeEnd->setDate(QDate::currentDate()); //绑定变动自动填入视频流地址
connect(ui->cboxCompany, SIGNAL(currentIndexChanged(int)), this, SLOT(initAddr()));
connect(ui->cboxType, SIGNAL(currentIndexChanged(int)), this, SLOT(initAddr()));
connect(ui->txtName, SIGNAL(textChanged(QString)), this, SLOT(initAddr()));
connect(ui->txtPwd, SIGNAL(textChanged(QString)), this, SLOT(initAddr()));
connect(ui->txtIP, SIGNAL(textChanged(QString)), this, SLOT(initAddr()));
connect(ui->cboxCh, SIGNAL(currentIndexChanged(int)), this, SLOT(initAddr()));
connect(ui->cboxRtsp, SIGNAL(currentIndexChanged(int)), this, SLOT(initAddr()));
connect(ui->dateTimeStart, SIGNAL(dateTimeChanged(QDateTime)), this, SLOT(initAddr()));
connect(ui->dateTimeEnd, SIGNAL(dateTimeChanged(QDateTime)), this, SLOT(initAddr()));
} void frmVideoPlayNvr::initIcon()
{
quint32 size = 15;
quint32 pixWidth = 20;
quint32 pixHeight = 15;
QSize iconSize = QSize(pixWidth, pixHeight); QPixmap pix1 = IconHelper::Instance()->getPixmap(QUIConfig::TextColor, 0xf04b, size, pixWidth, pixHeight);
QPixmap pix2 = IconHelper::Instance()->getPixmap(QUIConfig::TextColor, 0xf00d, size, pixWidth, pixHeight);
QPixmap pix3 = IconHelper::Instance()->getPixmap(QUIConfig::TextColor, 0xf04d, size, pixWidth, pixHeight);
QPixmap pix4 = IconHelper::Instance()->getPixmap(QUIConfig::TextColor, 0xf061, size, pixWidth, pixHeight); ui->btnPlay->setIconSize(iconSize);
ui->btnDelete->setIconSize(iconSize);
ui->btnPause->setIconSize(iconSize);
ui->btnNext->setIconSize(iconSize); ui->btnPlay->setIcon(QIcon(pix1));
ui->btnDelete->setIcon(QIcon(pix2));
ui->btnPause->setIcon(QIcon(pix3));
ui->btnNext->setIcon(QIcon(pix4));
} void frmVideoPlayNvr::initAddr()
{
QString company = ui->cboxCompany->currentText();
QString type = ui->cboxType->currentText();
QString name = ui->txtName->text().trimmed();
QString pwd = ui->txtPwd->text().trimmed();
QString ip = ui->txtIP->text().trimmed();
int ch = ui->cboxCh->currentIndex();
int rtsp = ui->cboxRtsp->currentIndex();
QString dateStart = ui->dateTimeStart->dateTime().toString("yyyy-MM-dd HH:mm:ss");
QString dateEnd = ui->dateTimeEnd->dateTime().toString("yyyy-MM-dd HH:mm:ss"); //深广NVR
//实时预览格式 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
//先转换时间戳,1970年到该时间经过的秒数
QDateTime startTime = QDateTime::fromString(dateStart, "yyyy-MM-dd HH:mm:ss");
QDateTime stopTime = QDateTime::fromString(dateEnd, "yyyy-MM-dd HH:mm:ss");
qint64 startTimeSec = startTime.toTime_t();
qint64 stopTimeSec = stopTime.toTime_t(); //海康NVR
//实时预览格式 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
QString starttime = ui->dateTimeStart->dateTime().toString(Qt::ISODate);
QString endtime = ui->dateTimeEnd->dateTime().toString(Qt::ISODate);
starttime = starttime.replace("-", "");
starttime = starttime.replace(":", "");
starttime = starttime.toLower();
endtime = endtime.replace("-", "");
endtime = endtime.replace(":", "");
endtime = endtime.toLower(); QString addr;
if (company == "深广") {
if (type == "实时视频") {
addr = QString("rtsp://%1:%2@%3:554/live?channel=%4&stream=%5")
.arg(name).arg(pwd).arg(ip).arg(ch + 1).arg(rtsp);
} else if (type == "回放视频") {
addr = QString("rtsp://%1:%2@%3:554/file?channel=%4&start=%5&stop=%6")
.arg(name).arg(pwd).arg(ip).arg(ch + 1).arg(startTimeSec).arg(stopTimeSec);
}
} else if (company == "海康") {
if (type == "实时视频") {
addr = QString("rtsp://%1:%2@%3:554/Streaming/Channels/%4%5%6")
.arg(name).arg(pwd).arg(ip).arg(ch + 1).arg(0).arg(rtsp + 1);
} else if (type == "回放视频") {
addr = QString("rtsp://%1:%2@%3:554/Streaming/tracks/%4%5?starttime=%6&endtime=%7")
.arg(name).arg(pwd).arg(ip).arg(ch + 1).arg("01").arg(starttime).arg(endtime);
}
} else if (company == "大华") {
if (type == "实时视频") { } else if (type == "回放视频") { }
} ui->txtAddr->setText(addr);
} void frmVideoPlayNvr::initVideo()
{
videoMax = false;
videoCount = 4;
videoIndex = 0; for (int i = 0; i < videoCount; i++) {
#ifdef videovlc
VlcWidget *widget = new VlcWidget;
widget->setCallback(true);
//widget->setHardware("auto");
#elif videoffmpeg
FFmpegWidget *widget = new FFmpegWidget;
//widget->setHardware("d3d11va");
#elif easyplayer
EasyPlayerWidget *widget = new EasyPlayerWidget;
#else
VideoWidget *widget = new VideoWidget;
#endif //设置背景文字
widget->setBgText(QString("通道 %1").arg(i + 1));
//设置背景图片
widget->setBgImage(QImage(":/bg_novideo.png"));
//设置url地址
widget->setUrl("");
//设置悬浮条可见
widget->setFlowEnable(false);
//设置是否自动重连
widget->setCheckLive(false); widget->installEventFilter(this);
widget->setProperty("index", i);
widget->setObjectName(QString("video%1").arg(i + 1));
widgets.append(widget);
} //加入到布局中
ui->gridLayout->addWidget(widgets.at(0), 0, 0);
ui->gridLayout->addWidget(widgets.at(1), 0, 1);
ui->gridLayout->addWidget(widgets.at(2), 1, 0);
ui->gridLayout->addWidget(widgets.at(3), 1, 1);
} void frmVideoPlayNvr::on_btnPlay_clicked()
{
QString addr = ui->txtAddr->toPlainText();
if (addr.isEmpty()) {
return;
} widgets.at(videoIndex)->setUrl(addr);
widgets.at(videoIndex)->close();
widgets.at(videoIndex)->open();
widgets.at(videoIndex)->setFocus();
} void frmVideoPlayNvr::on_btnDelete_clicked()
{
widgets.at(videoIndex)->close();
widgets.at(videoIndex)->setFocus();
} void frmVideoPlayNvr::on_btnPause_clicked()
{
widgets.at(videoIndex)->pause();
widgets.at(videoIndex)->setFocus();
} void frmVideoPlayNvr::on_btnNext_clicked()
{
widgets.at(videoIndex)->next();
widgets.at(videoIndex)->setFocus();
}

Qt编写安防视频监控系统16-设备播放的更多相关文章

  1. Qt编写安防视频监控系统2-视频播放

    一.前言 视频播放功能是核心功能之一,为了统一管理接口,统一封装成一个控件,对外提供seturl open close方法即可,不用去管内部的具体处理,这样就可以提供多种接口来实现统一的管理,比如vl ...

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. YUV和RGB格式单像素所占内存大小分析

    图片的大小定 义为:w * h,宽高分别为w和h 一.YUV格式 1.1.YUV420格式存储方式:先Y,后V,中间是U.其中的Y是w * h,U和V是w/2 * (h/2)举例:如果w = 4,h ...

  2. javascript学习5、JS面向对象

    创建对象的几种常用方式 1.使用Object或对象字面量创建对象 2.工厂模式创建对象 3.构造函数模式创建对象 4.原型模式创建对象 1.使用Object或对象字面量创建对象 JS中最基本创建对象的 ...

  3. C语言入门hello world

    1.安装软件 c语言开发工具众多,初学者推荐使用Dev-Cpp 5.6.3 TDM-GCC x64 4.8.1 Setup.exe:安装过程全部默认安装即可. 2.使用Dev-Cpp编写第一个入门实例 ...

  4. 学习:Lucas定理

    模板题 在数论中,Lucas定理用于计算二项式系数\({\tbinom {m}{n}}\)被质数\(p\)除的所得的余数. 描述 设\(p\)为素数,\(a,b\in N_+\),且 \[a=a_kp ...

  5. ie下的透明度,用滤镜filter:alpha

    .box{ width:100px; height:100px; background-color:#000; filter:alpha(Opacity=50); opacity: 0.5; }

  6. 【转载】windbg 常用命令详解

    windbg 常用命令详解 https://blog.csdn.net/chenyujing1234/article/details/7743460 vertarget 显示当前进程的大致信息 lmv ...

  7. Presto Infrastructure at Lyft

    转载一篇关于 lyft presto 平台建设的实践 Overview Early in 2017 we started exploring Presto for OLAP use cases and ...

  8. pmm docker-compose 运行试用

    pmm 是一个很不错的mysql.mongo.postgresql 数据库监控平台,基于prometheus.grafana.exporter 算是一个比较完整 的数据库分析平台 参考架构图 环境准备 ...

  9. 洛谷p2370yyy2015c01的U盘题解

    没什么特殊的想法 就是看自己很久没有更新关于题解类的文章了而已 (其实这是我好久之前做的, 只是把它从洛谷博客搬到了这里而已) 题目 首先分析题目要二分 他长成这个亚子太二分了 所以就要二分 最好是先 ...

  10. HHHOJ #153. 「NOI模拟 #2」Kotomi

    抽代的成分远远大于OI的成分 首先把一个点定为原点,然后我们发现如果我们不旋转此时答案就是所有位置的\(\gcd\) 如果要选择怎么办,我们考虑把我们选定的网格边连同方向和大小看做单位向量\(\vec ...