You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VS2017中QT5 QMediaPlayer无法显示视频(ServiceMissingError)求助

Qt5 + Visual Studio 2017 视频播放 ServiceMissingError 解决方案

问题概述

基于Windows的C++ GUI项目,使用Visual Studio 2017构建,Qt5开发(未使用Qt Creator),在Widget中调用QMediaPlayer播放视频,代码取自Qt官方文档,编译正常但运行时视频无法显示,界面始终空白。调用setMedia()后触发QMediaPlayer::ServiceMissingError(错误码5),m_mediaPlayer->state()和m_mediaPlayer->mediaStatus()值始终为0。

空白界面:
空白界面

相关代码

头文件

#include <QFileDialog>
#include <QStandardPaths>

#include <QtMultimedia/qmediacontent.h>
#include <QtMultimedia/qmediaplayer.h>
#include <QtMultimediaWidgets/qvideowidget.h>
#include <QtMultimedia/qmediaplaylist.h>

class signalWidget : public QWidget
{
public:
    QVideoWidget *videoWidget;
    QMediaPlayer* m_mediaPlayer;
    QAbstractButton *m_playButton;
    QSlider *m_positionSlider;
    QLabel *m_errorLabel;
    void setUrl(const QUrl &url);

public slots:
        void openFile();
        void play();    
        void mediaStateChanged(QMediaPlayer::State state);
        void positionChanged(qint64 position);
        void durationChanged(qint64 duration);
        void setPosition(int position);
        void handleError();
};

源文件

void signalWidget::handleError()
{
    m_playButton->setEnabled(false);
    const QString errorString = m_mediaPlayer->errorString();
    QString message = "Error: ";
    if (errorString.isEmpty())
        message += " #" + QString::number(int(m_mediaPlayer->error()));
    else
        message += errorString;
    m_errorLabel->setText(message);

    std::cout << " ERROR = " << message.toStdString() << "\n";
}

void signalWidget::positionChanged(qint64 position)
{
std::cout << " position = " << position << "\n";
    m_positionSlider->setValue(position);
}

void signalWidget::durationChanged(qint64 duration)
{
std::cout << " duration = " << duration << "\n";
    m_positionSlider->setRange(0, duration);
}

void signalWidget::setPosition(int position)
{
std::cout << " position = " << position << "\n";
    m_mediaPlayer->setPosition(position);
}

void signalWidget::mediaStateChanged(QMediaPlayer::State state)
{
    std::cout << " state = " << state << "\n";
    switch(state) {
    case QMediaPlayer::PlayingState:
        m_playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPause));
        break;
    default:
        m_playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay));
        break;
    }
}

 void signalWidget::MediaError(QMediaPlayer::Error error)
 {
  std::cout << " Media Error: " << error << "\n";
 }

 void signalWidget::ChangedStatus(QMediaPlayer::MediaStatus status)
 {
  std::cout << " Status changed to: " << status << "\n";
 }

void signalWidget::play()
{
std::cout << " currentMedia = " << m_mediaPlayer->currentMedia().canonicalUrl().toString().toStdString() << 
                                                    ", playerState = " << m_mediaPlayer->state() << "   E\n";

    switch (m_mediaPlayer->state()) {
    case QMediaPlayer::PlayingState:
        m_mediaPlayer->pause();
        break;
    default:
        m_mediaPlayer->play();
        break;
    }

    std::cout << " playerState = " << m_mediaPlayer->state() << ", playerMediaState = " << m_mediaPlayer->mediaStatus() << "\n";
}

void signalWidget::setUrl(const QUrl &url)
{
    m_errorLabel->setText(QString());
    setWindowFilePath(url.isLocalFile() ? url.toLocalFile() : QString());
    m_mediaPlayer->setMedia(url);
    m_playButton->setEnabled(true);
std::cout << " currentMedia = " << m_mediaPlayer->currentMedia().canonicalUrl().toString().toStdString() << 
                                                    ", player State = " << m_mediaPlayer->state() <<
                                                    ", player ERROR = " << m_mediaPlayer->error();

}

void signalWidget::openFile()
{
    QFileDialog fileDialog(this);
    fileDialog.setAcceptMode(QFileDialog::AcceptOpen);
    fileDialog.setWindowTitle(tr("Open Movie"));
    QStringList supportedMimeTypes = m_mediaPlayer->supportedMimeTypes();
    if (!supportedMimeTypes.isEmpty())
        fileDialog.setMimeTypeFilters(supportedMimeTypes);
    fileDialog.setDirectory(QStandardPaths::standardLocations(QStandardPaths::MoviesLocation).value(0, QDir::homePath()));
    if (fileDialog.exec() == QDialog::Accepted)
        setUrl(fileDialog.selectedUrls().constFirst());
}

