本篇文章介绍QT实现视频播放器的过程,视频播放器功能包括选择视频文件,播放暂停,显示视频播放时长和总时长,带进度条,并且进度条可拖动。
1.实现视频播放器,主要用到QMediaPlayer和QVideoWidget两个类。创建好工程后,在.pro文件中加入:QT += multimedia multimediawidgets
QT += core gui multimedia multimediawidgets
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++17
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
premiere.cpp \
sliderbar.cpp \
HEADERS += \
premiere.h \
sliderbar.h \
FORMS += \
premiere.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
RESOURCES += \
resource.qrc
2.这是我项目中的UI界面,btn_open是打开视频文件按钮,widget用来做视频输出窗口,progress是视频播放进度条,btn_play是播放暂停按钮,label用来显示视频播放时长和总时长。
3.创建播放器 和视频输出对象。
.h文件中创建
private:
Ui::Premiere *ui;
QVideoWidget *videowidget;
QMediaPlayer *player;
.cpp文件中设置
Premiere::Premiere(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Premiere)
{
ui->setupUi(this);
player = new QMediaPlayer(this);
videowidget = new QVideoWidget(ui->widget); //把ui中的widget设置为视频播放窗口
QVBoxLayout *layout = new QVBoxLayout; //设置布局
layout->addWidget(videowidget);
ui->widget->setLayout(layout);
}
如果视频文件打开后,视频没有显示出来,并且报错为:
DirectShowPlayerService::doRender: Unresolved error code 0x80040266
说明没有视频解码器,可参考文章:
QT无法播放视频:报错:DirectShowPlayerService::doRender: Unresolved error code 0x80040266_泡泡上道了的博客-CSDN博客
下面展示项目中的所有代码,总共有4个文件,Premiere类的.h和.cpp文件实现视频播放器,SliderBar类的.h和.cpp文件实现进度条移动等。
Premiere.h
#ifndef PREMIERE_H
#define PREMIERE_H
#include <QWidget>
#include <QMediaPlayer>
#include <QVideoWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class Premiere; }
QT_END_NAMESPACE
class Premiere : public QWidget
{
Q_OBJECT
public:
Premiere(QWidget *parent = nullptr);
~Premiere();
void onPlayerPosition(qint64 pos);
private slots:
void on_btn_open_clicked();
void on_btn_play_clicked();
void onMediaStatusChanged(QMediaPlayer::MediaStatus status);
void updateTimes(qint64 position);
private:
Ui::Premiere *ui;
QVideoWidget *videowidget;
QMediaPlayer *player;
qint64 m_currentPosition; //当前时长
qint64 m_duration; // 总时长
};
#endif // PREMIERE_H
Premiere.cpp文件
#include "premiere.h"
#include "ui_premiere.h"
#include "sliderbar.h"
#include <QMediaPlayer>
#include <QVideoWidget>
#include <QFileDialog>
#include <QDateTime>
Premiere::Premiere(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Premiere)
{
ui->setupUi(this);
player = new QMediaPlayer(this);
videowidget = new QVideoWidget(ui->widget);
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(videowidget);
ui->widget->setLayout(layout);
ui->progress->setEnabled(false);
connect(player, &QMediaPlayer::mediaStatusChanged, this, &Premiere::onMediaStatusChanged);
//视频播放进度条
connect(player,&QMediaPlayer::positionChanged,ui->progress,&SliderBar::setValue);
connect(player,&QMediaPlayer::durationChanged,ui->progress,&SliderBar::setDurationPosition);
connect(ui->progress,&SliderBar::sigProgress,this,&Premiere::onPlayerPosition);
//显示视频播放时长
connect(player,&QMediaPlayer::positionChanged,this,&Premiere::updateTimes);
connect(player,&QMediaPlayer::durationChanged,this,&Premiere::updateTimes);
}
Premiere::~Premiere()
{
delete ui;
}
/**
* @brief Premiere::on_progress_valueChanged
* @param value
* @caption 视频播放进度条
*/
void Premiere::onPlayerPosition(qint64 pos)
{
disconnect(player,&QMediaPlayer::positionChanged,ui->progress,&SliderBar::setValue);
player->setPosition(pos);
m_currentPosition = pos; //更新当前播放位置
connect(player,&QMediaPlayer::positionChanged,ui->progress,&SliderBar::setValue);
}
/**
* @brief Premiere::on_btn_open_clicked
* @caption 打开视频文件按钮
*/
void Premiere::on_btn_open_clicked()
{
//获取视频文件路径
QString videoFilePath = QFileDialog::getOpenFileName(this, "选择视频文件", QDir::homePath(), "视频文件 (*.mp4 *.avi)");
// 将 QVideoWidget 设置为 QMediaPlayer 的输出设备
player->setVideoOutput(videowidget);
// 加载视频文件
player->setMedia(QUrl::fromLocalFile(videoFilePath));
// 播放视频
player->pause();
ui->progress->setEnabled(true);
}
/**
* @brief Premiere::on_btn_play_clicked
* @caption 播放暂停按钮
*/
void Premiere::on_btn_play_clicked()
{
if(player->state()==QMediaPlayer::PlayingState)
{
//当前正在播放,点击按钮暂停
player->pause();
ui->btn_play->setIcon(QIcon(":/resource/play.png"));
}
else
{
//当前处于暂停状态,点击按钮播放
player->play();
ui->btn_play->setIcon(QIcon(":/resource/stop.png"));
}
}
void Premiere::onMediaStatusChanged(QMediaPlayer::MediaStatus status)
{
if (status == QMediaPlayer::EndOfMedia)
{
// 视频播放完毕,将按钮状态设置为暂停状态
ui->btn_play->setIcon(QIcon(":/resource/play.png"));
player->setPosition(0);
}
}
/**
* @brief Premiere::updateTimes
* @param position
* @caption 设置视频当前时长和总时长
*/
void Premiere::updateTimes(qint64 position)
{
m_currentPosition = position;
QTime currentTime(0,0,0);
currentTime = currentTime.addMSecs(position);
m_duration = player->duration();
QTime totalTime(0,0,0);
totalTime = totalTime.addMSecs(m_duration);
QString currentTimeString = currentTime.toString("hh:mm:ss");
QString totalTimeString = totalTime.toString("hh:mm:ss");
ui->label->setText(currentTimeString+"/"+totalTimeString);
}
SliderBar.h
这个类的作用有3个:1)接收QMediaPlaer发来的进度信息,更新进度条;2)当用户操作进度条时,不再让进度条响应QMediaPlaer发来的进度信息;3)当用户完成对进度条的拖动后,向QMediaPlaer发送播放位置更新信息。
这个类的实现参考了文章:qt实现视频播放器_setvideooutput(m_pplayerwidget)_金色熊族的博客-CSDN博客
#ifndef SLIDERBAR_H
#define SLIDERBAR_H
#include <QSlider>
#include <QMouseEvent>
class SliderBar : public QSlider
{
Q_OBJECT
public:
SliderBar(QWidget *parent = 0);
public slots:
void setDurationPosition(qint64 max_len);
signals:
void sigProgress(qint64 pos);
protected:
void mouseReleaseEvent(QMouseEvent *e);
void mousePressEvent(QMouseEvent *e);
void mouseMoveEvent(QMouseEvent *e);
};
#endif // SLIDERBAR_H
SliderBar.cpp
#include "sliderbar.h"
SliderBar::SliderBar(QWidget *parent):QSlider(parent)
{
}
void SliderBar::setDurationPosition(qint64 max_len)
{
setRange(0,max_len);
}
void SliderBar::mouseReleaseEvent(QMouseEvent *e)
{
qint64 pos = this->value();
emit sigProgress(pos);
QSlider::mouseReleaseEvent(e);
}
void SliderBar::mousePressEvent(QMouseEvent *e)
{
QSlider::mousePressEvent(e);
}
void SliderBar::mouseMoveEvent(QMouseEvent *e)
{
QSlider::mouseMoveEvent(e);
}
效果展示:进度条可拖动