QT商业播放器

QT商业播放器

总体架构图

在这里插入图片描述

架构优点:解耦,采用生产者消费者设计模式,各个线程各司其职,通过消息队列高效协作

这个项目是一个基于ijkplayer和ffplayer.c的QT商业播放器,
项目有5部分构成:
前端QT用户界面
后端是集成了ffplayer.c的类--播放的核心逻辑,
中间层有3个模块,一是ijkmp类-暴露给前后端向消息队列发消息,二是参考ijkplayer实现的单链表消息队列,三是用QThread启动的消息循环线程--循环取消息处理业务下面我来依次说明这些模块:

QT界面

用户界面设计

基本机制

利用QT的信号和槽函数机制,界面事件触发后向消息队列发送消息

  1. 界面元素事件绑定信号
  2. 信号绑定槽函数
  3. 槽函数向消息队列发送对应事件的消息,通知ffplay开始工作
  4. ffplay将视频画面回调到qt界面,声音回调到SDL音频播放流
  5. ffplay内部通过各个信号量控制工作流状态,响应消息只需要调用接口改变ffplay内部的各个信号量即可

元素事件包括:

  • 播放,暂停,停止

  • 快进,快退(按钮seek)

  • 进度条seek

  • 音量控制

  • 文件路径

后端ffplay类

播放器的播放逻辑–一个播放器真正的灵魂部分

主要接口

主要接口就是stream_open(),和stream_close()

  • stream_open负责启动线程和各个队列
  • stream_close负责关闭线程并且回收资源

主要工作流程

  • 解复用线程将从媒体文件中解出来的原始码流包插入到音频包队列和视频包队列

    1.创建解复用上下文结构体(对文件数据的格式化)avformat_alloc_context
    2.打开文件,主要是探测协议类型avformat_open_input
    3.探测媒体类型,可得到当前文件的封装格式,音视频编码参数等信息avformat_find_stream_info
    4.获取音频和视频流标志--为了5划分包av_find_best_stream
    5.【循环】读取媒体数据,得到的是音视频分离后、解码前的数据包,将数据包插入到对应的包队列av_read_framevideo_packet_queue.pushaudio_packet_queue.push
    
  • 2个解码线程从对应包队列中拿到包数据,由对应的解码器解码出帧数据,将音频帧插入到音频帧队列,视频帧插入到视频帧队列

    1.创建解码上下文avcodec_alloc_context3
    2.从解复用上下文中获取码流的信息,并绑定到解码上下文中avcodec_parameters_to_context
    3.配置解码器,根据对应码流的格式配置(codec_id)avcodec_find_decoder
    4.初始化解码器avcodec_open2
    5.【循环】从包队列中获取包,将包丢到解码器,解码出帧数据,加入到帧队列【视频解码线程】video_packet_queue.getavcodec_send_packetavcodec_receive_framevideo_frame_queue.push【音频解码线程】audio_packet_queue.getavcodec_send_packetavcodec_receive_frameaudio_frame_queue.push
    
  • 播放线程从帧队列中拿到帧数据,经过音视频同步后,视频帧数据回调到qt的Widget容器,绘制出画面;音频数据回调到SDL音频播放函数

    【音频播放线程】
    1.初始化音频设备SDL_OpenAudio
    2.配置数据回调函数【循环】取帧队列数据拷贝到SDL音频播放流中audio_frame_queue.get【视频播放线程】
    1.配置QT显示窗口painter.drawImage
    2.获取队列当前Frame,使用ffmpeg的Scale3转换算法将frameYUV格式图像统一转为RGB格式图像,调用QT显示窗口的刷新回调函数video_frame_queue.get视频同步音频:计算音视频pts差,设置阈值,大于渲染上一帧,小于丢帧Scale3video_refresh_callback
    

亮点

缓存队列

这个部分有2部分队列,包队列和帧队列

包队列

包队列是原始码流包的缓存队列

2个帧队列
H264码流包队列NALU包:由分割符(00 00 00 01)、头信息、压缩数据构成AAC码流包队列ADTS包:由分隔符(0xFFF)、头信息、压缩数据构成

