2024-07-13 Qt6.5版本后视频渲染

文章目录

  • 前言
  • 一、先上代码
    • 1.将yuv/nv12等解码后的视频数据放入QVideoSink内
    • 2.将AVFrame数据保存进QVideoSink
    • 3.在qml中的显示
    • 4.同理,在widget中也可显示
  • 二、QVideoFarme支持的格式
  • 三、说说渲染效率问题


前言

Qt 6版本中,视频播放能力得到了质的飞越,相对于qt5,变化也很多,具体变化可以看官方说明 https://www.qt.io/blog/qt-multimedia-in-qt-6

在Qt5版本中,如果需要播放一个视频,由于后端的解码能力很弱,绝大多数需要写解码的代码,但是在Qt6中,后端加入了ffmpeg,解码已经不是我们所需解决的问题,Qt Multimedia 可以很好的去播放视频
但是,在项目中大家可能不止会播放本地视频,很多情况下需要播放在线视频,比较低延时的rtsp流,udp裸流等等。对于需要实时性高的同学来说,qt的后端能力还是没有做好。这时还是需要自己处理视频流。

在Qt5时代,要播放一个低延时视频流,通常是使用ffmpeg自己解封装,解码视频流后,再将yuv/nv12等视频数据交给qt去渲染,问题是qt渲染能力低,很早大家使用sdl等工具去渲染视频,但由于sdl和qt各自使用自己的渲染事件,常会导致闪烁等问题,后来开始使用opengl,手写shader自己处理yuv数据,这个方案确实可行,效率也很高,但是得学习opengl相关知识。

但到了Qt6,新的QVideoSink,完全具备各视频的渲染,yuv,nv12等常见格式一点都不在话下,而且支持多种渲染方式,比如opengl和d3d11,d3d9等等,它主要是使用了Qt6的QRHI技术,有兴趣的同学可以去了解了解。

我这里主要讲讲如何使用ffmpeg解码+QVideoSink进行视频渲染播放


一、先上代码

1.将yuv/nv12等解码后的视频数据放入QVideoSink内

class VideoSourceRenderer : public QObject
{Q_OBJECTQ_PROPERTY(QVideoSink* videoSink READ videoSink WRITE setVideoSink NOTIFY videoSinkChanged)public:VideoSourceRenderer(){}QVideoSink* videoSink() const{return m_videoSink.get();}void  setVideoSink(QVideoSink* videoSink){if (m_videoSink == videoSink)return;m_videoSink = videoSink;emit videoSinkChanged();}signals:void videoSinkChanged();
private:QPointer<QVideoSink> m_videoSink;QVideoFrameFormat    m_videoFrameFormat;
public:bool init(int width, int height,QVideoFrameFormat::PixelFormat fmt){QSize _size(width, height);m_videoFrameFormat = QVideoFrameFormat(_size, fmt);m_videoSink->setVideoFrame(m_videoFrameFormat);return true;}// 这里怎么操作都可以,只要将解码后的yuv或者nv12等格式的数据放入QVideoFrame内,再设置给videoSink即可bool draw(const unsigned char* y, int y_pitch, const unsigned char* u, int u_pitch,const unsigned char* v, int v_pitch) {bool        re = false;QVideoFrame frame(QVideoFrameFormat(QSize(m_width, m_height), m_videoFrameFormat.pixelFormat()));if (!frame.isValid() || !frame.map(QVideoFrame::WriteOnly)) {return false;}if (y && y_pitch > 0)memcpy(frame.bits(0), y, y_pitch * m_height);if (u && u_pitch > 0)memcpy(frame.bits(1), u, u_pitch * m_height / 2);if (v && v_pitch > 0)memcpy(frame.bits(2), v, v_pitch * m_height / 2);frame.setStartTime(0);frame.unmap();m_videoSink->setVideoFrame(frame);return re;}
};

2.将AVFrame数据保存进QVideoSink

我这里是从项目中摘出来的代码,如果有同学在使用中,可不必这样,原则上只是拷贝AVFrame的数据

