QTAV的编译、使用及遇到的问题

最近有个功能需求,界面可以直播显示某个特定摄像头的实时画面,通过对Qt本身的 QMiediaPlayer,和其他一些在网上找到的组件做了一些对比,最终选择了QtAv作为我们的组件使用。

QtAV 是一个基于 Qt 和 FFmpeg 的跨平台、高性能多媒体播放框架。

一、QtAV的编译

从 Github 上下载到的是 QtAV 的源码,或者说由于每个开发者使用的 VS 或者 Qt 版本的不同,从而迫使我们不得不自己手动对 QtAV 进行编译,而 QtAV 的编译过程相对来说是非常简单的。

  1. 下载编译依赖组件

    因为 QtAV 是一个基于 Qt 和 FFmpeg 的跨平台多媒体播放器,所以在编译 QtAV 之前,需要我们下载一些依赖的组件。

    对于 FFmpeg, 可以选择下载其源码并自己构建。

    也可以选择直接下载已经构建好的组件。对于 windows 的用户,可以选择下载文件。 QtAV-depends-windows-x86+x64.7z

    为了方便,我这边是选择下载已经编译好的组件版本。

  2. 下载QtAv源码

    QtAV 的源码在 GitHub 上可以直接下载。

  3. 编译

    编译之前,我们需要将下载下来的 QtAV 依赖的组件进行引用,因为我们需要使用 QtCreator 编译 QtAv,所以,首先需要将 QtAV-depends-windows-x86+x64.7z 解压缩之后的文件夹中的 lib 和 include 文件夹拷贝到你本地 Qt 对应的目录下。

    需要注意的是,需要对应编译的版本,比如,我用的 msvc2017_64 编译,所以对应的就需要拷贝到下面的路径 D:\Qt\Qt5.12.5\5.12.5\msvc2017_64\include。也可以不进行拷贝,而是通过修改构建环境里面的INCLUDE和LIB的值进行对应的添加,这边需要注意的是,一定要注意是32位还是64位

    拷贝完成之后,直接用 QtCreator 打开 QtAV 源码中的 QtAV.pro 文件,右键构建即可,等待编译完成。

    编译完成之后,在编译路径下面 lib_win_x86_64 文件夹下面会生成需要的 dll 和 lib 文件,如果以后需要方便的使用,则可以双击编译路径下面的 sdk_install.bat 文件,该文件的作用是,将编译生成的动态库、静态库已经头文件全部复制到编译 QtAV 对应的 Qt 目录下,这样,以后在使用的时候,直接在 pro 文件中引入 QtAV 模块即可。QT += av avwidgets

    如果使用 VS + QT 开发环境,也可以直接使用,或者将对应的库文件拷贝使用。
    相应的 sdk_uninstall.bat 文件会删除拷贝的文件。

二、QtAv的使用

为了方便,我对多媒体播放的部分进行了简单的封装。提供了一些简单的接口,以便外部的调用,而这个程序因为比较简单,所以我用了一个按钮来控制视频的播放和暂停。并且使用了 hideEvent 来作为 stop 的信号。

class AvMediaWidget : public QWidget
{Q_OBJECTpublic:...void setSource(const QString& source);void pause(const bool pause);void stop();void start();protected:virtual void enterEvent(QEvent *event) override;virtual void leaveEvent(QEvent *event) override;virtual void hideEvent(QHideEvent *event) override;
private:void initPage();private:Ui::AvMediaWidget *ui;QtAV::AVPlayer* m_player{ nullptr };QtAV::WidgetRenderer* m_renderer{ nullptr };QString m_source{ QString() };
};

首先,直接 new 一个 AVPlayer 的对象,因为我没有用到Video,所以也就用可一个简单的 WidgetRenderer 作为 player的载体,如果需要做视频播放器的话,可以使用 VideoWidget 类。

void AvMediaWidget::initPage()
{m_player = new AVPlayer();m_renderer = new WidgetRenderer();Widgets::registerRenderers();ui->verticalLayout->addWidget(m_renderer);m_renderer->show();m_player->setRenderer(m_renderer);m_player->setBufferMode(QtAV::BufferBytes);m_player->setBufferValue(1024);...
}

紧接着,我用了一个QPushButton,这个按钮的功能主要是用来控制播放的播放、暂停。样式了,就好比是我们经常看视频时点了暂停的那样。

{auto btn = new QPushButton(this);auto layout = new QHBoxLayout(this);btn->setProperty("type", "player");layout->addWidget(btn);layout->setContentsMargins(15, 0, 0, 0);m_renderer->setLayout(layout);connect(btn, &QPushButton::clicked, this, [this](){if (!m_player->isPlaying()){start();auto btn = static_cast<QPushButton*>(sender());if (btn == nullptr){return;}btn->setVisible(false);return;}m_player->pause(!m_player->isPaused());auto btn = static_cast<QPushButton*>(sender());if (btn == nullptr){return;}btn->setProperty("status", m_player->isPaused() ? "player-start" : "player-stop");this->style()->unpolish(btn);this->style()->polish(btn);});...
}

