介绍
在本系列,我打算花大篇幅讲解我的 gitee 项目音视频播放器,在这个项目,您可以学到音视频解封装,解码,SDL渲染相关的知识。您对源代码感兴趣的话,请查看基于FFmpeg和SDL的音视频播放器
如果您不理解本文,可参考我的前一篇文章音视频项目—基于FFmpeg和SDL的音视频播放器解析(八)
解析
这篇文章我们会解析项目的父类 Queue,其子类 AVPacketQueue 和 AVFrameQueue 均需要继续其特性。
我们先大体看一下 Queue 的源码
#pragma once #ifndef QUEUE_H_ #define QUEUE_H_ #include
#include#include using namespace std; template class Queue { public: Queue(){} ~Queue(){} void Abort() { abort = 1; cond_t.notify_all(); } int Push(T val) { lock_guard 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 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 lock(mutex_t); if (abort == 1) { return -1; } if (queue_t.empty()) { return -2; } val = queue_t.front(); return 0; } int Size() { lock_guard lock(mutex_t); return queue_t.size(); } private: int abort = 0; mutex mutex_t; condition_variable cond_t; queue 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 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 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 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 lock(mutex_t); return queue_t.size(); } 这个函数负责返回队列的大小。上锁,返回队列大小。
好了,我们今天介绍了父类 Queue,大家感到困难的话,因为是由于互斥锁和条件变量的原因,如果采用单线程开发的话,就不用这么麻烦,但是为了提高性能,采用多线程,保证安全性,就要麻烦一点。
那么接下来我们就可以讲 Queue 的子类,avpacketqueue 和 avframequeue 了。
欲知后事如何,请听下回分解。