In the actual code, these codecs are divided into encoder/decoder, multiplexer/demultiplexer and equipment, which correspond to codecs, input and output formats and equipment respectively. At the beginning of the main function, these three objects are initialized. In avcodec_register_all, many codecs are registered, including H.264 decoder and X264 encoder for video.
Register _ decoder (H264, H264);
REGISTER_ENCODER (LIBX264,libx 264);
Find the relevant macro code, as shown below
#define REGISTER_ENCODER(X,x) { /
External AVCodec x # # _ encoder; /
if(CONFIG _ # # X # # _ ENCODER)av codec _ register(& amp; X # # _ encoder); }
#define REGISTER_DECODER(X,x) { /
External AVCodec x # # _ decoder; /
if(CONFIG _ # # X # # _ DECODER)av codec _ register(& amp; X # # _ decoder); }
In this way, libx264_encoder and h264_decoder are actually registered in the code according to the compilation options such as config _ # # x # _ encoder, and the registration process takes place in the avcodec_register(AVCodec *codec) function. In fact, it is to add libx264_encoder and h264_decoder specific codecs to the global linked list first_AVCodec. The input parameter avcodec is a structure, which can be understood as the base class of codec, including not only the name, id and other attributes, but also the function pointers to be implemented in each specific codec extension class below.
int(* init)(AVCodecContext *);
int (*encode)(AVCodecContext *,uint8_t *buf,int buf_size,void * data);
int(* close)(AVCodecContext *);
int (*decode)(AVCodecContext *,void *outdata,int *outdata_size,
const uint8_t *buf,int buf _ size);
void(* flush)(AVCodecContext *);
Continue to trace libX264, that is, the static coding library of X264, which was introduced as an H.264 encoder during FFMPEG compilation. There is the following code in libx264.c
AVCodec libx264_encoder = {
. name = "libx264 ",
. Type = codec type video,
. Id = codec _ID_H264,
. priv _ data _ size = sizeof(x264 context),
. init = X264_init,
. Code = X264 _ frame,
. Off = X264 _ Off,
. Capability = codec _ upper limit _ delay,
. Pix _ fmts = (enumpixel format []) {PIX _ FMT _ yuv420p, pix _ fmt _ none},
. long _ name = NULL _ IF _ CONFIG _ SMALL(" libx 264h . 264/AVC/MPEG-4 AVC/MPEG-4 part 10 "),
};
Here, the properties and methods from AVCodec are specially specified. In ...
. init = X264_init,
. Code = X264 _ frame,
. Off = X264 _ Off,
The function pointer points to specific functions, and these three functions will be realized by using the API provided in libx264 static library, which is the main interface function of x264. Pix_fmts defines the supported input formats, where 4: 2: 0.
PIX_FMT_YUV420P,///& lt; Plane YUV 4:2:0, 12bpp, (1cr&; Cb samples every 2xy samples)
X264Context seen above encapsulates the context management data that X264 needs.
Typedef structure x264 context {
x264 _ param _ t params
x264 _ t * enc
x264 _ picture _ t pic
AVFrame out _ pic
} X264Context
It belongs to the void *priv_data variable of avcodeContext structure and defines the private context attribute of each codec. Like the context base class, avcodeContext also provides other context attributes such as screen resolution and quantization range, as well as function pointers such as rtp_callback of codec.
Back to the main function, we can see that various codecs have been completed. After input and output formats and device registration, context initialization and encoding and decoding parameters will be read in, and then the av_encode () function will be called for specific encoding and decoding work. Look at this process according to the comments of this function:
1.iostream initialization.
2. Determine the required codec according to iostream and initialize it.
3. Write each part of the output file.
Pay attention to steps 2 and 3 to see how to achieve polymorphism by using the codec base class analyzed earlier. Looking at the relationship of this code, we find that in FFMPEG, the class diagram can be used to represent the approximate codec combination.
Refer to 3 for the meaning of these structures (see appendix). A series of functions of utils.c will be called here, and the avcodec_open () function here will be called when the codec is opened, which will run the following code:
avctx-& gt; Codec = codec;
avctx-& gt; Codec id = codec-> id;
avctx-& gt; frame _ number = 0;
if(avctx-& gt; Codec->; init){
ret = avctx-& gt; Codec->; init(avctx);
Initialize a specific adaptive codec, here avctx->; Codec->; Init(avctx) is a concrete initialization function defined by calling the function pointer in AVCodec, such as X264_init.
Avcodec_encode_video () and avcodec_encode_audio () are called by output_packet () for audio and video encoding, with function pointer avctx->; Codec->; Encode () calls the encoding function of the adaptive encoder, such as X264_frame, to do specific work.
From the above analysis, we can see how FFMPEG uses object-oriented to abstract encoding and decoding behavior, and materializes each encoding and decoding entity through combination and inheritance. Imagine adding a new decoder H265 to FFMPEG, and the things to do are as follows:
1. Add CONFIG_H265_DECODER to the configuration compilation configuration.
2. Register H265 decoder with macro.
3. define AVCodec 265_decoder variable, and initialize properties and function pointers.
4. Use the decoder API to concretize the function pointer, such as the init of 265_decoder.
After completing the above steps, the new decoder can be put into FFMPEG, and the external matching and operation rules are realized through the polymorphism of the base class.
4.X264 architecture analysis
X264 is an open source H.264 encoder initiated by French college students in 2004. It optimizes the assembly-level code of PC, abandons the functions with low performance-efficiency ratio such as slicing and multiple reference frames, and improves the coding efficiency. It has been introduced by FFMPEG as a .264 coding library and transplanted to many DSP embedded platforms. X264 in FFMPEG has been analyzed as an example in the third section, and we will continue to deepen our understanding of related content in combination with X264 framework.
Before looking at the code, think about how to analyze a specific encoder object-oriented. Abstractions of different algorithms in entropy coding and various estimation algorithms in intra or inter coding can be constructed as classes.
In X264, the external API and context variables we see are declared in X264.h, and in API functions, the functions about auxiliary functions are defined in common.c
void x264 _ picture _ alloc(x264 _ picture _ t * pic,int i_csp,int i_width,int I _ height);
void x264 _ picture _ clean(x264 _ picture _ t * pic);
int x264_nal_encode( void *,int *,int b_annexeb,x264 _ nal _ t * nal);
The encoding function is defined in encoder.c
X264 _ t * x264 _ encoder _ open (x264 _ param _ t *);
int x264 _ encoder _ reconfig(x264 _ t *,x264 _ param _ t *);
int x264 _ encoder _ headers(x264 _ t *,x264_nal_t **,int *);
int x264_encoder_encode ( x264_t *,x264_nal_t **,int *,x264_picture_t *,x264 _ picture _ t *);
Void x264 _ encoder _ off (x264 _ t *);
In the x264.c file, there is a program's main function, which can be regarded as an example of API use. It also realizes the actual function by calling API and context variables in x264.h
X264 x264_t, the most important structure of recording context data, is defined in common.h, which includes all H.264 coding related variables from thread control variables to specific SPS, PPS, quantization matrix and cabac context. It contains the following structure
x264 _ predict _ t predict _ 16x 16[4+3];
x264 _ predict _ t predict _ 8x8c[4+3];
x264 _ predict 8x 8 _ t predict _ 8x 8[9+3];
x264 _ predict _ t predict _ 4x 4[9+3];
x264 _ predict _ 8x8 _ filter _ t predict _ 8x8 _ filter;
x264 _ pixel _ function _ t pixf
x264 _ mc _ functions _ t mc
x264 _ dct _ function _ t dctf
x264 _ zigzag _ function _ t zigzagf
x264 _ quant _ function _ t quantf
x264 _ deblock _ function _ t loopf
After tracing, we can see that they are either function pointers or structures composed of function pointers, which is very desirable to declare the interface interface in an object-oriented way. These function pointers will be initialized in the x264_encoder_open () function. The initialization here firstly realizes code segments according to different functions provided by different CPUs, and many of them may be implemented by assembly to improve the efficiency of code operation. Secondly, the functions with similar functions are managed centrally. For example, four prediction functions like intra 16 and nine prediction functions of intra4 are all managed through function pointer arrays.
X264_encoder_encode () is the main function responsible for encoding, which contains x264_slice_write () responsible for specific encoding at slice level, including intra-frame and inter-frame macroblock encoding. Here, cabac and cavlc are based on h->; Param.b_cabac, run x264_macroblock_write_cabac () and x264_macroblock_write_cavlc () to write code streams respectively. This part of the function is classified according to the file definition and basically runs according to the coding flow chart, which looks more like a process-oriented programming method. After the specific function pointer is initialized, the program has been run according to the coding process. From the overall architecture, x264 uses this kind of interface to realize weak coupling and reusability, and x264_t is used as the through context to realize information encapsulation and polymorphism.
In this paper, the code architecture of FFMPEG/X264 is roughly analyzed, and the object-oriented coding with C language is emphatically introduced. Although it will not be forced to move closer to C++, it also has its own implementation characteristics to ensure practicality. It is worth learning from the planning of C language software projects.