下面是为了在刚开始或者是停止播放之后,使得界面上会一直存在一个 start 的三角形,所以,对按钮进行了样式表的设置。

 {connect(m_player, &AVPlayer::stopped, this, [this]() {auto btn = m_renderer->findChild<QPushButton*>();if (btn == nullptr){return;}btn->setProperty("status", "player-start");btn->setVisible(true);this->style()->unpolish(btn);this->style()->polish(btn);});
}

而我们希望在播放的过程中,不能有一个按钮影响观感,所以,用了下面两个函数,来控制按钮的显示和隐藏以及根据当前播放器的状态进行样式表的设置。

void AvMediaWidget::enterEvent(QEvent *event)
{if (!m_player->isPlaying()){return;}auto btn = m_renderer->findChild<QPushButton*>();if (btn == nullptr){return;}btn->setVisible(true);btn->setProperty("status", m_player->isPaused() ? "player-start" : "player-stop");this->style()->unpolish(btn);this->style()->polish(btn);
}
void AvMediaWidget::leaveEvent(QEvent *event)
{if (!m_player->isPlaying() || m_player->isPaused()){return;}auto btn = m_renderer->findChild<QPushButton*>();if (btn == nullptr){return;}btn->setVisible(false);
}

三、遇到的问题

1、 VS + QT 环境中报错

因为我使用的开发环境是 VS + QT 的,所以,我在使用的过程中需要将编译好的库文件拷贝到我对应的工程下面,并进行引用。

而在我的测试工程中,发现一个很有意思的事情,就是 Debug 模式下, 一切正常,但只要一切到 Release 版本,通过单步调试,发现,只要执行

m_renderer = new WidgetRenderer();

软件必崩,并且伴随报错 QWidget: Must construct a QApplication before a QWidget

这个错误消息,一般对应着两种情况:

  1. 就是在 main.cpp 执行 QApplication a(argc, argv); 之前就已经有 QWidget 对象被构建了,这主要体现在一下 static QWidget

  2. 很简单,就是 Debug 和 Release 版本对不上,也就是混用了

很明确的是我知道我的整个工程里面是没有静态的 QWidget 的,那么就只剩下第二种一种情况了,就是 Debug 和 Release 版本混用了。为了验证问题,我排查了好几遍,甚至写了有一个 QtCreator 的工程去验证了了下是不是编译库文件的问题,结果没问题。

也找了很多的信息,反正就是只要一起,就崩。debug就是没问题。

也不知道什么时候,突然想起来,既然我现在能保证我所有的 VS 的配置是正确的,但是 VS 是有 Qt 的,那么这个Qt的配置是不是正确的,检查发现,果然,我在VS的release下面配的Qt是debug的。

一个很简单的问题,却耗费了我大半个下午的时候去排查问题。而我们经常会忽略这些很小的细节,以至于多花费更多的精力和时间。

2、rtsp 服务的拉流总是会失败

测试的过程中发现,用 rtmp 服务拉流是没问题的,但是拉取 rtsp 服务的流的时候总是拉不下来,然后我用前面下载下来的 ffmpeg 单独做了一组测试。

ffplay.exe rtsp://.... 
ffplay.exe rtmp://ns8.indexforce.com/home/mystream
ffplay.exe -rtsp_transport tcp rtsp://.... 

发现,后面两种情况是可一的。那么,问题就是该找找要怎样去设置当需要拉取 rtsp 服务流的时候,使用 tcp 去拉。

后来没发现,就改了一下源码,进行重编译。

在 QtAV 的源码中找到 AVDemuxer.cpp 文件,在该文件

void checkNetwork() {// FIXME: is there a good way to check network? now use URLContext.flags == URL_PROTOCOL_FLAG_NETWORK// not network: concat cache pipe avdevice crypto?if (!file.isEmpty()&& file.contains(QLatin1String(":"))&& (file.startsWith(QLatin1String("http")) //http, https, httpproxy|| file.startsWith(QLatin1String("rtmp")) //rtmp{,e,s,te,ts}|| file.startsWith(QLatin1String("mms")) //mms{,h,t}|| file.startsWith(QLatin1String("ffrtmp")) //ffrtmpcrypt, ffrtmphttp|| file.startsWith(QLatin1String("rtp:"))|| file.startsWith(QLatin1String("rtsp:"))|| file.startsWith(QLatin1String("sctp:"))|| file.startsWith(QLatin1String("tcp:"))|| file.startsWith(QLatin1String("tls:"))|| file.startsWith(QLatin1String("udp:"))|| file.startsWith(QLatin1String("gopher:")))) {network = true;}
}

