播放器实战24 解封装模块添加close

本文探讨了多媒体文件打开增多导致内存占用增加的问题,重点分析了解封装线程的关闭过程和内存释放策略。通过在xdecodethread基类中统一清理功能,减少重复代码,并在子类中处理特有部分。音频线程和视频线程在关闭时释放了特有的资源如resample和audioplay。问题定位在解码后的AVFrame未及时释放,通过调用av_frame_free()解决了内存泄漏问题,使进程内存稳定在合理范围。

随着打开的多媒体文件的增多,占用的内存也会越来越多:
在这里插入图片描述

在这里插入图片描述

访问媒体文件的起点是通过xplay2.cpp中的xdemuxthread.open(),因此清理也从xdemuxthread开始:

void xdemuxthread::Close()
{
	isexit = true;
	wait();
	
	if (vt) vt->Close();
	if (at) at->Close();
	mux.lock();
	delete vt;
	delete at;
	vt = NULL;
	at = NULL;
	mux.unlock();
}

1.vt与at是解封装线程来调用的,因为解封装线程要负责来清理vt与at
2.为了防止指针删到一半,然后其他线程突然来使用删掉的指针指针造成bug,因此要将这四句加锁
3.我们在删除一个指针之后,编译器只会释放该指针所指向的内存空间,而不会删除这个指针本身,因此还要将这些new出来的指针置null

对于vt与at的close来说,它们有大部分功能都是一样的,因此把一样的功能放在他们的共同基类xdecodethread中:

void xdecodethread::Close()
{
	Clear();

	//等待线程退出
	isexit = true;
	wait();
	decode->close();
	mux.lock();
	delete decode;
	decode = NULL;
	mux.unlock();
}
class xaudiothread:public xdecodethread
{
public:
	long long pts = 0;
	xaudiothread();
	virtual ~xaudiothread();
	void run();
	virtual bool open(AVCodecParameters* par, int samplerate, int channels);
protected:
	std::mutex amux;

	xaudioplay* audioplay=0;
	xresample* resample=0;
};

```cpp
class xvideothread:public xdecodethread
{
public:
	xvideothread();
	virtual ~xvideothread();
	virtual bool open(AVCodecParameters*par,ivideocall*call,int width,int height);
	void run();
	long long synpts = 0;
protected:
	xvideowidget* video=0;
	ivideocall* call = 0;

	std::mutex  vmux;
};

下面在对特有的部分处理:
音频线程特有的res与ap

void xaudiothread::Close()
{
	xdecodethread::Close();
	if (resample)
	{
		resample->Close();
		amux.lock();
		delete resample;
		resample = NULL;
		amux.unlock();
	}
	if (audioplay)
	{
		audioplay->close();
		amux.lock();
		audioplay = NULL;
		amux.unlock();
	}
}

先调用其父类的清理共同部分,再清理自己的独有的部分
audioplay为单例模式,不需要delete
单例模式:保证一个类仅有一个实例,并提供一个该实例的全局访问点。 ——《设计模式》GoF
在软件系统中,经常有这样一些特殊的类,必须保证他们在系统中只存在一个实例,才能确保它们的逻辑正确性、以及良好的效率。
对于不同的媒体文件,它们使用的都是同一个audioplay

在xplay2的析构中调用该close:

Xplay2::~Xplay2()
{
	dt.Close();
}

但是发现并没有什么卵用
可以从进程内存的图中看到内存占了2G,因此主要是解码后的视频数据没有得到释放

然后查看关于解码的receive(),果然在这里出了问题:

//可能一次send多次receive
		while (!isexit)
		{
			AVFrame* frame = decode->receive();
			if (!frame)break;
			if(call)
			{
				call->Repaint(frame);
			}
			else {
				cout << "repaint fail " << endl;
			}
			av_frame_free(&frame);
		}

当把从解码队列接收到的frame给repaint完后,这个frame就没用了,因此用av_frame_free(&frame)将其释放掉
在这里插入图片描述
此时进程内存稳定在250MB左右,每帧音频或者视频数据,在其播放或者绘制完后,都会立刻得到释放。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值