视频监控组件经历过数十年的迭代,从最初的只简单播放个rtsp视频流,到现在支持各种音频视频文件格式(mp3、wav、mp4、asf、rm、rmvb、mkv等)、支持各种视频流格式(rtp、rtsp、rtmp、http等)、支持本地摄像头设备等。后面又陆续搞了音视频同步,硬解码、音视频文件保存等,陆陆续续完善了很久,再到后面搞了共享解码线程,打开相同地址的16路1080P主码流,CPU占用从70%降到了5%,这个提升是巨大的,和我追求极致完美的代码追求相符合,当然做不到完美,但是尽可能做到比以前更好。
把视频监控组件全部搞定以后,移植到视频监控系统中花了不少的精力,包括所有的视频配置参数,全部撤换成新版的按照最新的监控组件的,包括画面显示策略(自动调整/等比缩放/拉伸填充)、视频显示模式(句柄/绘制/GPU)、硬件加速类型(none/dxva2/d3d11va)、通信方式(tcp/udp)、解码策略(速度优先/质量优先/均衡处理/最快速度)、缓存大小等,去掉了一些几百年不用的参数,所有参数都有默认值。
公众号:Qt实战,各种开源作品、经验整理、项目实战技巧,专注Qt/C++软件开发,视频监控、物联网、工业控制、嵌入式软件、国产化系统应用软件开发。
公众号:Qt入门和进阶,专门介绍Qt/C++相关知识点学习,帮助Qt开发者更好的深入学习Qt。多位Qt元婴期大神,一步步带你从入门到进阶,走上财务自由之路。
void frmMain::initWidget()
{
//中间视频监控通道+子模块
frmModule *module = new frmModule;
ui->stackedWidget->addWidget(module);
//停靠窗体加载完成发送信号通知生成菜单
connect(module, SIGNAL(loadModuleFinshed(QList, QList)),
this, SLOT(initAction(QList, QList)));
//模块切换显示隐藏通知主界面更新菜单
connect(module, SIGNAL(visibilityChangedFromModule(QString, bool)),
this, SLOT(visibilityChangedFromModule(QString, bool)));
//菜单切换模块显示隐藏通知模块类处理
connect(this, SIGNAL(visibilityChangedFromMain(QString, bool)),
module, SLOT(visibilityChangedFromMain(QString, bool)));
//视频回放
frmVideo *video = new frmVideo;
ui->stackedWidget->addWidget(video);
//电子地图
frmMap *map = new frmMap;
ui->stackedWidget->addWidget(map);
//备用模块
frmMain1 *main1 = new frmMain1;
ui->stackedWidget->addWidget(main1);
//日志记录
frmData *data = new frmData;
ui->stackedWidget->addWidget(data);
//系统设置
frmConfig *config = new frmConfig;
ui->stackedWidget->addWidget(config);
//关联样式改变信号自动重新设置图标等处理
connect(AppEvent::Instance(), SIGNAL(changeStyle()), this, SLOT(initIcon()));
connect(AppEvent::Instance(), SIGNAL(changeStyle()), this, SLOT(initLogo()));
connect(AppEvent::Instance(), SIGNAL(changeLogo()), this, SLOT(initLogo()));
connect(AppEvent::Instance(), SIGNAL(changeTitleInfo()), this, SLOT(initTitleInfo()));
connect(AppEvent::Instance(), SIGNAL(fullScreen(bool)), this, SLOT(fullScreen(bool)));
connect(AppEvent::Instance(), SIGNAL(mouseButtonRelease()), this, SLOT(mouseButtonRelease()));
}
void frmMain::initNav()
{
QList names, texts;
names << "btnView" << "btnVideo" << "btnMap" << "btnMain1" << "btnData" << "btnConfig";
texts << "视频监控" << "视频回放" << "电子地图" << AppData::TitleMain1 << "日志查询" << "系统设置";
icons << 0xe68c << 0xe68d << 0xe695 << AppData::IconMain1 << 0xe699 << 0xe706;
//根据设定实例化导航按钮对象
for (int i = 0; i < texts.count(); ++i) {
QToolButton *btn = new QToolButton;
CommonNav::initNavBtn(btn, names.at(i), texts.at(i), false);
connect(btn, SIGNAL(clicked(bool)), this, SLOT(buttonClicked()));
ui->layoutNav->addWidget(btn);
btns << btn;
}
//自动打开上次的窗体
btns.first()->setChecked(true);
int index = names.indexOf(AppConfig::LastFormMain);
index >= 0 ? btns.at(index)->click() : btns.first()->click();
//强制改成默认视频界面
//btns.at(0)->click();
btns.at(3)->setVisible(AppConfig::EnableMain1);
}
void frmMain::initIcon()
{
int count = btns.count();
for (int i = 0; i < count; ++i) {
CommonNav::initNavBtnIcon(btns.at(i), icons.at(i), false);
}
}
void frmMain::buttonClicked()
{
//判断是否有对应模块的权限
QAbstractButton *btn = (QAbstractButton *)sender();
if (!UserHelper::checkPermission(btn->text())) {
btn->setChecked(false);
//切换到永远有权限的页面
QMetaObject::invokeMethod(btns.at(0), "clicked");
return;
}
//切换到当前窗体
ui->stackedWidget->setCurrentIndex(btns.indexOf(btn));
//取消其他按钮选中
foreach (QAbstractButton *b, btns) {
b->setChecked(b == btn);
}
//保存最后的窗体索引
AppConfig::LastFormMain = btn->objectName();
AppConfig::writeConfig();
}