QT+ffmpeg+多线程的视频播放器的基本使用

13 篇文章 2 订阅
2 篇文章 0 订阅

一、简述

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

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

二、实现效果

部分视频转成动图

三、基本实现思路

四、核心代码

视频的解码和多线程封装成的类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函数

源码下载链接(包括演示视频): 

QT+ffmpeg+多线程的视频播放器的代码-C/C++文档类资源-CSDN下载

  • 13
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
课程摘要1 Qt音视频开发实战 是陈超老师用10年以上音视频一线实战开发经验,四年音视频开发教学经验打造的Qt音视频开发课程。2 Qt音视频开发实战以Qt c++开发为中心。所有课程全部围绕Qt音视频开发展开。3 非常适合那些只做Qt开发的工程师来学习,学习更容易一些。学习目标,培养高级Qt音视频开发工程师.4 Qt音视频开发实战适合那些掌握Qt基础开发,初级开发工程师,月薪在20k以下,通过学习,达到更高薪水的Qt高级开发工程师。 课程优势1 老师过去15年+ 音视频,网络通讯,数字图像处理一线实战经验。过去四年积累了丰富的音视频开发教学经验,学员从年薪30w~50w,就职于腾讯,阿里等各大互联网公司。2 老师10多年Qt开发经验,长期大量使用Qt开发项目,国内最早一批使用Qt的程序员。3 QQ 一对一教学指导,阶段性作业案例小项目指导,就业面试指导。 课程内容1 Qt 核心基础加强。对于那些学了很多年Qt开发而不得要领的学员非常友好。2 音视频开发基础。音视频原理,RGB YUV, 音频原理。图像压缩编码,音频压缩编码,H.264压缩,H.264编码原理 I P B SPS PPS解析,   视频存储容器,mp4 , AAC.  Qt音频视频采集,FFmpeg编码,解码,x264编码,AAC编码。mp3编码。格式转换。视频播放器内核。图像渲染。3 OpenGL数字图像处理基础。OpenGL基础,渲染管线,shader编程。滤镜,美颜,后期处理。编写渲染引擎。4 网络socket通讯编程,自定义私有协议。TCP/UDP音视频传输。 学员要求1 熟悉c/c++,掌握Qt基本控件,类基础。2 每天学习两小时,学习周期3~5个月,做完练习,小项目。
Qt C++ 中,创建一个线程可以使用 `QThread` 类。以下是一个简单的示例,展示如何创建一个类并为其设置四个线程: ```cpp #include <QThread> class MyThread : public QObject { Q_OBJECT public: MyThread(QObject *parent = nullptr) : QObject(parent) {} public slots: void doSomeWork() { // Do some work... } }; int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); MyThread thread1; QThread workerThread1; thread1.moveToThread(&workerThread1); workerThread1.start(); MyThread thread2; QThread workerThread2; thread2.moveToThread(&workerThread2); workerThread2.start(); MyThread thread3; QThread workerThread3; thread3.moveToThread(&workerThread3); workerThread3.start(); MyThread thread4; QThread workerThread4; thread4.moveToThread(&workerThread4); workerThread4.start(); // Connect signals to slots QObject::connect(&workerThread1, &QThread::started, &thread1, &MyThread::doSomeWork); QObject::connect(&workerThread2, &QThread::started, &thread2, &MyThread::doSomeWork); QObject::connect(&workerThread3, &QThread::started, &thread3, &MyThread::doSomeWork); QObject::connect(&workerThread4, &QThread::started, &thread4, &MyThread::doSomeWork); return app.exec(); } ``` 在这个示例中,我们创建了一个名为 `MyThread` 的类,并将其继承自 `QObject`。该类有一个名为 `doSomeWork()` 的公共槽函数,用于在单独的线程中执行一些工作。我们创建了四个 `MyThread` 实例,并为每个实例创建了一个 `QThread` 对象。然后,我们将每个 `MyThread` 实例移动到其对应的线程中,并启动线程。最后,我们将每个线程的 `started` 信号连接到其对应的 `MyThread` 实例的 `doSomeWork()` 槽函数上。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ze言

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值