前言
虽说ffplay是一个简单的播放器,但是其实内部一点也不简单,其实笔者也不知道说它简单的理由是什么,是因为它只有一个点c文件???
ffplay内部细节繁多,想要深入分析不单单要掌握音视频的相关概念,还要掌握多线程等相关知识,但是不得不说ffplay确实是学习的播放器开发的一个最佳例子。
建议想要学习ffplay的童鞋们集成后边阅读边增加注释,多阅读几次,相信你每次阅读都会有不同的理解与收获...
本文使用的ffplay.c的版本是搭配ffmpeg5.0的版本。
ffplay代码大致架构
关于fplay的架构很难三言两语说得清楚,而且本人对它的理解也不是很深,加上行笔比较啰嗦,可能就更加描述不清了,因此笔者制作了一张图,这张图描述了ffplay的三大子线程工作内容,当然如果加上字幕的话有四个子线程。
ffplay总体架构
图导出的可能有点模糊,再加上上传图床后不知道有没有更加模糊了,想要高清大图的可以后台留言,加v信索取。
上图只是简单地画出了ffplay的大体架构,不同版本的代码API名称可能有点不同,但是大致思路肯定是一致的。这个图也忽略了一些细节,比如解码线程与读取线程的同步处理等。
ffplay关键数据结构
1、VideoState
VideoState可以说是ffplay的内部管家了,几乎能拿到ffplay内部的所有变量以及相关状态。下面是笔者加了注释的的VideoState源码:
关于SDL相关的,以及一些filter相关的笔者忽略了,因为从本质上讲它们不属于ffplay的核心内容。
2、 MyAVPacketList
MyAVPacketList是表示待解码数据包的数据内容。
在新版本中笔者感觉这个结构体有些鸡肋,因为它是搭配PacketQueue使用的,但是PacketQueue又没有直接使用它,而是拷贝了它的数据...
3、PacketQueue
PacketQueue表示待解码包的队列,就是从流文件中读取到的数据包,然后将它们放入到这个容器中去,然后等待解码线程获取进行消费,涉及到线程安全、互斥量、条件变量等。
4、Clock
时钟是ffplay中一个很重要的概念,没了它音视频同步就没法做。音频和视频都有各自的时钟,在同步的时候以参考系看自己到底是快了还是慢了及时作出校正。
这个看不懂不要紧,后面在音视频同步中我们再详细介绍下这个结构体。
5、Frame
Frame表示解码后的数据帧,它内部封装了ffmpeg的结构体AVFrame。
6、FrameQueue
FrameQueue解释解码后的待播放的数据帧队列,它是环形的队列,通过索引进行操作内部元素,涉及到线程安全、互斥量、条件变量等。
7、Decoder
Decoder是ffplay封装的解码器结构体,其实内部是调用了ffmpeg的API进行解码音频、视频、字幕等,内部封装了子线程。
关于ffpaly的整体架构今天就先介绍到这里,关于ffplay内部的其他细节问题,我们将在后面继续介绍,敬请关注。
播放序列
在上面的数据结构的介绍中我们看到几乎每个结构体都含有一个类似于serial这样的播放序列的字段,那么这个播放序列的字段是干啥用的呢?
所谓的播放序列是指一个连续的播放过程,比如播放了一个媒体流一直没有进行操作就是一个播放序列,一旦操作了播放位置就是另外一个播放序列了,比如说开始播放的时候播放序列是0,进行了seek操作之后播放序列就不是0了,会变成1,每次seek之后播放序列都会加1,然后在读取线程、解码线程、SDL显示过程中都进行当前的数据包、数据帧是否是属于最新的播放序列的内容的判断,如果不属于的话将被直接丢弃掉,如果是属于当前播放序列的话就进行入队或解码或播放等相关操作。
领取专属 10元无门槛券
私享最新 技术干货