Simplest FFmpeg-based decoder-pure version (not including Libavformat)

Source: Internet
Author: User

=====================================================

The simplest list of ffmpeg-based video player series articles:

100 lines of code for the simplest FFMPEG+SDL-based video player (sdl1.x)

The simplest ffmpeg+sdl-based video player Ver2 (with SDL2.0)

Simplest FFmpeg-based decoder-pure version (not including Libavformat)

=====================================================


This document records a more "pure" ffmpeg-based video decoder. The previously recorded video player based on FFmpeg is actually a decoder:

The simplest ffmpeg+sdl-based video player Ver2 (using SDL2.0)

This player called the FFmpeg in the Libavformat and libavcodec two libraries to complete the video decoding work. But this is not a "pure" decoder. The decoder Libavformat complete the parsing of the encapsulation format, and LIBAVCODEC completes the decoding work. A "pure" decoder, in theory, only need to use libavcodec is enough, do not need to use Libavformat. The decoder recorded in this paper is a "pure" decoder, which simply decodes the compressed video stream of H.264/HEVC and other formats into YUV data by calling Libavcodec.

Flow chart

This document records the pure version of the FFmpeg-based decoder function call flowchart as shown in. It should be noted that the input of this decoder must contain only the video encoded data "bare stream" (for example, H. T, Hevc Stream file), but not the encapsulated format of the media data (such as AVI, MKV, MP4).


The functions of the key functions in the flowchart are listed as follows:
Avcodec_register_all (): Registers all codecs.
Avcodec_find_decoder (): Find the decoder.
AVCODEC_ALLOC_CONTEXT3 (): Allocates memory for Avcodeccontext.
Avcodec_open2 (): Opens the decoder.
Avcodec_decode_video2 (): Decodes a frame of data.
There are two normally "less common" functions:
Av_parser_init (): initializes the Avcodecparsercontext.
Av_parser_parse2 (): resolves to get a packet.

The two structures that store data are listed below:
Avframe: Storing the decoded pixel data of a frame
Avpacket: Storing a frame (in general) compressing encoded data

Avcodecparser

The Avcodecparser is used to parse the input data stream and divide it into a frame-by-frame compressed encoded data. The comparison of the image is the long continuous data "cut" into a segment of the data. His core function is Av_parser_parse2 (). It is defined as follows.

/** * Parse a packet. * * @param s parser context. * @param avctx codec context. * @param poutbuf set to pointer to parsed buffer or NULL if not yet finished. * @param poutbuf_size set to a size of parsed buffer or zero if not yet finished. * @param buf input buffer. * @param buf_size input length, to signal EOF, this should is 0 (so, the last frame can is output). * @param pts Input Presentation timestamp. * @param DTS Input decoding timestamp. * @param pos input byte position in stream. * @return The number of bytes of the input bitstream used.                                        * * Example: * @code * while (in_len) {* len = Av_parser_parse2 (Myparser, Avcodeccontext, &data, &size, * In_data, In_len, * pts, DTS, POS); * In_data + = Len; * In_len-= len; * * IF (size) * DECODE_FRAME (data, size); *} * @endcode */int AV_PARSER_PARse2 (Avcodecparsercontext *s, Avcodeccontext *avctx, uint8_t **poutbuf, int *poutb                     Uf_size, const uint8_t *buf, int buf_size, int64_t pts, int64_t DTS, int64_t POS);

Where poutbuf points to the parsed output compressed encoded data frame, buf points to the input of the compressed encoded data. If the output data is empty after the function executes (poutbuf_size is 0), the resolution is not completed, and you need to call AV_PARSER_PARSE2 () again to resolve a portion of the data before the parsed data frame can be obtained. When the output data is not empty when the function is executed, the resolution is completed and the frame data in the POUTBUF can be taken out for subsequent processing.

Contrast

Simply record this "pure version" video decoder using only Libavcodec and the different video decoders that use Libavcodec+libavformat.

