QT商业播放器
QT商业播放器
总体架构图
架构优点:解耦,采用生产者消费者设计模式,各个线程各司其职,通过消息队列高效协作
这个项目是一个基于ijkplayer和ffplayer.c的QT商业播放器,
项目有5部分构成:
前端QT用户界面
后端是集成了ffplayer.c的类--播放的核心逻辑,
中间层有3个模块,一是ijkmp类-暴露给前后端向消息队列发消息,二是参考ijkplayer实现的单链表消息队列,三是用QThread启动的消息循环线程--循环取消息处理业务下面我来依次说明这些模块:
QT界面
用户界面设计
基本机制
利用QT的信号和槽函数机制,界面事件触发后向消息队列发送消息
- 界面元素事件绑定信号
- 信号绑定槽函数
- 槽函数向消息队列发送对应事件的消息,通知ffplay开始工作
- ffplay将视频画面回调到qt界面,声音回调到SDL音频播放流
- 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的绝对值
相关文章:
QT商业播放器
QT商业播放器 总体架构图 架构优点:解耦,采用生产者消费者设计模式,各个线程各司其职,通过消息队列高效协作 这个项目是一个基于ijkplayer和ffplayer.c的QT商业播放器, 项目有5部分构成: 前端QT用户界面 后端是集成了…...
Python的函数
近期遇到了一个没怎么看懂的Python函数的形式。 def twoSum(self, nums: List[int], target: int) -> List[int]: 后来上网查了资料。...
【物联网】STM32的中断机制不清楚?看这篇文章就足够了
在嵌入式系统中,中断是一种重要的机制,用于处理来自外部设备的异步事件。STM32系列微控制器提供了强大的中断控制器,可以方便地处理各种外部中断和内部中断。本文将详细介绍STM32中断的结构和使用方法。 文章目录 1. 什么叫中断2. 中断优先级…...
深入剖析红黑树:优雅地平衡二叉搜索树
目录 一.红黑树的概念二.插入操作三.与AVL树的比较 一.红黑树的概念 在之前的学习中,我们了解了二叉搜索平衡树,AVL树通过控制每个结点中的平衡因子的绝对值不超过1,实现了一个高性能的树。而相较于AVL的高度平衡,红黑树觉得AVL为…...
C10K问题:高并发模型设计
一、循环服务器模型 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <signal.h> #include <sys/types.h> #include <sys/socket.h> //*******// #include &l…...
哈希/散列--哈希表[思想到结构][==修订版==]
文章目录 1.何为哈希?1.1百度搜索1.2自身理解1.3哈希方法/散列方法1.4哈希冲突/哈希碰撞1.5如何解决?哈希函数的设计 2.闭散列和开散列2.1闭散列/开放定址法2.2开散列/链地址法/开链法1.概念2.容量问题3.字符串问题4.开散列性能测试5.开散列与闭散列比较 3.代码实现[配备详细…...
成都建筑模板批发市场在哪?
成都作为中国西南地区的重要城市,建筑业蓬勃发展,建筑模板作为建筑施工的重要材料之一,在成都也有着广泛的需求。如果您正在寻找成都的建筑模板批发市场,广西贵港市能强优品木业有限公司是一家值得关注的供应商。广西贵港市能强优…...
亨元模式 结构型模式之六
1.定义 享元模式是一种结构型设计模式, 它允许你在消耗少量内存的情况下支持大量对象。 2.滑滑梯问题 在说明亨元模式之前,我们先看看关于滑滑梯的程序设计。小区的楼下只有三个滑滑梯,但是想玩的小朋友却非常多。怎么设计计滑滑梯资源的管理…...
面试题: Spring中Bean的实例化和Bean的初始化有什么区别?
Spring中Bean的实例化和Bean的初始化有什么区别? 背景答案扩展知识什么是实例化什么是初始化 个人评价我的回答 背景 想换工作, 看了图灵周瑜老师的视频想记录一下, 算是学习结果的一个输出. 答案 Spring 在创建一个Bean对象时, 会先创建出一个Java对象, 会通过反射来执行…...
阻塞队列,生产者消费者模型
目标: 1. 认识与使用阻塞队列 2. 认识与实现消费者模型 目录 阻塞队列的特点 生产者消费者模型 生产者消费者模型的优点 阻塞队列实现该模型 阻塞队列的特点 1. 线程安全 2. 带有阻塞特性 (1)如果队列为空,继续出队列&a…...
【RCRL充放电时间相关计算】
一. 基础知识 L、C元件称为“惯性元件”,即电感中的电流、电容器两端的电压,都有一定的“电惯性”,不能突然变化。充放电时间,不光与L、C的容量有关,还与充/放电电路中的电阻R有关。RC电路的时间常数:τRC…...
C++ primer plus--输入、输出和文件
17 输入、输出和文件 17.1 C 输入和输出概述 C 把输入和输出看做字节流。输入时,程序从输入流中抽取字节;输出时,程序将字节插到输出流中。 缓冲区是内存中的临时存储区域,是程序与文件或其他 I/O 设备之间的桥梁。 17.2 使用…...
案例题--Web应用考点
案例题--Web应用考点 负载均衡技术微服务XML和JSON无状态和有状态真题 在选择题中没有考察过web的相关知识,主要就是在案例分析题中考察 负载均衡技术 应用层负载均衡技术 传输层负载均衡技术 就近的找到距离最近的服务器,并进行分发 使用户就近获取…...
MySQL的SQL 优化:提升数据库性能
1. 插入操作优化 1.1 使用多值插入 通常情况下,插入大量数据时,使用多值插入语句比逐行插入更高效。例如,将多个数据行打包成一个 INSERT 语句: INSERT INTO users (name, email) VALUES (Alice, aliceexample.com), (Bob, bob…...
【匠心打造】从0打造uniapp 可视化拖拽设计 c_o 第十篇
一、click one for uniapp置顶: 全部免费开源 (你商业用途也没关系,不过可以告诉我公司名或者项目名,放在官网上好看点。哈哈-_-) 二、写在之前 距离上一篇更新已经大约4个月了,公司的事情,自己的一些琐事一直没时间…...
BIT-5-操作符详解(C语言初阶学习)
1. 各种操作符的介绍。 2. 表达式求值 1. 操作符分类: 算术操作符 移位操作符 位操作符 赋值操作符 单目操作符 关系操作符 逻辑操作符 条件操作符 逗号表达式 下标引用、函数调用和结构成员 2. 算术操作符 - * / % 除了 % 操作符…...
【重拾C语言】三、分支程序设计(双分支和单分支程序设计、逻辑判断、多分支程序设计、枚举类型表示;典型例题:判断闰年和求一元二次方程根)
目录 前言 三、分支程序设计 3.1 判断成绩是否及格——双分支程序设计 3.2 成绩加上获奖信息—单分支程序设计 3.3 逻辑判断——布尔类型 3.4 获奖分等级——多分支程序设计 3.5 表示汽车种类——枚举类型 3.6 例题 3.6.1 例题——判断某个年份是否闰年 3.6.2 例题—…...
Shiro应用到Web Application
一、权限基础 a) 认证(你是谁?) 判断你(被认证者)是谁的过程。通常被认证者提供用户名和密码。 常见的认证包含如下几种: 匿名认证:允许访问资源,不做任何类型的安全检查。表单认证:访问资源之前,需要提…...
【POST请求-腾讯翻译君-爬虫案例】
原因:尝试多个在线翻译平台,由于返回数据存在加密原因(暂时不会解密),最总找到 ”腾讯翻译君“ 完成爬虫案例POST请求测试 案例测试网址 腾讯翻译 :https://fanyi.qq.com/ import requests import jsoncla…...
多卡片效果悬停效果
效果展示 页面结构 从页面的结构上看,在默认状态下毛玻璃卡片是有层次感的效果叠加在一起,并且鼠标悬停在卡片区域后,卡片整齐排列。 CSS3 知识点 transform 属性的 rotate 值运用content 属性的 attr 值运用 实现页面整体布局 <div …...
首饰饰品经营商城小程序的作用是什么
首饰如耳钉、戒指、手镯等除了高价值产品外,还有很多低价产品,市场需求客户众多,在实际经营中,商家们也会面临一些痛点。 私域话题越来越多加之线上线下同行竞争、流量匮乏等,更对商家选择自建商城经营平台。 通过【…...
华为OD机试真题【服务器能耗统计】
1、题目描述 【服务器能耗统计】 服务器有三种运行状态:空载、单任务、多任务,每个时间片的能耗的分别为1、3、4; 每个任务由起始时间片和结束时间片定义运行时间; 如果一个时间片只有一个任务需要执行,则服务器处于单任务状志; 如果一个时间片有多个任务需要执行,则服务器处于…...
ubuntu按下del却出现空格(命令行下键盘错乱)
问题: 有一天远程我的ubuntu 20.04,发现为何按 del 会产生空格后移的效果,up键也会重叠显示,首先感觉是这个远程软件有问题,于是又换了xshell,发现还是不行,只能打开积灰已久的笔记本࿰…...
Go开始:Go基本元素介绍
目录 标识符与关键字Go中的标识符Go关键字关键字示例 具名的函数常规函数代码示例 方法代码示例 高阶函数代码示例 匿名函数与Lambda表达式代码示例 闭包代码示例 具名的值变量基本数据类型复合数据类型指针类型 常量基本常量类型枚举常量常量表达式 定义类型和类型别名类型定义…...
十二、【漏洞复现】Rails任意文件读取(CVE-2019-5418)
十二、【漏洞复现】Rails任意文件读取(CVE-2019-5418) 12.1、漏洞原理 Ruby on Rails是一个使用 Ruby 语言写的开源 Web 应用框架,它是严格按照 MVC 结构开发的。它努力使自身保持简单,来使实际的应用开发时的代码更少,使用最少…...
【计算机视觉|人脸建模】学习从4D扫描中获取的面部形状和表情的模型
本系列博文为深度学习/计算机视觉论文笔记,转载请注明出处 标题:Learning a model of facial shape and expression from 4D scans 链接:Learning a model of facial shape and expression from 4D scans | ACM Transactions on Graphics Pe…...
【ADB】蓝牙总结
ADB 打开蓝牙关闭蓝牙打开Setting查看蓝牙地址查看蓝牙名称查看蓝牙是否开启车机蓝牙Setting配置路径wifi 打开蓝牙 adb root adb shell svc bluetooth enable 关闭蓝牙 adb root adb shell bluetooth disable 打开Setting adb shell am start -n com.android.settings/.S…...
嵌入式系统设计与应用---ARM处理器体系结构(学习笔记)
ARM处理器概述 Cortex-A8处理器工作模式 ps:除用户模式以外的其他模式被称为非用户模式或特权模式;除用户模式及系统模式以外的其他模式可称为异常模式 Cortex-A8存储器管理 ARM的基本数据类型 字节(Byte)&#…...
计算机竞赛 身份证识别系统 - 图像识别 深度学习
文章目录 0 前言1 实现方法1.1 原理1.1.1 字符定位1.1.2 字符识别1.1.3 深度学习算法介绍1.1.4 模型选择 2 算法流程3 部分关键代码 4 效果展示5 最后 0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 毕业设计 图像识别 深度学习 身份证识别…...
StarRocks数据导入
1、相关环境 Flink作为当前流行的流式计算框架,在对接StarRocks时,若直接使用JDBC的方式"流式"写入数据,对StarRocks是不友好的,StarRocks作为一款MVCC的数据库,其导入的核心思想还是"攒微批降频率&qu…...
湘潭做网站 z磐石网络/四川seo整站优化
一、使用MFC的CTime类来得到时间:CTime必须调用赋值函数,使用其静态函数来初始化例如:CTime time=CTime::GetCurrentTime();这样就可以直接调用time的内部方法得到你想要的当前的时间了。二、使用MFC的COleDateTime来得…...
在社保网站上怎么做员工的退费/搜索引擎网站优化推广
我在IE8浏览器里看学习视频,老是出现SyeFader:iexploerr.ese-应用程序错误。应用程序发生异常 未知的软件异常(0xc06d007e),位置为0x7c812fd3不知道如何解决,请高手帮忙,谢谢转载于:https://blog.51cto.com/8871829/14…...
什么是网络营销师/优化seo是什么
题意: 给出一个\(n(0 \leq n \leq 10^{12})\),问\(n\)个\(M\)形的折线最多可以把平面分成几部分。 分析: 很容易猜出来这种公式一定的关于\(n\)的一个二次多项式。 不妨设\(f(n)an^2bnc\)。 结合样例我们可以列出\(3\)个方程:\(f(…...
深圳外包企业网站/黑马培训机构可靠吗
很早以前就装了虚拟机,现在终于装上了Linux。虽然机子的配置还不错,虚拟机一般也不会特别卡,但是来回切换有时也是一件十分令人头疼的事情。虽然说不卡,但是CPU占用率还是很高的。也十分耗电。所以自从听说了有Xshell这个神器之后…...
建筑人才网 中高端招聘网站/全网整合营销公司
基于SSH的长途汽车票务售票系统的设计(Struts2,MySQL)(含录像)(毕业论文说明书14000字,程序代码,MySQL数据库)摘 要随着科学技术的不断提高,计算机科学日渐成熟,其强大的功能已为人们深刻认识,它已进入人类社会的各个领域并发挥着越来越重要…...
金华市网站建设/创建网站的流程是什么
1.表达的逻辑 2.思考的逻辑 3.解决问题的逻辑 4.演示的逻辑转载于:https://www.cnblogs.com/launhing/p/5587415.html...