[FFmpeg+Qt development] Decoding process detailed analysis + code examples

Table of Contents

1. Overview of FFMPEG

?2. FFMPEG decoding

2.1 Decoding process

2.2 Decoding example


1. FFMPEG Overview

  • FFmpeg is a set of open source computer programs that can be used to record, convert, and convert digital audio and video into streams.
  • FFmpeg adopts LGPL or GPL license; it provides a complete solution for recording, converting and streaming audio and video; it also includes a very advanced audio\video codec library libavcodec. In order to ensure high portability and codec quality, Many codes in libavcodec are developed from scratch.
  • FFmpeg is developed under the Linux platform, but it can also be compiled and run in other operating system environments, including Windows, Mac OS X, etc.
  • FFmpeg was first initiated by Fabrice Bellard and was mainly maintained by Michael Niedermayer from 2004 to 2015. Many FFmpeg developers come from the MPlayer project, and currently FFmpeg is also placed on the server of the MPlayer project team.
  • The name FFmpeg comes from the MPEG video coding standard, and the “FF” in front of it stands for “Fast Forward”.

Download link:Download FFmpeg

For specific download details, please see: Qt + FFmpeg—-environment construction under windows_Yanli Zhu’s blog-CSDN blog_ffmpeg development environment construction

?

?2. FFMPEG decoding

2.1 decoding process

Decoding: The process of decoding the compressed stream data (encoded data) obtained after decapsulating the video in the encapsulated format to obtain pixel data.

For example: decode
H.264
Compressed code stream data is obtained
YUV
(or
RGB
) pixel data.

The decoding flow chart is as follows:

Decoding idea analysis:

  1. Register all components av_register_all()
  2. Open video file avformat_open_input() may fail to open
  3. Get video information Video code stream, audio code stream, text code stream
  4. Find stream information avformat_find_stream_info()
  5. Find decoder avcodec_find_decoder() may not be found
  6. Open decoder avcodec_open2()
  7. Read a frame of code stream data in the code stream av_read_frame()
  8. Decode and read one frame of code stream data Get one frame of pixel data YUV RGB
  9. Repeat steps 7-8 until all frames of the video have been processed
  10. Turn off decoder
  11. Close video file

Several important structures in the decoding process:

  • AVFormatContext

The encapsulation format context structure is also the overall structure that holds information related to the video file encapsulation format.

  • AVInputFormat//AVOutpufFormat

Each packaging format (such as FLV, MKV, MP4, AVI) corresponds to one structure.

  • AVStream

Each video (audio) stream in the video file corresponds to one this structure.

  • AVCodecContext

The encoder context structure stores video (audio) encoding and decoding related information.

  • AVCodec

Each video (audio) codec (such as H.264 decoder) corresponds to one structure.

  • AVPacket

Stores one frame of compressed encoded data.

  • AVFrame

Stores one frame of decoded pixel (sampling) data.

2.2 decoding example

Definition of decoding class:

//ffmpeg is implemented in C language. To introduce code written in C, you need to use extern.
extern "C"
{
#include <libavcodec/avcodec.h> //Encoding
#include <libavdevice/avdevice.h>
#include <libavformat/avformat.h> //Encapsulation format processing
#include <libavutil/error.h>
#include <libswscale/swscale.h> //Pixel processing
#include <libswresample/swresample.h> //Zoom
}
class fdecode
{
public:
    fdecode();
    //Register component
    void registerFFmpeg();
    //Open video stream
    void openVIdeoStream(QString filename);
    //Video name
    QString filename;
protected:
private:
};

The specific implementation is as follows:

Register all components

void fdecode::registerFFmpeg()
{
    //Register all components
    av_register_all();
}

Open video file

 AVFormatContext *forContent;//Structure used to save video-related information
    forContent=avformat_alloc_context();//Allocate space

    //Open video file
    int res=avformat_open_input( & amp;forContent,filename.toStdString().c_str(),nullptr,nullptr);
    if(res!=0)//Determine whether to open the video file
    {
        qDebug()<<"Cannot open video file";
        return;
    }

