Qt+FFmpeg播放RTSP H264视频流(3)- RTSP视频流播放
RTSP视频播放器
通过上两篇博客:Qt+FFmpeg播放RTSP H264视频流(1)- 在Qt项目加入FFmpeg库 和Qt+FFmpeg播放RTSP H264视频流(2)- FFmpeg自定义类封装已经大概了解了FFmpeg的工作过程,本编接上两篇完成一个简单的RTSP播放器。大致界面如下,代码下载地址:Qt工程完整代码下载
播放逻辑如下:
RTSP_Player播放类
RTSP_Player.h
#ifndef RTSP_PLAYER_H
#define RTSP_PLAYER_H
#include "MyFFmpeg.h"
#include <QObject>
class RTSP_Player : public QObject
{
Q_OBJECT
public:
enum PlayerState {
FFmpegInitFail = 0,
FFmpegInitSucc,
FFmpegStoped
};
explicit RTSP_Player(MyFFmpeg *ffmpeg = nullptr, QObject *parent = nullptr);
void SetPlayerUrl(QString playerUrl);
signals:
void SigOpenUrlResult(int result);
public slots:
void PlayerStart();
void PlayerStop();
private:
volatile bool m_stopped; // 停止播放标识,为true时停止播放,退出播放循环
QString m_playerUrl; // 播放url
MyFFmpeg *m_ffmpeg; // MyFFmepg指针
};
#endif // RTSP_PLAYER_H
RTSP_Player.cpp
#include "RTSP_Player.h"
#include <QThread>
RTSP_Player::RTSP_Player(MyFFmpeg *ffmpeg, QObject *parent)
: QObject(parent)
, m_ffmpeg(ffmpeg)
{
}
void RTSP_Player::SetPlayerUrl(QString playerUrl)
{
this->m_playerUrl = playerUrl;
}
void RTSP_Player::PlayerStart()
{
if (m_ffmpeg == NULL){
emit SigOpenUrlResult(RTSP_Player::FFmpegInitFail);
return;
}
m_ffmpeg->MyFFmpegSetUrl(this->m_playerUrl);
if (m_ffmpeg->MyFFmpegInit() != 0) {
emit SigOpenUrlResult(RTSP_Player::FFmpegInitFail);
return;
}
emit SigOpenUrlResult(RTSP_Player::FFmpegInitSucc);
m_stopped = false;
while (1) {
if (m_stopped){
qDebug("--------------- stop ----------------");
break;
}
if (!m_ffmpeg) {
break;
}
if (m_ffmpeg->MyFFmpepReadFrame() < 0) {
qDebug("--------------- get frame fail, stop -----------");
break;
}
QThread::msleep(0.02);
}
m_ffmpeg->MyFFmpegDestroy();
emit SigOpenUrlResult(RTSP_Player::FFmpegStoped);
qDebug("---------------- quit -----------------");
return;
}
void RTSP_Player::PlayerStop()
{
m_stopped = true;
}
FFmpegLibTestFrm UI界面类
FFmpegLibTestFrm.h
#ifndef FFMPEGLIBTESTFRM_H
#define FFMPEGLIBTESTFRM_H
#include <QMainWindow>
#include <QImage>
#include <QThread>
#include "RTSP_Player.h"
namespace Ui {
class FFmpegLibTestFrm;
}
class FFmpegLibTestFrm : public QMainWindow
{
Q_OBJECT
public:
explicit FFmpegLibTestFrm(QWidget *parent = 0);
~FFmpegLibTestFrm();
void MyFFmpegTest();
void PlayStart();
void PlayStop();
void PlayProcess();
protected:
void paintEvent(QPaintEvent *e);
void closeEvent(QCloseEvent *e);
private slots:
void SlotGetOneFrame(QImage img);
void SlotOpenUrlResult(int result);
void on_btnPlayer_clicked();
signals:
void SigPlayStart();
private:
QString m_playUrl;
MyFFmpeg *m_ffmpeg = nullptr;
RTSP_Player *m_player = nullptr;
QImage m_image;
QThread *m_playThread = nullptr;
private:
Ui::FFmpegLibTestFrm *ui;
};
#endif // FFMPEGLIBTESTFRM_H
FFmpegLibTestFrm.cpp
#include "FFmpegLibTestFrm.h"
#include "ui_FFmpegLibTestFrm.h"
#include "MyHelper.h"
#include <QPainter>
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavdevice/avdevice.h>
#include <libavformat/version.h>
#include <libavutil/time.h>
#include <libavutil/mathematics.h>
}
FFmpegLibTestFrm::FFmpegLibTestFrm(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::FFmpegLibTestFrm)
{
ui->setupUi(this);
m_ffmpeg = new MyFFmpeg;
connect(m_ffmpeg, SIGNAL(MyFFmpegSigGetOneFrame(QImage)), this, SLOT(SlotGetOneFrame(QImage)));
ui->labVideo->setStyleSheet("QLabel{border:2px solid green}");
ui->labVideo->installEventFilter(this);
ui->btnPlayer->setEnabled(true);
}
FFmpegLibTestFrm::~FFmpegLibTestFrm()
{
delete ui;
}
void FFmpegLibTestFrm::MyFFmpegTest()
{
MyFFmpeg *ffmpeg = new MyFFmpeg();
QString rtspUrl = "rtsp://192.168.88.168:554/0";
ffmpeg->MyFFmpegSetUrl(rtspUrl);
if (ffmpeg->MyFFmpegInit() == 0) {
int i;
for (i = 0; i < 5; i++) {
ffmpeg->MyFFmpepReadFrame();
}
} else {
qDebug("MyFFmpegInit fail!\n");
}
delete ffmpeg;
}
void FFmpegLibTestFrm::PlayStop()
{
if (m_player)
{
m_player->PlayerStop();
}
if (m_playThread)
{
m_playThread->quit();
m_playThread->wait(1000);
delete m_playThread;
m_playThread = nullptr;
}
if (m_player)
{
delete m_player;
m_player = nullptr;
}
}
void FFmpegLibTestFrm::PlayStart()
{
this->PlayStop();
m_playThread = new QThread();
m_player = new RTSP_Player(m_ffmpeg);
m_player->SetPlayerUrl(m_playUrl);
connect(this, SIGNAL(SigPlayStart()), m_player, SLOT(PlayerStart()));
connect(m_player, SIGNAL(SigOpenUrlResult(int)), this, SLOT(SlotOpenUrlResult(int)));
m_player->moveToThread(m_playThread);
m_playThread->start();
}
void FFmpegLibTestFrm::PlayProcess()
{
this->PlayStart();
emit SigPlayStart();
}
void FFmpegLibTestFrm::SlotOpenUrlResult(int result)
{
if (result == RTSP_Player::FFmpegInitFail)
{
this->PlayStop();
QString rtspUrl = ui->txtRTSPURL->text().trimmed();
QString errMsg = "打开" + rtspUrl + "失败";
MyHelper::ShowMessageBoxError(errMsg);
ui->btnPlayer->setText("start");
}
else if (result == RTSP_Player::FFmpegInitSucc)
{
ui->btnPlayer->setText("stop");
}
else if (result == RTSP_Player::FFmpegStoped)
{
ui->btnPlayer->setText("start");
}
ui->btnPlayer->setEnabled(true);
}
void FFmpegLibTestFrm::SlotGetOneFrame(QImage image)
{
m_image = image;
this->update();
}
void FFmpegLibTestFrm::closeEvent(QCloseEvent *event)
{
this->PlayStop();
}
void FFmpegLibTestFrm::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
if (m_image.size().width() <= 0)
return;
QImage img = m_image.scaled(ui->labVideo->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
int x = ui->labVideo->geometry().x();
int y = ui->labVideo->geometry().y();
painter.drawImage(QPoint(x, y), img);
}
void FFmpegLibTestFrm::on_btnPlayer_clicked()
{
if (ui->btnPlayer->text().compare("start") == 0) {
m_playUrl = ui->txtRTSPURL->text().trimmed();
if (m_playUrl.length() <= (int)strlen("rtsp://")) {
MyHelper::ShowMessageBoxError("请输入rtsp播放地址!");
return;
}
ui->btnPlayer->setEnabled(false);
this->PlayProcess();
} else if (ui->btnPlayer->text().compare("stop") == 0) {
ui->btnPlayer->setEnabled(false);
this->PlayStop();
}
}