Qt 播放视频失败

版权声明:本文为博主原创文章,未经同意不允许转载! https://blog.csdn.net/wb175208/article/details/84527642

利用VS+Qt自己定义播放视频文件mp4,

  1. 首先选中模块:
    在这里插入图片描述
  2. 自己编辑代码编
#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;
}

  1. 编写客户端调用,返回错误:ResourceError。刚开始以为是中文路径的问题,修改路径之后还是不行,不能播放出来。

  2. 然后使用QtCreater进行重新编译,编译成功,但是运行的时候出现错误:

DirectShowPlayerService::doRender: Unresolved error code 0x80040266 (IDispatch error #102)

解决方案:
Qt 中的多媒体播放,底层是使用DirectShowPlayerService,所以安装一个DirectShow解码器LAV Filters,就可以解决运行出错问题。

解码器下载

猜你喜欢

转载自blog.csdn.net/wb175208/article/details/84527642