Get video file information

 //Open video file successfully and obtain file information
    res = avformat_find_stream_info(forContent,nullptr);//Check whether there is relevant video stream information
    if(res<0)
    {
        qDebug()<<"No streaming information"<<endl;
        return;
    }

    //A video stream has multiple streams, which are stored in the streams array in forContentext.
    int videoType=-1;
    //nb_streams represents how many structure information there are in the encapsulation format. Normally there are two: audio information and video information.
    for(int i=0;i<forContent->nb_streams;i + + ) //i is less than the number of streams
    {
        if(forContent->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)//Video stream
        {
            videoType=i;//Identification type
            break;
        }
    }
    //Determine whether there is video stream information
    if(videoType==-1)
    {
        qDebug()<<"No video stream related information"<<endl;
        return;
    }

Find the corresponding decoder according to the encoding ID in the encoding and decoding context

 //Context object structure corresponding to the codec: saves the decoder information and the width, height, and pixel information of the graphics
    AVCodecContext *codec=forContent->streams[videoType]->codec;
    //Find the corresponding video stream decoder
    AVCodec *decoder = avcodec_find_decoder(codec->codec_id);
    if(decoder==nullptr)//Determine whether the decoder is found
    {
        qDebug()<<"No corresponding decoder"<<endl;
        return;
    }

Open the decoder

 //The decoder is found, open the decoder
    res = avcodec_open2(codec,decoder,nullptr);
    if(res!=0)
    {
        qDebug()<<"Decoder opening failed"<<endl;
        return;
    }

Read preparation to obtain YUV and RGB pixel data

 //Prepare to read frame data--AVPacket is used to store compressed data frame by frame (h264)
    AVPacket *pkt=nullptr;
    //Set the buffer and open space
    pkt=(AVPacket *) malloc(sizeof(AVPacket));
    int size=codec->width*codec->height;//Calculate the data size of an image
    av_new_packet(pkt,size);

    /* pictureRGB saves the decoded RGB pixel data
        * pictureYUV saves the decoded YUV pixel data
        * picture saves unprocessed pixel data
        */
    AVFrame *pictureRGB,*pictureYUV,*picture=nullptr;

    //memory allocation
    pictureRGB=av_frame_alloc();
    pictureYUV=av_frame_alloc();
    picture=av_frame_alloc();

    //Size and format settings RGB
    pictureRGB->width=codec->width;//Width
    pictureRGB->height=codec->height;//height
    pictureRGB->format=codec->pix_fmt;//Format setting

    //Size and format settings YUV
    pictureYUV->width=codec->width;//width
    pictureYUV->height=codec->height;//height
    pictureYUV->format=codec->pix_fmt;//Format setting

    //How big is the YUV RGB pixel data obtained after decoding one frame of code stream data?
    int numByte_RGB=avpicture_get_size(AV_PIX_FMT_RGB32,codec->width,codec->height);
    int numByte_YUV=avpicture_get_size(AV_PIX_FMT_YUV420P,codec->width,codec->height);

    //The open space is used to save the YUV RGB pixel data size
    uint8_t *buffer_RGB=(uint8_t *)av_malloc(numByte_RGB*sizeof(uint8_t));
    uint8_t *buffer_YUV=(uint8_t *)av_malloc(numByte_YUV*sizeof(uint8_t));

    //Filling of pixel data
    avpicture_fill((AVPicture *)pictureRGB,buffer_RGB,AV_PIX_FMT_RGB32,codec->width,codec->height);
    avpicture_fill((AVPicture *)pictureYUV,buffer_YUV,AV_PIX_FMT_YUV420P,codec->width,codec->height);

    //conversion rules
    SwsContext *sws_RGB=nullptr;//Structure to save conversion rules
    SwsContext *sws_YUV=nullptr;//Structure to save conversion rules

    //Conversion rule settings AV_PIX_FMT_YUV420P AV_PIX_FMT_RGB32
    sws_RGB=sws_getContext(codec->width,codec->height,codec->pix_fmt,
                           codec->width,codec->height,AV_PIX_FMT_RGB32, //target format
                           SWS_BICUBIC,nullptr,nullptr,nullptr); //Conversion rules
    sws_YUV=sws_getContext(codec->width,codec->height,codec->pix_fmt,
                           codec->width,codec->height,AV_PIX_FMT_YUV420P,//target format
                           SWS_BICUBIC,nullptr,nullptr,nullptr); //Conversion rules
    
    //File that saves h.264 compressed code stream data
    FILE *fp=fopen("fileout/alenH264.h264","wb + ");//The file name can be defined by yourself
    //File to save yuv pixel data
    FILE *fp_yuv=fopen("fileout/alenyuv.yuv","wb + ");//The file name can be defined by yourself

