当前位置:网站首页>QT display ffmpeg decoded pictures

QT display ffmpeg decoded pictures

2022-06-25 13:09:00 Bellerian

One 、 Preface

As I said before, we passed FFmpeg Decode video , Save video frames as pictures , This time we will play the decoded pictures ;

Ideas :

  • First , Decoding is still a ten step strategy , But this cannot be placed in the main thread , Time consuming operations will jam the interface , So we put the decoding operation into the sub thread to run ;
  • secondly , The child thread cannot directly modify the main interface UI, So the sub threads are decoded through the signal slot QImage Transfer to the main interface display ;
  • Last , The main interface updates the transmitted pictures to QLabel You can go up. ;

Two 、 Effect display

Qt Show FFmpeg Decoded picture


3、 ... and 、 Detailed code

Decoding thread class

#ifndef VIDEOPLAYER_H
#define VIDEOPLAYER_H

extern "C"{
    
    #include "libavcodec/avcodec.h"
    #include "libavformat/avformat.h"
    #include "libavutil/pixfmt.h"
    #include "libswscale/swscale.h"
}

#include <stdio.h>

#include <QThread>
#include <QImage>
#include <QDebug>

class VideoPlayer : public QThread
{
    
    Q_OBJECT
public:
    VideoPlayer();

protected:
    void run();

signals:
    void sig_post_oneFrame(const QImage& image);
};

#endif // VIDEOPLAYER_H

#include "videoplayer.h"

VideoPlayer::VideoPlayer()
{
    

}

void VideoPlayer::run()
{
    
    // Variable definitions 
    //==================================================================================
    char *file_path = "C:/Users/wangjichuan/Desktop/2.mp4";   // File path 

    ///===== First step =====
    // initialization FFMPEG  Only by calling this can the encoder and decoder be used normally 
    av_register_all();
    ///===================================================================

    ///===== The second step =====
    AVFormatContext *pFormatCtx;    // Describes the composition and basic information of a media file or media stream 
    pFormatCtx = avformat_alloc_context();  // Assign a unpacked context pointer 

    // Open file 
    if (avformat_open_input(&pFormatCtx, file_path, NULL, NULL) != 0) {
     // File information is stored in the file context , It can be processed later 
        printf(" Can't open file ");
        return;
    }
    ///===================================================================

    ///===== The third step =====
    // Find out if there is information flow in the file 
    if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
    
        printf(" No information flow found in the file ");
        return;
    }

    // Loop to find the stream information contained in the video , Until you find a video type stream 
    // And then I recorded it   Save to videoStream variable 
    // Here we only deal with video streaming   The audio stream ignores him first 
    int videoStream = -1;
    int i;
    for (i = 0; i < pFormatCtx->nb_streams; i++) {
    
        if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
    
            videoStream = i;
        }
    }

    // If videoStream by -1  The video stream was not found 
    if (videoStream == -1) {
    
        printf(" No video stream found in file ");
        return;
    }
    ///===================================================================

    ///===== Step four =====
    AVCodecContext *pCodecCtx;      // Describe the data structure of the codec context , It contains many parameters needed by codec 
    AVCodec *pCodec;                // A structure that stores codec information 

    // Find the decoder 
    pCodecCtx = pFormatCtx->streams[videoStream]->codec;    // Get the encoder context in the video stream 
    pCodec = avcodec_find_decoder(pCodecCtx->codec_id);     // Get the encoder of the video stream 

    if (pCodec == NULL) {
    
        printf(" Encoder not found ");
        return;
    }
    ///===================================================================

    ///===== Step five =====
    // Turn on the decoder 
    //==================================================================================
    if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
    
        printf(" Unable to open encoder ");
        return;
    }
    ///===================================================================

    ///===== Step six =====
    static struct SwsContext *img_convert_ctx;  // For video image conversion 
    img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,
            pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height,
            AV_PIX_FMT_BGR32, SWS_BICUBIC, NULL, NULL, NULL);
    ///===================================================================

    ///===== Step seven =====
    int numBytes;
    numBytes = avpicture_get_size(AV_PIX_FMT_BGR32, pCodecCtx->width,pCodecCtx->height);
    ///===================================================================

    ///===== Step eight =====
    AVFrame *pFrame, *pFrameRGB;    // Store audio and video raw data ( That is, uncoded data ) The structure of the body 
    pFrame = av_frame_alloc();
    pFrameRGB = av_frame_alloc();

    uint8_t *out_buffer;            // cache 
    out_buffer = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t));
    avpicture_fill((AVPicture *) pFrameRGB, out_buffer, AV_PIX_FMT_BGR32,
            pCodecCtx->width, pCodecCtx->height);
    ///===================================================================

    ///===== Step nine =====
    AVPacket *packet;               // Save to understand reuse (demuxer) after , decode (decode) Previous data ( It's still compressed data ) And some additional information about the data 
    int ret, got_picture;

    int y_size = pCodecCtx->width * pCodecCtx->height;
    packet = (AVPacket *) malloc(sizeof(AVPacket)); // Allocate one packet
    av_new_packet(packet, y_size); // Distribute packet The data of 

    av_dump_format(pFormatCtx, 0, file_path, 0); // Output video information 

    while (1)
    {
    
        if (av_read_frame(pFormatCtx, packet) < 0) {
    
            break; // I think the video is finished 
        }

        if (packet->stream_index == videoStream) {
    
            ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture,packet);

            if (ret < 0) {
    
                printf("decode error.");
                return;
            }

            if (got_picture) {
    
                sws_scale(img_convert_ctx,
                        (uint8_t const * const *) pFrame->data,
                        pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data,
                        pFrameRGB->linesize);

                QImage image(pFrameRGB->data[0], pCodecCtx->width, pCodecCtx->height, pFrameRGB->linesize[0], QImage::Format_RGB32);
                emit sig_post_oneFrame(image);
            }
        }
        av_free_packet(packet);
    }
    ///===================================================================

    ///===== Step 10 =====
    av_free(out_buffer);
    av_free(pFrameRGB);
    avcodec_close(pCodecCtx);
    avformat_close_input(&pFormatCtx);
    ///===================================================================
}


Main form class

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QDebug>
#include <QLabel>

QT_BEGIN_NAMESPACE
namespace Ui {
     class MainWindow; }
QT_END_NAMESPACE

#include "videoplayer.h"

class MainWindow : public QMainWindow
{
    
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    QLabel* label;
    VideoPlayer* m_player;

public slots:
    void slot_get_oneFrame(const QImage& image);


private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    
    ui->setupUi(this);

    label = new QLabel(this);
    this->setCentralWidget(label);

    m_player = new VideoPlayer;
    connect(m_player,SIGNAL(sig_post_oneFrame(QImage)),this,SLOT(slot_get_oneFrame(QImage)));
    m_player->start();
}

MainWindow::~MainWindow()
{
    
    delete ui;
}

void MainWindow::slot_get_oneFrame(const QImage& image)
{
    
    label->setPixmap(QPixmap::fromImage(image));
}
原网站

版权声明
本文为[Bellerian]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/176/202206251223251829.html