为什么 QMediaPlayer::duration() 给我的值为 -1?

Why is QMediaPlayer::duration() giving me a value of -1?

这是我的代码:

QString BoatProgramming::setDuration(QString path)
{
    if (path.isNull()) { return ""; }
    QMediaPlayer mp;
    mp.setMedia(QUrl::fromLocalFile("/home/akiva/deleteme.ogg"));
    qDebug() << mp.duration(); // Outputting a value of -1

    m_Duration = QString::number(mp.duration());
    emit durationChanged();
    return m_Duration;
}

显然某处有错误,但除了检查文件名之外,我很遗憾地不知道问题是什么。难道只是不支持.ogg?我是在对象完全加载到内存之前调用函数吗?还是其他原因?

谢谢。

QMediaPlayer::setMedia() 执行异步加载,从 docs:

This function returns immediately after recording the specified source of the media. It does not wait for the media to finish loading and does not check for errors. Listen for the mediaStatusChanged() and error() signals to be notified when the media is loaded and when an error occurs during loading.

这意味着在立即调用 setMedia() 后查询 QMediaPlayer 以获取 duration() 可能不起作用,因为 QMediaPlayer 可能尚未加载媒体。

为了保证在调用duration()之前加载完成,必须监听mediaStatusChanged()信号,只有在mediaStatus() [=33]时才得到duration() =] QMediaPlayer::LoadedMedia。这是一个最小的例子:

#include <QtWidgets>
#include <QtMultimedia>

int main(int argc, char* argv[])
{
    QApplication app(argc, argv);
    QLabel label; //a label to display duration

    QString fileName = QFileDialog::getOpenFileName(nullptr, "Open Media File");

    QMediaPlayer mp;
    mp.setMedia(QUrl::fromLocalFile(fileName));
    QObject::connect(&mp, &QMediaPlayer::mediaStatusChanged,
                     [&](QMediaPlayer::MediaStatus status){
        if(status == QMediaPlayer::LoadedMedia) //when loading is finished
        {
            //show duration in a label
            qint64 duration= mp.duration();
            label.setText(QString("Duration: %1 ms.\n\nThat is: %2")
                          .arg(duration)
                          .arg(QDateTime::fromTime_t(duration/1000).toUTC()
                               .toString("hh:mm:ss")));
            label.show();
        }
    });

    return app.exec();
}