class TiVideoEngineManager : public QObject{Q_OBJECT
public:Q_PROPERTY(VideoSourceRenderer* videoRenderer READ videoRenderer CONSTANT)TiVideoEngineManager(){m_videoRenderer = new VideoSourceRenderer();startTimer(1);}protected:void timerEvent(QTimerEvent* event) override{//Get AVFrame from ffmpeg decodec,AVFrame* frame = m_decodec.getFrame();if (frame && m_videoRenderer) {m_videoRenderer->draw(frame->data[0], frame->linesize[0], frame->data[1], frame->linesize[1],frame->data[2], frame->linesize[2]);}}private:VideoSourceRenderer* m_videoRenderer = nullptr;
};

3.在qml中的显示

在QML中,使用VideoOutput即可完美显示
在qml中时,需要提前进行注册TiVideoEngineManager ,VideoSourceRenderer 不然qml会无法访问

// in qml
VideoOutput {id:videoutputComponent.onCompleted: {//需要提前注册好TiVideoEngineManagerTiVideoEngineManager.videoRenderer.videoSink = videoutput.videoSink}
}

4.同理,在widget中也可显示

widget中我并未测试,但是QVideoWidget内也同样有videoSink,要在QVideoWidget显示视频,只需将yuv数据设置进videoSink后即可。

二、QVideoFarme支持的格式

可以查看官方手册https://doc.qt.io/qt-6/qvideoframeformat.html#PixelFormat-enum
它格式很多,不确实是否都可以使用,但是常见的yuv数据格式都是支持的

三、说说渲染效率问题

我在渲染YUV数据时,界面使用的是qml,会发现渲染会比纯使用opengl慢100ms,找了找发现,在Windows上,Qt6.5后,Qt整个界面的渲染默认是根据系统平台决定的,在win11上默认使用的是D3D11,这会导致QVideoSink也是使用D3D11进行yuv的渲染,在理想中,windows中d3d11渲染yuv视频应该会更快才对,但实际并没有。

在尝试将Qt整个界面的渲染改为Opengl后,整个渲染速度即可手写的opengl渲染速度一样。
所以我认为是Qt的RHI中,d3d11的视频渲染没有写好,在Qt官方提交过bug,官方人员只说是关注,不知道后续能不能解决

如果真的需要关心这100ms的渲染效率,可以尝试在main函数的第一行设置

QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL); 

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

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

相关文章

【JavaScript】 变量提升和函数提升

变量提升 1. 允许在变量声明之前即被访问。 2. 在代码执行之前&#xff0c;把当前作用域中var声明的变量全部提到当前作用域的最前面。 3. 只提升声明&#xff0c;不提升赋值。 function fn(){console.log(num)var num 10 } 相当于以下代码&#xff1a; function fn(){…

Tomcat底层原理

Tomcat是一个开源的Java Servlet容器&#xff0c;它实现了Java Servlet和JavaServer Pages (JSP) 技术&#xff0c;用于运行Java Web应用。它是由Apache软件基金会开发和维护的。以下是对Tomcat底层原理的详细解析&#xff1a; 1. 启动流程 Tomcat的启动流程主要分为以下几个…

【计算机毕业设计】013新闻资讯微信小程序

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

Python数据分析案例51——基于K均值的客户聚类分析可视化

案例背景 本次案例带来的是最经典的K均值聚类&#xff0c;对客户进行划分类别的分析&#xff0c;其特点是丰富的可视化过程。这个经典的小案例用来学习或者课程作业在合适不过了。 数据介绍 数据集如下: 客户的编码&#xff0c;性别&#xff0c;年龄&#xff0c;年收入&#…

Vue2-集成路由Vue Router介绍与使用

文章目录 路由&#xff08;Vue2&#xff09;1. SPA 与前端路由2. vue-router基本使用创建路由组件声明路由链接和占位标签创建路由模块挂载路由模块 3. vue-router进阶路由重定向嵌套路由动态路由编程式导航导航守卫 本篇小结 更多相关内容可查看 路由&#xff08;Vue2&#xf…

安全防御----防火墙综合实验2

安全防御----防火墙综合实验2 一、题目 二、实验要求&#xff1a; 1&#xff0c;DMZ区内的服务器&#xff0c;办公区仅能在办公时间内&#xff08;9&#xff1a;00 - 18&#xff1a;00&#xff09;可以访问&#xff0c;生产区的设备全天可以访问. 2&#xff0c;生产区不允许访…

雷赛运动控制卡编程(1)

一、运动控制卡选择 电气常用知识-CSDN博客 如下旋转控制卡 DMC3800八轴高性能点位卡 - 东莞市雅恰达机电有限公司 轴少的时候选择脉冲系列卡 轴多的话就选总线型系列控制卡 样品 架构&#xff1a; 二、 添加文件 dll 添加接口文件 【最全&#xff0c;带注释版】雷赛运动…

设置控件背景颜色

在Qt中&#xff0c;设置控件的背景颜色可以通过多种方式实现&#xff0c;但最常用的方法是使用QStyle、QPainter或QPalette。以下是几种设置控件背景颜色的方法&#xff1a; 使用setStyleSheet 对于大多数Qt控件&#xff0c;最简单的方法是使用setStyleSheet方法。这个方法允…

OpenCV中使用Canny算法在图像中查找边缘

操作系统&#xff1a;ubuntu22.04OpenCV版本&#xff1a;OpenCV4.9IDE:Visual Studio Code编程语言&#xff1a;C11 算法描述 Canny算法是一种广泛应用于计算机视觉和图像处理领域中的边缘检测算法。它由John F. Canny在1986年提出&#xff0c;旨在寻找给定噪声条件下的最佳边…

Python+wxauto=微信自动化?

Pythonwxauto微信自动化&#xff1f; 一、wxauto库简介 1.什么是wxauto库 wxauto是一个基于UIAutomation的开源Python微信自动化库。它旨在帮助用户通过编写Python脚本&#xff0c;轻松实现对微信客户端的自动化操作&#xff0c;从而提升效率并满足个性化需求。这一工具的出现&…

详细分析Sql Server中的declare基本知识

目录 前言1. 基本知识2. Demo3. 拓展Mysql4. 彩蛋 前言 实战探讨主要来源于触发器的Demo 1. 基本知识 DECLARE 语句用于声明变量 声明的变量可以用于存储临时数据&#xff0c;并在 SQL 查询中多次引用 声明变量&#xff1a;使用 DECLARE 语句声明一个或多个变量变量命名&a…

SpringBoot整合JAX-RS接口

目录 二、创建RESTful资源 三、注册JAX-RS资源 四、修改配置等信息 五、启动SpringBoot程序、访问服务 六、遇到的问题 七、与feign进行配合使用 1、接口定义 2、接口实现 3、注册资源 4、调用方web服务实现&#xff0c;跟注入普通服务一样 5、启动两个服务&#xff…

html5——表单

目录 表单基本结构 表单标签 常用表单元素 文本框 密码框 邮箱 单选按钮 复选框 文件域 隐藏域 列表框 多行文本域 lable标签 表单按钮 常用表单属性 只读与禁用 placeholder required pattern autofocus autocomplete 用于指定表单是否有自动完…

NoSQL之redis的配置与优化

一、redis数据库的基础介绍与对比 Redis(RemoteDictionaryServer&#xff0c;远程字典型)是一个开源的、使用C语言编写的NoSQL数据库。Redis 基于内存运行并支持持久化&#xff0c;采用 key-value(键值对)的存储形式&#xff0c;是目前分布式架构中不可或缺的一环。 1.非关系…

昇思25天打卡营-mindspore-ML- Day23-应用实践-RNN实现情感分类

学习了关于 RNN 算法及其应用。RNN&#xff0c;即循环神经网络&#xff0c;是一种专门用于处理序列数据的神经网络。其基本原理是通过循环连接&#xff0c;让网络能够记住之前的输入信息&#xff0c;并将其用于后续的计算&#xff0c;从而捕捉序列数据中的时间依赖关系。 RNN …

百日筑基第二十天-一头扎进消息队列3-RabbitMQ

百日筑基第二十天-一头扎进消息队列3-RabbitMQ 如上图所示&#xff0c;RabbitMQ 由 Producer、Broker、Consumer 三个大模块组成。生产者将数据发送到 Broker&#xff0c;Broker 接收到数据后&#xff0c;将数据存储到对应的 Queue 里面&#xff0c;消费者从不同的 Queue 消费数…

我的智能辅助大师-办公小浣熊

一、基本介绍 随着2022年ChatGPT为代表的AI工具对互联网领域进行第一次冲击后&#xff0c;作为一名对编程领域涉足不算特别深的一名程序员&#xff0c;对AI大模型的接触也真的不能算少了&#xff0c;这是时代的必然趋势。在此之前也曾接触过很多的AI工具&#xff0c;他们都能在…

【Vscode】显示多个文件 打开多个文件时实现标签栏多行显示

Vscode显示多个文件&VSCode打开多个文件时实现标签栏多行显示 写在最前面一、解决打开文件的时候只显示一个tab的办法解决办法如下&#xff1a; 二、文件标签栏多行显示设置步骤&#xff1a; &#x1f308;你好呀&#xff01;我是 是Yu欸 &#x1f30c; 2024每日百字篆刻时…

Service Mesh 是一种用于处理服务间通信的基础设施层

Service Mesh 是一种用于处理服务间通信的基础设施层&#xff0c;它通常与微服务架构一起使用&#xff0c;以提供诸如服务发现、负载均衡、熔断、监控、追踪和安全性等功能。Service Mesh 的一个流行实现是 Istio&#xff0c;它基于 Envoy 代理和 Kubernetes。 然而&#xff0…

电脑维护全攻略:让你的“战友”焕发新生

目录 电脑维护全攻略&#xff1a;让你的“战友”焕发新生 引言 方向一&#xff1a;了解你的“战友” 1.1 电脑品牌与型号的选择 1.2 电脑硬件配置的重要性 1.3 电脑软件配置的重要性 方向二&#xff1a;日常维护措施 2.1 定期清理与优化 2.2 保持良好的上网习惯 2.3 …