QT+Opencv实现视频流播放

1.简单流程

 首先通过opencv打开视频流,获取到数据帧,然后将数据帧转换为QT可识别的图像,显示到QT界面上。

2.opencv解码线程源码

//DecodeOpencv.h

#pragma once

#include 
#include 

#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"

class DecodeOpencv : public QThread
{
	Q_OBJECT

Q_SIGNALS:
	void sigSendFrame(cv::Mat mat);

public:
	DecodeOpencv(QObject *parent = nullptr);
	~DecodeOpencv();

public:
	void setUrl(QString url);

	void setStoped(bool stop);

protected:
	void run();

private:
	QString m_rtsp;

	bool m_isStop = false;
};
//DecodeOpencv.cpp

#include "DecodeOpencv.h"
#include 

DecodeOpencv::DecodeOpencv(QObject *parent)
	: QThread(parent)
{
	qRegisterMetaType("cv::Mat");
}

DecodeOpencv::~DecodeOpencv()
{
	m_isStop = true;
}

void DecodeOpencv::setUrl(QString url)
{
	m_rtsp = url;
}

void DecodeOpencv::setStoped(bool stop)
{
	m_isStop = stop;
}

void DecodeOpencv::run()
{
	cv::VideoCapture cap;

	if (m_rtsp.isEmpty())
	{
		qDebug() << "未找到视频流地址";
		return;
	}
	bool suc = false;
	if (m_rtsp.contains("localhost:camera"))
	{
		suc = cap.open(0); //打开本地摄像头
	}
	else
	{
		suc = cap.open(m_rtsp.toStdString()); //打开网络流地址
	}

	if (!suc)
	{
		qDebug() << "播放失败";
		return;
	}

	while (true)
	{
		if (!m_isStop)
		{
			cv::Mat frame;
			cap >> frame;
			if (frame.empty())
			{
				qDebug() << "播放帧解析失败";
				continue;
			}
			emit sigSendFrame(frame);
		}
		else
		{
			qDebug() << "停止播放";
			break;
		}
	}
}

3.QT界面

 QT+Opencv实现视频流播放_第1张图片

//ShowMatWidget.h

#pragma once

#include 
#include "ui_ShowMatWidget.h"
#include "DecodeOpencv.h"

class ShowMatWidget : public QWidget
{
	Q_OBJECT

public:
	ShowMatWidget(QWidget *parent = Q_NULLPTR);
	~ShowMatWidget();

private Q_SLOTS:
	void slotBtnConnected();

	void slotGetFrame(cv::Mat mat);

	QImage cvMat2QImage(const cv::Mat& mat);

private:
	Ui::ShowMatWidget ui;

	DecodeOpencv *m_thread = nullptr;
};

//ShowMatWidget.cpp

#include "ShowMatWidget.h"

#include 

ShowMatWidget::ShowMatWidget(QWidget *parent)
	: QWidget(parent)
{
	ui.setupUi(this);

	m_thread = new DecodeOpencv(this);

	connect(m_thread, &DecodeOpencv::sigSendFrame, this, &ShowMatWidget::slotGetFrame);

	connect(ui.pushButton, &QPushButton::clicked, this, &ShowMatWidget::slotBtnConnected);
}

ShowMatWidget::~ShowMatWidget()
{
}

void ShowMatWidget::slotBtnConnected()
{
	m_thread->setUrl(ui.lineEdit->text());
	m_thread->start();
}

void ShowMatWidget::slotGetFrame(cv::Mat mat)
{
	QImage image = cvMat2QImage(mat);

	ui.label->setPixmap(QPixmap::fromImage(image));
}

QImage ShowMatWidget::cvMat2QImage(const cv::Mat& mat)
{
	//8位,通道数为1
	if (mat.type() == CV_8UC1)
	{
		QImage image(mat.cols, mat.rows, QImage::Format_Indexed8);
		image.setColorCount(256);
		for (int i = 0; i < 256; i++)
		{
			image.setColor(i, qRgb(i, i, i));
		}

		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位,通道数为3
	else if (mat.type() == CV_8UC3)
	{
		const uchar *pSrc = (const uchar*)mat.data;
		QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
		return image.rgbSwapped();
	}
	//8位,通道数为4
	else if (mat.type() == CV_8UC4)
	{
		qDebug() << "CV_8UC4";

		const uchar *pSrc = (const uchar*)mat.data;
		QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
		return image.copy();
	}
	//32位,通道数为3
	else if (mat.type() == CV_32FC3)
	{
		cv::Mat temp;
		mat.convertTo(temp, CV_8UC3);

		const uchar *pSrc = (const uchar*)temp.data;
		QImage image(pSrc, temp.cols, temp.rows, temp.step, QImage::Format_RGB888);
		return image.rgbSwapped();
	}
	else
	{
		qDebug() << "ERROR: Mat could not be converted to QImage.";
		return QImage();
	}
}

你可能感兴趣的:(音视频开发,Qt进阶,qt,opencv,视频处理,流媒体,rtsp)