QMediaPlayer 不加载媒体也不发射 mediaStatusChanged() 信号
QMediaPlayer Not Loading Media And Not Emitting mediaStatusChanged() Signals
我最近开始使用 Qt 并尝试使用 QMediaPlayer 播放声音文件。
我的程序编译和 运行s 但声音文件没有播放,QMediaPlayer 似乎卡在 QMediaPlayer::LoadingMedia
状态。
此外 - 可能相关 - QMediaPlayer 似乎从未发出其 mediaStatusChanged
或 error
信号(尽管这可能是我没有正确连接它们?)
当我 运行 程序如下时,它到达 while
循环并且永远不会离开。如果我在循环中查询 player->mediaStatus()
,它会不断地 returns 2 (QMediaPlayer::LoadingMedia
).
当我 运行 它省略了 while 循环时,程序继续 运行 直到它到达执行结束,没有 运行-time 错误但是 - 如您所料- 文件未播放。
有趣的是,while
循环之前的两个 cout
报告玩家的 mediaStatus
和 state
表明 mediaStatus
从 1 (在第一个例子中,在设置媒体之前)到 2(在设置媒体之后)但是我的 ChangedStatus
插槽从未被调用,尽管 connect
ing 到 mediaStatusChanged
在 run
函数。
运行:Debian Jessie,Qt5.7/Qt5.9
AudioPlayer.h
#include <QThread>
#include <QMediaPlayer>
class AudioPlayer : public QThread {
Q_OBJECT
public:
AudioPlayer();
public slots:
void ChangedStatus(QMediaPlayer::MediaStatus);
void MediaError(QMediaPlayer::Error);
protected:
void run();
};
AudioPlayer.cpp:
AudioPlayer::AudioPlayer(){}
void AudioPlayer::run()
{
QMediaPlayer* player = new QMediaPlayer();
connect(player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), this, SLOT(ChangedStatus(QMediaPlayer::MediaStatus)));
connect(player, SIGNAL(error(QMediaPlayer::Error)), this, SLOT(MediaError(QMediaPlayer::Error)));
std::cout << "Got player!" << std::endl;
std::cout << "\n\n\tPlayer state: " << player->state() << "\n\tMediaState: " << player->mediaStatus() << std::endl;
player->setMedia(QUrl::fromLocalFile("/home/me/test.wav") );
std::cout << "Set source" << std::endl;
std::cout << "\n\n\tPlayer state: " << player->state() << "\n\tMediaState: " << player->mediaStatus() << std::endl;
while(player->mediaStatus() != QMediaPlayer::MediaStatus::LoadedMedia)
{//
}
player->setVolume(100);
std::cout << "Set volume" << std::endl;
player->play();
std::cout << "Played" << std::endl;
}
void AudioPlayer::MediaError(QMediaPlayer::Error error)
{
std::cout << "Media Error: " << error << std::endl;
}
void AudioPlayer::ChangedStatus(QMediaPlayer::MediaStatus status)
{
std::cout << "Status changed to: " << status << std::endl;
}
main.cpp:
#include "audioplayer.h"
using namespace std;
int main()
{
cout << "Hello World!" << endl;
AudioPlayer myAudioPlayer;
myAudioPlayer.start();
std::cout << "myAudioPlayer started. Waiting...." << std::endl;
myAudioPlayer.wait();
std::cout << "myAudioPlayer returned." << std::endl;
return 0;
}
额外信息:
现在,最初,我没有使用 QThread 并试图在 main.cpp
中完成这一切(只是声明一个 QMediaPlayer 并尝试设置媒体和播放)但这给了我 QObject::startTimer: timers cannot be started from another thread warning
运行-几个地方的时间错误(QMediaPlayer
的声明,我认为是 play
命令),所以我采用了上述方法 - 虽然我不是确保子类化 QThread 必然是最好的方法。这也是为什么一切(声明等)都在 run
函数中完成的原因 - 将 QMediaPlayer 作为 AudioPlayer 的成员并在构造函数中初始化它给出了同样的错误。
我编译了 运行 Qt 的播放器示例(来自 multimediawidgets),通过浏览和选择我的 test.wav
,它可以播放文件,所以我认为这不是兼容性问题。我查看了 Player 示例源,但没有看到任何我遗漏的内容跳出,这看起来像是我的问题的原因。
您应该创建一个 QApplication 对象并使用它的消息循环。我建议您测试以下内容:
#include "audioplayer.h"
using namespace std;
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
AudioPlayer myAudioPlayer;
myAudioPlayer.start();
return a.exec();
}
你至少会提高你的信号。如果媒体状态达到 QMediaPlayer::StoppedState
或发生任何错误,您可以调用 QApplication::instance()->quit()
来停止您的应用程序。
编辑: 最好使用新样式的连接,例如:
connect(player, &QMediaPlayer::mediaStatusChanged, this, &QMediaPlayer::ChangedStatus);
它更可靠,您不必像 QMediaPlayer::MediaStatus
和 Q_DECLARE_METATYPE()
那样注册特定的参数类型
因为QMediaPlayer
class 包含了另一种方法error
,签名不同,信号连接稍微复杂一些。这是因为编译器不知道您指的是哪个 error
方法。在这种情况下 static_cast
是解决这种歧义的方法:
connect(
player,
static_cast<void(QMediaPlayer::*)(QMediaPlayer::Error )>(&QMediaPlayer::error),
this,
&AudioPlayer::MediaError
);
请注意,Wave 文件只是一个可以包含任意压缩数据流的容器文件。可能需要先安装适当的操作系统多媒体编解码器。在 Microsoft Windows Qt-Framework 依赖于已安装的多媒体编解码器(.ax 文件)。
您的 AudioPlayer::run
方法将在不等待媒体播放的情况下结束。所以你应该在线程结束之前的某个地方等待 Stopped
状态。但是最好不要直接使用 run
方法,而是使用 QThreads 消息循环。
class AudioPlayer : public QThread {
public:
AudioPlayer() : _Player(nullptr) {
moveToThread(this); // AudioPlayer object become part of this new thread
}
public slots:
void setVolume(int);
void load(QString Media);
// ...
void play() {
// Never directly access any members since they may belong to a different thread
if (thread() != QThread::currentThread()) {
QMetaObject::invokeMethod(this, "play", Qt::QueuedConnection);
} else {
_Player->play();
}
}
void stop() {
quit(); // Quiting thread message loop
}
private:
QMediaPlayer* _Player;
void run() {
_Player = new QMediaPlayer(this);
connect(...) // All connections go here...
int Result = QThread::exec();
_Player->stop();
delete _Player;
}
private slots:
void HandleStatusChange(QMediaPlayer::MediaStatus Status) {
emit statusChanged(Status); // Redirect so that the main application can handle this signal too
}
signals:
void statusChanged((QMediaPlayer::MediaStatus);
};
我最近开始使用 Qt 并尝试使用 QMediaPlayer 播放声音文件。
我的程序编译和 运行s 但声音文件没有播放,QMediaPlayer 似乎卡在 QMediaPlayer::LoadingMedia
状态。
此外 - 可能相关 - QMediaPlayer 似乎从未发出其 mediaStatusChanged
或 error
信号(尽管这可能是我没有正确连接它们?)
当我 运行 程序如下时,它到达 while
循环并且永远不会离开。如果我在循环中查询 player->mediaStatus()
,它会不断地 returns 2 (QMediaPlayer::LoadingMedia
).
当我 运行 它省略了 while 循环时,程序继续 运行 直到它到达执行结束,没有 运行-time 错误但是 - 如您所料- 文件未播放。
有趣的是,while
循环之前的两个 cout
报告玩家的 mediaStatus
和 state
表明 mediaStatus
从 1 (在第一个例子中,在设置媒体之前)到 2(在设置媒体之后)但是我的 ChangedStatus
插槽从未被调用,尽管 connect
ing 到 mediaStatusChanged
在 run
函数。
运行:Debian Jessie,Qt5.7/Qt5.9
AudioPlayer.h
#include <QThread>
#include <QMediaPlayer>
class AudioPlayer : public QThread {
Q_OBJECT
public:
AudioPlayer();
public slots:
void ChangedStatus(QMediaPlayer::MediaStatus);
void MediaError(QMediaPlayer::Error);
protected:
void run();
};
AudioPlayer.cpp:
AudioPlayer::AudioPlayer(){}
void AudioPlayer::run()
{
QMediaPlayer* player = new QMediaPlayer();
connect(player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), this, SLOT(ChangedStatus(QMediaPlayer::MediaStatus)));
connect(player, SIGNAL(error(QMediaPlayer::Error)), this, SLOT(MediaError(QMediaPlayer::Error)));
std::cout << "Got player!" << std::endl;
std::cout << "\n\n\tPlayer state: " << player->state() << "\n\tMediaState: " << player->mediaStatus() << std::endl;
player->setMedia(QUrl::fromLocalFile("/home/me/test.wav") );
std::cout << "Set source" << std::endl;
std::cout << "\n\n\tPlayer state: " << player->state() << "\n\tMediaState: " << player->mediaStatus() << std::endl;
while(player->mediaStatus() != QMediaPlayer::MediaStatus::LoadedMedia)
{//
}
player->setVolume(100);
std::cout << "Set volume" << std::endl;
player->play();
std::cout << "Played" << std::endl;
}
void AudioPlayer::MediaError(QMediaPlayer::Error error)
{
std::cout << "Media Error: " << error << std::endl;
}
void AudioPlayer::ChangedStatus(QMediaPlayer::MediaStatus status)
{
std::cout << "Status changed to: " << status << std::endl;
}
main.cpp:
#include "audioplayer.h"
using namespace std;
int main()
{
cout << "Hello World!" << endl;
AudioPlayer myAudioPlayer;
myAudioPlayer.start();
std::cout << "myAudioPlayer started. Waiting...." << std::endl;
myAudioPlayer.wait();
std::cout << "myAudioPlayer returned." << std::endl;
return 0;
}
额外信息:
现在,最初,我没有使用 QThread 并试图在 main.cpp
中完成这一切(只是声明一个 QMediaPlayer 并尝试设置媒体和播放)但这给了我 QObject::startTimer: timers cannot be started from another thread warning
运行-几个地方的时间错误(QMediaPlayer
的声明,我认为是 play
命令),所以我采用了上述方法 - 虽然我不是确保子类化 QThread 必然是最好的方法。这也是为什么一切(声明等)都在 run
函数中完成的原因 - 将 QMediaPlayer 作为 AudioPlayer 的成员并在构造函数中初始化它给出了同样的错误。
我编译了 运行 Qt 的播放器示例(来自 multimediawidgets),通过浏览和选择我的 test.wav
,它可以播放文件,所以我认为这不是兼容性问题。我查看了 Player 示例源,但没有看到任何我遗漏的内容跳出,这看起来像是我的问题的原因。
您应该创建一个 QApplication 对象并使用它的消息循环。我建议您测试以下内容:
#include "audioplayer.h"
using namespace std;
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
AudioPlayer myAudioPlayer;
myAudioPlayer.start();
return a.exec();
}
你至少会提高你的信号。如果媒体状态达到 QMediaPlayer::StoppedState
或发生任何错误,您可以调用 QApplication::instance()->quit()
来停止您的应用程序。
编辑: 最好使用新样式的连接,例如:
connect(player, &QMediaPlayer::mediaStatusChanged, this, &QMediaPlayer::ChangedStatus);
它更可靠,您不必像 QMediaPlayer::MediaStatus
和 Q_DECLARE_METATYPE()
因为QMediaPlayer
class 包含了另一种方法error
,签名不同,信号连接稍微复杂一些。这是因为编译器不知道您指的是哪个 error
方法。在这种情况下 static_cast
是解决这种歧义的方法:
connect(
player,
static_cast<void(QMediaPlayer::*)(QMediaPlayer::Error )>(&QMediaPlayer::error),
this,
&AudioPlayer::MediaError
);
请注意,Wave 文件只是一个可以包含任意压缩数据流的容器文件。可能需要先安装适当的操作系统多媒体编解码器。在 Microsoft Windows Qt-Framework 依赖于已安装的多媒体编解码器(.ax 文件)。
您的 AudioPlayer::run
方法将在不等待媒体播放的情况下结束。所以你应该在线程结束之前的某个地方等待 Stopped
状态。但是最好不要直接使用 run
方法,而是使用 QThreads 消息循环。
class AudioPlayer : public QThread {
public:
AudioPlayer() : _Player(nullptr) {
moveToThread(this); // AudioPlayer object become part of this new thread
}
public slots:
void setVolume(int);
void load(QString Media);
// ...
void play() {
// Never directly access any members since they may belong to a different thread
if (thread() != QThread::currentThread()) {
QMetaObject::invokeMethod(this, "play", Qt::QueuedConnection);
} else {
_Player->play();
}
}
void stop() {
quit(); // Quiting thread message loop
}
private:
QMediaPlayer* _Player;
void run() {
_Player = new QMediaPlayer(this);
connect(...) // All connections go here...
int Result = QThread::exec();
_Player->stop();
delete _Player;
}
private slots:
void HandleStatusChange(QMediaPlayer::MediaStatus Status) {
emit statusChanged(Status); // Redirect so that the main application can handle this signal too
}
signals:
void statusChanged((QMediaPlayer::MediaStatus);
};