利用VS+Qt自己定义播放视频文件mp4,
- 首先选中模块:
- 自己编辑代码编
#ifndef VIDEOPLAYER_H
#define VIDEOPLAYER_H
#include <QMediaPlayer>
#include <QMovie>
#include <QWidget>
#include <string>
#include "MyPlayerDef.h"
QT_BEGIN_NAMESPACE
class QAbstractButton;
class QSlider;
class QGraphicsVideoItem;
class QLabel;
QT_END_NAMESPACE
class VideoPlayer : public QWidget {
Q_OBJECT
public:
VideoPlayer(QWidget *parent = 0);
~VideoPlayer();
//设置当前窗口大小
inline QSize sizeHint() const {
return QSize(900, 800);
}
//设置视频播放路径
void setVideoPath(QString strPath);
//播放
void playVideo(std::string time);
//运行播放时间
void runTime(std::string time);
//暂停
void pauseVideo();
void nextVideoFrame();//下一帧
void backVideoFrame();//上一帧
//设置开始时间
void setStartTime(QString startTime);
//设置播放速率
void setPlayRate(qreal rate);
//设置回调函数结构
inline void setCallBackFun(CallBackFun* callBackFun) {
fun = callBackFun;
}
private:
void closeEvent(QCloseEvent *event);
long str2Second(std::string time);
std::string second2Str(long nTime);
void handleCursor(QMediaPlayer::MediaStatus status);
void setStatusInfo(const QString &info);
void displayErrorMessage();
bool jdgeTime(std::string time);//判断时间是否在视频播放的时间内
public slots:
void slotOpenFile();
void slotPlay();
void slotNextFrame();
void slotBackFrame();
void slotSpeedUp();
void slotSpeedDown();
private slots:
void slotMediaStateChanged(QMediaPlayer::State state);
void slotStatusChanged(QMediaPlayer::MediaStatus status);
void slotBufferingProgress(int progress);
void slotPositionChanged(qint64 position);
void slotDurationChanged(qint64 duration);
void slotSetPosition(int position);
void slotRotateVideo(int angle);
void slotHandleError();
private:
QString path;//视频文件路径
QString trackInfo;
QString statusInfo;
QMediaPlayer mediaPlayer;
QGraphicsVideoItem *videoItem = nullptr;
QAbstractButton *playButton = nullptr;//播放
QAbstractButton *nextFrameButton = nullptr;//下一帧
QAbstractButton *backFrameButton = nullptr;//上一帧
QAbstractButton *speedUpButton = nullptr;//加速
QAbstractButton *speedDownButton = nullptr;//减速
QLabel* rateLabel = nullptr;//显示速率
double currentRate = 1.0;//当前播放速率
QSlider *positionSlider= nullptr;
qint64 currentTime = 0;//当前播放时间
qint64 startTime = 0;//开始播放的时间
qint64 vedioLongTime = 0;//视频时长
QLabel* startLabel = nullptr;//开始时间
QLabel* endLabel = nullptr;//结束时间
CallBackFun* fun = nullptr;
};
#endif
#include "videoplayer.h"
#include <QtWidgets>
#include <QVideoSurfaceFormat>
#include <QGraphicsVideoItem>
#include <QDebug>
#include <QMessageBox>
VideoPlayer::VideoPlayer(QWidget *parent)
: QWidget(parent)
, mediaPlayer(0, QMediaPlayer::VideoSurface)
, videoItem(0)
, playButton(0)
, positionSlider(0) {
videoItem = new QGraphicsVideoItem;
videoItem->setSize(QSizeF(800, 450));//设置窗口大小
QGraphicsScene *scene = new QGraphicsScene(this);
QGraphicsView *graphicsView = new QGraphicsView(scene);
scene->addItem(videoItem);
QSlider *rotateSlider = new QSlider(Qt::Horizontal);
rotateSlider->setRange(-180, 180);
rotateSlider->setValue(0);
connect(rotateSlider, SIGNAL(valueChanged(int)),this, SLOT(slotRotateVideo(int)));
QAbstractButton *openButton = new QPushButton(tr("Open..."));
connect(openButton, SIGNAL(clicked()), this, SLOT(slotOpenFile()));
//打开按钮
playButton = new QPushButton;
playButton->setEnabled(false);
playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay));
connect(playButton, SIGNAL(clicked()),this, SLOT(slotPlay()));
//上一帧
backFrameButton = new QPushButton;
backFrameButton->setEnabled(false);
backFrameButton->setText(QStringLiteral("上一帧"));
connect(backFrameButton, SIGNAL(clicked()), this, SLOT(slotBackFrame()));
//下一帧
nextFrameButton = new QPushButton;
nextFrameButton->setEnabled(false);
nextFrameButton->setText(QStringLiteral("下一帧"));
connect(nextFrameButton, SIGNAL(clicked()), this, SLOT(slotNextFrame()));
//加速
speedUpButton = new QPushButton;
speedUpButton->setEnabled(false);
speedUpButton->setIcon(style()->standardIcon(QStyle::SP_MediaSeekForward));
connect(speedUpButton, SIGNAL(clicked()), this, SLOT(slotSpeedUp()));
//减速
speedDownButton = new QPushButton;
speedDownButton->setEnabled(false);
speedDownButton->setIcon(style()->standardIcon(QStyle::SP_MediaSeekBackward));
connect(speedDownButton, SIGNAL(clicked()), this, SLOT(slotSpeedDown()));
//速率
rateLabel = new QLabel;
rateLabel->setText(QStringLiteral("×1.0"));
//时间轴
positionSlider = new QSlider(Qt::Horizontal);
positionSlider->setRange(0, 0);
connect(positionSlider, SIGNAL(sliderMoved(int)),this, SLOT(slotSetPosition(int)));
//开始时间
startLabel = new QLabel;
startLabel->setMinimumWidth(60);
//结束时间
endLabel = new QLabel;
endLabel->setMinimumWidth(60);
//时间轴
QBoxLayout *controlLayout = new QHBoxLayout;
#if 0
controlLayout->addWidget(openButton);
#endif
controlLayout->addWidget(positionSlider);//时间轴
controlLayout->addWidget(startLabel);//开始时间
controlLayout->addWidget(endLabel);//结束时间
//播放控制
QBoxLayout *controlLayout2 = new QHBoxLayout;
controlLayout2->addWidget(backFrameButton);//上一帧
controlLayout2->addWidget(nextFrameButton);//下一帧
controlLayout2->addWidget(playButton);//播放
controlLayout2->addWidget(speedDownButton);//减速
controlLayout2->addWidget(speedUpButton);//加速
controlLayout2->addWidget(rateLabel);//速率
QBoxLayout *layout = new QVBoxLayout;
controlLayout->setMargin(10);
controlLayout2->setMargin(10);
layout->addWidget(graphicsView);
#if 0
layout->addWidget(rotateSlider);
#endif
layout->addLayout(controlLayout);
layout->addLayout(controlLayout2);
setLayout(layout);
mediaPlayer.setVideoOutput(videoItem);//设置输出窗口
connect(&mediaPlayer, SIGNAL(stateChanged(QMediaPlayer::State)),this, SLOT(slotMediaStateChanged(QMediaPlayer::State)));//视频播放状态信号槽
connect(&mediaPlayer, SIGNAL(positionChanged(qint64)), this, SLOT(slotPositionChanged(qint64)));//进度条控制视频进度
connect(&mediaPlayer, SIGNAL(durationChanged(qint64)), this, SLOT(slotDurationChanged(qint64)));//获取视频长度
typedef void (QMediaPlayer::*ErrorSignal)(QMediaPlayer::Error);
connect(&mediaPlayer, static_cast<ErrorSignal>(&QMediaPlayer::error),this, &VideoPlayer::slotHandleError);//错误信息输出
//记录视频的各种状态
connect(&mediaPlayer, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)),this, SLOT(slotStatusChanged(QMediaPlayer::MediaStatus)));
connect(&mediaPlayer, SIGNAL(bufferStatusChanged(int)), this, SLOT(slotBufferingProgress(int)));
}
VideoPlayer::~VideoPlayer() {
if (playButton != nullptr){
delete playButton;
playButton = nullptr;
}
if (nextFrameButton != nullptr) {
delete nextFrameButton;
nextFrameButton = nullptr;
}
if (backFrameButton != nullptr) {
delete backFrameButton;
backFrameButton = nullptr;
}
if (speedUpButton != nullptr) {
delete speedUpButton;
speedUpButton = nullptr;
}
if (speedDownButton != nullptr) {
delete speedDownButton;
speedDownButton = nullptr;
}
if (positionSlider != nullptr){
delete positionSlider;
positionSlider = nullptr;
}
if (videoItem!=nullptr){
delete videoItem;
videoItem = nullptr;
}
}
//槽函数 - 打开文件
void VideoPlayer::slotOpenFile() {
QString fileName = QFileDialog::getOpenFileName(this, tr("Open Movie"), QDir::homePath());
if (!fileName.isEmpty()) {
mediaPlayer.setMedia(QUrl::fromLocalFile(fileName));
playButton->setEnabled(true);
nextFrameButton->setEnabled(true);
backFrameButton->setEnabled(true);
speedUpButton->setEnabled(true);
speedDownButton->setEnabled(true);
}
}
//槽函数 - 播放控制
void VideoPlayer::slotPlay() {
switch (mediaPlayer.state()) {
case QMediaPlayer::PlayingState:{
std::string time = second2Str(currentTime);
if (fun != nullptr){
fun->funPlay(false, time);
}
mediaPlayer.pause();
break;
}
default:{
std::string time = second2Str(currentTime);
if (fun != nullptr) {
fun->funPlay(true, time);
}
mediaPlayer.play();
break;
}
}
}
void VideoPlayer::slotMediaStateChanged(QMediaPlayer::State state) {
switch (state) {
case QMediaPlayer::PlayingState:
playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPause));
break;
default:
playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay));
break;
}
}
void VideoPlayer::slotStatusChanged(QMediaPlayer::MediaStatus status) {
handleCursor(status);
switch (status) {
case QMediaPlayer::UnknownMediaStatus:
case QMediaPlayer::NoMedia:
case QMediaPlayer::LoadedMedia:
case QMediaPlayer::BufferingMedia:
case QMediaPlayer::BufferedMedia:
setStatusInfo(QString());
break;
case QMediaPlayer::LoadingMedia:
setStatusInfo(QStringLiteral("加载中..."));
break;
case QMediaPlayer::StalledMedia:
setStatusInfo(QStringLiteral("媒体停滞"));
break;
case QMediaPlayer::EndOfMedia:
QApplication::alert(this);
break;
case QMediaPlayer::InvalidMedia:
displayErrorMessage();
break;
}
}
void VideoPlayer::handleCursor(QMediaPlayer::MediaStatus status) {
#ifndef QT_NO_CURSOR
if (status == QMediaPlayer::LoadingMedia ||
status == QMediaPlayer::BufferingMedia ||
status == QMediaPlayer::StalledMedia)
setCursor(QCursor(Qt::BusyCursor));
else
unsetCursor();
#endif
}
void VideoPlayer::displayErrorMessage() {
setStatusInfo(mediaPlayer.errorString());
}
void VideoPlayer::setStatusInfo(const QString &info) {
statusInfo = info;
if (!statusInfo.isEmpty())
setWindowTitle(QString("%1 | %2").arg(trackInfo).arg(statusInfo));
else
setWindowTitle(trackInfo);
}
//槽函数 - 当前播放的进度
void VideoPlayer::slotPositionChanged(qint64 position) {
positionSlider->setValue(position);
currentTime = startTime + position/1000;
std::string time = second2Str(currentTime);
QString str = QString::fromStdString(time);
startLabel->setText(str);
if (fun != nullptr) {
fun->funCurrentTime(time);
}
}
//槽函数 - 获取视频的时间长度
void VideoPlayer::slotDurationChanged(qint64 duration) {
positionSlider->setRange(0, duration);
vedioLongTime = duration;
long end = startTime + (duration / 1000);
QString str = "/ ";
str += QString::fromStdString(second2Str(end));
endLabel->setText(str);
}
void VideoPlayer::slotSetPosition(int position) {
mediaPlayer.setPosition(position);
}
void VideoPlayer::slotRotateVideo(int angle) {
qreal x = videoItem->boundingRect().width() / 2.0;
qreal y = videoItem->boundingRect().height() / 2.0;
videoItem->setTransform(QTransform().translate(x, y).rotate(angle).translate(-x, -y));
}
//槽函数 - 错误处理
void VideoPlayer::slotHandleError() {
const QString errorString = mediaPlayer.errorString();
QString message = "Error: ";
if (errorString.isEmpty()) {
message += " # " + QString::number(int(mediaPlayer.error()));
} else {
message += errorString;
}
QMessageBox::warning(NULL, QStringLiteral("错误"), message);
}
//设置视频路径
void VideoPlayer::setVideoPath(QString strPath) {
mediaPlayer.setMedia(QUrl::fromLocalFile(strPath));
}
//播放视频
void VideoPlayer::playVideo(std::string time) {
if (mediaPlayer.state() != QMediaPlayer::PlayingState) {
if (!jdgeTime(time)){//当前时间不在视频播放的时间内
return;
}
mediaPlayer.play();
if (time.size() == 0){
mediaPlayer.pause();
}
playButton->setEnabled(true);
nextFrameButton->setEnabled(true);
backFrameButton->setEnabled(true);
speedUpButton->setEnabled(true);
speedDownButton->setEnabled(true);
}
}
//暂停视频
void VideoPlayer::pauseVideo() {
if (mediaPlayer.state() == QMediaPlayer::PlayingState) {
mediaPlayer.pause();
}
}
//窗口关闭
void VideoPlayer::closeEvent(QCloseEvent *event){
if (mediaPlayer.state() != QMediaPlayer::StoppedState){
mediaPlayer.stop();
}
}
//设置开始时间
void VideoPlayer::setStartTime(QString startTimeStr){
startTime = str2Second(startTimeStr.toStdString());
currentTime = startTime;
startLabel->setText(startTimeStr);
}
//时间转换成秒数
long VideoPlayer::str2Second(std::string time) {
int nHour, nMin, nSecond;
sscanf(time.c_str(), "%d:%d:%d", &nHour, &nMin, &nSecond);
long nTime = nHour * 3600 + nMin * 60 + nSecond;
return nTime;
}
//秒数转换成字符串
std::string VideoPlayer::second2Str(long nTime) {
int h = nTime / 3600;
int m = (nTime - h * 3600) / 60;
int s = nTime - h * 3600 - m * 60;
char buf[64] = { 0 };
sprintf(buf, "%02d:%02d:%02d", h, m, s);
return std::string(buf);
}
//设置播放速率
void VideoPlayer::setPlayRate(qreal rate) {
currentRate = rate;
QString strRate = QString(QStringLiteral("×%1")).arg(currentRate, 3, 'f', 1);
rateLabel->setText(strRate);
mediaPlayer.setPlaybackRate(currentRate);
}
void VideoPlayer::slotBufferingProgress(int progress) {
setStatusInfo(tr("Buffering %1%").arg(progress));
}
//槽函数 - 下一帧
void VideoPlayer::slotNextFrame() {//以下调用过程不可修改
nextVideoFrame();
std::string time = second2Str(currentTime);
if (fun != nullptr) {
fun->funNextFrame(time);
}
}
//槽函数 - 上一帧
void VideoPlayer::slotBackFrame() {//以下调用过程不可修改
backVideoFrame();
std::string time = second2Str(currentTime);
if (fun != nullptr) {
fun->funBackFrame(time);
}
}
//槽函数 - 加速
void VideoPlayer::slotSpeedUp() {//以下调用过程不可修改
currentRate = currentRate * 2;
setPlayRate(currentRate);
if (fun != nullptr) {
fun->funRate(currentRate);//回调接口
}
}
//槽函数 - 减速
void VideoPlayer::slotSpeedDown() {//以下调用过程不可修改
currentRate = currentRate / 2;
setPlayRate(currentRate);
if (fun!=nullptr){
fun->funRate(currentRate);//回调接口
}
}
//对外接口 - 下一帧
void VideoPlayer::nextVideoFrame() {
currentTime = currentTime * 1000;
currentTime += 1000;
long t = currentTime;
if (currentTime >= vedioLongTime) {
currentTime = vedioLongTime / 1000;
t = vedioLongTime;
}
mediaPlayer.setPosition(t);
}
//对外接口 - 上一帧
void VideoPlayer::backVideoFrame() {
currentTime = currentTime * 1000;
currentTime -= 1000;
if (currentTime <= 0) {
currentTime = startTime;
}
mediaPlayer.setPosition(currentTime);
}
//运行播放时间
void VideoPlayer::runTime(std::string time) {
long second = str2Second(time);
if (second == startTime){
mediaPlayer.play();
}
}
//判断当前时间是否在视频播放的时间内
bool VideoPlayer::jdgeTime(std::string time) {
currentTime = str2Second(time);
//当前播放时间在视频开始时间和视频结束时间之间
if (currentTime >= startTime && currentTime <= (startTime + vedioLongTime)) {
mediaPlayer.setPosition((currentTime - startTime) * 1000);
return true;
}
return false;
}
-
编写客户端调用,返回错误:ResourceError。刚开始以为是中文路径的问题,修改路径之后还是不行,不能播放出来。
-
然后使用QtCreater进行重新编译,编译成功,但是运行的时候出现错误:
DirectShowPlayerService::doRender: Unresolved error code 0x80040266 (IDispatch error #102)
解决方案:
Qt 中的多媒体播放,底层是使用DirectShowPlayerService,所以安装一个DirectShow解码器LAV Filters,就可以解决运行出错问题。