使用Qt5和OpenCV做视频播放器

声明在前头:本文是查阅整合了众多网友的知识的基础上实现的。

首先,说在前头。通过实现了使用OpenCV做播放器的过程,才发现OpenCV真的不适合做播放器,至少是没有什么太多视频处理理论基础认识的初学者。实现过程中也是历尽千辛万苦,查阅很多资料。

使用环境是Qt5.7.0+VS2013+OpenCV2.4.13。在这里就不说环境搭建了,如果会使用动态库,这些步骤应该不是问题。但是写本文的原因是如何使用代码去实现。

 

废话不多说,直接上代码。

 

首先看头文件 OpenCVDemo3.h

#ifndef OPENCVDEMO3_H
#define OPENCVDEMO3_H


#include <QtWidgets/QWidget>
#include "ui_OpenCVDemo3.h"
//opencv头文件引用
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <QTimer>
#include <QImage>
using namespace cv;
class OpenCVDemo3 : public QWidget
{
	Q_OBJECT


public:
	OpenCVDemo3(QWidget *parent = 0);
	~OpenCVDemo3();
	QImage  MatToQImage(const cv::Mat& mat);
private slots:
	void onBtnClicked();
	void onTimeout();
	void onBtnFastClicked();
	void onBtnSlowClicked();
private:
	Ui::OpenCVDemo3Class ui;
	VideoCapture capture; //用来读取视频结构
	QTimer timer;//视频播放的定时器
	int beishu;//调节播放速率
	int delay;//帧延迟时间
};


#endif // OPENCVDEMO3_H


下面是源文件OpenCVDemo3.cpp

#include "OpenCVDemo3.h"
#include <QDebug>
OpenCVDemo3::OpenCVDemo3(QWidget *parent)
	: QWidget(parent)
	, beishu(1)
	,delay(0)
{
	ui.setupUi(this);
	connect(ui.pushButton, SIGNAL(clicked()), this, SLOT(onBtnClicked()));
	connect(ui.pushButton_fast, SIGNAL(clicked()), this, SLOT(onBtnFastClicked()));
	connect(ui.pushButton_slow, SIGNAL(clicked()), this, SLOT(onBtnSlowClicked()));
	connect(&timer, SIGNAL(timeout()), this, SLOT(onTimeout()));
}

OpenCVDemo3::~OpenCVDemo3()
{
	capture.release();
}
void OpenCVDemo3::onBtnFastClicked()
{

	beishu = beishu * 2;
	timer.stop();
	timer.start(delay / beishu);
}
void OpenCVDemo3::onBtnSlowClicked()
{
	beishu = beishu / 2;
	timer.stop();
	timer.start(delay / beishu);
}
void OpenCVDemo3::onBtnClicked()
{

	//打开视频文件:其实就是建立一个VideoCapture结构
	capture.open("F:\\win32\\openCVDemo1\\OpenCVDemo2\\2.mp4");
	//检测是否正常打开:成功打开时,isOpened返回ture
	if (!capture.isOpened())
		ui.textEdit->append("fail to open!");
	//获取整个帧数
	long totalFrameNumber = capture.get(CV_CAP_PROP_FRAME_COUNT);
	ui.textEdit->append(QString::fromLocal8Bit("整个视频共 %1 帧").arg(totalFrameNumber));

	ui.label->resize(QSize(capture.get(CV_CAP_PROP_FRAME_WIDTH), capture.get(CV_CAP_PROP_FRAME_HEIGHT)));
	//设置开始帧()
	long frameToStart = 0;
	capture.set(CV_CAP_PROP_POS_FRAMES, frameToStart);
	ui.textEdit->append(QString::fromLocal8Bit("从第 %1 帧开始读").arg(frameToStart));

	//获取帧率
	double rate = capture.get(CV_CAP_PROP_FPS);
	ui.textEdit->append(QString::fromLocal8Bit("帧率为:第 %1 ").arg(rate));

	delay = 1000 / rate;
	timer.start(delay / beishu);

}
void OpenCVDemo3::onTimeout()
{
	Mat frame;
	//读取下一帧
	if (!capture.read(frame))
	{
		ui.textEdit->append(QString::fromLocal8Bit("读取视频失败"));
		return;
	}

	QImage image=MatToQImage(frame);
	
	ui.label->setScaledContents(true);
	QSize qs = ui.label->rect().size();
	ui.label->setPixmap(QPixmap::fromImage(image).scaled(qs));
	
	ui.label->repaint();
	//这里加滤波程序

	long totalFrameNumber = capture.get(CV_CAP_PROP_POS_FRAMES);

	ui.textEdit->append(QString::fromLocal8Bit("正在读取第:第 %1 帧").arg(totalFrameNumber));


}
QImage OpenCVDemo3::MatToQImage(const cv::Mat& mat)
{
	// 8-bits unsigned, NO. OF CHANNELS = 1    
	if (mat.type() == CV_8UC1)
	{
		QImage image(mat.cols, mat.rows, QImage::Format_Indexed8);
		// Set the color table (used to translate colour indexes to qRgb values)    
		image.setColorCount(256);
		for (int i = 0; i < 256; i++)
		{
			image.setColor(i, qRgb(i, i, i));
		}
		// Copy input Mat    
		uchar *pSrc = mat.data;
		for (int row = 0; row < mat.rows; row++)
		{
			uchar *pDest = image.scanLine(row);
			memcpy(pDest, pSrc, mat.cols);
			pSrc += mat.step;
		}
		return image;
	}
	// 8-bits unsigned, NO. OF CHANNELS = 3    
	else if (mat.type() == CV_8UC3)
	{
		// Copy input Mat   
		const uchar *pSrc = (const uchar*)mat.data;
		// Create QImage with same dimensions as input Mat    
		QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
		return image.rgbSwapped();
	}
	else if (mat.type() == CV_8UC4)
	{
		// Copy input Mat    
		const uchar *pSrc = (const uchar*)mat.data;
		// Create QImage with same dimensions as input Mat    
		QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
		return image.copy();
	}
	else
	{
		return QImage();
	}
}

 

总结在最后:

首先使用OpenCV做播放视频的实例不少,很多网友都提供了源代码。但是往往大多数都是使用OpenCV自己的播放窗口,然后使用一个while循环来做。但是真正的使OpenCV和Qt结合在一起的大多是摄像头的代码。所以本文在整合网友资源的同时,加入了自己的想法,来实现播放本地视频。

然后,曾尝试使用多线程来解决播放问题,但是在尝试的过程中,发现不可行。所以果断放弃了。使用定时器是网上的一贯用法。但是有一些视频的fps信息和帧数信息不准确时,却会出现问题。

最后,本代码只是实现了视频的播放,但是视频中的音频信息却无法播放。所以这是不推荐使用它做播放器的原因。所以做视频播放器还是推荐FFMpeg和VLC,更专业些。

2019.10.3

对源码做了少许修改后,在github上进行更新,地址:https://github.com/obervose/OpenCVDemo3.git

 

 

 

  • 2
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值