PacketQueue 是一个链表队列

  • 内存充足情况下:可以不限制将数据包放入队列中,不需要考虑队列的大小。

  • 控制队列大小:如果我们需要控制队列的大小,我们可以使用以下三个变量来限制队列节点的数量:

    size:控制队列中数据包的总大小。

    duration:控制队列中数据包的总播放时间。

    nb_packets:控制队列中数据包的数量。

    在ffplay中,限制所有队列总大小为:15mb
    这是一个经验数值,大概能缓存4k视频2.4s左右而我在设计的时候直接用的各队列播放时间<2.4s控制即可
    超过就队满,不让存包数据,限制队列大小
    
帧队列

帧队列是解码后的可播放音视频数据

视频帧队列每一帧都是YUV格式图像数据音频帧队列每一帧都是PCM采样帧流数据

FrameQueue是一个循环数组队列

  • 数组队列适合于事先明确了缓冲区的最⼤容量的情形

  • 避免假队空----定义一个size

  • 写端位于解码线程,读端位于播放线程

  • 设置互斥锁机制—线程安全

在ffplay中:一般设置为音频队列最大9帧,视频队列最大3帧因为缓存的是解码后的帧,所以队列不能设置过大,过大容易爆内存,通常是缓存一个比较小的值

ijk播放器核心类

里面维护一个消息队列和真正的播放器ffplayer

ijk播放器核心类暴露给前端的接口都是往消息队列中插入消息,不会直接操作ijkplayer。

比如开始播放,暂停,seek等,都是前端调用ijkmp暴露给前端的接口,向消息队列中插入消息,然后在消息循环线程取消息时,在消息分发过滤器中才操作ijkplayer

消息循环子线程

使用QThread启动message_loop消息循环线程

方便利用QT的信号和槽函数机制,qt_ui及时响应后端发给前端的消息

设置消息分发过滤器,处理前端发给后端的消息

设计

在这里插入图片描述

流程

message_loop是QThread启动的具体run函数,里面主要是一个while循环,调用ijkmp的消息分发过滤器获取消息,然后根据返回的消息做响应

而ijkmp的消息分发过滤器会先检测这个消息

  • 如果是前端发向后端的消息,就直接调用ffplay类控制播放,继续取下一个消息;
  • 如果是后端发向前端的消息,就直接返回给message_loop循环线程,让message_loop利用信号和槽函数,控制qt界面的响应

亮点

  • 采用消息分发过滤器模块,只开辟一个线程,同步处理2个端的业务

消息队列

概念

  • 消息队列是连接qt界面和ijk播放器核心之间的桥梁

  • 作用就是传输指令

  • 本质就是结构体单链表队列

消息节点设计
  • 数据域:设计为三个int值,1个任意类型值+任意类型值的释放函数指针

  • 指针域:next指针指向下一个节点

两个队列
  • 工作消息队列:正常请求消息节点,增删

  • 回收消息队列:空消息节点,循环使用

亮点

  • 使用回收消息队列

    使用回收消息队列可以有效提高程序效率插入消息节点时先从回收消息队列中直接取空节点赋值新消息,如果没有再创建新节点赋值新消息取节点后,把消息节点清空,插入到回收消息队列中
    

功能实现

播放暂停停止

  • 前端qt界面发送相应消息

  • 在消息循环中,检测到消息,调用ffplay相关接口,改变ffplay类中的控制变量,进而改变线程状态(线程内循环会检测这些变量)

  • 播放暂停是设置了一个暂停标志位,暂停1,播放0

    在播放线程会去检测暂停标志位,如果暂停线程就休眠100ms,然后continue跳过本次循环
    
  • 停止是设置了一个退出标志位,停止1,未停止0

    各个线程都会检测退出标志位,如果退出,break退出循环
    

快进、快退、进度条seek

1.前端发送seek消息,并携带对应seek后的位置-时间戳
2.消息循环检测到后,调用ffplay类相关接口,改变ffplay类中的控制变量seek_req--标记位seek_pos--seek时间戳
3.在解复用线程中检测seek_req,调用ffmpeg的API seek到对应位置,并且刷新包队列和帧队列,给新的包的serial++avformat_seek_fileserial--标记位,区分不同seek段,播放的时候会检测
4.在解码线程中中检测seek_req,向解码器加入冲刷包,冲刷解码器--因为解码器解码会缓存一些帧(IP帧)

音视频同步

