QT+ffmpeg+多线程的视频播放器

一、简述

视频播放器实质是快速的播放图片,一般情况下,人的眼睛一秒可以扫过25帧图片,这样看起来有视频播放的效果。有的人可能会想到通过把视频全部解码完,然后把解码后得到所有的图片保存下来再开始播放,那么问题来了,如果这个视频非常的大(有好几百兆),就会导致播放器都打开了迟迟没有响应的情况,使得体验感大大下降。

因此,我们可以进行边解码边播放,才有时效性,所以就引入了线程实现并发,界面是主线程,解码是子线程(详见我的博客:多线程的简单使用,这里不做过多阐述),下面就来实现边解码视频边在窗口播放的效果。

二、基本实现思路

本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg webRTC rtmp hls rtsp ffplay srs↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

三、核心代码

视频的解码和多线程封装成的类fdecode,fdecode继承QThread,重写虚函数run

1、解码线程类fdecode.cpp:

QImage desImage = QImage((uchar*)buffer,codec->width,codec->height,
                                         QImage::Format_RGB32,nullptr,nullptr);//RGB像素数据 
                //每解码一帧图像给显示窗口发送一个显示图像的信号
                emit sendImage(desImage);//触发信号
                msleep(25);//播放倍速设置,可以通过延时来调
void fdecode::registerFFmpeg()
{
    av_register_all();//注册所有组件
 
}
 
void fdecode::run()//里面执行的是整个解码的流程
{
    this->registerFFmpeg();
    this->fileName = "Warcraft3_End.avi";
    this->openVideoStream(this->fileName);
}

2、播放界面类playwidget.cpp: 

#include "playwidget.h"
 
playWidget::playWidget()
{
    this->resize(800,368);
    //先创建解码线程对象
    this->fdec = new fdecode();
 
    connect(fdec,SIGNAL(sendImage(QImage)),this,SLOT(receiveImage(QImage)));//注意sendImage和receiveImage的参数
    //启动解码线程
    fdec->start();
}
void playWidget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    if(!this->img.isNull())
    {
        painter.drawImage(QRect(0,0,800,368),this->img);
    }
 
}
void playWidget::receiveImage(QImage img)
{
    this->img = img;
    this->update();
}

3、main.cpp

 

详细思路:

1、得到的每一帧RGB图像怎么处理?

每解码一帧图像给播放界面发送一个显示图像的信号

2、解码得到的图片怎么在播放界面显示?

使用信号和槽的机制(.h文件中一定要加Q_OBJECT)信号不需要实现,槽要实现

在解码这边得到一张图片就发送一个信号,播放界面收到信号就显示图片

信号写在解码线程类fdecode里,信号的参数要大于等于槽函数的参数

3、信号在哪触发?

解码线程类fdecode中解码生成一帧图片的时候(用emit触发)

4、在哪接收信号?

播放界面类中定义槽(public slots)用来接收信号

5、在播放界面接收图片要关联信号和槽,在哪里关联呢?

在播放界面的构造函数里面用connect

6、在播放界面构造函数里进行创建解码线程对象、启动解码线程(启动时就会调用run函数)、关联信号和槽

connect四个参数:信号发送者(解码线程对象)、发什么信号、 谁接收信号 、做什么事情

7、界面上接收的图片一直在变,怎么办?

接收到一张图片要保存到播放界面类中(定义QImage类成员接收),然后再绘制图片(重绘事件void paintEvent(QPaintEvent *);)

8、什么时候触发QPaintEvent?

不会一直调用,receiveImage中接收一张图片后,调用更新函数update触发

注意:

(1) 发信号的是谁,signal就在谁的.h中声明,接收的是谁,槽函数就在谁的.h中声明 (2) connect 在创建了新线程后执行,之后执行线程的start函数

如果你对音视频开发感兴趣,觉得文章对您有帮助,别忘了点赞、收藏哦!或者对本文的一些阐述有自己的看法,有任何问题,欢迎在下方评论区与我讨论!

本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg webRTC rtmp hls rtsp ffplay srs↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

猜你喜欢

转载自blog.csdn.net/m0_60259116/article/details/127055713