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

一、简述

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

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

二、实现效果

部分视频转成动图

三、基本实现思路

QT+ffmpeg+多线程的视频播放器的基本使用_第1张图片

四、核心代码

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

QT+ffmpeg+多线程的视频播放器的基本使用_第2张图片

详细思路:

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下载

你可能感兴趣的:(Qt实战,流媒体,线程,qt,音视频,多线程)