方法末尾增加下面代码,告诉,如果是 rtsp 服务,则使用 TCP 方式。

if(file.startsWith(QLatin1String("rtsp:")))options[QStringLiteral("rtsp_transport")]=QStringLiteral("tcp");

3、rtsp 测试地址太少了

基本上在网上能找到的能够正常测试的 rtsp 地址都已经不能用了,要怎么办呢?

访问 rtsp 的 官网。
拉到最下方,在 free 区域下面点击 Get Started 按钮,在接下来的界面中输入可用的邮箱,rtsp 会发送一封邮件,打开邮件中的地址,会生成两条可测试的 rtsp 流地址,并且每个月有 2G 的流量。

后续在测试的过程中还发现了其他的一些问题,比如花屏问题,也找了一些其他的库做了对比,下一节再来展开看看。

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

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

相关文章

CSAPP - string_length反汇编

虽然先前已经把 phase_1 和 phase_2 做出来了&#xff0c; 但其实是参考了网络上的答案&#xff0c; 仅仅是大概知道了关键汇编代码。但其实并没有真的懂。为啥呢&#xff1f;因为很多模棱两可的地方是靠猜测的&#xff0c;而猜测是脆弱的。 重新看 phase_1&#xff0c; 第一个…

用win系统搭建Minecraft世界服务器,MC开服教程,小白开服教程

雨云VPS用Windows系统搭建我的世界世界服务器&#xff0c;Minecraft开服教程&#xff0c;小白开服教程&#xff0c;MC 1.19.4版本服务器搭建教程。 此教程使用 Mohist 1.19.4 服务端&#xff0c;此服务端支持Forge模组和Bukkit/Spigot/Paper插件&#xff0c;如果需要开其他服务…

Linux 开启Swap交换内存

Linux 开启Swap交换内存 Linux 开启Swap交换内存 Linux 开启Swap交换内存 由于阿里云服务器内存空间有点小&#xff0c;但是又不能加内存&#xff0c;则想到使用Swap交换空间&#xff0c;用硬盘空间充当内存使用。 开启步骤&#xff0c;以4G为例&#xff1a; 1.创建交换文件…

K8S---kubectl top

一、简介 该命令类似于linux–top命令&#xff0c;用于显示node和pod的CPU和内存使用情况 二、命令行 /opt/kubernetes/bin/kubectl --kubeconfig /opt/kubernetes/conf/default-admin.kubeconfig top pod --help /opt/kubernetes/bin/kubectl --kubeconfig /opt/kube…

MySQL-索引回顾

索引是面试高频问答题&#xff0c;参考百度/CSDN/尚硅谷/黑马程序员/阿里云开发者社区&#xff0c;决定将索引知识回顾一下&#xff0c;忘记时&#xff0c;点开即可&#xff0c;时刻保持更新&#xff0c;事不宜迟&#xff0c;即刻享用。 索引概述 索引&#xff08;index&#…

transbigdata笔记:数据预处理

0 数据 使用 transbigdata/docs/source/gallery/data/TaxiData-Sample.csv at main ni1o1/transbigdata (github.com) 和transbigdata/docs/source/gallery/data/sz.json at main ni1o1/transbigdata (github.com) 0.1 导入库 import transbigdata as tbd import pandas …

VTK开发调试环境下载(VTK开发环境一步到位直接开发,无需自己配置编译 VS2017+Qt5.12.10+VTK)

一、无与伦比的优势 直接下载代码就可以调试的VTK代码仓库。 二、资源制作原理 这个资源根据VTK源码 编译出动态库文件 pdb lib dll 文件&#xff08; x64 debug &#xff09; 并将这两者同时放在一个代码仓库里&#xff0c;下载就能用。 三、使用方法&#xff08;vtk-so…

【Java代码审计】硬编码密码篇

【Java代码审计】硬编码密码篇 1.硬编码2.案例3.修复方案 1.硬编码 硬编码密码是指在系统中采用明文的形式存储密码&#xff0c;通常会导致严重的身份验证失败&#xff0c;这对于系统管理员而言可能很难检测到&#xff0c;一旦检测到&#xff0c;也很难修复。硬编码密码会造成…

使用rembg库提取图像前景(移除图像背景),并构建web应用

1、图像中的前景与背景 在深度学习图像处理领域中&#xff0c;图像内容可以被定义为前景与背景两部分&#xff0c;其中感兴趣图形的被定义为前景&#xff0c;不感兴趣区域的背景。如在目标检测中&#xff0c;被框出来的目标则被定义为前景。此外&#xff0c;前景识别也可以理解…

网络安全B模块(笔记详解)- nmap扫描渗透测试

