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

这篇具有很好参考价值的文章主要介绍了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_OBJECT

public:
    ...
    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 的流量。

后续在测试的过程中还发现了其他的一些问题,比如花屏问题,也找了一些其他的库做了对比,下一节再来展开看看。文章来源地址https://www.toymoban.com/news/detail-788510.html

到了这里,关于QTAV的编译、使用及遇到的问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Qt Qml 多媒体播放视频(MediaPlayer)遇到的问题及解决方法

    Qml 多媒体播放视频开发过程中遇到的问题,记录一下。 创建的Qt Quick Ui Prototype工程,视频播放正常。但是相同的代码在Qt Quick Application(compat)中却不能正常显示。 Qt Quick Ui Prototype目录结构 Qt Quick Application(compat) 目录结构 Qt Quick Ui Prototype 工程 这里没有什么需要注意的,按照

    2024年02月05日
    浏览(39)
  • QT中使用ffmpeg的api进行视频的播放

    在了解ffmpeg使用api进行视频的播放之前,我们首先了解一下视频的播放流程。 首先是我们最常见的视频文件,在播放流程中首先是要打开视频文件,将视频文件中的数据进行解封装,之后再将解封装之后的视频进行解码。解码之后的视频便是视频帧的数据,之后将视频帧数据

    2024年02月14日
    浏览(27)
  • QT ubuntu下开发视频播放 FFmpeg

    ubuntu 安装FFmpeg T113VideoDemo.pro mainwindow.h mainwindow.cpp

    2024年02月14日
    浏览(33)
  • Qt-FFmpeg开发-视频播放(5)

    目录 音视频/FFmpeg #Qt Qt-FFmpeg开发-视频播放【软/硬解码 + OpenGL显示YUV/NV12】 1、概述 2、实现效果 3、FFmpeg硬解码流程 4、优化av_hwframe_transfer_data()性能低问题 5、主要代码 5.1 解码代码 5.2 OpenGL显示RGB图像代码 6、完整源代码 更多精彩内容 👉个人内容分类汇总 👈 👉音视频开发

    2023年04月08日
    浏览(23)
  • Qt-FFmpeg开发-视频播放(4)

    更多精彩内容 👉个人内容分类汇总 👈 👉音视频开发 👈 最近研究了一下FFmpeg开发,功能实在是太强大了,网上ffmpeg3、4的文章还是很多的,但是学习嘛,最新的还是不能放过,就选了一个最新的ffmpeg n5.1.2版本,和3、4版本api变化还是挺大的; 在这个Demo里主要使用Qt + FFm

    2023年04月25日
    浏览(32)
  • Qt音视频开发38-ffmpeg视频暂停录制的设计

    基本上各种播放器提供的录制视频接口,都是只有开始录制和结束录制两个,当然一般用的最多的也是这两个接口,但是实际使用过程中,还有一种可能需要中途暂停录制,暂停以后再次继续录制,将中间部分视频不需要录制,跳过这部分不需要的视频,而且录制的视频文件

    2023年04月20日
    浏览(48)
  • FFMpeg-3、基于QT实现音视频播放显示

    1、音视频播放的基础知识 内容来自雷神博客 1、在Windows平台下的视频播放技术主要有以下三种:GDI,Direct3D和OpenGL;音频播放技术主要是DirectSound。 SDL本身并不具有播放显示的功能,它只是封装了底层播放显示的代码 记录三种视频显示技术:GDI,Direct3D,OpenGL。其中Direct3D包

    2024年02月03日
    浏览(47)
  • qt+ffmpeg 实现音视频播放(二)之音频播放

    通过  avformat_open_input () 打开媒体文件并分配和初始化  AVFormatContext   结构体。 函数原型如下: int avformat_open_input(AVFormatContext **ps, const char *url, AVInputFormat *fmt, AVDictionary **options); 参数说明: - `ps`:指向 `AVFormatContext` 结构体指针的指针,用于存储打开的媒体文件的信息。

    2024年04月22日
    浏览(40)
  • 项目实战——Qt实现FFmpeg音视频转码器

    本文记录使用 Qt 实现 FFmepg 音视频转码器项目的开发过程。 1、首先创建一个 Qt 项目,选择 MSVC2017 32bit 作为其编译器 2、将 FFmpeg 相关库及源文件拷贝到当前目录下 3、注释 prepare_app_arguments 函数(这里方便后面我们运行时可以指定相应的转码参数) 4、将所需的一些 dll 动态库

    2024年01月23日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包