PS: Using the Libavcodec+libavformat decoder reference article "
(1) The following functions related to Libavformat do not exist in the "pure version" video decoder.
Av_register_all (): Register all codecs, multiplexing/demultiplexer components, etc. where Avcodec_register_all () is called to register all codec-related components.
Avformat_alloc_context (): Creates the Avformatcontext struct body.
Avformat_open_input (): Open an input stream (file or network address). It calls Avformat_new_stream () to create the Avstream struct. Avformat_new_stream () is called AVCODEC_ALLOC_CONTEXT3 () to create the Avcodeccontext struct.
Avformat_find_stream_info (): Gets information about the media.
Av_read_frame (): Gets a frame of compressed encoded data for the media. where Av_parser_parse2 () is called.
(2) added the following functions.
Avcodec_register_all (): Registers only the components of the codec. such as encoders, decoders, bitstream filters, and so on, but do not register multiplexing/demultiplexer, these and codec-independent components.
AVCODEC_ALLOC_CONTEXT3 (): Creates the Avcodeccontext struct body.
Av_parser_init (): initializes the Avcodecparsercontext struct.
Av_parser_parse2 (): Uses Avcodecparser to separate a frame of compressed encoded data from the input data stream.
(3) The process of the program has changed.
In the "Libavcodec+libavformat" video decoder, using Avformat_open_input () and Avformat_find_stream_info () can parse out the input video information (such as the width of the video, High) and assigned to the relevant structure. So we can get this information when we initialize it by reading the corresponding fields.
In the "pure" decoder is not the case, because there is no such function, it is not possible to get the video parameters at the time of initialization. In the "pure" decoder, this information can be obtained through AVCODEC_DECODE_VIDEO2 (). So we can get this information only after we have successfully decoded the first frame, by reading the corresponding fields.


Source
/** * Simplest FFmpeg based video decoder (pure version) * Simplest FFmpeg Decoder pure * * Lei hua Lei Xiaohua * [email protected] * Communication University/Digital TV Technology * Communication University of china/digital TV technology * http://blog.csdn.net/leixiaohua1020 * * * This program implements video stream (support HEVC, H.264,MPEG2, etc.) are decoded into YUV data. * It only uses libavcodec (without using Libavformat). * Is the simplest ffmpeg video decoding aspect of the tutorial. * Learn this example to understand the decoding process of ffmpeg. * This software are a simplest decoder based on FFmpeg. * It decode Bitstreams to YUV pixel data. * It just use LIBAVCODEC (does not contains Libavformat). * Suitable for beginner of FFmpeg. */#include <stdio.h>extern "C" {#include "libavcodec/avcodec.h" #include "libswscale/swscale.h"};//test    Different codec#define test_h264 0#define TEST_HEVC 1int Main (int argc, char* argv[]) {Avcodec *pcodec; Avcodeccontext *pcodecctx= NULL;    Avcodecparsercontext *pcodecparserctx=null;    int frame_count; FILE *fp_in;    FILE *fp_out; avframe*pframe,*pframeyuv;uint8_t *out_buffer;const int in_buffer_size=4096;uint8_t in_buffer[in_buffer_size + FF_input_buffer_padding_size]={0};uint8_t *cur_ptr;int cur_size; Avpacket packet;int ret, got_picture;int y_size; #if test_hevcavcodecid Codec_id=av_codec_id_hevc;char filepath_in[]= " Bigbuckbunny_480x272.hevc "; #elseAVCodecID codec_id=av_codec_id_h264;char filepath_in[]=" Bigbuckbunny_ 480x272.h264 "; #endifchar filepath_out[]=" BIGBUCKBUNNY_480X272.YUV "; int first_time=1;struct Swscontext *img_convert    _ctx;//av_log_set_level (Av_log_debug); Avcodec_register_all ();    Pcodec = Avcodec_find_decoder (codec_id);        if (!pcodec) {printf ("Codec not found\n");    return-1;    } Pcodecctx = Avcodec_alloc_context3 (PCODEC);        if (!pcodecctx) {printf ("Could not allocate video codec context\n");    return-1; }pcodecparserctx=av_parser_init (codec_id); if (!pcodecparserctx) {printf ("Could not allocate video parser context\n");    return-1;} if (pcodec->capabilities&codec_cap_truncated) pcodecctx->flags|= codec_flag_truncated;  /* We don't send complete frames */      if (Avcodec_open2 (Pcodecctx, Pcodec, NULL) < 0) {printf ("Could not open codec\n");    return-1;    }//input File fp_in = fopen (filepath_in, "RB");        if (!fp_in) {printf ("Could not open input stream\n");    return-1;    }//output filefp_out = fopen (Filepath_out, "WB"), if (!fp_out) {printf ("Could not open Output YUV file\n"); return-1;} Pframe = Av_frame_alloc (); Av_init_packet (&packet); while (1) {cur_size = Fread (In_buffer, 1, in_buffer_size, FP        _IN);        if (cur_size = = 0) break;        Cur_ptr=in_buffer; while (cur_size>0) {int len = Av_parser_parse2 (Pcodecparserctx, Pcodecctx,&packet.data, &packet.size,cur_ PTR, Cur_size, Av_nopts_value, Av_nopts_value, av_nopts_value); Cur_ptr + = len;cur_size-= len;if (packet.size==0) Continue;//some Info from avcodecparsercontextprintf ("Packet size:%6d\t", packet.size); switch (pcodecparserctx-> Pict_type) {case av_picture_type_i:printf ("type:i\t"); Break;case Av_picture_type_p:printf ("type:p\t"); Break;case av_picture_type_b:printf ("type:b\t"); break;default:printf ("type:other\t") ); break;} printf ("Output number:%4d\t", Pcodecparserctx->output_picture_number);p rintf ("offset:%8ld\n", pcodecparserctx- >cur_offset); ret = Avcodec_decode_video2 (Pcodecctx, Pframe, &got_picture, &packet); if (Ret < 0) {printf (" Decode Error. (decoding error) \ n "); return ret;} if (got_picture) {if (first_time) {printf ("\ncodec full name:%s\n", Pcodecctx->codec->long_name);p rintf ("width: %d\nheight:%d\n\n ", pcodecctx->width,pcodecctx->height);//swscontextimg_convert_ctx = Sws_getContext ( Pcodecctx->width, Pcodecctx->height, Pcodecctx->pix_fmt, Pcodecctx->width, PCodecCtx->height, PIX_ fmt_yuv420p, sws_bicubic, NULL, NULL, and NULL); Pframeyuv=avcodec_alloc_frame (); out_buffer= (uint8_t *) Av_malloc (avpicture_get_size (pix_fmt_yuv420p, pCodecCtx- >width, Pcodecctx->height)); Avpicture_fill ((Avpicture *) PFRAMEYUV, Out_buffer, pix_fmt_yuv420p, pCodecCtx- >width, pcodecctx->height); y_size=pcodecctx->width*pcodecctx->height;first_time=0;} printf ("Succeed to decode 1 frame!\n"); Sws_scale (Img_convert_ctx, (const uint8_t* const*) Pframe->data, pframe-> Linesize, 0, Pcodecctx->height, Pframeyuv->data, pframeyuv->linesize); Fwrite (Pframeyuv->data[0],1,y_     Size,fp_out);   Y fwrite (pframeyuv->data[1],1,y_size/4,fp_out);   Ufwrite (pframeyuv->data[2],1,y_size/4,fp_out);    V}}}//flush Decoder packet.data = NULL; Packet.size = 0;while (1) {ret = Avcodec_decode_video2 (Pcodecctx, Pframe, &got_picture, &packet); if (Ret < 0) {p rintf ("Decode Error." ( decoding error) \ n "); return ret;} if (!got_picture) break;if (got_picture) {printf ("Flush decoder:succeed to decode 1 frame!\n"); Sws_scale (Img_convert_ CTX, (const uint8_t* const*) Pframe->data, pframe->linesize, 0, Pcodecctx->height, Pframeyuv->data,     pframeyuv->linesize); fwrite (pframeyuv->data[0],1,y_size,fp_out); Yfwrite (Pframeyuv->data[1],1,y_siZe/4,fp_out);   Ufwrite (pframeyuv->data[2],1,y_size/4,fp_out);    V}} fclose (fp_in); fclose (fp_out); Sws_freecontext (IMG_CONVERT_CTX); Av_parser_close (PCODECPARSERCTX); Av_frame_free (&AMP;PFRAMEYUV); Av_frame_free ( &pframe); Avcodec_close (PCODECCTX); Av_free (pcodecctx); return 0;}


