VS2022+QT6.7+FFmpeg 简单实现解码播放(详细注释)

目录

一、具体实现

二、实现效果


本文在VS中使用QT环境,基于FFmpeg核心库,在QT子线程中解码播放本地视频!!

话不多少,直接上代码!!

一、具体实现

 QtWidgetsApplication2.cpp

#include "QtWidgetsApplication2.h"

QtWidgetsApplication2::QtWidgetsApplication2(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);
   
    mythread* sth = new mythread(); //创建子线程对象
    sth->moveToThread(thread);      //将子线程对象移动到线程中
    
    connect(sth, &mythread::send_data, this, &QtWidgetsApplication2::read_data); //获取子线程发送的数据显示在label上
 
    connect(thread,&QThread::started,sth,&mythread::run);  //线程开始信号链接

    connect(ui.pushButton, &QPushButton::clicked, this , [=]() {
        ui.label->setScaledContents(true); //label适应视频大小
        thread->start();  //线程开始,播放视频
        });
}

void QtWidgetsApplication2::closeEvent(QCloseEvent* event)  //窗口关闭事件
{
    thread->quit();  //退出线程
    thread->wait();  //等待线程真正退出 (安全)
}

void mythread::run()
{
    avdevice_register_all(); //硬件设备注册
    avformat_network_init(); //网络注册
        
    char filename[1024] = "C:\\Users\\suolide-zjq\\Desktop\\mp4\\1.mp4";                 //文件路径
    int avformat_open_ret = avformat_open_input(&formatcontext, filename, NULL, NULL);   //打开文件         
    int avformat_find_ret = avformat_find_stream_info(formatcontext, NULL);              //获取音视频流信息
                                                             
    for (int i = 0; i < formatcontext->nb_streams; i++) {                                //寻找视频流
        if (formatcontext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
            streamIndex = i;
            break;
        }
    }
 
    // 将参数从 AVCodecParameters 转换到 AVCodecContext
    avcodec_parameters_to_context(codeccontext, formatcontext->streams[streamIndex]->codecpar);

    //查找合适的解码器
    const AVCodec* codec = avcodec_find_decoder(codeccontext->codec_id);

    //打开解码器
    int avcodec_open_ret = avcodec_open2(codeccontext, codec, NULL);

    //输入视频帧初始化
    AVFrame* frame = av_frame_alloc();

    //数据包初始化
    AVPacket* packet = av_packet_alloc();

    //输出RGB帧初始化
    AVFrame* frameRGB = av_frame_alloc();

    //计算缓冲区大小并分配动态内存
    uint8_t* pOutbuffer = (uint8_t*)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_RGB24,
                                             codeccontext->width, codeccontext->height, 1));

    //初始化缓冲区
    int ret = av_image_fill_arrays(frameRGB->data, frameRGB->linesize, pOutbuffer, AV_PIX_FMT_RGB24, 
                                             codeccontext->width, codeccontext->height, 1);

    //获取图像转换上下文
    SwsContext* sws = sws_getContext(codeccontext->width, codeccontext->height, 
                                     codeccontext->pix_fmt,
                                     codeccontext->width, codeccontext->height,
                                     AV_PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
 
    //循环解码
    while (av_read_frame(formatcontext, packet) >= 0) {
        if (packet->stream_index == streamIndex) {
            
            //用于将一个封装好的媒体包(avpacket)发送给解码器上下文(avcodeccontext)
            avcodec_send_packet(codeccontext, packet);
            
            //获取解码后的帧,从0开始,直到解码完成
            decode_video_ret = avcodec_receive_frame(codeccontext, frame);
           
            if (decode_video_ret >= 0) { 
               
                //视频流数据转换为rgb图像数据
                sws_scale(sws, frame->data, frame->linesize, 0, codeccontext->height, frameRGB->data, frameRGB->linesize);
                
                //数据转换为图像
                QImage image((uchar*)pOutbuffer, codeccontext->width, codeccontext->height, QImage::Format_RGB888);
                
                //延时
                QThread::msleep(30);

                //显示图像
                send_data(image);
            }
        }
    } 
}

void QtWidgetsApplication2::read_data(QImage image)
{
    ui.label->setPixmap(QPixmap::fromImage(image));  //将image显示在label上
}

QtWidgetsApplication2::~QtWidgetsApplication2()
{}

 QtWidgetsApplication2.h

#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_QtWidgetsApplication2.h"
#include <QDebug>
#include <QLabel>
#include <QThread>
#include <QImage>

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>
#include <libavutil/imgutils.h> 
}

class QtWidgetsApplication2 : public QMainWindow
{
    Q_OBJECT
public:
    QtWidgetsApplication2(QWidget *parent = nullptr);
    ~QtWidgetsApplication2();
    QThread* thread = new QThread(this); //线程
    void closeEvent(QCloseEvent* event); //关闭窗口事件
 
public slots:
    void read_data(QImage image);

private:
    Ui::QtWidgetsApplication2Class ui;
};

class mythread : public QObject
{
    Q_OBJECT
public:
    //析构函数,释放内存
    ~mythread()
    {
        avcodec_free_context(&codeccontext);
        avformat_close_input(&formatcontext);
    }
    //创建封装格式上下文
    AVFormatContext* formatcontext = avformat_alloc_context();
    
    //创建解码器上下文
    AVCodecContext* codeccontext = avcodec_alloc_context3(nullptr);
    
    //视频流索引标志位
    int streamIndex = -1;
    
    //获取解码后的帧标志位
    int decode_video_ret;
signals:
    void send_data(QImage image);
public slots:
    void run();
private:
    QtWidgetsApplication2* parent;
};

 main.cpp

#include "QtWidgetsApplication2.h"
#include <QtWidgets/QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QtWidgetsApplication2 w;
    w.show();
    return a.exec();
}

二、实现效果

 ui界面拖入label、pushbuttond474b6a682394f6a8975b617fec73c4a.png

5f7c3ec51e9f4047ba9a6a38ffab632f.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值