## 一、前言
在轮询
视频的时候,通常都是需要将之前的视频全部关闭,然后打开下一组视频,在这个切换的过程中,如果是按照常规的做法,比如先关闭再打开新的视频,肯定会出现空白黑屏之类的过度空白区间,如何避免这个
问题实现无感知的无缝切换,是个需要稍微懂点脑筋的问题,有一个比较好的做法就是,准备双倍的通道或者后台解码
线程,在收到需要切换指令的时候,先后台打开解码线程,直到打开完成能够正常出
图像,此时再去关闭之前的解码线程,这样就相当于无缝对接上了,不会说是中间等待打开解码到能正常出图像的过程空白。但是这样又存在一个问题,那就是轮询间隔时间不是非常准确,会有个1-2s的偏差,基本上这个偏差也能接受就是,所以如果是60s的轮询间隔,你可以在58s的时候就开始打开另外一组的解码线程,2s后全部正常出图像后就关联到视频控件上
显示,把之前的解码线程关闭并销毁。这样处理下来,既保证了切换过程无感知,又保证了不会过度开销占用CPU,也就切换的期间刚好有双倍的解码线程,只要内存足够,这点性能牺牲还是值得的。
## 二、效果图
## 三、体验地址
1. 国内站点:[
https://gitee.com/feiyangqingyun](https://gitee.com/feiyangqingyun)
2. 国际站点:[
https://github.com/feiyangqingyun](https://github.com/feiyangqingyun)
3. 个人作品:[
https://blog.csdn.net/feiyangqingyun/article/details/97565652](https://blog.csdn.net/feiyangqingyun/article/details/97565652)
4. 体验地址:[
https://pan.baidu.com/s/1d7TH_GEYl5nOecuNlWJJ7g](https://pan.baidu.com/s/1d7TH_GEYl5nOecuNlWJJ7g) 提取码:01jf
文件名:bin_video_demo/bin_linux_video。
## 四、相关代码
```cpp
#include "frmdemovideochange.h"
#include "ui_frmdemovideochange.h"
#include "quihelper.h"
#include "videourl.h"
#include "videohelper.h"
#include "videowidgetx.h"
frmDemoVideoChange::frmDemoVideoChange(QWidget *parent) : QWidget(parent), ui(new Ui::frmDemoVideoChange)
{
ui->setupUi(this);
this->initForm();
}
frmDemoVideoChange::~frmDemoVideoChange()
{
delete ui;
}
void frmDemoVideoChange::showEvent(QShowEvent *)
{
static bool isLoad = false;
if (!isLoad) {
isLoad = true;
on_btnChange_clicked();
}
}
void frmDemoVideoChange::initForm()
{
ui->cboxUrl->addItems(VideoUrl::getUrls(VideoUrl::HttpVideo | VideoUrl::Other));
ui->cboxUrl2->addItems(VideoUrl::getUrls(VideoUrl::HttpVideo | VideoUrl::Other));
ui->cboxUrl->lineEdit()->setText(AppConfig::VideoChangeUrl1);
ui->cboxUrl2->lineEdit()->setText(AppConfig::VideoChangeUrl2);
//实例化视频控件(这里放两个用于交替无缝切换)
videoWidget1 = new VideoWidget;
videoWidget2 = new VideoWidget;
this->initVideo(videoWidget1);
this->initVideo(videoWidget2);
currentIndex = 1;
videoWidget1->setVisible(true);
}
void frmDemoVideoChange::initVideo(VideoWidget *videoWidget)
{
//设置窗体参数
WidgetPara widgetPara = videoWidget->getWidgetPara();
widgetPara.fillColor = "#110F11";
widgetPara.scaleMode = ScaleMode_Aspect;
videoWidget->setWidgetPara(widgetPara);
//设置解码内核
VideoPara videoPara = videoWidget->getVideoPara();
VideoHelper::initVideoCore(videoPara);
videoWidget->setVideoPara(videoPara);
//加入到布局并关联打开成功信号
videoWidget->setVisible(false);
ui->gridLayout->addWidget(videoWidget);
connect(videoWidget, SIGNAL(sig_receivePlayStart(int)), this, SLOT(receivePlayStart(int)));
}
void frmDemoVideoChange::receivePlayStart(int time)
{
ui->btnChange->setEnabled(true);
if (currentIndex == 0) {
videoWidget2->setVisible(false);
videoWidget1->setVisible(true);
videoWidget2->stop();
} else if (currentIndex == 1) {
videoWidget1->setVisible(false);
videoWidget2->setVisible(true);
videoWidget1->stop();
}
}
void frmDemoVideoChange::on_btnChange_clicked()
{
ui->btnChange->setEnabled(false);
currentIndex = (currentIndex == 0 ? 1 : 0);
AppConfig::VideoChangeUrl1 = ui->cboxUrl->currentText();
AppConfig::VideoChangeUrl2 = ui->cboxUrl2->currentText();
AppConfig::writeConfig();
//先后台默默的打开不显示(等待打开成功后再显示)
if (currentIndex == 0) {
videoWidget1->open(AppConfig::VideoChangeUrl1);
} else if (currentIndex == 1) {
videoWidget2->open(AppConfig::VideoChangeUrl2);
}
}
```