FFmpeg video decoder

FFmpeg video decoder_ffmpeg decoder-CSDN blog

1. Introduction to FFmpeg library

2.FFmpeg decoding function

2.1 FFmpeg decoding flow chart

av_read_frame(): Loops to read data frame by frame, which is actually h264 code stream

2.2 Introduction to FFmpeg decoding function

3. Data structure of FFmpeg decoding

Display timestamp: The minutes and seconds that this frame should be displayed based on the member variable time_base of AVStream, the time base of the stream
AVPacket: Install h.264 data (data before decoding, encoded data)
AVFrame: Install YUV data (decoded data, decoded data)

4. Supplementary knowledge: Why does the decoded data need to be processed by the sws_scale() function?

5. After-class exercises

/**
 * The simplest decoder based on FFmpeg
 * Simplest FFmpeg Decoder
 *
 * Lei Xiaohua
 *[email protected]
 * Communication University of China/Digital TV Technology
 * Communication University of China / Digital TV Technology
 * http://blog.csdn.net/leixiaohua1020
 *
 * This program implements the decoding of video files (supports HEVC, H.264, MPEG2, etc.).
 * It is the simplest tutorial on FFmpeg video decoding.
 * By studying this example, you can understand the decoding process of FFmpeg.
 * This software is a simplest video decoder based on FFmpeg.
 * Suitable for beginners of FFmpeg.
 *
 */

#include <stdio.h>

#define __STDC_CONSTANT_MACROS

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

int main(int argc, char* argv[])
{
    AVFormatContext* pFormatCtx; // All information stored about the video
    int i, videoindex; // videoindex: the serial number value of the video stream
    AVCodecContext* pCodecCtx;
    AVCodec* pCodec;
    AVFrame* pFrame, * pFrameYUV;
    uint8_t* out_buffer;
    AVPacket* packet;
    int y_size;
    int ret, got_picture;
    struct SwsContext* img_convert_ctx;


    //The path of the audio and video file to be decoded
    char filepath[] = "./test.avi";

    //The number of video frames
    int frame_cnt;

    // 1. Initialize and register all components
    //av_register_all();
    avformat_network_init();
    pFormatCtx = avformat_alloc_context();
     
    // 2. Open the video file
    if (avformat_open_input( & amp;pFormatCtx, filepath, NULL, NULL) != 0) {
        printf("Couldn't open input stream.\
");
        return -1;
    }

    // 3. Get video stream information
    if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
        printf("Couldn't find stream information.\
");
        return -1;
    }

    // Get stream information and decode it
    videoindex = -1;
    
    //Find the serial number value of the video stream
    // nb_streams: There are several streams recorded. Generally, stream[0] is video and stream[1] is audio.
    for (i = 0; i < pFormatCtx->nb_streams; i + + )
        if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
            //The enumeration value AVMEDIA_TYPE_VIDEO is 0, indicating video

            videoindex = i;
            break;
        }

    if (videoindex == -1) {
        printf("Didn't find a video stream.\
");
        return -1;
    }

    //AVCodecParameters: used to save basic parameter information of audio and video streams
    AVCodecParameters* codecParameters = pFormatCtx->streams[videoindex]->codecpar;
    pCodecCtx = avcodec_alloc_context3(nullptr);
    avcodec_parameters_to_context(pCodecCtx, codecParameters);

    // 4. Find the decoder, eg: H.264 encoder
    // pCodecCtx=pFormatCtx->streams[videoindex]->codec;
    pCodec = (AVCodec*)avcodec_find_decoder(pCodecCtx->codec_id);
    if (pCodec == NULL) {
        printf("Codec not found.\
");
        return -1;
    }

    // 5. Open the decoder
    if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
        printf("Could not open codec.\
");
        return -1;
    }

    // open a file
    FILE * fp, * fp_264, * fp_yuv;
    fopen_s( & amp;fp, "info.txt", "wb + ");
    fopen_s( & amp;fp_264, "output264.h264", "wb + ");
    fopen_s( & amp;fp_yuv, "outputyuv.yuv", "wb + ");

    /*
     * Here is the code for the terminal to output video information
     * Taken from pFormatCtx, using fprintf()
     */

    //Write to file info.txt
    fprintf(fp, "Duration: %d μs\
", pFormatCtx->duration); // Microseconds, converted to seconds divided by 1e6
    fprintf(fp, "Packaging format:%s\
", pFormatCtx->iformat->long_name);
    fprintf(fp, "Resolution: %d*%d\
", pCodecCtx->width, pCodecCtx->height);


    
    packet = av_packet_alloc();
    pFrame = av_frame_alloc();
    pFrameYUV = av_frame_alloc();

    out_buffer = (uint8_t*)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 1));
    av_image_fill_arrays(pFrameYUV->data, pFrameYUV->linesize, out_buffer, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 1);


    //Output video file information
    printf("--------------- File Information ----------------\
");
    
    /*
    * av_dump_format() function:
      Print detailed information about the input or output format, such as
    * duration, bitrate, streams, container, programs, metadata, side data,
    * codec and time base.
    */
    av_dump_format(pFormatCtx, 0, filepath, 0);
    printf("-------------------------------------------------- --\
");
    img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);

    //Number of video frames
    frame_cnt = 0;

    // Output H264 code stream
    // 6. av_read_frame(): Read a frame of compressed data from the input file.
    while (av_read_frame(pFormatCtx, packet) >= 0) {
        if (packet->stream_index == videoindex) {
            // videoindex: determine whether it is a video


            /*
             * Output the code of H264 code stream here
             * Taken from packet, use fwrite() to write the data in the memory to the file output264.h264
            */
            fwrite(packet->data, 1, packet->size, fp_264);

            if (avcodec_send_packet(pCodecCtx, packet) < 0) {
                printf("avcodec_send_packet failed!.\
");
                continue;
            }

            while (1)
            {
                ret = avcodec_receive_frame(pCodecCtx, pFrame);
                if (ret != 0)break;

                // The sws_scale function processes the generated image, and the generated data is stored in pFrameYUV
                sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);
                
                // Output the sequence number of the processed frame
                printf("Decoded frame index: %d\
", frame_cnt);


                /*
                 * Add the code to output YUV here
                 * Taken from pFrameYUV, using fwrite()
                 *
                 *
                 * data[0]: Y data, all bright points on the screen, black and white data
                 * data[1]: U data, the data is one quarter of Y
                 * "U" and "V" represent chroma,
                   Its function is to describe the color and saturation of the image, and is used to specify the color of the pixels.
                 * data[2]: V data, the data is one quarter of Y
                 */
                fwrite(pFrameYUV->data[0], 1, pCodecCtx->width * pCodecCtx->height, fp_yuv);
                fwrite(pFrameYUV->data[1], 1, pCodecCtx->width * pCodecCtx->height / 4, fp_yuv);
                fwrite(pFrameYUV->data[2], 1, pCodecCtx->width * pCodecCtx->height / 4, fp_yuv);
                frame_cnt + + ;
            }
        }
        av_packet_unref(packet);
    }

    sws_freeContext(img_convert_ctx);

    fclose(fp);
    fclose(fp_264);
    fclose(fp_yuv);
    av_frame_free( & amp;pFrameYUV);
    av_frame_free( & amp;pFrame);
    avcodec_close(pCodecCtx);
    avformat_close_input( & amp;pFormatCtx);

    return 0;
}