QT 6.6.0 + FFmpeg + SDL2实现音频视频播放(视频帧播放多线程改进)

B站视频讲解

GitHub源码下载地址

目录

实现思路

附加知识点 

第一点:AVRational 有理数结构体

第二点:AVCodecContext 结构体包含的sample_aspect_ratio

第三点:av_q2d 函数

第四点:SDL中自定义事件

第五点:SDL2中的SDL_PollEvent和SDL_WaitEvent之间的区别

SDL_PollEvent

SDL_WaitEvent


初学案例教程
QT6.6.0实现打开电脑摄像头或其他的外接摄像头(实现拍照功能)
QT6.6.0实现简单的录音器
QT6.6.0实现一个简单的视频和音频播放器
QT6.6.0实现简单的视频录制(包含语音录制)器
QT6.6.0关于QMediaMetaData功能以及列子说明使用方法
QT6.6.0实现QtCamera功能(拍照,录像以及图像和视频的相关配置)
T6.6.0实现更好的视频播放器(前期改进)
QT6.6.0实现图表如饼图,柱状图,散点图以及盒图等的基本使用
QT6.6.0实现客户端Socket编程以及socket测试软件通信
QT6.6.0 实现服务端Server和多个客户端Client通信以及socket测试软件通信
QT6.6.0 实现QNetworkAccessManager的基本应用以及其拓展使用
QT6.6.0 实现服务端Server和多个客户端Client互相发送文件信息
QT6.6.0和QT6.0以下的版本实现FTP文件上传和下载(过程详解)
QT6.6.0实现QNetworkInterface网络接口,QHostAddress网络地址IP以及域名解析等相关信息查询。
QT6.6.0基于QTcpSocket和QTcpServer实现多个客户端群聊
QT6.6.0实现基于UDP协议的简单通信(过程详解)
QT 6.6.0基于UDP协议实现广播和多播机制(过程详解)
QT 6.6.0基于UDP协议实现群聊功能(过程详解)
QT 6.6.0中OpenCV两种环境的配置方法以及基本使用例子
QT 6.6.0 中基于OpenCV的图像变换以及基于鼠标点击移动事件的图像绘制
QT 6.6.0 基于OpenCV对图像进行旋转,缩放和裁剪等操作
QT 6.6.0 基于OpenCV实现图像风格的改变(add和subtract)
PyTorch 训练之后的网络模型.pth转.onnx文件并对图像进行预测
QT 6.6.0 基于OpenCV加载.pth模型文件转换之后的ONNX模型文件,并且实现图像分类
QT 6.6.0 基于OpenCV中的cv::dnn::ClassificationModel实现图像分类
yolov5目标检测和QT 6.6.0 基于OpenCV加载yolov5.onnx模型文件实现目标检测
FCN图像分割和QT 6.6.0 加载分割FCN_Resnet50.ONNX模型文件进行图像分割(过程详解)
QT 6.6.0 中基于SDL2库实现WAV音频格式的播放(过程详解)
QT 6.6.0 中SDL2库的基本使用以及利用SDL2库创建的界面实现音频播放(过程详解)
QT 6.6.0 中基于SDL2,SDL2_ttf,SDL2_image,SDL2_mixer实现音频播放器(改进版)
QT 6.6.0 + SDL2 + SDL2_mixer实现音频播放器(改进)
QT 6.6.0 中基于FFmpeg + SDL2 + SDL2_mixer实现音频录音(过程详解)
QT 6.6.0 + FFmpeg + SDL2实现MP4视频播放(过程详解)
QT 6.6.0 + FFmpeg + SDL2实现视频播放器(视频和音频同时播放-改进)
QT 6.6.0 + FFmpeg + SDL2实现音频视频播放(改进)

        前一篇博文我们已经讲了关于视频播放的进一步改进,并且也使用到了多线程等操作,之所以会这样做的原因还是因为后期在拓展功能的时候更加的方便,比如快进,快退等功能。这篇博文主要是对视频帧读取,解码以及显示部分进行了拆解,将视频帧读取和解码部分分别放到了不同的线程,并且其中还使用了定时器,互斥量和条件变量,细节请看代码,同时也会视频讲解。其中参考了参考1 和 参考2

        实现的整体流程:

整体代码实现流程

视频帧播放流程:

注:可以看到这个视频帧播放流程其实看了代码之后并没有像上面画的流程图那么简单,其中很多细节之处都省略了,视频代码讲解不封将细讲。 

音频数据播放流程:

注:关于音频数据播放部分的流程实现之前的视频已经讲解,请看视频讲解 。

        视频帧数据和音频数据保存到链队列中的结构如下:

实现思路

  1. 创建窗口和渲染器,用于视频文件的选择,播放以及程序关闭
  2. 选择视频MP4文件
  3. 视频数据读取线程
    1. 根据打开的视频文件,得到视频流和音频流其对应的流索引号,用于后面视频帧和音频数据读取时所用
    2. 找到对应的视频流和音频流索引号的同时,分别找到对应的视频和音频解码信息
    3. 音频相关参数配置以及用于缩放的视频帧格式定义
    4. 读取视频帧数据和音频数据,分别存储到视频和音频链队列中
    5. 定义从视频帧解码线程
      1. 从视频链队列中取出视频帧数据(同时要判断队列中是否有数据可取,如果没有数据可取就跳出循环并加锁和等待入队列函数发出条件信号)
      2. 对视频帧数据解码和缩放操作(这个过程中也涉及加锁和解锁等操作)
      3. 显示视频帧(显示视频帧的同时也会涉及到高宽比的缩放操作)
    6.  

      如果为音频数据播放

      1.  读取音频数据(根据音频流索引号判断当前是否为音频数据)

      2. 向链队列中加入音频数据

        1.  加锁Mutex

        2.  将音频数据加入链队列中

        3.  发送信号通知

        4. 解锁Mutex

      3.  从链队列中取出音频数据

        1.  加锁Mutex

        2. 判断链队列中是否有数据可取

        3. 如果有数据集可取,即可取出并进行音频数据解码如果没有数据可取,则等待信号通知

        4. 解锁Mutex

  4.    
  5. 视频播放完成之后,关闭播放窗口,可以继续选择播放或者选择其他视频文件播放
  6. 关闭主线程窗口,完全结束视频播放。

注:这个文字的解释部分并没有十分清楚的从细节上讲解,不想看这个文字部分的小伙伴就直接看视频讲解即可。

附加知识点 

第一点:AVRational 有理数结构体

typedef struct AVRational {  
    int num; ///< Numerator  
    int den; ///< Denominator  
} AVRational;
AVRational 是 FFmpeg 中用于表示有理数(即分数)的结构体。它通常用于处理与时间、
帧率、比特率等相关的数值,尤其是在音视频处理领域。
  • num:分子(Numerator)

    • 这是有理数的上部分,表示分数的分子。
  • den:分母(Denominator)

    • 这是有理数的下部分,表示分数的分母。

AVRational 结构体的主要用途包括:

  1. 时间表示:在处理时间戳时,AVRational 可以用来表示时间的比率,例如帧率(frames per second, fps)或采样率(samples per second, sps)。

  2. 比特率:在音视频编码中,AVRational 可以用来表示比特率,例如每秒多少比特。

  3. 转换和计算:由于有理数可以精确表示分数,使用 AVRational 可以避免浮点数运算带来的精度问题。在进行时间、帧率等计算时,可以使用 AVRational 进行加法、减法、乘法和除法等操作。

第二点AVCodecContext 结构体包含的sample_aspect_ratio

样本宽高比(Sample Aspect Ratio)

  • sample_aspect_ratio(四舍五入的整数) 是一个 AVRational 类型的字段,表示视频帧的宽高比。它通常用于描述视频图像的像素宽度与高度的比例。

第三点:av_q2d 函数

将 AVRational 类型的有理数转换为双精度浮点数(double)。这个函数的主要作用是将表示为分数的值(如帧率、比特率等)转换为更易于处理的浮点数格式。

第四点:SDL中自定义事件

  1. 定义事件类型:使用 SDL_USEREVENT 及其后续的事件类型(SDL_USEREVENT + n)来定义您的自定义事件。

  2. 创建事件:使用 SDL_Event 结构体来创建和初始化事件。

  3. 推送事件:使用 SDL_PushEvent 将事件推送到事件队列。

  4. 处理事件:在事件循环中检查并处理自定义事件。

#define FF_REFRESH_EVENT (SDL_USEREVENT) //定义定时刷新界面的事件
#define FF_QUIT_EVENT (SDL_USEREVENT + 1) //定义退出程序的事件

第五点:SDL2中的SDL_PollEventSDL_WaitEvent之间的区别

SDL_PollEvent
  • 功能SDL_PollEvent 用于检查事件队列中是否有待处理的事件。
  • 阻塞行为:该函数是非阻塞的。如果事件队列中没有事件,SDL_PollEvent 会立即返回 0,并不会等待事件的到来。
  • 使用场景:适用于需要在主循环中频繁检查事件的场景,例如游戏循环中,在每一帧中检查事件并更新游戏状态。
SDL_WaitEvent
  • 功能SDL_WaitEvent 用于等待事件的到来,并在事件到达时处理它。
  • 阻塞行为:该函数是阻塞的。如果事件队列为空,SDL_WaitEvent 会阻塞程序,直到有事件到达。
  • 使用场景:适用于需要在没有事件时不消耗 CPU 资源的场景,例如在 GUI 应用程序中,在没有事件时让程序处于等待状态。

QT 6.6.0 + FFmpeg+SDL2实现音频视频播放

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值