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
相关产品推荐
相关产品推荐

