The X264 open source project implements the video encoding of H.264, but does not provide a corresponding decoder. FFMPEG Open Source Multimedia Codes Collect the source code of almost all media formats on the market. The H264.c is a separate source file that can normally decode X264 encoded stream, which is also basically the same as the above-described encoding or decoding CODEC application case. This section describes how H264.C implements the H.264 video decoding process.
H264.C source files have thousands of lines, the amount of code is large, it is very inconvenient to browse, analyze and transplant. At the same time, the document also rely on other source files, the organizational structure is more complex, and the platform is not based on Windows-based VC ++, which has brought a lot of inconveniences to compile, tracking. The "Chapter7 \ FFMPEG_H264" directory in the disc exhibits a project case "FFMPEG_H264" extracted from the C language extracted from FFMPEG. The file function classification of "FFMPEG_H264" is clear, compiled under the VC ++ 2005 platform, and the support of MMX, pure C language project facilitates the transplant of the embedded platform. The following is starting from the main function, step-in analysis of the process of implementing the H.264 video decoding. FFMPEG_H264 Project1 decoded the main program
Function main implementation of H.264 video decoding console applications, including all processes of the solution work. Its function call relationship is shown in the figure.
These applications, the topology of the process with the aforementioned MPEG-1 video decoding process is basically the same, including avcodec_init, avcodec_register_all, avcodec_find_decoder, avcodec_all_context, avcodec_open, avcodec_all_frame, avcodec_decode_video, avcodec_close like ffmpeg of several common module, wherein avcodec_decode_video is a decoder The core is marked in the figure. The code of the main function is implemented as follows:
Int main () {
FILE * INP_FILE;
FILE * OUT_FILE;
INT I;
INT NALLEN; / * NAL length * /
Unsigned char * buf; / *h.264 code stream * /
INT got_picture; / * Decoding a frame image * /
INT consumed_bytes; / * The code stream length consumed by the decoder * /
INT CNT = 0;
Avcodec * CODEC; / * Codes CODEC * /
AvcodecContext * c; / * Codes CODEC Context * /
Avframe * Picture; / * Decoded image * /
/ * Output and output files * /
INP_FILE = FOPEN ("E: \\ Bitavc \\ Busn_Dsp.264", "RB");
OUT_FILE = FOPEN ("E: \\ BitAvc \\ DSP_DEC.YUV", "WB");
Nallen = 0;
/ * Allocate memory and initialize 0 * /
BUF = (unsigned char *) Calloc (500 * 1024, sizeof (char));
/ * Initialization of CODEC, initialize some constant tables * /
Avcodec_init ();
/ * Register CODEC * /
AVCODEC_REGISTER_ALL ();
/ * Find H264 CODEC * /
CODEC = AVCODEC_FIND_DECODER (CODEC_ID_H264);
IF (! CODEC) Return 0;
/ * Initialize the default parameters of CODEC * /
C = AVCODEC_ALLOC_CONTEXT ();
IF (! c) Return 0;/ * 1. Open CODEC, here is initialized H.264 decoder, call DECODE_INIT local functions * /
IF (AVCODEC_OPEN (C, CODEC) <0) Return 0;
/ * Application space for Avframe, and clear * /
Picture = avcodec_alloc_frame ();
IF (! Picture) Return 0;
/ * Cyclic decoding * /
While (! feof) {
/ * Get a NAL package from the code stream * /
Nallen = getNexTnal (INP_FILE, BUF);
/ * 2. NAL decoding, call DECODE_FRAME Local Function * /
ConsuMed_bytes = avcodec_decode_video (C, Picture, & Got_Picture, BUF, NALLEN);
CNT ++;
/ * Output current decoding information * /
Printf ("NO: =% 4D, Length =% 4D \ n", CNT, ConsuMed_bytes;
/ * Returns <0 Indicates the decoded data head, returns> 0, indicating the decoding frame image * /
IF (consumed_bytes> 0)
{
/ * Extract the decoded image from the two-dimensional space * /
For (i = 0; i
height; i ++)
FWRITE (Picture-> Data [0] + i * Picture-> LineSize [0], 1, c-> width, out_file;
For (i = 0; i height / 2; i ++)
FWRITE (Picture-> Data [1] + i * Picture-> LineSize [1], 1, C-> width / 2, out_file;
For (i = 0; i height / 2; i ++)
FWRITE (Picture-> Data [2] + i * Picture-> LineSize [2], 1, C-> Width / 2, Out_File; / * Close the file * /
IF (INP_FILE) Fclose (INP_FILE);
IF (out_file) fclose (out_file);
/ * 3. Turn off CODEC, release resources, call DECODE_END local function * /
IF (c) {
AVCODEC_CLOSE (C);
AV_FREE (C);
C = NULL;
}
/ * Release AVFrame Space * /
IF (Picture) {
AV_Free (Picture);
Picture = NULL;
}
/ * Release memory * /
IF (buf) {
Free (BUF);
BUF = NULL; }
Return 0;}
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100 In the above process, steps 1 to 8 are the basic steps of FFmPEG at coding or decoding. The feature of the analysis function name will find that CODEC's processing function is prefixed as "AVCODEC_". In order to use the H.264 decoder CODEC, first need to define CODEC, as shown below:
AVCODEC H264_DECODER = {
"H264", // decoder name
CODEC_TYPE_VIDEO, // Decoder Type, Video
CODEC_ID_H264, // Decoder ID
SizeOf (H264Context), // decoder context
Decode_init, // decoder initialization
NULL, / / Encoder, disabled
Decode_end, // Destroy the decoder
Decode_frame, // decoding
0, // CODEC compatibility, disabled
}; 1234567891011
Therefore, the actual decoding processing module is implemented with DECODE_INIT, DECODE_FRAME, DECODE_END. Use a public function interface in the main function to access the functions here. Examples, for example, register CODEC.
/ **
* Simple call to register all the codecs.
* /
Void Avcodec_register_all (void)
{
Static int initection = 0;
IF (InInd! = 0)
Return;
InInited = 1;
Register_avcodec (& H264_Decoder);
// av_register_codec_parser (& H264_PARSER);
} 1234567891011121314
Therefore, the CODEC decoder actually invokes the three subunies in the H264.c to complete the decoding task.
2 configuration decoder
The above is a registration and definition decoder, where the ffmpeg's AVCODEC_OPEN module opens CODEC, and actually invokes the DECode_init local function to create, configure the H.264 decoder.
Int avcodec_open (avcodeccontext * avctx, avcodec * codec)
{
int R;
IF (avctx-> codec) return -1; / * Codec pointer valid * /
AVCTX-> CODEC = CODEC; / * Pointing CODEC * /
AVCTX-> CODEC_ID = CODEC-> ID; / * CODEC name * /
AVCTX-> frame_number = 0;
#if 1
IF (codec-> priv_data_size> 0) {/ * CODEC structure is not 0 * /
/ * Application Space for CODEC * /
AVCTX-> priv_data = av_mallocz (codec-> priv_data_size);
IF (! avctx-> priv_data)
Return -ENMEM;
} else {
AVCTX-> priv_data = null;
}
#ENDIF
/ * Initialization of CODEC * /
Ret = avctx-> codec-> init (avctx);
/ * If it fails, release the context structure * /
IF (RET <0) {
AV_FreeP (& AvcTX-> Priv_Data);
Return Ret;
}
Return 0;
} 1234567891011121314151617181920212223242526272829
The initialization of the decoder, including setting the default decoding parameters, the image width, and the initialization of the I frame prediction function, etc., then the pixel format is a planar mode of the I420; the final set is the initialization of the variable length encoded VLC table.
3 H.264 video decoding
The video decoding module is done by ffmpeg's avcodec_decode_video (). Since the H.264 code stream has passed NAL packaging, you need to call the getNextNal () module before calling the decoder to read the analysis of a NAL package from the code stream file, which is looking for NAL's header 0x00 00 00 00 00 00 00 00 00 00 00 00 00 00 00, then Pass the data between the two headers to the VCL decoder avcodec_decode_video () implementation decoding:
/ **
* Decode a frame.
* @Param BUF BitStream Buffer, Must Be ff_input_buffer_padding_size larger dam @padding_size larger1 the actual read bytes
* Because Some Optimized BitStream Readers Read 32 or 64 Bit at ONCE AND COLD Read over the end
* @Param buf_size the size of the buffer in bytes
* @Param got_picture_ptr Zero if no frame could be decompressed, OtherWise, IT IS NON ZERO
* @return -1 if error, OtherWise Return The Number of
* Bytes used.
* /
Int avcodec_decode_video (AvcodecContext * Avctx, Avframe * Picture,
INT * GOT_PICTURE_PTR,
UINT8_T * BUF, INT BUF_SIZE)
{
int R;
/ * There is no decoding ID * /
* GOT_PICTURE_PTR = 0;
/*H.264 decoding * /
Ret = avctx-> codec-> decode (avctx, // decoder context
Picture, // Decoded image
GOT_PICTURE_PTR, // Image Decoding Identification
BUF, // The code stream to be decoded
BUF_SIZE); // Code Flow Length
/ * If you use MMX or other instructions, you need to call this function * /
EMMS_C ();
/ * Decoded is an image, not header data * /
IF (* got_picture_ptr)
AVCTX-> Frame_Number ++;
Return Ret;
}
1234567891011121314151617181920212223242526272829303323334
The VCL decoder described above calls the FFMPEG's common function interface Decode, which is the actual decoding function decode_frame implementation of the VCL decoding of the H.264 in accordance with the incoming code stream and length. If the MMX instruction is used during the decoding process and exit, use the float / double type, you need to use the EMMS instruction (EMPTY MMX State) to cool the MMX status to restore the previous CPU status. The actual decoding function decode_frame implements the virtual decoding of the VCL, and the topology of the module is shown in the figure.
The Decode_Frame decoded video encoding layer VCL data in the figure, and the module core is decode_nal_units.
Static int decode_frame (AvcodecContext * Avctx, / * decoder context * /
Void * data, / * Structure of the decoded image * /
INT * DATA_SIZE, / * Structure Size * /
UINT8_T * BUF, / * Code Space * /
INT buf_size) / * Code Flow Length * /
{
H264Context * h = avctx-> priv_data; / * decoder context * /
MPEgencContext * s = & h-> s; / * MPEGENCCONTEXT pointer * /
Avframe * Pict = data; / * Image space * /
INT buf_index; / * Current code stream position * /
S-> Flags = avctx-> flags; / * CODEC logo * /
S-> Flags2 = avctx-> flags2; / * CODEC logo 2 * /
IF (buf_size == 0) {/ * code stream is not empty * /
Return 0;
}
/ * Truncated code stream decoding * /
IF (S-> Flags & Codec_Flag_Truncated) {
INT next = find_frame_end (& S-> Parse_Context, buf, buf_size);
IF (FF_COMBINE_FRAME (& S-> Parse_Context, Next, & Buf, & Buf_size) <0)
Return BUF_SIZE;
}
/ * Decoding of special data in the code stream * /
IF (S-> Avctx-> EXTRADATA_SIZE && S-> Picture_Number == 0) {
IF (0 avctx-> extradata, s-> avctx-> extradata_size)))))
Return -1;
}
/ * Normal decoding * /
BUF_INDEX = Decode_nal_units (h, buf, buf_size);
IF (BUF_INDEX <0)
Return -1;
#if 0 / * B frame * /
IF (S-> Pict_Type == B_TYPE || S-> Low_DELAY) {
* Pict = * (avframe *) & S-> Current_Picture;
} else {
* Pict = * (avframe *) & S-> Last_Picture;
}
#ENDIF
/ * No decoded output image, decoding head data * /
IF (! s-> current_picture_ptr) {
AV_LOG (H-> S.AVCTX, AV_LOG_DEBUG, "ERROR, NO FRAME \ N");
Return -1;
}
/ * Has a decoded image output * /
* Pict = * (avframe *) & S-> Current_Picture;
Assert (Pict-> DATA [0]);
/ * Indicates decoded output * /
* DATA_SIZE = SizeOf (AVFrame);
/ * Return the current consumption code stream * /
Return GET_CONSUMED_BYTES (S, BUF_INDEX, BUF_SIZE);
}
123456781617181920212223242526272829303333333434444344454647484950515253
During the above decoding process, first, if the truncated stream, the decoded code stream is combined with one frame image; whether there is a special data in the code stream such as a Huffman table, then normal decoding NAL; final output decoded image and The length of the stream consumed. Where the core is NAL decoding decode_nal_units.
4 NAL package solution
The basic unit in the H.264 stream is behaving as each independent NAL package, so the decoded process function decode_nal_units () implements the decoding NAL package. The topology of the module is shown in the figure:
NAL decoding in the above figure mainly includes a sequence parameter set SPS, an image parameter set PPS, an instant decoding brush film IDR, an image tab slice_header, an image slice, and other structures, Decode decode_nal_units implementation process is as follows:
/ * NAL unit decoding * /
Static int decode_nal_units (H264Context * H, // decoder handle
UINT8_T * BUF, // Code Space
INT buf_size) {// code stream length
MPEgencContext * const S = & h-> s;
AvcodecContext * const avctx = s-> avctx;
INT buf_index = 0;
/ * Cyclic decoding * /
For (;;) {
INT consumed; // consumes the length
INT DST_LENGTH; / / Target Length
INT bit_length; // Bit length
UINT8_T * PTR; // Temporary Pointer
/ * Search prefix start code: 0x 00 00 01 * /
For (; buf_index + 3 = BUF_SIZE) BREAK;
/ * Index post-shift * /
BUF_INDEX + = 3;
/ * Network abstraction layer NAL unpack * /
PTR = decode_nal (h, buf + buf_index, & dst_length, & consumed, buf_size - buf_index);
IF (PTR [DST_LENGTH - 1] == 0) DST_LENGTH -;
/ * Determine the accurate end position of the code stream * /
Bit_length = 8 * DST_LENGTH - DECODE_RBSP_TRAILING (PTR + DST_LENGTH - 1);
IF (S-> AVCTX-> Debug & ff_debug_startcode) {
AV_LOG (h-> s.avctx, av_log_debug, "nal% D at% D Length% D \ N", H-> NAL_UNIT_TYPE, BUF_INDEX, DST_LENGTH);
}
/ * Index post-shift * /
BUF_INDEX + = ConsuMed;
IF (S-> hurry_up == 1 && H-> NAL_REF_IDC == 0)
CONTINUE;
Switch (h-> nal_unit_type) {/ * Performs Decoding according to NAL type * /
Case nal_idr_slice: // idR
IDR (h); //////
Case nal_slice: // Image slice SLICE decoding
/ * Initialized code stream pointer * /
INIT_GET_BITS (& S-> GB, PTR, Bit_Length);
H-> intra_gb_ptr =
H-> inter_gb_ptr = & S-> GB;
S-> Data_Partitioning = 0;
/ * Decoded image slice * /
IF (decode_slice_header (h) <0) return -1;
IF (h-> redundant_pic_count == 0 && S-> hurry_up <5)
/ **************** Image piece data decoding * /
Decode_slice (h);
/ **************** Image piece data decoding * /
Break;
Case Nal_DPA: // Data Partition A
INIT_GET_BITS (& S-> GB, PTR, Bit_Length);
H-> intra_gb_ptr =
H-> inter_gb_ptr = NULL;
S-> Data_Partitioning = 1;
/ * Decoded image slice * /
IF (decode_slice_header (h) <0) return -1;
Break;
Case nal_dpb: // Data Partition B
INIT_GET_BITS (& H-> intra_GB, PTR, Bit_length);
H-> intra_gb_ptr = & h-> intra_GB;
Break;
Case Nal_DPC: // Data Partition C
INIT_GET_BITS (& H-> Inter_gb, PTR, Bit_Length);
H-> interface_gb_ptr = & h-> inter_gb;
IF (h-> redundant_pic_count == 0 && H-> intra_gb_ptr && S-> Data_Partitioning && S-> HURRY_UP <5)
Decode_slice (h);
Break;
Case nal_sei: // Supplemental enhancement information
Break;
Case Nal_SPS: // Sequence Parameter Set SPS
/ * Initialized code stream * /
INIT_GET_BITS (& S-> GB, PTR, Bit_Length);
/ * SPS decoding * /
Decode_seq_parameter_set (h);
IF (S-> Flags & Codec_Flag_low_DELAY)
S-> low_delay = 1;
AVCTX-> HAS_B_FRAMES =! S-> low_delay;
Printf ("Decode SPS \ N");
Break;
Case nal_pps: // Image parameter set PPS
/ * Initialized code stream * /
INIT_GET_BITS (& S-> GB, PTR, Bit_Length);
/ * PPS decoding * /
Decode_picture_parameter_set (h);
Printf ("Decode PPS \ N");
Break;
Case Nal_Picture_Delimiter:
Break;
Case nal_filter_data:
Break;
DEFAULT:
AV_LOG (AVCTX, AV_LOG_ERROR, "Unknown Nal Code:% D \ N", H-> nal_unit_type;
}
/ * Image frame type * /
S-> current_picture.pict_type = S-> Pict_Type;
/ * Key frame type initialization * /
S-> current_picture.key_frame = s-> pict_type == i_type;
}
/ * No decoded output image * /
IF (! s-> current_picture_ptr) Return BUF_INDEX; // No Frame
/ * Modify image sequence POC * /
H-> prev_frame_num_offset = h-> frame_num_offset;
H-> prev_frame_num = h-> frame_num;
IF (S-> Current_Picture_Ptr-> Reference) {
H-> prev_poc_msb = h-> poc_msb;
H-> prev_poc_lsb = h-> poc_lsb;
}
/ * Tag reference frame * /
IF (S-> Current_Picture_Ptr-> Reference)
Execute_ref_pic_marking (h, h-> mmco, h-> mmco_index);
Else
Assert (h-> mmco_index == 0);
/ * Code flow fault end * /
FF_ER_FRAME_END (S);
/ * Decoding a frame is completed, extended image * /
MPV_FRAME_END (S);
Return buf_index;
}
123456789
Our other product: