介绍
在本系列,我打算花大篇幅讲解我的 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 了。
欲知后事如何,请听下回分解。