Read compressed data frame by frame and save code stream data and YUV and RGB pixel data

 int count=0;//Save pictures
    //Read compressed data frame by frame
    while(av_read_frame(forContent,pkt)==0)//read data
    {
        if(pkt->stream_index == videoType)//Determine whether a frame of code stream data is the video stream that needs to be obtained
        {
            fwrite(pkt->data,pkt->size,1,fp);//Write to file
            int got_picture_ptr=-1;
            //Decode to get YUV
            res = avcodec_decode_video2(codec,picture, & amp;got_picture_ptr,pkt);
            if(res < 0)
            {
                qDebug()<<"Decoding error"<<endl;
                return;
            }
            //Compress code stream data, decoded pixel data, determine whether there is data that can be decoded, and who to decode
            if(got_picture_ptr!=0)//Decoding operation
            {
                //Remove the bad data obtained by decoding
                sws_scale(sws_RGB,picture->data,picture->linesize,0,picture->height,
                          pictureRGB->data,pictureRGB->linesize);//RGB
                sws_scale(sws_YUV,picture->data,picture->linesize,0,picture->height,
                          pictureYUV->data,pictureYUV->linesize);//YUV

                //Output YUV file
                //AVFrame pixel frame is written to the file
                fwrite(pictureYUV->data[0],size,1,fp_yuv); //y data
                fwrite(pictureYUV->data[1],size/4,1,fp_yuv);//udata
                fwrite(pictureYUV->data[2],size/4,1,fp_yuv);//v data

                //Set to output a picture every 25 frames
                count + + ;
                if(count%==0)
                {
                    QImage image((uchar *)pictureRGB->data[0],pictureRGB->width,pictureRGB->height,QImage::Format_RGB32);//pixel data
                    QString imageName = QString("image/test%1.jpg").arg(count);
                    image.save(imageName);//Save image function
                }
            }
        }
        //Release package and AVFrame resources
        av_packet_unref(pkt);
        av_frame_unref(picture);
    }
    qDebug()<<"Save code stream data successfully"<<endl;

Resource release

 //Close h.264
    fclose(fp);
    //Close YUV file
    fclose(fp_yuv);
    //Release AVFrame
    av_frame_free( & amp;picture);
    //Close decoder
    avcodec_close(codec);
    //Release the video information structure
    avformat_free_context(forContent);

Test the main function code as follows:

int main(int argc, char *argv[])
{
    //QApplication a(argc, argv);
    //Widget w;
    //w.show();
    fdecode *decode = new fdecode;
    decode->registerFFmpeg();
    decode->openVIdeoStream("filein/alen.avi");
    //return a.exec();
}

The saved H.264, yuv files and image data are as follows:

H.264, yuv file

Picture data (one screenshot every 25 frames)

Use the following applications to play the H.264 and YUV files we obtained

Let’s play Japanese comics that bloggers like!

The effect is as follows:

?FFMPEG technology—environment configuration, see:

FFmpeg + Qt development (1): Detailed steps for setting up the environment under Windows_Yuanlizhu’s blog-CSDN blog_ffmpeg library

?FFMPEG technology—encoding process, see:

[FFmpeg + Qt development] Encoding process, ordinary video encoding + detailed examples, learn it in one go_Yuanlizhu’s blog-CSDN blog

?FFMPEG technology—transcoding process, see:

[FFmpeg + Qt development] Transcoding process H.264 conversion (mov, mp4, avi, flv) and other video formats with detailed examples_Yanli Zhu’s Blog-CSDN Blog

? This article mainly introduces the decoding part of FFmpeg technology. If you have any questions, you are welcome to learn and communicate in the comment area!

? I think the blogger’s writing is good, trouble! like! Comment! collect! Please support me! Crabs, you guys!