视频监控组件经历过数十年的迭代,从最初的只简单播放个rtsp视频流,到现在支持各种音频视频文件格式(mp3、wav、mp4、asf、rm、rmvb、mkv等)、支持各种视频流格式(rtp、rtsp、rtmp、http等)、支持本地摄像头设备等。后面又陆续搞了音视频同步,硬解码、音视频文件保存等,陆陆续续完善了很久,再到后面搞了共享解码线程,打开相同地址的16路1080P主码流,CPU占用从70%降到了5%,这个提升是巨大的,和我追求极致完美的代码追求相符合,当然做不到完美,但是尽可能做到比以前更好。
把视频监控组件全部搞定以后,移植到视频监控系统中花了不少的精力,包括所有的视频配置参数,全部撤换成新版的按照最新的监控组件的,包括画面显示策略(自动调整/等比缩放/拉伸填充)、视频显示模式(句柄/绘制/GPU)、硬件加速类型(none/dxva2/d3d11va)、通信方式(tcp/udp)、解码策略(速度优先/质量优先/均衡处理/最快速度)、缓存大小等,去掉了一些几百年不用的参数,所有参数都有默认值。
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();
}