音视频同步这块有3种方式,视频同步音频,音频同步视频,加入外部时钟,音视频一块同步外部时钟因为研究发现用户对于音频更加敏感,所以一般都是让视频去同步音频
我这个项目中采用的就是视频去同步音频基本思路就是视频帧播放快于音频帧播放:睡一会,持续渲染最后一帧视频帧播放慢于音频帧播放:丢帧处理然后还要一个点就是音视频同步流畅的范围是音频时间戳-视频时间戳在-100ms到25ms内,这是一个国际标准,可以拿这个区间作为检测的阈值范围具体做法在视频播放时,检测当前视频帧播放时间戳pts和当前音频帧时间戳的差值diff(diff=音频pts-视频pts)如果差值diff在-100ms到25ms内,就说明已经同步如果差值diff超过25ms,说明音频快于视频,视频慢了,视频丢帧不渲染如果差值diff小于-100ms,说明音频慢于视频,视频快了,持续渲染最后一帧,然后视频线程休眠差值diff的绝对值

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/95319.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

专题一:双指针【优选算法】

双指针应用场景&#xff1a; 数组划分、数组分块 目录 一、移动0 二、复写0 从后向前 三、快乐数 链表带环 四、盛水最多的容器 单调性双指针 五、有效三角形个数 单调性双指针 六、和为s的两个数字 七、三数之和 细节多 需再练 一、移动0 class Solution { public:void move…

小程序入门笔记(一) 黑马程序员前端微信小程序开发教程

微信小程序基本介绍 小程序和普通网页有以下几点区别&#xff1a; 运行环境&#xff1a;小程序可以在手机的操作系统上直接运行&#xff0c;如微信、支付宝等&#xff1b;而普通网页需要在浏览器中打开才能运行。 开发技术&#xff1a;小程序采用前端技术进行开发&#xff0c;…

Html+Css+Js计算时间差,返回相差的天/时/分/秒(从未来的一个日期时间到当前日期时间的差)。

Html部分 <!DOCTYPE html> <html><head><meta charset"utf-8" /><title></title><link rel"stylesheet" type"text/css" href"css/index.css" /><script src"js/index.js" t…

仿牛客论坛项目 笔记

文章目录 环境配置bean是什么最终成品功能数据库与缓存一致性整个web系统后端的结构spring mvc相关controller常见的代码写法mybatis相关常识测试、调试相关计网相关component相关注解spring全家桶族谱spring衍生框架 run之后发生了什么什么是spring&#xff0c;spring和bean的…

【计算机组成原理】考研真题攻克与重点知识点剖析 - 第 2 篇:数据的表示和运算

前言 本文基础知识部分来自于b站&#xff1a;分享笔记的好人儿的思维导图与王道考研课程&#xff0c;感谢大佬的开源精神&#xff0c;习题来自老师划的重点以及考研真题。此前我尝试了完全使用Python或是结合大语言模型对考研真题进行数据清洗与可视化分析&#xff0c;本人技术…

开源协作开发者内容平台Vrite

什么是 Vrite &#xff1f; Vrite 是一个开源协作空间&#xff0c;用于创建、管理和部署产品文档、技术博客和知识库。它旨在提供高质量、集成的用户和开发人员体验。 Vrite 具有以下功能&#xff1a; 内置管理仪表板&#xff0c;用于使用看板或列表视图管理内容生产和交付&am…

SpringCloud(二)Docker、Spring AMQP、ElasticSearch

文章目录 DockerDocker与虚拟机Docker架构镜像、容器、镜像托管平台Docker架构Docker实践 Spring AMQP简单使用案例工作队列- WorkQueue发布订阅服务FanoutExchangeDirectExchangeTopicExchange 消息转换器 ElasticSearch倒排索引IK分词器IK分词拓展与停用字典 操作索引库mappi…

Dubbo 融合 Nacos 成为注册中心

Nacos 作为 Dubbo 生态系统中重要的注册中心实现&#xff0c;本文将会介绍如何进行 Dubbo 对接 Nacos 注册中心的工作。 预备工作 请确保后台已经启动 Nacos 服务 快速上手 Dubbo 融合 Nacos 成为注册中心的操作步骤非常简单&#xff0c;大致步骤可分为“增加 Maven 依赖”…

创建vue3工程

一、新建工程目录E:\vue\projectCode\npm-demo用Visual Studio Code 打开目录 二、点击新建文件夹按钮&#xff0c;新建vue3-01-core文件夹 三、右键vue3-01-core文件夹点击在集成终端中打开 四、初始化项目&#xff0c;输入npm init 一直敲回车直到创建成功如下图 npm init 五…

