通过学习跟着写了一个音视频播放器。内容有点多,所以我就不打算在博客都展示出来了,这里就展示一下每个类的核心逻辑。思路很清晰,这里就简单讲解一下吧((~o ̄3 ̄)~)
音视频队列
- packet队列
avpacketqueue存储解复用线程中读取到的packet数据,因为队列的实现比较简单,我就展示一下该类的结构吧
1 | class AVPacketQueue |
- frame视频队列
avframequeue存储解码线程中解码后的frame数据,类结构如下
1 | class AVFrameQueue |
线程分工
-
主线程
主要完成线程的创建,让子线程完成具体的工作。因为主线程对程序的理解挺重要的,所以你可以在文章的最后直接看到主线程的源码 -
解复用线程
demuxthread完成音频的解复用,并将pkt数据写入packet队列,同时音视频的相关参数也由该线程提供。
1 | while(abort_ != 1){ |
- 解码线程
decodethread完成音视频的解码,并将解码后的数据写入frame队列。
1 | while(abort_ != 1){ |
输出渲染
- 音频输出
audiooutput这里涉及到SDL对播放音频的处理。实际上SDL会自己建立线程完成对音频数据的获取,即通过回调的方式,所以最主要的就是要设计好回调函数,下面是回调函数的设计
1 | void fill_audio_pcm(void *udata, Uint8 *stream, int len){ |
- 视频输出
videooutput在主线成里调用videooutput的一个循环输出的方法,实现视频的渲染,但这样的方式肯定是不好的,总之就先这样吧(ㄟ( ▔, ▔ )ㄏ)
1 | int VideoOutput::MainLoop() |
RefreshLoopWaitEvent()这个函数的设计主要是在等待事件的同时完成音视频的对齐,由于是视频对齐音频,在视频质量很高的情况下,会出现视频跟不上音频的情况,所以我在主线程里设置了一个等待时间,目的是让解码线程先运行一段时间,让视频播放时提前有一些数据,避免视频解码过慢造成的问题。但这样肯定是不行的,我想到用开多个视频解码线程的方式解决,但这样又会引出许多问题(>﹏<)但我相信会在以后的学习中,这将不会是问题(o( ̄︶ ̄)o)
音视频同步
avsync 音视频的同步有三种方式,这里采用的是视频基于音频的播放,对时间的获取和设置都是通过该类实现的,内容很少我就直接贴出来了
1 | AVSync(){} |
主函数
1 |
|
说些什么吧!