C++多线程实现解封装和解码的解耦合(基于FFmpeg4.1)

这篇博客记录一下使用多线程来对FFmpeg的demux模块和decode模块的降耦合,解封装和解码各自单独占用一个线程,正常来讲音频解码和视频解码应该各自占用一个线程,在这里为了简单就把他们合并为了一个线程,没加入视频和音频的渲染,读者可以根据情况自行添加。

运行效果:

C++多线程实现解封装和解码的解耦合(基于FFmpeg4.1)_第1张图片
C++多线程实现解封装和解码的解耦合(基于FFmpeg4.1)_第2张图片

- 启动之后两个线程成功进入,在媒体文件读取结束后安全停止线程。

所有的文件示意图:

C++多线程实现解封装和解码的解耦合(基于FFmpeg4.1)_第3张图片

XThread类:线程函数的基类,解封装模块和解码模块分别对其进行继承。
IDemux类:解封装模块的接口类,对XThread进行继承。
FFDemux类:解封装模块的具体实现类,继承IDemux类
IDecode类:解码模块的接口类,对XThread进行继承
FFDecode类:解码模块的实现类,对IDecode进行继承
XData类:数据类,主要用于解码和解封装之间的数据传递(AVPacket等)对AVPacket设计成列表,进行缓冲。

添加视频渲染的部分直接在IDecode的线程中把解码后的数据传递给SDL就可以了,可以自行添加。

Main函数

#include 
#include "FFDemux.h"
#include "FFDecode.h"
#include 
extern "C"
{
#include 
}
/*
* 之前的错误就是list的元素一直用的是AVPacket* ,现在改成XData
* 以前那种做法不能够将XData的isAudio正确传递到send和Recv函数,所以导致了错误。
*/
int main(int argc, char* argv[])
{
	std::list<XData>* Lpkt =new std::list<XData>();
	char url[] = "test.mov";
	IDemux* dm = new FFDemux();
	IDecode* de = new FFDecode();
	de->pkt = Lpkt; 
	dm->packet = Lpkt;
	if (!dm->Open(url))
	{
		return -1;
	}
	XData apara=dm->GetAPara();
	bool re=de->Open(apara);
	if (!re)
	{
		printf("de->Open(apara) failed!\n");
		return -1;
	}
	XData vpara = dm->GetVPara();
	re = de->Open(vpara);
	if (!re)
	{
		printf("de->Open(vpara) failed!\n");
		return -1;
	}
	//读取pkt线程开始
	dm->Start();
	//解码模块开始
	de->Start();
	while (true)
	{
		if (dm->stopthread)
		{
			//停止线程
			dm->Stop();
			while (!de->pkt->empty())
			{
				Sleep(1);//等待解码线程把剩余pkt解码完毕。
			}
			de->Stop();//停止解码线程运行
			dm->Close();
			de->Close();
			apara.Drop();
			vpara.Drop();
			return 0;
		}
		Sleep(10);
	}
}

其他的代码太多了,这里就不贴了,可以在下方的链接下载,包含一个单线程的视频播放器(有视频和音频的渲染),还包含本篇博文介绍的工程。下载使用vs打开即可运行。

[1] vs工程—C++多线程实现解封装和解码的解耦合(基于FFmpeg4.1)

你可能感兴趣的:(FFmpeg)