Qt/C++开发经验小技巧311-315

  1. 关于流媒体推拉流延时的几点说明。
  • 经常看到一些流媒体相关的程序,号称零延迟,不用怀疑,这肯定吹牛逼的。
  • 搞音视频开发,有个核心的指标就是实时性,也就是延迟多少毫秒,这个问题问的也是最多的。
  • 音视频文件几乎不存在实时性问题,只有音视频流才有实时性的指标。
  • 延迟多久这个涉及到很多方面,也要看你如何计算,从推流开始计算还是从拉流开始计算。
  • 很多小伙伴们并不能明白什么叫延时,认为随便一个播放器播放出来的画面跟原始流画面时间差就是延时,其实这是对延时最大的误解。延时不是表象,很多人在测试延时时很不专业,对延时测试的专业性认识不足。
  • 下面整理的是zlm作者写的关于延时的文章,非常完整而且有代表性。
  • 采集延时:在采集摄像头或显卡画面时,由于fps的限制和cpu性能、内存拷贝速度等客观限制,采集画面成YUV/RGB等数据时会有一定的延时,一般延时为毫秒级别。由于一般编码器对输入数据格式存在限制,譬如要求统一输入YUV420P,这样在做RGB->YUV420P转换时,也会有转换计算延时(这个可以通过libyuv库来降低)。总而延时,采集延时大概为毫秒级别,如果fps为25,那么一般采集延时会有40毫秒(1000毫秒/25fps)以上的延时,在内存拷贝和颜色转换时,又可能增加若干毫秒的延时。
  • 编码延时:在把原始画面输入到编码器时,并不会立即输出编码后的数据,特别是在开启B帧时,由于需要参考后面的P帧,那么延时会更大,所以延时敏感的情况下一般不开启B帧,这种情况下编码延时应该是毫秒级别,不是很大。
  • 上行延时:编码后的数据,要经过一定的协议打包才能写入socket,然后传输给推流服务器或拉流代理服务器,协议打包会有一定的内存拷贝和计算量,那么会增加延时,不过这个延时很小,基本忽略不计。数据在上传到服务器时,这个延时可大可小,取决于网络质量。
  • 转换延时:服务器在收到数据后,要读socket缓存、协议解析、解复用、重新打包等操作,不过总体而言,这个延时比较小,基本没什么影响。有时,服务器为了提高性能,会采取合并写的机制,也就是收到一定量的数据后才会一并转发,这个延时一般为几百毫秒,ZLMediaKit默认300毫秒左右,不过ZLMediaKit默认关闭合并写,也就是这个延时也很小。
  • 下行延时:流媒体在把视频数据转发给播放器时,会存在网络发送,这个延时大小取决于网络质量,ZLMediaKit在关闭低延时模式时,还会增加MSG_MORE和关闭TCP_NODELAY导致的延时,不过ZLMediaKit默认开启低延时模式。
  • 播放延时:播放器延时主要有网路接收延时、协议解析解复用延时、解码延时、缓存延时、渲染延时组成,这些延时中缓存延时最大,因为一般的播放器为了保证在网络抖动情况下视频播放的流畅性,会以增加延时为代价,增加播放缓存,这样在网络变差时,不至于播放缓冲卡顿。而且为了音视频同步,也必须确保一定的缓存量。这种延时一般都是秒级别,一般5秒左右。有部分播放策略是接收到数据后立即解码显示比如rtsp视频流,这样可以做到延迟最小。
  • 缓存延时:流媒体服务器为了能让播放器立即出画面,往往会缓存最近的一个I帧,这个I帧往后的所有音视频数据被称作为GOP缓存。如果不缓存GOP,那么播放器要等下一个I帧才能解码成功或不花屏,显然为了提高播放体验,这个GOP缓存是不能去掉的。而一般GOP短则1~3秒,长则10几秒,这个跟采集端编码器设置有关,服务器改变不了。但是由于一般的播放器收到缓存后,并不会丢弃过多的画面来确保低延时。况且播放器还希望有一定的缓存来确保播放的流畅性,所以这个GOP缓存将会增大播放器的延时。
  • 综合延时:最快可以做到200-300ms的延迟,比如rtsp视频流,对实时性要求高,可以不做缓存和音视频同步,收到就立即解码播放。hls一般最快可以做到5s延迟,flv一般可以做到3s延迟。
  • 最终总结:综合考虑实时性以及支持的音视频格式,个人建议,推流用rtsp推流(支持的音视频格式最友好,比如支持265),拉流在web上个人推荐用ws-flv格式拉流(支持的格式多,没有6个同源的限制),拉流在可执行文件上用rtsp(格式多而且实时性最好,可以最快速度解码播放),在网页上虽然webrtc实时性最好,但是不支持265,这个就难搞。
  1. Qt自带的对话框的按钮设置中文。
