1.在暂停按钮上添加信号槽
pushButton就是暂停按钮,将点击信号发送给PlayOrPause()函数
要把槽函数放在slots中:
public slots:
void openfile();
void PlayOrPause();
2.xplay2.cpp中对点击做反应
1.当按下暂停后,xplay的ispause与当前解封装线程的ispause取反为true
2.显示出当前值
3.把取反后的值传回解封装线程
void Xplay2::PlayOrPause()
{
bool isPause = !dt.isPause;
SetPause(isPause);
dt.SetPause(isPause);
}
void Xplay2::SetPause(bool isPause)
{
if (isPause)
//当传进来的bool值为真时,在控件上显示“播 放”
ui.pushButton->setText(QString::fromLocal8Bit("播 放"));
else
ui.pushButton->setText(QString::fromLocal8Bit("暂 停"));
}
3.解封装线程再把暂停信号分发给视频线程和音频线程
在xplay2.cpp,解封装线程,视频线程,音频线程中都添加bool类型的isPause成员
void xdemuxthread::SetPause(bool isPause)
{
mux.lock();
isPause = true;
//同时启动视频线程与音频线程的暂停
if (at) at->SetPause(isPause);
if (vt) vt->SetPause(isPause);
mux.unlock();
}
4.视频线程与音频线程暂停
void xaudiothread::SetPause(bool isPause)
{
amux.lock();
this->isPause = isPause;
amux.unlock();
}
void xvideothread::SetPause(bool isPause)
{
mux.lock();
this->isPause = isPause;
mux.unlock();
}
在各自的run中当当前isPause为true时解锁并延时再进入循环判断,知道在此点击暂停按钮将这些模块的isPause当设为false时才能继续播放:
if (isPause)
{
vmux.unlock();
msleep(5);
continue;
}
4.音频播放停止缓慢
视频使用OpenGL渲染,来一帧渲染一帧,但是音频使用的是QAudioOutput类型输出,其存在一个缓冲队列,因此在音频线程暂停时,需要再把这个暂停信息传给QAudioOutput
void xaudiothread::SetPause(bool isPause)
{
amux.lock();
this->isPause = isPause;
if (audioplay)
audioplay->SetPause(isPause);
amux.unlock();
}
audioplay类为xaudioplay类用工厂模式创建的类
在class audioplay :public xaudioplay中添加SetPause
void SetPause(bool isPause)
{
mux.lock();
if (!output)
{
mux.unlock();
return;
}
if (isPause)
{
output->suspend();
}
else
{
output->resume();
}
mux.unlock();
}
xaudioplay* audioplay=0;audioplay为xaudioplay型指针,该类型为工厂模式中的基类,
audioplay->SetPause(isPause);通过基类调用子类方法,之前并没有赋值给该指针某个子类对象,因此要在基类中把SetPause()声明为纯虚函数:
virtual void SetPause(bool isPause) = 0;
再回到音频线程的run();
void xaudiothread::run()
{
unsigned char* pcm = new unsigned char[1024 * 1024 * 10];
while (!isexit)
{
amux.lock();
if (isPause)
{
amux.unlock();
msleep(5);
continue;
}
AVPacket* pkt = pop();
if (!decode)
{
amux.unlock();
msleep(1);
continue;
}
if ( !resample || !audioplay)
{
amux.unlock();
msleep(1);
continue;
}
bool re = decode->send(pkt);
if (!re)
{
amux.unlock();
msleep(1);
continue;
}
while (!isexit)
{
AVFrame* frame = decode->receive();
if (!frame)break;
pts = decode->pts-audioplay->GetNoPlayMs();
int size = resample->Resample(frame, pcm);
while (!isexit)
{
if (size <= 0)break;
//缓冲未播完,空间不够
if (audioplay->Getfree() < size)
{
msleep(1);
continue;
}
audioplay->write(pcm, size);
break;
}
}
amux.unlock();
}
delete []pcm;
}
可能缓冲队列未播完,造成了音频播放停止的延迟,然后当
if (audioplay->Getfree() < size):当缓冲中空余的空间小于需要使用的空间时等待一秒再continue(就不往播放器里写音频数据了)
如果当不小时,即使isPause=true也会继续往里面写,因此把判断暂停也加进去:
if (audioplay->Getfree() < size||isPause)
再将音频线程中暂时设置的加锁取消掉,目的是早点停掉音频播放,并且isPause通过人为控制,只有两个状态,去锁了一般也不会造成问题
void xaudiothread::SetPause(bool isPause)
{
//amux.lock();
this->isPause = isPause;
if (audioplay)
audioplay->SetPause(isPause);
//amux.unlock();
}