首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >QMediaPlayer不加载媒体也不发射mediaStatusChanged()信号

QMediaPlayer不加载媒体也不发射mediaStatusChanged()信号
EN

Stack Overflow用户
提问于 2017-08-15 15:33:29
回答 1查看 3.3K关注 0票数 3

我最近开始使用Qt,并尝试使用QMediaPlayer播放一个声音文件。

我的程序编译和运行,但声音文件没有播放,QMediaPlayer似乎卡在QMediaPlayer::LoadingMedia状态。

而且--而且可能是相关的-- QMediaPlayer似乎从来没有发出过它的mediaStatusChangederror信号(虽然这可能是我没有正确地连接它们?)

当我按下面的方式运行程序时,它会到达while循环,永远不会离开。如果我在循环中查询player->mediaStatus(),它会不断地返回2 (QMediaPlayer::LoadingMedia)。

当我在省去while循环的情况下运行它时,该程序将继续运行,直到它到达执行结束时为止,没有任何运行时错误,但是--正如您所预期的--文件不会被播放。

有趣的是,在while循环之前的两个whiles(它报告播放器的mediaStatusstate )显示,mediaStatus从1(在设置媒体之前)更改为2(在设置媒体之后),但我的ChangedStatus插槽从未被调用,尽管在run函数的开头有connectmediaStatusChanged

跑步: Debian Jessie,Qt5.7/Qt5.9

AudioPlayer.h

代码语言:javascript
复制
#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:

代码语言:javascript
复制
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:

代码语言:javascript
复制
#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,它可以播放该文件,因此我不认为这是一个兼容性问题。我看了看球员的例子来源,但没有看到任何跳出,我错过了,这似乎是我的问题的原因。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-08-16 06:39:18

您应该创建一个QApplication对象并使用它的消息循环。我建议你测试以下几点:

代码语言:javascript
复制
#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()来停止应用程序。

编辑:更好地使用新的样式连接,如:

代码语言:javascript
复制
connect(player, &QMediaPlayer::mediaStatusChanged, this, &QMediaPlayer::ChangedStatus);

它更可靠,您不需要向QMediaPlayer::MediaStatus这样的Q_DECLARE_METATYPE()注册特定的参数类型

因为QMediaPlayer类包含另一个具有不同签名的方法error,所以信号连接要复杂一些。这是因为编译器不知道您所指的是哪个error方法。在本例中,static_cast是解决这种模糊性的方法:

代码语言:javascript
复制
connect(
    player,
    static_cast<void(QMediaPlayer::*)(QMediaPlayer::Error )>(&QMediaPlayer::error),
    this,
    &AudioPlayer::MediaError
);

请注意,Wave文件只是可以包含任意压缩数据流的容器文件。可能需要首先安装适当的操作系统多媒体编解码器。在中,依赖于已安装的多媒体编解码器(.ax文件)。

AudioPlayer::run方法将在不等待播放媒体的情况下结束。因此,您应该在线程结束之前在某个位置等待Stopped状态。但是,最好不是直接使用run方法,而是使用QThreads消息循环。

代码语言:javascript
复制
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);
};
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45696232

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档