国庆加速度!新增功能点锁定功能,敏捷开发新增估算功能,助力项目快速突破!

大家好&#xff0c;CoCode开发云旗下Co-Project V3.6智能项目管理平台正式发布&#xff0c;平台新增功能点锁定功能、敏捷开发模式新增估算板块和两种估算方式。 功能点锁定功能进一步提高了项目估算的灵活性和准确性&#xff0c;有利于提高项目估算效率&#xff1b;而敏捷开发…

JAVA面经整理(8)

一)为什么要有区&#xff0c;段&#xff0c;页&#xff1f; 1)页是内存和磁盘之间交互的基本单位内存中的值修改之后刷到磁盘的时候还是以页为单位的索引结构给程序员提供了高效的索引实现方式&#xff0c;不过索引信息以及数据记录都是记录在文件上面的&#xff0c;确切来说是…

六、互联网技术——数据存储

文章目录 一、存储系统层次结构二、按照重要性分类三、磁盘阵列RAID三、RAID基础四、磁盘阵列分级五、数据备份与恢复六、容灾与灾难恢复 一、存储系统层次结构 常见的三层存储体系结构如下图所示&#xff0c;分为高速缓冲存储器、主存储器和外存储器。 二、按照重要性分类 …

Android自定义Drawable---灵活多变的矩形背景

Android自定义Drawable—灵活多变的矩形背景 在安卓开发中&#xff0c;我们通常需要为不同的按钮设置不同的背景以实现不同的效果&#xff0c;有时还需要这些按钮根据实际情况进行变化。如果采用编写resource中xml文件的形式&#xff0c;就需要重复定义许多只有微小变动的资源…

【LeetCode热题100】--34.在排序数组中查找元素的第一个和最后一个位置

34.在排序数组中查找元素的第一个和最后一个位置 二分查找中&#xff0c;寻找 leftIdx 即为在数组中寻找第一个大于等于 target 的下标&#xff0c;寻找 rightIdx 即为在数组中寻找第一个大于 target 的下标&#xff0c;然后将下标减一。进行两次查找 class Solution {public …

43 验证二叉搜索树

验证二叉搜索树 理解题意&#xff1a;验证搜索二叉树&#xff1a;中序遍历是升序题解1 递归&#xff08;学习学习&#xff01;&#xff09;题解2 中序遍历&#xff08;保持升序&#xff09; 给你一个二叉树的根节点 root &#xff0c;判断其是否是一个 有效的二叉搜索树。 有…

Flutter项目安装到Android手机一直显示在assembledebug

问题 Flutter项目安装到Android手机一直显示在assembledebug 原因 网络不好&#xff0c;gradle依赖下载不下来 解决方案 修改如下的文件 gradle-wrapper.properties 使用腾讯提供的gradle镜像下载 distributionUrlhttps://mirrors.cloud.tencent.com/gradle/gradle-7.5…

mac openssl 版本到底怎么回事 已解决

在mac 安装node多版本的时候&#xff0c;有可能把原有的 openssl1.1 版本 直接要再一次升级了&#xff0c;无奈的 php环境 编译器是 openssl 1.1 还是 3.0 &#xff0c;今天来个底朝天的找问题。 brew search openssl 有安装 三个版本。 但是错误提示 是第二个版本。 brew …

十月四日作业

1、服务器 头文件&#xff1a; #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTcpServer> //服务器头文件 #include <QTcpSocket> //客户端头文件 #include <QList> //链表容器 #include <…

传输层协议—TCP协议

传输层协议—TCP协议 文章目录 传输层协议—TCP协议TCP协议段格式四位首部长度TCP协议如何根据目的端口号将数据传输给指定进程&#xff1f;32位序列号和32位确认序列号可靠性问题 TCP报头标志位16位紧急指针16位检验和确认应答机制超时重传机制再谈三次握手四次挥手 连接管理机…

什么是数学建模(mooc笔记)

什么是数学建模 前提&#xff1a;我们数学建模国赛计划选择C题&#xff0c;故希望老师的教学中侧重与C题相关性大的模型及其思想进行培训。之后的学习内容中希望涉及以下知识点&#xff1a; logistic回归相关知识点。如&#xff1a;用法、适用、限制范围等。精学数学建模中常…