The run result determines the decoder that needs to be used by setting the macro defined at the beginning of the program.
Test different codec#define test_h264  0#define TEST_HEVC  1

When the test_h264 is set to 1, decode the "bigbuckbunny_480x272.h264" of the. h file.
When TEST_HEVC is set to 1, the Hevc file "Bigbuckbunny_480x272.hevc" is decoded.

The decoded data is saved to the file "BIGBUCKBUNNY_480X272.YUV" in yuv420p format.

In addition, the program will print out some of the information in the Avcodecparsercontext, such as the frame type, as shown in the process.


Enter the H: Code stream as shown below.


Output yuv420p pixel data as shown in.



Download the simplest FFmpeg decoder pure project was added as a sub-project in the simplest FFmpeg player 2 project. The information for the new simplest FFmpeg Player 2 project is as follows.

simplest ffmpeg player 2

Version 2.3

SourceForge home: https://sourceforge.net/projects/simplestffmpegplayer/

csdn:http://download.csdn.net/detail/leixiaohua1020/8322307

This program realizes the decoding and display of video files (support HEVC,H.264,MPEG2, etc.).
Is the simplest ffmpeg video decoding aspect of the tutorial.
You can learn about the decoding process of ffmpeg by studying this example.
The project consists of 3 projects:
Simplest_ffmpeg_player: Standard Edition, the beginning of ffmpeg learning.
SIMPLEST_FFMPEG_PLAYER_SU:SU (SDL Update), added a simple SDL event.
simplest_ffmpeg_decoder_pure: a pure decoder.

Simplest FFmpeg-based decoder-pure version (not including Libavformat)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.