目录
第一篇关于FFmpeg + SDL2实现视频播放的博文仅仅只是实现了视频的播放,并没有实现音频的播放;第二篇关于FFmpeg + SDL2实现视频播放的博文是在第一篇的基础上进行改进实现了音视频的播放;而这篇博文还是关于FFmpeg + SDL2实现视频播放,到这里,可能会有小伙伴会问了,怎么还是音视频播放呢?有什么改进吗?
如果看了第二篇关于FFmpeg + SDL2实现视频播放博文的小伙伴应该知道,那篇博文中我们最终确实是实现了音视频播放,并且其中使用了多线程 + 互斥量 + 条件变量,但是也有小伙伴应该发现了如果要把该功能拓展到比如实现暂停,快进等功能的话,不容易。因此,本文是基于前面的博文进行改进,使用链队列来保存音频数据,参考了链接1 和 链接2 。
以下是这次实现的整体思路:

实现思路
- 创建窗口和渲染器,用于视频文件的选择,播放以及程序关闭
- 选择视频MP4文件
- 根据打开的视频文件,得到视频流和音频流其对应的流索引号,用于后面视频帧和音频数据读取时所用
- 找到对应的视频流和音频流索引号的同时,分别找到对应的视频和音频解码信息
- 读取视频数据,并判断当前的数据为视频帧数据还是音频数据
- 如果为视频帧数据,
- 视频帧解码(视频帧的缩放和转换操作)
- 实时更新视频帧
- 如果为音频数据
- 读取音频数据(根据音频流索引号判断当前是否为音频数据)
- 向链队列中加入音频数据
- 加锁Mutex
- 将音频数据加入链队列中
- 发送信号通知
- 解锁Mutex
- 从链队列中取出音频数据
- 加锁Mutex
- 判断链队列中是否有数据可取
- 如果有数据集可取,即可取出并进行音频数据解码
- 如果没有数据可取,则等待信号通知
- 解锁Mutex
- 如果为视频帧数据,
- 视频播放完成之后,关闭播放窗口,可以继续选择播放或者选择其他视频文件播放
- 关闭主线程窗口,完全结束视频播放。
注:上面的改进是否比之前变得更加复杂了,主要是因为便于后期进行功能上的拓展。
链队列实现
如果对链队列已经忘记或者不是很清楚的小伙伴,建议先去了解一下,然后下面我将画一个用于本文的链队列结构:

第一步:构建结构体数据结构
typedef struct Packet {
AVPacket av_packet; //记录节点的数据
struct Packet* next; //指向下一个节点
int serial; //暂时未用到
} Packet;
struct PacketQueue {
Packet * first_pkt,*last_pkt; //分别用于指向链队列的头部和尾部
int nb_packets; //记录节点的个数
int size; //记录当前已经加入到链队列中节点的所有数据
SDL_mutex * mutex; //用于互斥加锁
SDL_cond * cond; //用于等待信号通知和发送信号
};
第二步:初始化链队列

第三步:向链队列中加入数据

注:每一行的注释都已经写出来了,向链队列中加入加入数据是从指向最后一个节点开始加入的,取出数据是从链队列的头部开始的,因为加入数据的顺序是从头部开始的。
第四步:从队列中取出数据

注:取出数据的过程从头部开始,节点数减一,注意取出头部的数据之后记得释放节点的资源。
QT 6.6.0 + FFmpeg+SDL2实现音频视频播放
760

被折叠的 条评论
为什么被折叠?