//信息框设置中文
QMessageBox dialog(QMessageBox::Question, "询问", text);
dialog.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
dialog.button(QMessageBox::Yes)->setText("确 定");
dialog.button(QMessageBox::No)->setText("取 消");
return dialog.exec();//输入框设置中文
QInputDialog dialog;
dialog.setOkButtonText("确定");
dialog.setCancelButtonText("取消");
return dialog.exec();//对话框设置中文
QFileDialog dialog;
dialog.setOption(QFileDialog::DontUseNativeDialog, true);
QLabel *lookinLabel = dialog.findChild<QLabel*>("lookInLabel");
lookinLabel->setText("文件目录:");
  1. 有时候需要对树状节点进行搜索过滤显示,匹配到的节点显示,没有匹配的隐藏。这个功能很多地方用,封装了一个静态函数直接调用。
//调用方法 QtHelper::search(ui->treeWidget, "测试", 5);
void QtHelper::search(QTreeWidget *treeWidget, const QString &key, int level)
{//找到所有匹配的节点QList<QTreeWidgetItem *> items = treeWidget->findItems(key, Qt::MatchContains | Qt::MatchRecursive);//将匹配到的节点加入队列/该节点的父节点也相当于匹配/不然父节点隐藏子节点也会跟着隐藏QList<QTreeWidgetItem *> itemAll;foreach (QTreeWidgetItem *item, items) {//当前节点的所有父节点也添加进去/几次循环相当于几个层级for (int i = 0; i < level; ++i) {//去重添加if (!itemAll.contains(item)) {itemAll << item;}//为空表示没有父节点则跳出循环item = item->parent();if (!item) {break;}}}//遍历所有节点/匹配的节点显示否则隐藏QTreeWidgetItemIterator it(treeWidget);while (*it) {(*it)->setHidden(!itemAll.contains(*it));++it;}
}
  1. 在Qt中实现组播是非常容易的事情,从4.8开始支持组播,为啥要用组播而不是广播?因为广播会产生广播数据风暴,每个设备都会收到,而且针对某个网段的广播比如192.168.0.255,不能跨网段。而组播不仅可以跨网段,还不会出现数据风暴,只对加入了组播的目标进行数据发送,非常适合用来做局域网设备搜索和配置。在测试过程中,如果是两台真机之间测试组播,没有问题,但是很多时候开发机只有一台,最多就是在开发机上安装了虚拟机,可以有多个系统可以测试,那么问题来了,虚拟机之间的组播需要经过设置才能正常通信。第一点就是虚拟机的网络必须是桥接模式,也就是网络地址和宿主主机同一网段。第二点最关键,需要在两个虚拟机产生的网卡设备(VMware Network Adapter VMnet1/VMware Network Adapter VMnet8)右键属性进去设置,在此连接使用下列项目中勾选一个VMware Bridge Protocol确定,重启网卡即可。
//绑定端口
udpSocket->bind(QHostAddress("0.0.0.0"), 6789);
//设置组播数据不给自己发送/一般都会有这个设置/防止数据又发给自己造成死循环
udpSocket->setSocketOption(QAbstractSocket::MulticastLoopbackOption, 0);
//加入组播地址
udpSocket->joinMulticastGroup(QHostAddress("224.0.0.10"));
//往组播发送数据
udpSocket->writeDatagram("hello", QHostAddress("224.0.0.10"), 6789);
//接收数据和UDP接收数据处理完全一致
  1. 在Qt中结构体数据也是可以保存到ini配置文件,只不过保存后的数据是一堆qbytearray之类的字符,所以如果可读性优先,建议不要存储结构体数据,最起码也要是格式化后的结构体数据存储进去。要想用QSettings保存结构体数据,必须在结构体中重载实现输入输出数据流。
struct ClientConfig {int tabIndex;    QString serverInfo;  //重载数据流输出friend QDataStream &operator << (QDataStream &out, const ClientConfig &clientConfig) {out << clientConfig.tabIndex;        out << clientConfig.serverInfo;        return out;}//重载数据流输入friend QDataStream &operator >> (QDataStream &in, ClientConfig &clientConfig){in >> clientConfig.tabIndex;        in >> clientConfig.serverInfo;        return in;}
};//必须加上下面这句用来注册元数据类型,不然报错
//error: static assertion failed: Type is not registered, please use the Q_DECLARE_METATYPE macro to make it known to Qt's meta-object system
Q_DECLARE_METATYPE(ClientConfig)//定义
ClientConfig clientConfig;//读取
set.beginGroup("ClientConfig");
clientConfig = set.value("clientConfig").value<ClientConfig>();
set.endGroup();//写入
set.beginGroup("ClientConfig");
set.setValue("clientConfig", QVariant::fromValue(clientConfig)); 
set.endGroup();

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

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

相关文章

windows-web1

