播放器实战26 添加暂停

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();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值