构造函数实现

signalWidget::signalWidget(int widget_id)
{
        m_mediaPlayer = new QMediaPlayer(this, QMediaPlayer::VideoSurface);
        videoWidget = new QVideoWidget;
    
        QAbstractButton *openButton = new QPushButton(tr("Open..."));
        connect(openButton,SIGNAL(clicked()),this,SLOT(openFile()));

        m_playButton = new QPushButton;
        m_playButton->setEnabled(false);
        m_playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay));
        connect(m_playButton, SIGNAL(clicked()), this, SLOT(play()));

        m_positionSlider = new QSlider(Qt::Horizontal);
        m_positionSlider->setRange(0, 0);
        connect(m_positionSlider, SIGNAL(sliderMoved()), this, SLOT(setPosition()));

        m_errorLabel = new QLabel;
        m_errorLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);

        m_errorLabel->setAutoFillBackground(true); // IMPORTANT!
        m_errorLabel->setStyleSheet("QLabel { background-color : pink; color : blue; }");

        QBoxLayout *controlLayout = new QHBoxLayout;
        controlLayout->setMargin(0);
        controlLayout->addWidget(openButton);
        controlLayout->addWidget(m_playButton);
        controlLayout->addWidget(m_positionSlider);

        QBoxLayout *layout = new QVBoxLayout;
        layout->addWidget(videoWidget);
        layout->addLayout(controlLayout);
        layout->addWidget(m_errorLabel);
        layout->setMargin(0); //! to avoid wasting spaces with margins
        setLayout(layout);

        m_mediaPlayer->setVideoOutput(videoWidget);
        connect(m_mediaPlayer, SIGNAL(stateChanged()), this, SLOT(mediaStateChanged()));
        connect(m_mediaPlayer, SIGNAL(positionChanged()), this, SLOT(mediaStateChanged()));
        connect(m_mediaPlayer, SIGNAL(durationChanged()), this, SLOT(durationChanged()));
        connect(m_mediaPlayer, SIGNAL(Error()), this, SLOT(handleError()));

}

解决方案

1. 补全Qt多媒体组件安装

Qt5多媒体功能依赖专属组件,需确保安装Qt时勾选了Qt Multimedia和Qt Multimedia Widgets模块;若手动编译Qt,需确认qtmultimedia、qtmultimediawidgets模块已编译并正确链接到项目。

2. 部署多媒体运行时插件

Windows下Qt多媒体依赖特定插件,需将以下文件复制到程序运行目录(与exe同级):

  • Qt安装目录plugins/mediaservice下的所有文件
  • Qt安装目录plugins/platforms/qwindows.dll(GUI项目通常已部署,但缺失会导致多媒体服务加载失败)
  • 视频解码依赖:复制Qt自带的avcodec-xx.dll、avformat-xx.dll、avutil-xx.dll、swscale-xx.dll(或安装LAV Filters等第三方解码器)

3. 修复信号槽连接错误

构造函数中存在信号与槽参数不匹配、信号名称错误的问题,修正后代码如下:

m_mediaPlayer->setVideoOutput(videoWidget);
// 匹配信号与槽的参数类型和数量
connect(m_mediaPlayer, SIGNAL(stateChanged(QMediaPlayer::State)), this, SLOT(mediaStateChanged(QMediaPlayer::State)));
connect(m_mediaPlayer, SIGNAL(positionChanged(qint64)), this, SLOT(positionChanged(qint64)));
connect(m_mediaPlayer, SIGNAL(durationChanged(qint64)), this, SLOT(durationChanged(qint64)));
connect(m_mediaPlayer, SIGNAL(error(QMediaPlayer::Error)), this, SLOT(handleError()));
// 新增媒体状态变化信号连接,便于排查问题
connect(m_mediaPlayer, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), this, SLOT(ChangedStatus(QMediaPlayer::MediaStatus)));

4. 验证视频路径与编码

  • 确保setMedia()传入的本地文件路径无中文或特殊字符,若需支持中文,需在项目初始化时设置编码:QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
  • 测试MP4、AVI等Qt默认支持的视频格式,避免使用过于小众的编码格式

内容的提问来源于stack exchange,提问作者RKum

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 03:44:59