windows-web1 挑战内容 前景需要: 小李在值守的过程中,发现有CPU占用飙升,出于胆子小,就立刻将服务器关机,并找来正在吃苕皮的hxd帮他分析,这是他的服务器系统,请你找出以下内容,并作为通关条件: 1.攻击者的shell密码 2.攻击者的IP地址 3.攻击者的隐藏账户名称 4.攻击…

CF708E Students Camp

先设 \(D(i)\) 表示 \(k\) 次吹风中 \(i\) 次成功吹在特定行的概率,有 \[D(i)={k \choose i}p^i(1-p)^{k-i} \]设 \(P(l,r)\) 表示某一行只剩下 \((l,r)\) 的砖块的概率,由于左右两边显然独立,于是我们有: \[P(l,r) =D(l-1)D(m-r) \]再设 \(f(i,l,r)\) 表示第 \(i\) 行剩下…

2025.3.27 鲜花

如何优雅的使用 stl如何优雅的使用 stl啥背景,杀乌鸡 ``` Viumbe vyote vya mungu wetu na mfalme wetu Pazeni sauti ili nasi mwimbe Pazeni sauti ili nasi mwimbe Pazeni sauti Pazeni sauti Viumbe vyote vya mungu wetu na mfalme wetu Pazeni sauti ili nasi mwimbe Pa…

读DAMA数据管理知识体系指南32参考数据和主数据概念(下)

读DAMA数据管理知识体系指南32参考数据和主数据概念(下)1. 主数据 1.1. 主数据是有关业务实体(如雇员、客户、产品、金融结构、资产和位置等)的数据,这些实体为业务交易和分析提供了语境信息 1.2. 实体是客观世界的对象(人、组织、地方或事物等)​ 1.3. 实体被实体、实例…

Springboot3+Vue3实现JWT登录鉴权

做鉴权原因: 管理系统的数据是敏感的,隐私的,每个角色的权限是不同的,必须在数据的增删改查操作时候对访问的用户进行权限验证 JWT(Json Web Token) 用于在网络应用间安全的传递消息。它以紧凑且自包含的方式,通过JSON对象在各方之间传递经过验证的信息。JWT通常由三部分…

搜维尔科技:SenseGlove触觉反馈手套-自动化和培训的突破

触觉力反馈技术领导者SenseGlove和机器人操控创新者Aeon宣布推出HEART项目。此次合作将虚拟现实 、力反馈触觉手套(SenseGlove)和机器人系统(Aeon)集成在一起,以实现直观控制和实时力反馈,使机器人训练更加方便和有效。 自动化和培训的突破 由于产品需求不断变化以及机器…

搜维尔科技:Haption通用遥控控制器,可轻松集成到工业机器人控制中

TeleRobotics EXtender (TREX) 是一个专为力反馈远程操作而设计的框架。它为操作员必须在危险、具有挑战性或受限的环境中操作的情况提供了一种创新的解决方案,使他们能够在不暴露自己风险的情况下执行任务。借助 TREX,操作员可以手动控制远程机器人,具有很高的灵活性和精确…

Elasticsearch 的搜索功能

Elasticsearch 的搜索功能建议阅读顺序:Elasticsearch 入门 Elasticsearch 搜索(本文)1. 介绍 使用 Elasticsearch 最终目的是为了实现搜索功能,现在先将文档添加到索引中,接下来完成搜索的方法。 查询的分类:叶子查询:叶查询子句在特定字段中查找特定值,例如 match、t…

20242213 实验二《Python程序设计》实验报告

20242213 2024-2025-2 《Python程序设计》实验2报告 课程:《Python程序设计》 班级: 2422 姓名: 刘宗林 学号:20242213 实验教师:王志强 实验日期:2025年3月26日 必修/选修: 公选课 1.实验内容设计并编写一个计算器程序,实现基本运算功能;功能包括加、减、乘、除、取余…

《实战Java高并发程序设计(第3版)》 | PDF免费下载

《实战Java高并发程序设计(第3版)》主要介绍基于Java的并行程序设计基础、思路、方法和实战。第一,立足于并行程序基础,详细介绍Java并行程序设计的基本方法。第二,进一步详细介绍JDK对并行程序的强大支持,帮助读者快速、稳健地进行并行程序开发。第三,详细讨论“锁”的…

《DeepSeek原理与项目实战》 | PDF免费下载

DeepSeek 是一种基于 Transformer 架构的生成式 AI(Artificial Intelligence)大模型,融合了MoE 架构、混合精度训练、分布式优化等先进技术,具备强大的文本生成、多模态处理和任务定制化能力。本书系统性地介绍了开源大模型 DeepSeek-V3 的核心技术及其在实际开发中的深度应…

实现极限网关(INFINI Gateway)配置动态加载

还在停机更新 Gateway 配置,OUT 了。 今天和大家分享一个 Gateway 的功能:动态加载配置(也称热更新或热加载)。 这个功能可以在 Gateway 不停机的情况下更新配置并使之生效。 配置样例如下: path.data: data path.logs: logconfigs:auto_reload: true # set true to auto …