Qt+FFmpeg播放RTSP H264视频流(3)- RTSP视频流播放

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();
    }
}

播放效果

RTSP简单播放器

代码下载

完整demo代码

Qt中使用FFmpeg播放RTSP H264视频流的方法如下[^1][^2]: 1. 首先,确保你已经安装了QtFFmpeg,并且已经将FFmpeg的库文件添加到Qt项目中。 2. 创建一个Qt项目,并在项目文件中添加FFmpeg的头文件和库文件的路径。 3. 在Qt的代码中,使用FFmpeg的API来实现视频流播放。以下是一个简单的示例代码: ```cpp #include <QCoreApplication> #include <QDebug> #include <QThread> extern "C" { #include <libavformat/avformat.h> #include <libavcodec/avcodec.h> #include <libswscale/swscale.h> } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // 初始化FFmpeg av_register_all(); // 创建AVFormatContext对象 AVFormatContext *formatContext = avformat_alloc_context(); // 打开视频流 if (avformat_open_input(&formatContext, "rtsp://your_rtsp_url", nullptr, nullptr) != 0) { qDebug() << "无法打开视频流"; return -1; } // 查找视频流信息 if (avformat_find_stream_info(formatContext, nullptr) < 0) { qDebug() << "无法获取视频流信息"; return -1; } // 查找视频流索引 int videoStreamIndex = -1; for (int i = 0; i < formatContext->nb_streams; i++) { if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { videoStreamIndex = i; break; } } // 如果找不到视频流索引,退出程序 if (videoStreamIndex == -1) { qDebug() << "找不到视频流"; return -1; } // 获取视频解码器参数 AVCodecParameters *codecParameters = formatContext->streams[videoStreamIndex]->codecpar; // 查找视频解码器 AVCodec *codec = avcodec_find_decoder(codecParameters->codec_id); if (codec == nullptr) { qDebug() << "找不到视频解码器"; return -1; } // 创建解码器上下文 AVCodecContext *codecContext = avcodec_alloc_context3(codec); if (avcodec_parameters_to_context(codecContext, codecParameters) < 0) { qDebug() << "无法创建解码器上下文"; return -1; } // 打开解码器 if (avcodec_open2(codecContext, codec, nullptr) < 0) { qDebug() << "无法打开解码器"; return -1; } // 创建帧对象 AVFrame *frame = av_frame_alloc(); // 创建解码后的帧对象 AVFrame *decodedFrame = av_frame_alloc(); // 创建解码后的帧的缓冲区 uint8_t *buffer = nullptr; int bufferSize = av_image_get_buffer_size(AV_PIX_FMT_RGB24, codecContext->width, codecContext->height, 1); buffer = (uint8_t *)av_malloc(bufferSize * sizeof(uint8_t)); av_image_fill_arrays(decodedFrame->data, decodedFrame->linesize, buffer, AV_PIX_FMT_RGB24, codecContext->width, codecContext->height, 1); // 创建视频转换上下文 SwsContext *swsContext = sws_getContext(codecContext->width, codecContext->height, codecContext->pix_fmt, codecContext->width, codecContext->height, AV_PIX_FMT_RGB24, SWS_BILINEAR, nullptr, nullptr, nullptr); // 读取视频帧 AVPacket packet; while (av_read_frame(formatContext, &packet) >= 0) { if (packet.stream_index == videoStreamIndex) { // 解码视频帧 avcodec_send_packet(codecContext, &packet); avcodec_receive_frame(codecContext, frame); // 转换视频帧格式 sws_scale(swsContext, frame->data, frame->linesize, 0, codecContext->height, decodedFrame->data, decodedFrame->linesize); // 在这里可以将解码后的帧显示到界面上 // 延时一段时间,模拟视频播放 QThread::msleep(40); } av_packet_unref(&packet); } // 释放资源 av_frame_free(&frame); av_frame_free(&decodedFrame); avcodec_free_context(&codecContext); avformat_close_input(&formatContext); avformat_free_context(formatContext); return a.exec(); } ``` 请注意,上述代码只是一个简单的示例,实际的视频播放功能可能需要更多的处理和错误处理。
评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值