Qt6.9 是目前在线安装包能安装的最新完整版本,最近在用该版本开发一个音频播放器,遇到了声音异常的问题。为了探究问题的原因,这里结合不同Qt版本进行分析,最后给出解决方案。
1. 问题
1.1 源代码
在这里我构建一个简单的MainWindow案例,通过拖拽音频文件 (如mp3文件) 到软件上触发音频播放。首先,直接上完整代码,基于QMainWindow建立的三个文件:
- AudioPlayTest.h
#pragma once
#include <QtWidgets>
#include <QMediaPlayer>
#include <QAudioOutput>
#include <QtWidgets/QMainWindow>
#include "ui_AudioPlayTest.h"
class AudioPlayTest : public QMainWindow
{
Q_OBJECT
public:
AudioPlayTest(QWidget *parent = nullptr);
protected:
void dragEnterEvent(QDragEnterEvent* event) override;
void dropEvent(QDropEvent* event) override;
private:
Ui::AudioPlayTestClass ui;
QMediaPlayer* mediaPlayer;
QAudioOutput* audioOutput;
};
- AudioPlayTest.cpp
#include "AudioPlayTest.h"
AudioPlayTest::AudioPlayTest(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
setAcceptDrops(true);
mediaPlayer = new QMediaPlayer(this);
audioOutput = new QAudioOutput(this);
mediaPlayer->setAudioOutput(audioOutput);
audioOutput->setVolume(0.5);
}
void AudioPlayTest::dragEnterEvent(QDragEnterEvent * event)
{
if (event->mimeData()->hasUrls())
event->acceptProposedAction();
}
void AudioPlayTest::dropEvent(QDropEvent* event)
{
const auto urls = event->mimeData()->urls();
if (!urls.isEmpty()) {
const QString filePath = urls[0].toLocalFile();
mediaPlayer->setSource(QUrl::fromLocalFile(filePath));
mediaPlayer->play();
}
}
- main.cpp
#include "AudioPlayTest.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
AudioPlayTest w;
w.show();
return a.exec();
}
1.2 问题表现
在上述代码生成可执行文件并运行后,我们可以发现并没有声音出现。此外,如果打开了CMD调试窗口,可以发现错误警告如下:

2. 分析
查阅参考资料1时,我发现Qt6相对于Qt5的媒体模块有了调整。Qt 6多媒体模块完全放弃了Qt5基于插件的基础结构,它只有一个后端,后端只与操作系统有关,且后端对用户是隐藏的。因此上述的错误,很可能是后端(ffmpeg库)不兼容导致的。为了验证这个猜想,我用另外两个不同的Qt版本进行测试。
2.1 Qt5.15.2 版本测试
为了验证环境没问题,首先回到Qt5。Qt5生成时不需要指定QAudioOutput,也无法指定声音,AudioPlayTest.cpp中的代码修改为
#include "AudioPlayTest.h"
AudioPlayTest::AudioPlayTest(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
setAcceptDrops(true);
mediaPlayer = new QMediaPlayer(this);
}
void AudioPlayTest::dragEnterEvent(QDragEnterEvent * event)
{
if (event->mimeData()->hasUrls())
event->acceptProposedAction();
}
void AudioPlayTest::dropEvent(QDropEvent* event)
{
const auto urls = event->mimeData()->urls();
if (!urls.isEmpty()) {
const QString filePath = urls[0].toLocalFile();
mediaPlayer->setMedia(QUrl::fromLocalFile(filePath));
mediaPlayer->play();
}
}
运行程序,将音频文件拖入软件,声音正常,测试通过!
2.2 Qt6.5.3 版本测试
以上说明环境没问题,应该就是Qt版本的问题。但是卸载重装Qt6.9.0后,依然如此。网上也找了很多解决方案,比如认为Qt 依赖系统可用的音频后端(如 WASAPI)指定失败,需要加上代码"qputenv(“QT_AUDIO_BACKEND”, “wasapi”)"强行指定,又或者用其他音频格式文件(如wav格式)进行测试等等,均未解决。最后干脆,我这边将版本后退一些,以6.5.3为例,结果发现,代码不修改的情况下,测试通过!
2.3 三个不同Qt版本的媒体依赖库对比
对于用到的三个不同版本,用windeployqt工具对依赖库进行打包对比,可以发现三个不同版本软件的差异

可以发现,Qt6确实把audio里的库封装起来了,Qt6.5.3相较于Qt5.15.2简洁了一些。但是,到了Qt6.9.0版本后,ffmpeg底层等库暴露出来了,软件再度臃肿。
3. 解决方案
根据上述分析,目前最佳的解决方案便是放弃6.9.0版本,直接回退到6.5.3 (其他旧版本还未测试,欢迎朋友们留言交流)。回退到Qt5的代价是需要改动大量代码,不太推荐。另外,我也将这个bug反馈给官方平台了,希望后面的版本能够得到修复。
《Qt6 C++开发指南》王维波等人著 ↩︎

9392

被折叠的 条评论
为什么被折叠?