nmap扫描渗透测试 1.通过BT5对服务器场景Linux进行TCP同步扫描 (使用工具Nmap,使用参数n,使用必须要使用的参数),并将该操作使用命令中必须要使用的参数作为Flag提交; Flag:sS 2.通过BT5对服务器场景Linux进行TCP同步扫描 (使用工具Nmap,使用参数n,使用必须要使用的参数…

oracle19c容器数据库data dump 数据泵传输数据(1)--pdb导pdb

目录 1.在pdb1创建实验环境 2.创建目标数据库pdb2 3.开始从pdb1全库导出 4.开始导入到pdb2 5. 解决报错&#xff1a;添加在pdb2添加users表空间 我們要記住一点&#xff1a;如果是全库导出导入的话&#xff0c;目标数据库没有的表空间我们要事先创建&#xff1a;不然就会导…

网工内推 | 高级网工,H3C认证优先,朝九晚六,周末双休

01 万德 招聘岗位&#xff1a;高级网络工程师 职责描述&#xff1a; 1、项目交付&#xff1a;项目管理和交付&#xff0c;包括项目前期的规划、实施以及后期的运维支持、项目验收等。 2、技术支持&#xff1a;为客户及合作伙伴提供网上问题远程和现场支持&#xff1b;对公司内…

移动通信系统关键技术多址接入MIMO学习(8)

1.Multiple-antenna Techniques多天线技术MIMO&#xff0c;从SISO到SIMO到MISO到如今的MIMO&#xff1b; 2.SIMO单发多收&#xff0c;分为选择合并、增益合并&#xff1b;SIMO&#xff0c;基站通过两路路径将信号发送到终端&#xff0c;因为终端接收到的两路信号都是来自同一天…

旋转的表示

欢迎访问我的博客首页。 旋转的表示 1.旋转轴的性质2.罗德里格斯公式3.右雅可比矩阵 三维空间内的旋转可以由三维旋转向量 n θ \bm n \theta nθ 表示。其中&#xff0c;单位向量 n \bm n n 表示旋转轴&#xff0c; θ \theta θ 表示旋转角度。旋转向量由一个轴和一个角表示…

大模型训练营Day3 基于 InternLM 和 LangChain 搭建你的知识库

本次的授课人是一个提示词开发项目的负责人。下面一起进入本期课程吧》 本次课程内容主要如下&#xff1a; 开篇交代了大模型的局限性&#xff0c;然后引出主题&#xff1a; 简单总结&#xff0c;大模型是根据数据集训练&#xff0c;很难使用具有实时性的数据进行重新训练&am…

Hana 实时数据同步优化(3)

简述 CloudCanal 近期对 Hana 源端链路做了新一轮优化&#xff0c;优化点主要来自用户实际场景使用&#xff0c;这篇文章简要做下分享。 本轮优化主要包含: 新增任务级增量表新增增量表定时清理能力新增增量表表结构自动演进能力任务延迟判定优化Hana 1.x 的兼容产品化和文档…

Oracle数据库19c OCP 1z0-082考场真题解析第24题

考试科目&#xff1a;1Z0-082 考试题量&#xff1a;90 通过分数&#xff1a;60% 考试时间&#xff1a;150min 本文为云贝教育郭一军guoyJoe原创&#xff0c;请尊重知识产权&#xff0c;转发请注明出处&#xff0c;不接受任何抄袭、演绎和未经注明出处的转载。【云贝教育】Orac…

玻璃酒瓶市场分析:行业仍呈现长期向好的发展势头

玻璃工艺酒瓶的外表可以让别人领略到中国酒文化的艺术价值。在这些玻璃上&#xff0c;风景、人物、动物、书法艺术等图案记载着酒的历史、典故、产地等信息&#xff0c;此外青花、粉彩、素釉、斗彩、珐琅彩和五彩等瓷艺无所不包&#xff0c;算得上是现代藏品中的"古玩会&q…

X3En【禾川】

地址: P9-00 波特率:【005】 DI: P4.0 滤波【微秒us】P4.1 DI1【1】使能 P4.2 DI2【2】复位 P4.3 DI3【13】禁止脉冲 P4.4 DI4【5】 P4.5 DI5【25】 P4.6 DI6【14】 P4.7 DI7【15】 P4.8 DI8【0】 P4.9 DI9【0】P4.11 DI1【逻辑】0低电…

Nacos:微服务架构的得力助手

Nacos是一个开源的、易于使用的平台&#xff0c;用于构建云原生应用和微服务架构。它提供了一系列关键功能&#xff0c;帮助开发者更高效地管理和协调微服务。 一、Nacos的功能 1. 服务发现&#xff1a;在微服务架构中&#xff0c;服务的网络位置是动态变化的。Nacos通过服务注…