音视频项目—基于FFmpeg和SDL的音视频播放器解析(九)

介绍

在本系列,我打算花大篇幅讲解我的 gitee 项目音视频播放器,在这个项目,您可以学到音视频解封装,解码,SDL渲染相关的知识。您对源代码感兴趣的话,请查看基于FFmpeg和SDL的音视频播放器

如果您不理解本文,可参考我的前一篇文章音视频项目—基于FFmpeg和SDL的音视频播放器解析(八)

解析

这篇文章我们会解析项目的父类 Queue,其子类 AVPacketQueue 和 AVFrameQueue 均需要继续其特性。

我们先大体看一下 Queue 的源码

#pragma once
#ifndef QUEUE_H_
#define QUEUE_H_
#include<mutex>
#include<condition_variable>
#include<queue>
using namespace std;

template<typename T>
class Queue
{
public:
	Queue(){}
	~Queue(){}
	void Abort() {
		abort = 1;
		cond_t.notify_all();
	}
	int Push(T val) {
		lock_guard<mutex> lock(mutex_t);
		if (abort == 1) {
			return -1;
		}
		queue_t.push(val);
		cond_t.notify_one();
		return 0; 
	}
	int Pop(T& val, int timeout = 0) {
		unique_lock<mutex> lock(mutex_t);
		if (queue_t.empty()) {
			cond_t.wait_for(lock, chrono::milliseconds(timeout), [this] {
				return !queue_t.empty() | abort;
			});
		}
		if (abort == 1) {
			return -1;
		}
		if (queue_t.empty()) {
			return -2;
		}
		val = queue_t.front();
		queue_t.pop();
		return 0;
	}
	int Front(T& val) {
		lock_guard<mutex> lock(mutex_t);
		if (abort == 1) {
			return -1;
		}
		if (queue_t.empty()) {
			return -2;
		}
		val = queue_t.front();
		return 0;
	}

	int Size() {
		lock_guard<mutex> lock(mutex_t);
		return queue_t.size(); 
	}
private:
	int abort = 0;
	mutex mutex_t;
	condition_variable cond_t;
	queue<T> queue_t;
};

#endif

Queue 将声明与实现写在一起了,所以看上去比较多,其实函数只有 Abort,Push,Pop,Front,Size 这五个。

我们先看看私有成员。

abort:标识位,判断能不能接收数据

mutex:互斥锁

condition_variable:条件变量

queue:队列

说明一下,在代码当中,我们为什么要使用互斥锁,由于我们采用多线程并发的机制,为实现线程安全,我们就采用互斥锁。而条件变量是和互斥锁一起使用的。想深入了解的朋友可看条件变量(condition_variable)

然后我们看一下公有成员函数

Abort:
void Abort() {
    abort = 1;
	cond_t.notify_all();
}

这个函数负责终止程序并通知所有线程。

Push:
int Push(T val) {
	lock_guard<mutex> lock(mutex_t);
	if (abort == 1) {
		return -1;
	}
	queue_t.push(val);
	cond_t.notify_one();
	return 0; 
}

这个函数负责队列增加数据,上锁,增加数据,通知线程。

Pop:
int Pop(T& val, int timeout = 0) {
	unique_lock<mutex> lock(mutex_t);
	if (queue_t.empty()) {
	    cond_t.wait_for(lock, chrono::milliseconds(timeout), [this] {
			return !queue_t.empty() | abort;
		});
	}
	if (abort == 1) {
		return -1;
	}
	if (queue_t.empty()) {
		return -2;
	}
	val = queue_t.front();
	queue_t.pop();
	return 0;
}

这个函数负责队列弹出头部数据,上锁,如果队列为空,等待。当不为空时,赋值给参数并弹出数据。

Front:
int Front(T& val) {
	lock_guard<mutex> lock(mutex_t);
	if (abort == 1) {
		return -1;
	}
	if (queue_t.empty()) {
		return -2;
	}
	val = queue_t.front();
	return 0;
}

这个函数负责返回队列头部数据。上锁,判断是否为空,不为空则返回数据。

Size:
int Size() {
	lock_guard<mutex> lock(mutex_t);
	return queue_t.size(); 
}

这个函数负责返回队列的大小。上锁,返回队列大小。

好了,我们今天介绍了父类 Queue,大家感到困难的话,因为是由于互斥锁和条件变量的原因,如果采用单线程开发的话,就不用这么麻烦,但是为了提高性能,采用多线程,保证安全性,就要麻烦一点。

那么接下来我们就可以讲 Queue 的子类,avpacketqueue 和 avframequeue 了。

欲知后事如何,请听下回分解。

猜你喜欢

转载自blog.csdn.net/weixin_60701731/article/details/134454513