H.264解码器(Decoder)在初始化的时候调用了ff_h264_decode_init(),ff_h264_decode_init()又调用了下面几个函数进行解码器汇编函数的初始化工作(仅举了几个例子):ff_h264dsp_init():初始化DSP相关的汇编函数。包含了IDCT、环路滤波函数等。
ff_h264qpel_init():初始化四分之一像素运动补偿相关的汇编函数。
ff_h264_pred_init():初始化帧内预测相关的汇编函数。H.264解码器在关闭的时候调用了h264_decode_end(),h264_decode_end()又调用了ff_h264_remove_all_refs(),ff_h264_free_context()等几个函数进行清理工作。
H.264解码器在解码图像帧的时候调用了h264_decode_frame(),h264_decode_frame()调用了decode_nal_units(),decode_nal_units()调用了两类函数——解析函数和解码函数,如下所示。
(1)解析函数(获取信息):ff_h264_decode_nal():解析NALU Header。
ff_h264_decode_seq_parameter_set():解析SPS。
ff_h264_decode_picture_parameter_set():解析PPS。
ff_h264_decode_sei():解析SEI。
ff_h264_decode_slice_header():解析Slice Header。(2)解码函数(解码获得图像):ff_h264_execute_decode_slices():解码Slice。其中ff_h264_execute_decode_slices()调用了decode_slice(),而decode_slice()中调用了解码器中细节处理的函数(暂不详细分析):ff_h264_decode_mb_cabac():CABAC熵解码函数。
ff_h264_decode_mb_cavlc():CAVLC熵解码函数。
ff_h264_hl_decode_mb():宏块解码函数。
loop_filter():环路滤波函数。
ff_h264_decoderff_h264_decoder是FFmpeg的H.264解码器对应的AVCodec结构体。它的定义位于libavcodech264.c,如下所示。AVCodec ff_h264_decoder = { .name ="h264", .long_name = NULL_IF_CONFIG_SMALL("H.264/ AVC / MPEG-4 AVC / MPEG-4 part 10"), .type =AVMEDIA_TYPE_VIDEO, .id =AV_CODEC_ID_H264, .priv_data_size =sizeof(H264Context), .init =ff_h264_decode_init, .close =h264_decode_end, .decode =h264_decode_frame, .capabilities =/*CODEC_CAP_DRAW_HORIZ_BAND |*/ CODEC_CAP_DR1 | CODEC_CAP_DELAY |CODEC_CAP_SLICE_THREADS | CODEC_CAP_FRAME_THREADS, .flush =flush_dpb, .init_thread_copy =ONLY_IF_THREADS_ENABLED(decode_init_thread_copy), .update_thread_context = ONLY_IF_THREADS_ENABLED(ff_h264_update_thread_context), .profiles =NULL_IF_CONFIG_SMALL(profiles), .priv_class =&h264_class,};从ff_h264_decoder的定义可以看出:解码器初始化的函数指针init()指向ff_h264_decode_init()函数,解码的函数指针decode()指向h264_decode_frame()函数,解码器关闭的函数指针close()指向h264_decode_end()函数。
ff_h264_decode_init()ff_h264_decode_init()用于FFmpeg H.264解码器的初始化。该函数的定义位于libavcodech264.c,如下所示。//H.264解码器初始化函数av_cold intff_h264_decode_init(AVCodecContext *avctx){ H264Context *h = avctx->priv_data; int i; int ret; h->avctx = avctx; //8颜 {MOD}位深8bit h->bit_depth_luma = 8; //1代表是YUV420P h->chroma_format_idc = 1; h->avctx->bits_per_raw_sample = 8; h->cur_chroma_format_idc = 1; //初始化DSP相关的汇编函数。包含了IDCT、环路滤波函数等 ff_h264dsp_init(&h->h264dsp, 8, 1); av_assert0(h->sps.bit_depth_chroma == 0); ff_h264chroma_init(&h->h264chroma, h->sps.bit_depth_chroma); //初始化四分之一像素运动补偿相关的汇编函数 ff_h264qpel_init(&h->h264qpel, 8); //初始化帧内预测相关的汇编函数 ff_h264_pred_init(&h->hpc, h->avctx->codec_id, 8, 1); h->dequant_coeff_pps = -1; h->current_sps_id = -1; /* needed so that IDCT permutation is known early */ if (CONFIG_ERROR_RESILIENCE) ff_me_cmp_init(&h->mecc, h->avctx); ff_videodsp_init(&h->vdsp, 8); memset(h->pps.scaling_matrix4, 16, 6 * 16 * sizeof(uint8_t)); memset(h->pps.scaling_matrix8, 16, 2 * 64 * sizeof(uint8_t)); h->picture_structure =PICT_FRAME; h->slice_context_count = 1; h->workaround_bugs = avctx->workaround_bugs; h->flags =avctx->flags; /* set defaults */ // s->decode_mb = ff_h263_decode_mb; if (!avctx->has_b_frames) h->low_delay = 1; avctx->chroma_sample_location = AVCHROMA_LOC_LEFT; //初始化熵解码器 //CAVLC ff_h264_decode_init_vlc(); //CABAC ff_init_cabac_states(); //8-bit H264取0, 大于 8-bit H264取1 h->pixel_shift = 0; h->sps.bit_depth_luma = avctx->bits_per_raw_sample = 8; h->thread_context[0] = h; h->outputed_poc =h->next_outputed_poc = INT_MIN; for (i = 0; i < MAX_DELAYED_PIC_COUNT; i++) h->last_pocs[i] = INT_MIN; h->prev_poc_msb = 1 << 16; h->prev_frame_num = -1; h->x264_build = -1; h->sei_fpa.frame_packing_arrangement_cancel_flag = -1; ff_h264_reset_sei(h); if (avctx->codec_id == AV_CODEC_ID_H264) { if (avctx->ticks_per_frame == 1) { if(h->avctx->time_base.den < INT_MAX/2) { h->avctx->time_base.den*= 2; } else h->avctx->time_base.num /= 2; } avctx->ticks_per_frame = 2; } //AVCodecContext中是否包含extradata?包含的话,则解析之 if (avctx->extradata_size > 0 && avctx->extradata) { ret = ff_h264_decode_extradata(h, avctx->extradata,avctx->extradata_size); if (ret < 0) { ff_h264_free_context(h); return ret; } } if (h->sps.bitstream_restriction_flag && h->avctx->has_b_frames < h->sps.num_reorder_frames) { h->avctx->has_b_frames = h->sps.num_reorder_frames; h->low_delay = 0; } avctx->internal->allocate_progress = 1; ff_h264_flush_change(h); return 0;}从函数定义中可以看出,ff_h264_decode_init()一方面给H.264 解码器中一些变量(例如bit_depth_luma、chroma_format_idc等)设定了初始值,另一方面调用了一系列汇编函数的初始化函数(初始化函数的具体内容在后续文章中完成)。初始化汇编函数的的步骤是:首先将C版本函数赋值给相应模块的函数指针;然后检测平台的特性,如果不支持汇编优化(ARM、X86等),则不再做任何处理,如果支持汇编优化,则将相应的汇编优化函数赋值给相应模块的函数指针(替换掉C语言版本的效率较低的函数)。下面几个函数初始化了几个不同模块的汇编优化函数:ff_h264dsp_init():初始化DSP相关的汇编函数。包含了IDCT、环路滤波函数等。
ff_h264qpel_init():初始化四分之一像素运动补偿相关的汇编函数。
ff_h264_pred_init():初始化帧内预测相关的汇编函数。可以举例看一下个ff_h264_pred_init()的代码。
ff_h264_pred_init()
函数用于初始化帧内预测相关的汇编函数,定位于libavcodech264pred.c,如下所示。/** *Set the intra prediction function pointers. *///初始化帧内预测相关的汇编函数av_cold voidff_h264_pred_init(H264PredContext *h, int codec_id, const intbit_depth, intchroma_format_idc){#undef FUNC#undef FUNCC#define FUNC(a, depth) a ## _ ## depth#define FUNCC(a, depth) a ## _ ## depth ##_c#define FUNCD(a) a ## _c//好长的宏定义...(这种很长的宏定义在H.264解码器中似乎很普遍!)//该宏用于给帧内预测模块的函数指针赋值//注意参数为颜 {MOD}位深度#define H264_PRED(depth) if(codec_id != AV_CODEC_ID_RV40){ if (codec_id == AV_CODEC_ID_VP7 || codec_id == AV_CODEC_ID_VP8) { h->pred4x4[VERT_PRED ]=FUNCD(pred4x4_vertical_vp8); h->pred4x4[HOR_PRED ]= FUNCD(pred4x4_horizontal_vp8); } else { h->pred4x4[VERT_PRED ]=FUNCC(pred4x4_vertical ,depth); h->pred4x4[HOR_PRED ]=FUNCC(pred4x4_horizontal ,depth); } h->pred4x4[DC_PRED ]= FUNCC(pred4x4_dc , depth); if(codec_id == AV_CODEC_ID_SVQ3) h->pred4x4[DIAG_DOWN_LEFT_PRED ]= FUNCD(pred4x4_down_left_svq3); else h->pred4x4[DIAG_DOWN_LEFT_PRED ]= FUNCC(pred4x4_down_left , depth); h->pred4x4[DIAG_DOWN_RIGHT_PRED]= FUNCC(pred4x4_down_right , depth); h->pred4x4[VERT_RIGHT_PRED ]= FUNCC(pred4x4_vertical_right , depth); h->pred4x4[HOR_DOWN_PRED ]= FUNCC(pred4x4_horizontal_down , depth); if (codec_id == AV_CODEC_ID_VP7 || codec_id == AV_CODEC_ID_VP8) { h->pred4x4[VERT_LEFT_PRED ]=FUNCD(pred4x4_vertical_left_vp8); } else h->pred4x4[VERT_LEFT_PRED ]= FUNCC(pred4x4_vertical_left , depth); h->pred4x4[HOR_UP_PRED ]= FUNCC(pred4x4_horizontal_up , depth); if (codec_id != AV_CODEC_ID_VP7 && codec_id != AV_CODEC_ID_VP8){ h->pred4x4[LEFT_DC_PRED ]=FUNCC(pred4x4_left_dc ,depth); h->pred4x4[TOP_DC_PRED ]=FUNCC(pred4x4_top_dc ,depth); } else { h->pred4x4[TM_VP8_PRED ]=FUNCD(pred4x4_tm_vp8); h->pred4x4[DC_127_PRED ]=FUNCC(pred4x4_127_dc ,depth); h->pred4x4[DC_129_PRED ]=FUNCC(pred4x4_129_dc ,depth); h->pred4x4[VERT_VP8_PRED ]=FUNCC(pred4x4_vertical ,depth); h->pred4x4[HOR_VP8_PRED ]=FUNCC(pred4x4_horizontal ,depth); } if (codec_id != AV_CODEC_ID_VP8) h->pred4x4[DC_128_PRED ]=FUNCC(pred4x4_128_dc ,depth); }else{ h->pred4x4[VERT_PRED ]= FUNCC(pred4x4_vertical , depth); h->pred4x4[HOR_PRED ]= FUNCC(pred4x4_horizontal , depth); h->pred4x4[DC_PRED ]= FUNCC(pred4x4_dc , depth); h->pred4x4[DIAG_DOWN_LEFT_PRED ]= FUNCD(pred4x4_down_left_rv40); h->pred4x4[DIAG_DOWN_RIGHT_PRED]= FUNCC(pred4x4_down_right , depth); h->pred4x4[VERT_RIGHT_PRED ]= FUNCC(pred4x4_vertical_right , depth); h->pred4x4[HOR_DOWN_PRED ]= FUNCC(pred4x4_horizontal_down , depth); h->pred4x4[VERT_LEFT_PRED ]= FUNCD(pred4x4_vertical_left_rv40); h->pred4x4[HOR_UP_PRED ]= FUNCD(pred4x4_horizontal_up_rv40); h->pred4x4[LEFT_DC_PRED ]= FUNCC(pred4x4_left_dc , depth); h->pred4x4[TOP_DC_PRED ]= FUNCC(pred4x4_top_dc , depth); h->pred4x4[DC_128_PRED ]= FUNCC(pred4x4_128_dc , depth); h->pred4x4[DIAG_DOWN_LEFT_PRED_RV40_NODOWN]=FUNCD(pred4x4_down_left_rv40_nodown); h->pred4x4[HOR_UP_PRED_RV40_NODOWN]=FUNCD(pred4x4_horizontal_up_rv40_nodown); h->pred4x4[VERT_LEFT_PRED_RV40_NODOWN]= FUNCD(pred4x4_vertical_left_rv40_nodown); }\ h->pred8x8l[VERT_PRED ]= FUNCC(pred8x8l_vertical , depth); h->pred8x8l[HOR_PRED ]= FUNCC(pred8x8l_horizontal , depth); h->pred8x8l[DC_PRED ]= FUNCC(pred8x8l_dc , depth); h->pred8x8l[DIAG_DOWN_LEFT_PRED ]= FUNCC(pred8x8l_down_left , depth); h->pred8x8l[DIAG_DOWN_RIGHT_PRED]= FUNCC(pred8x8l_down_right , depth); h->pred8x8l[VERT_RIGHT_PRED ]= FUNCC(pred8x8l_vertical_right , depth); h->pred8x8l[HOR_DOWN_PRED ]= FUNCC(pred8x8l_horizontal_down , depth); h->pred8x8l[VERT_LEFT_PRED ]= FUNCC(pred8x8l_vertical_left , depth); h->pred8x8l[HOR_UP_PRED ]= FUNCC(pred8x8l_horizontal_up , depth); h->pred8x8l[LEFT_DC_PRED ]= FUNCC(pred8x8l_left_dc , depth); h->pred8x8l[TOP_DC_PRED ]= FUNCC(pred8x8l_top_dc , depth); h->pred8x8l[DC_128_PRED ]= FUNCC(pred8x8l_128_dc , depth);\ if (chroma_format_idc <= 1) { h->pred8x8[VERT_PRED8x8 ]=FUNCC(pred8x8_vertical ,depth); h->pred8x8[HOR_PRED8x8 ]=FUNCC(pred8x8_horizontal ,depth); }else { h->pred8x8[VERT_PRED8x8 ]=FUNCC(pred8x16_vertical ,depth); h->pred8x8[HOR_PRED8x8 ]=FUNCC(pred8x16_horizontal ,depth); } if (codec_id != AV_CODEC_ID_VP7 && codec_id != AV_CODEC_ID_VP8){ if (chroma_format_idc <= 1) { h->pred8x8[PLANE_PRED8x8]= FUNCC(pred8x8_plane , depth); } else { h->pred8x8[PLANE_PRED8x8]= FUNCC(pred8x16_plane , depth); } }else h->pred8x8[PLANE_PRED8x8]=FUNCD(pred8x8_tm_vp8); if (codec_id != AV_CODEC_ID_RV40 && codec_id != AV_CODEC_ID_VP7&& codec_id != AV_CODEC_ID_VP8) { if (chroma_format_idc <= 1) { h->pred8x8[DC_PRED8x8 ]=FUNCC(pred8x8_dc ,depth); h->pred8x8[LEFT_DC_PRED8x8]= FUNCC(pred8x8_left_dc , depth); h->pred8x8[TOP_DC_PRED8x8 ]= FUNCC(pred8x8_top_dc , depth); h->pred8x8[ALZHEIMER_DC_L0T_PRED8x8 ]= FUNC(pred8x8_mad_cow_dc_l0t,depth); h->pred8x8[ALZHEIMER_DC_0LT_PRED8x8 ]= FUNC(pred8x8_mad_cow_dc_0lt,depth); h->pred8x8[ALZHEIMER_DC_L00_PRED8x8 ]= FUNC(pred8x8_mad_cow_dc_l00,depth); h->pred8x8[ALZHEIMER_DC_0L0_PRED8x8 ]= FUNC(pred8x8_mad_cow_dc_0l0,depth); } else { h->pred8x8[DC_PRED8x8 ]=FUNCC(pred8x16_dc ,depth); h->pred8x8[LEFT_DC_PRED8x8]= FUNCC(pred8x16_left_dc , depth); h->pred8x8[TOP_DC_PRED8x8 ]= FUNCC(pred8x16_top_dc , depth); h->pred8x8[ALZHEIMER_DC_L0T_PRED8x8 ]= FUNC(pred8x16_mad_cow_dc_l0t,depth); h->pred8x8[ALZHEIMER_DC_0LT_PRED8x8 ]= FUNC(pred8x16_mad_cow_dc_0lt,depth); h->pred8x8[ALZHEIMER_DC_L00_PRED8x8 ]= FUNC(pred8x16_mad_cow_dc_l00,depth); h->pred8x8[ALZHEIMER_DC_0L0_PRED8x8 ]= FUNC(pred8x16_mad_cow_dc_0l0,depth); } }else{ h->pred8x8[DC_PRED8x8 ]=FUNCD(pred8x8_dc_rv40); h->pred8x8[LEFT_DC_PRED8x8]= FUNCD(pred8x8_left_dc_rv40); h->pred8x8[TOP_DC_PRED8x8 ]= FUNCD(pred8x8_top_dc_rv40); if (codec_id == AV_CODEC_ID_VP7 || codec_id == AV_CODEC_ID_VP8) { h->pred8x8[DC_127_PRED8x8]= FUNCC(pred8x8_127_dc , depth); h->pred8x8[DC_129_PRED8x8]= FUNCC(pred8x8_129_dc , depth); } } if (chroma_format_idc <= 1) { h->pred8x8[DC_128_PRED8x8 ]= FUNCC(pred8x8_128_dc , depth); }else { h->pred8x8[DC_128_PRED8x8 ]= FUNCC(pred8x16_128_dc , depth); }\ h->pred16x16[DC_PRED8x8 ]=FUNCC(pred16x16_dc ,depth); h->pred16x16[VERT_PRED8x8 ]=FUNCC(pred16x16_vertical ,depth); h->pred16x16[HOR_PRED8x8 ]=FUNCC(pred16x16_horizontal ,depth); switch(codec_id){ case AV_CODEC_ID_SVQ3: h->pred16x16[PLANE_PRED8x8 ]=FUNCD(pred16x16_plane_svq3); break; case AV_CODEC_ID_RV40: h->pred16x16[PLANE_PRED8x8 ]=FUNCD(pred16x16_plane_rv40); break; case AV_CODEC_ID_VP7: case AV_CODEC_ID_VP8: h->pred16x16[PLANE_PRED8x8 ]=FUNCD(pred16x16_tm_vp8); h->pred16x16[DC_127_PRED8x8]= FUNCC(pred16x16_127_dc , depth); h->pred16x16[DC_129_PRED8x8]= FUNCC(pred16x16_129_dc , depth); break; default: h->pred16x16[PLANE_PRED8x8 ]=FUNCC(pred16x16_plane ,depth); break; } h->pred16x16[LEFT_DC_PRED8x8]= FUNCC(pred16x16_left_dc , depth); h->pred16x16[TOP_DC_PRED8x8 ]= FUNCC(pred16x16_top_dc , depth); h->pred16x16[DC_128_PRED8x8 ]= FUNCC(pred16x16_128_dc , depth);\ /* special lossless h/v prediction for h264 */ h->pred4x4_add [VERT_PRED ]= FUNCC(pred4x4_vertical_add , depth); h->pred4x4_add [ HOR_PRED ]= FUNCC(pred4x4_horizontal_add , depth); h->pred8x8l_add [VERT_PRED ]=FUNCC(pred8x8l_vertical_add ,depth); h->pred8x8l_add [ HOR_PRED ]=FUNCC(pred8x8l_horizontal_add ,depth); h->pred8x8l_filter_add [VERT_PRED ]= FUNCC(pred8x8l_vertical_filter_add , depth); h->pred8x8l_filter_add [ HOR_PRED ]= FUNCC(pred8x8l_horizontal_filter_add , depth); if (chroma_format_idc <= 1) { h->pred8x8_add [VERT_PRED8x8]=FUNCC(pred8x8_vertical_add ,depth); h->pred8x8_add [ HOR_PRED8x8]=FUNCC(pred8x8_horizontal_add ,depth); }else { h->pred8x8_add [VERT_PRED8x8]=FUNCC(pred8x16_vertical_add ,depth); h->pred8x8_add [ HOR_PRED8x8]=FUNCC(pred8x16_horizontal_add ,depth); } h->pred16x16_add[VERT_PRED8x8]= FUNCC(pred16x16_vertical_add , depth); h->pred16x16_add[ HOR_PRED8x8]= FUNCC(pred16x16_horizontal_add , depth); //注意这里使用了前面那个很长的宏定义 //根据颜 {MOD}位深的不同,初始化不同的函数 //颜 {MOD}位深默认值为8,所以一般情况下调用H264_PRED(8) switch (bit_depth) { case 9: H264_PRED(9) break; case 10: H264_PRED(10) break; case 12: H264_PRED(12) break; case 14: H264_PRED(14) break; default: av_assert0(bit_depth<=8); H264_PRED(8) break; } //如果支持汇编优化,则会调用相应的汇编优化函数 //neon这些的 if (ARCH_ARM) ff_h264_pred_init_arm(h,codec_id, bit_depth, chroma_format_idc); //mmx这些的 if (ARCH_X86) ff_h264_pred_init_x86(h, codec_id, bit_depth,chroma_format_idc);}初看一眼ff_h264_pred_init()定义会给人一种很奇怪的感觉:前面的这个H264_PRED(depth)的宏定义怎么这么长?!实际上在FFmpeg的H.264解码器中这种很长的宏定义是很常见的。我个人觉得这么做主要是为了方便为不同的颜 {MOD}位深的码流初始化不同的功能函数。例如,对于常见的8bit码流,调用H264_PRED(8)就可以初始化相应的函数;对于比较新的10bit码流,调用H264_PRED(10)就可以初始化相应的函数。ff_h264_pred_init()的代码是开始于switch()语句的,可以看出该函数根据不同的bit_depth(颜 {MOD}位深)调用了不同的H264_PRED(bit_depth)宏。我们不妨展开一个H264_PRED()宏看看里面的代码究竟是什么。在这里我们选择最常见的8bit为例,看看H264_PRED(8)宏展开后的结果。
H264_PRED(8)
H264_PRED(8)用于初始化8bit颜 {MOD}位深C语言版本的帧内预测的函数。该宏定义展开后的结果如下所示。if(codec_id != AV_CODEC_ID_RV40){ if(codec_id == AV_CODEC_ID_VP7 || codec_id == AV_CODEC_ID_VP8) { h->pred4x4[0 ]= pred4x4_vertical_vp8_c; h->pred4x4[1 ]= pred4x4_horizontal_vp8_c; }else { //帧内4x4的Vertical预测方式 h->pred4x4[0 ]= pred4x4_vertical_8_c; //帧内4x4的Horizontal预测方式 h->pred4x4[1 ]= pred4x4_horizontal_8_c; } //帧内4x4的DC预测方式 h->pred4x4[2 ]= pred4x4_dc_8_c; if(codec_id== AV_CODEC_ID_SVQ3) h->pred4x4[3]= pred4x4_down_left_svq3_c; else h->pred4x4[3]= pred4x4_down_left_8_c; h->pred4x4[4]=pred4x4_down_right_8_c; h->pred4x4[5 ]= pred4x4_vertical_right_8_c; h->pred4x4[6 ]= pred4x4_horizontal_down_8_c; if(codec_id == AV_CODEC_ID_VP7 || codec_id == AV_CODEC_ID_VP8) { h->pred4x4[7 ]= pred4x4_vertical_left_vp8_c; }else h->pred4x4[7 ]= pred4x4_vertical_left_8_c; h->pred4x4[8 ]= pred4x4_horizontal_up_8_c; if(codec_id != AV_CODEC_ID_VP7 && codec_id != AV_CODEC_ID_VP8) { h->pred4x4[9 ]= pred4x4_left_dc_8_c; h->pred4x4[10 ]= pred4x4_top_dc_8_c; }else { h->pred4x4[9 ]= pred4x4_tm_vp8_c; h->pred4x4[12 ]= pred4x4_127_dc_8_c; h->pred4x4[13 ]= pred4x4_129_dc_8_c; h->pred4x4[10 ]= pred4x4_vertical_8_c; h->pred4x4[14 ]= pred4x4_horizontal_8_c; } if(codec_id != AV_CODEC_ID_VP8) h->pred4x4[11 ]= pred4x4_128_dc_8_c;}else{ h->pred4x4[0 ]= pred4x4_vertical_8_c; h->pred4x4[1 ]= pred4x4_horizontal_8_c; h->pred4x4[2 ]= pred4x4_dc_8_c; h->pred4x4[3]= pred4x4_down_left_rv40_c; h->pred4x4[4]=pred4x4_down_right_8_c; h->pred4x4[5 ]= pred4x4_vertical_right_8_c; h->pred4x4[6 ]= pred4x4_horizontal_down_8_c; h->pred4x4[7 ]= pred4x4_vertical_left_rv40_c; h->pred4x4[8 ]= pred4x4_horizontal_up_rv40_c; h->pred4x4[9 ]= pred4x4_left_dc_8_c; h->pred4x4[10 ]= pred4x4_top_dc_8_c; h->pred4x4[11 ]= pred4x4_128_dc_8_c; h->pred4x4[12]=pred4x4_down_left_rv40_nodown_c; h->pred4x4[13]=pred4x4_horizontal_up_rv40_nodown_c; h->pred4x4[14]=pred4x4_vertical_left_rv40_nodown_c;} h->pred8x8l[0 ]= pred8x8l_vertical_8_c;h->pred8x8l[1 ]= pred8x8l_horizontal_8_c;h->pred8x8l[2 ]= pred8x8l_dc_8_c;h->pred8x8l[3 ]= pred8x8l_down_left_8_c;h->pred8x8l[4]= pred8x8l_down_right_8_c;h->pred8x8l[5 ]= pred8x8l_vertical_right_8_c;h->pred8x8l[6 ]= pred8x8l_horizontal_down_8_c;h->pred8x8l[7 ]= pred8x8l_vertical_left_8_c;h->pred8x8l[8 ]= pred8x8l_horizontal_up_8_c;h->pred8x8l[9 ]= pred8x8l_left_dc_8_c;h->pred8x8l[10 ]= pred8x8l_top_dc_8_c;h->pred8x8l[11 ]= pred8x8l_128_dc_8_c; if (chroma_format_idc <= 1) { h->pred8x8[2 ]= pred8x8_vertical_8_c; h->pred8x8[1 ]= pred8x8_horizontal_8_c;} else { h->pred8x8[2 ]= pred8x16_vertical_8_c; h->pred8x8[1 ]= pred8x16_horizontal_8_c;}if (codec_id != AV_CODEC_ID_VP7 &&codec_id != AV_CODEC_ID_VP8) { if(chroma_format_idc <= 1) { h->pred8x8[3]=pred8x8_plane_8_c; }else { h->pred8x8[3]=pred8x16_plane_8_c; }} else h->pred8x8[3]=pred8x8_tm_vp8_c;if (codec_id != AV_CODEC_ID_RV40 &&codec_id != AV_CODEC_ID_VP7 && codec_id!= AV_CODEC_ID_VP8) { if(chroma_format_idc <= 1) { h->pred8x8[0 ]= pred8x8_dc_8_c; h->pred8x8[4]=pred8x8_left_dc_8_c; h->pred8x8[5]= pred8x8_top_dc_8_c; h->pred8x8[7]= pred8x8_mad_cow_dc_l0t_8; h->pred8x8[8]= pred8x8_mad_cow_dc_0lt_8; h->pred8x8[9]= pred8x8_mad_cow_dc_l00_8; h->pred8x8[10]= pred8x8_mad_cow_dc_0l0_8; }else { h->pred8x8[0 ]= pred8x16_dc_8_c; h->pred8x8[4]=pred8x16_left_dc_8_c; h->pred8x8[5]= pred8x16_top_dc_8_c; h->pred8x8[7]= pred8x16_mad_cow_dc_l0t_8; h->pred8x8[8]= pred8x16_mad_cow_dc_0lt_8; h->pred8x8[9]= pred8x16_mad_cow_dc_l00_8; h->pred8x8[10]= pred8x16_mad_cow_dc_0l0_8; }}else{ h->pred8x8[0 ]= pred8x8_dc_rv40_c; h->pred8x8[4]=pred8x8_left_dc_rv40_c; h->pred8x8[5]= pred8x8_top_dc_rv40_c; if(codec_id == AV_CODEC_ID_VP7 || codec_id == AV_CODEC_ID_VP8) { h->pred8x8[7]=pred8x8_127_dc_8_c; h->pred8x8[8]=pred8x8_129_dc_8_c; }}if (chroma_format_idc <= 1) { h->pred8x8[6]= pred8x8_128_dc_8_c;} else { h->pred8x8[6]= pred8x16_128_dc_8_c;} h->pred16x16[0 ]= pred16x16_dc_8_c;h->pred16x16[2 ]= pred16x16_vertical_8_c;h->pred16x16[1 ]= pred16x16_horizontal_8_c;switch(codec_id){case AV_CODEC_ID_SVQ3: h->pred16x16[3 ]=pred16x16_plane_svq3_c; break;case AV_CODEC_ID_RV40: h->pred16x16[3 ]=pred16x16_plane_rv40_c; break;case AV_CODEC_ID_VP7:case AV_CODEC_ID_VP8: h->pred16x16[3 ]=pred16x16_tm_vp8_c; h->pred16x16[7]= pred16x16_127_dc_8_c; h->pred16x16[8]= pred16x16_129_dc_8_c; break;default: h->pred16x16[3 ]=pred16x16_plane_8_c; break;}h->pred16x16[4]= pred16x16_left_dc_8_c;h->pred16x16[5 ]= pred16x16_top_dc_8_c;h->pred16x16[6 ]= pred16x16_128_dc_8_c; /* special lossless h/v prediction for h264*/ h->pred4x4_add [0 ]=pred4x4_vertical_add_8_c;h->pred4x4_add [ 1 ]= pred4x4_horizontal_add_8_c;h->pred8x8l_add [0 ]= pred8x8l_vertical_add_8_c;h->pred8x8l_add [ 1 ]= pred8x8l_horizontal_add_8_c;h->pred8x8l_filter_add [0 ]= pred8x8l_vertical_filter_add_8_c;h->pred8x8l_filter_add [ 1 ]= pred8x8l_horizontal_filter_add_8_c;if (chroma_format_idc <= 1) {h->pred8x8_add [2]= pred8x8_vertical_add_8_c;h->pred8x8_add [ 1]= pred8x8_horizontal_add_8_c;} else { h->pred8x8_add [2]= pred8x16_vertical_add_8_c; h->pred8x8_add [ 1]= pred8x16_horizontal_add_8_c;}h->pred16x16_add[2]=pred16x16_vertical_add_8_c;h->pred16x16_add[ 1]=pred16x16_horizontal_add_8_c;可以看出在H264_PRED(8)展开后的代码中,帧内预测模块的函数指针都被赋值以xxxx_8_c()的函数。例如帧内4x4的模式0被赋值以pred4x4_vertical_8_c(),帧内4x4的模式1被赋值以pred4x4_horizontal_8_c(),如下所示。//帧内4x4的Vertical预测方式h->pred4x4[0 ]= pred4x4_vertical_8_c;//帧内4x4的Horizontal预测方式h->pred4x4[1 ]= pred4x4_horizontal_8_c;在这里我们可以简单看一下pred4x4_vertical_8_c()函数。该函数完成了4x4帧内Vertical模式的预测。
pred4x4_vertical_8_c()
pred4x4_vertical_8_c()的定义位于libavcodech264pred_template.c,如下所示。//垂直预测//由上边像素推出像素值static void pred4x4_vertical_8_c (uint8_t*_src, const uint8_t *topright, ptrdiff_t_stride){ pixel *src = (pixel*)_src; int stride = _stride>>(sizeof(pixel)-1); /* * Vertical预测方式 * |X1 X2 X3 X4 * --+----------- * |X1 X2 X3 X4 * |X1 X2 X3 X4 * |X1 X2 X3 X4 * |X1 X2 X3 X4 * */ //pixel4代表4个像素值。1个像素值占用8bit,4个像素值占用32bit。 const pixel4 a= AV_RN4PA(src-stride); /* 宏定义展开后: * const uint32_t a=(((const av_alias32*)(src-stride))->u32); * 注:av_alias32是一个union类型的变量,存储4byte的int或者float。 * -stride代表了上一行对应位置的像素 * 即a取的是上1行像素的值。 */ AV_WN4PA(src+0*stride, a); AV_WN4PA(src+1*stride, a); AV_WN4PA(src+2*stride, a); AV_WN4PA(src+3*stride, a); /* 宏定义展开后: * (((av_alias32*)(src+0*stride))->u32 = (a)); * (((av_alias32*)(src+1*stride))->u32 = (a)); * (((av_alias32*)(src+2*stride))->u32 = (a)); * (((av_alias32*)(src+3*stride))->u32 = (a)); * 即a把a的值赋给下面4行。 */ }有关pred4x4_vertical_8_c()的代码在后续文章中再做详细分析,在这里就不再做过多解释了。
h264_decode_frame()h264_decode_frame()用于解码一帧图像数据。该函数的定义位于libavcodech264.c,如下所示。//H.264解码器-解码static int h264_decode_frame(AVCodecContext*avctx, void *data, int *got_frame,AVPacket *avpkt){ //赋值。buf对应的就是AVPacket的data const uint8_t *buf = avpkt->data; int buf_size =avpkt->size; //指向AVCodecContext的priv_data H264Context *h =avctx->priv_data; AVFrame *pict = data; int buf_index = 0; H264Picture *out; int i, out_idx; int ret; h->flags = avctx->flags; /* reset data partitioning here, to ensure GetBitContexts from previous * packets do not get used. */ h->data_partitioning = 0; /* end of stream, output what is still in the buffers */ // Flush Decoder的时候会调用,此时输入为空的AVPacket===================== if (buf_size == 0) { out: h->cur_pic_ptr = NULL; h->first_field = 0; // FIXME factorize this with the output code below //输出out,源自于h->delayed_pic[] //初始化 out = h->delayed_pic[0]; out_idx = 0; for (i = 1; h->delayed_pic[i] && !h->delayed_pic[i]->f.key_frame && !h->delayed_pic[i]->mmco_reset; i++) if (h->delayed_pic[i]->poc < out->poc) { //输出out,源自于h->delayed_pic[] //逐个处理 out = h->delayed_pic[i]; out_idx = i; } for (i = out_idx; h->delayed_pic[i]; i++) h->delayed_pic[i] = h->delayed_pic[i + 1]; if (out) { out->reference &= ~DELAYED_PIC_REF; //输出 //out输出到pict //即H264Picture到AVFrame ret = output_frame(h, pict, out); if (ret < 0) return ret; *got_frame = 1; } return buf_index; } //============================================================= if (h->is_avc && av_packet_get_side_data(avpkt,AV_PKT_DATA_NEW_EXTRADATA, NULL)) { int side_size; uint8_t *side = av_packet_get_side_data(avpkt,AV_PKT_DATA_NEW_EXTRADATA, &side_size); if (is_extra(side, side_size)) ff_h264_decode_extradata(h, side,side_size); } if(h->is_avc && buf_size >= 9 && buf[0]==1&& buf[2]==0 && (buf[4]&0xFC)==0xFC &&(buf[5]&0x1F) && buf[8]==0x67){ if (is_extra(buf, buf_size)) return ff_h264_decode_extradata(h, buf, buf_size); } //关键:解码NALU最主要的函数 //============================================================= buf_index = decode_nal_units(h, buf, buf_size, 0); //============================================================= if (buf_index < 0) return AVERROR_INVALIDDATA; if (!h->cur_pic_ptr && h->nal_unit_type ==NAL_END_SEQUENCE) { av_assert0(buf_index <= buf_size); goto out; } if (!(avctx->flags2 & CODEC_FLAG2_CHUNKS) &&!h->cur_pic_ptr) { if (avctx->skip_frame >= AVDISCARD_NONREF || buf_size >= 4 && !memcmp("Q264", buf, 4)) return buf_size; av_log(avctx, AV_LOG_ERROR, "no frame!
"); return AVERROR_INVALIDDATA; } if (!(avctx->flags2 & CODEC_FLAG2_CHUNKS) || (h->mb_y >= h->mb_height && h->mb_height)) { if (avctx->flags2 & CODEC_FLAG2_CHUNKS) decode_postinit(h, 1); ff_h264_field_end(h, 0); /* Wait for second field. */ //设置got_frame为0 *got_frame = 0; if (h->next_output_pic && ( h->next_output_pic->recovered)) { if (!h->next_output_pic->recovered) h->next_output_pic->f.flags |= AV_FRAME_FLAG_CORRUPT; //输出Frame //即H264Picture到AVFrame ret = output_frame(h, pict, h->next_output_pic); if (ret < 0) return ret; //设置got_frame为1 *got_frame = 1; if (CONFIG_MPEGVIDEO) { ff_print_debug_info2(h->avctx, pict, h->er.mbskip_table, h->next_output_pic->mb_type, h->next_output_pic->qscale_table, h->next_output_pic->motion_val, &h->low_delay, h->mb_width, h->mb_height, h->mb_stride, 1); } } } assert(pict->buf[0] || !*got_frame); return get_consumed_bytes(buf_index, buf_size);}从源代码可以看出,h264_decode_frame()根据输入的AVPacket的data是否为空作不同的处理:(1)若果输入的AVPacket的data为空,则调用output_frame()输出delayed_pic[]数组中的H264Picture,即输出解码器中缓存的帧(对应的是通常称为“Flush Decoder”的功能)。
(2)若果输入的AVPacket的data不为空,则首先调用decode_nal_units()解码AVPacket的data,然后再调用output_frame()输出解码后的视频帧(有一点需要注意:由于帧重排等因素,输出的AVFrame并非对应于输入的AVPacket)。下面看一下解码压缩编码数据时候用到的函数decode_nal_units()。
decode_nal_units()decode_nal_units()是用于解码NALU的函数。函数定义位于libavcodech264.c,如下所示。//解码NALU最主要的函数//h264_decode_frame()中://buf一般是AVPacket->data//buf_size一般是AVPacket->sizestatic int decode_nal_units(H264Context *h,const uint8_t *buf, int buf_size, intparse_extradata){ AVCodecContext *const avctx = h->avctx; H264Context *hx; ///< thread context int buf_index; unsigned context_count; int next_avc; int nals_needed = 0; ///< number of NALs that need decoding beforethe next frame thread starts int nal_index; int idr_cleared=0; int ret = 0; h->nal_unit_type= 0; if(!h->slice_context_count) h->slice_context_count= 1; h->max_contexts = h->slice_context_count; if (!(avctx->flags2 & CODEC_FLAG2_CHUNKS)) { h->current_slice = 0; if (!h->first_field) h->cur_pic_ptr = NULL; ff_h264_reset_sei(h); } //AVC1和H264的区别: //AVC1 描述:H.264 bitstream without start codes.是不带起始码0x00000001的。FLV/MKV/MOV种的H.264属于这种 //H264 描述:H.264 bitstream with start codes.是带有起始码0x00000001的。H.264裸流,MPEGTS种的H.264属于这种 // //通过VLC播放器,可以查看到具体的格式。打开视频后,通过菜单【工具】/【编解码信息】可以查看到【编解码器】具体格式,举例如下,编解码器信息: //编码: H264 – MPEG-4 AVC (part 10) (avc1) //编码: H264 – MPEG-4 AVC (part 10) (h264) // if (h->nal_length_size == 4) { if (buf_size > 8 && AV_RB32(buf) == 1 &&AV_RB32(buf+5) > (unsigned)buf_size) { //前面4位是起始码0x00000001 h->is_avc = 0; }else if(buf_size > 3 && AV_RB32(buf) > 1 &&AV_RB32(buf) <= (unsigned)buf_size) //前面4位是长度数据 h->is_avc = 1; } if (avctx->active_thread_type & FF_THREAD_FRAME) nals_needed = get_last_needed_nal(h, buf, buf_size); { buf_index = 0; context_count = 0; next_avc = h->is_avc ? 0 :buf_size; nal_index = 0; for (;;) { int consumed; int dst_length; int bit_length; const uint8_t *ptr; int nalsize = 0; int err; if (buf_index >= next_avc) { nalsize = get_avc_nalsize(h, buf,buf_size, &buf_index); if (nalsize < 0) break; next_avc = buf_index + nalsize; } else { buf_index =find_start_code(buf, buf_size, buf_index, next_avc); if (buf_index >= buf_size) break; if (buf_index >= next_avc) continue; } hx = h->thread_context[context_count]; //解析得到NAL(获得nal_unit_type等信息) ptr = ff_h264_decode_nal(hx, buf + buf_index, &dst_length, &consumed, next_avc - buf_index); if (!ptr || dst_length < 0) { ret = -1; goto end; } bit_length = get_bit_length(h, buf, ptr, dst_length, buf_index + consumed, next_avc); if (h->avctx->debug & FF_DEBUG_STARTCODE) av_log(h->avctx,AV_LOG_DEBUG, "NAL %d/%d at %d/%dlength %d
", hx->nal_unit_type,hx->nal_ref_idc, buf_index, buf_size, dst_length); if (h->is_avc && (nalsize != consumed) && nalsize) av_log(h->avctx,AV_LOG_DEBUG, "AVC: Consumed only%d bytes instead of %d
", consumed, nalsize); buf_index += consumed; nal_index++; if (avctx->skip_frame >= AVDISCARD_NONREF && h->nal_ref_idc == 0&& h->nal_unit_type != NAL_SEI) continue; again: if ( !(avctx->active_thread_type & FF_THREAD_FRAME) || nals_needed >= nal_index) h->au_pps_id = -1; /* Ignore per frame NAL unit type during extradata * parsing. Decoding slices is not possible in codec init * with frame-mt */ if (parse_extradata) { switch (hx->nal_unit_type) { case NAL_IDR_SLICE: case NAL_SLICE: case NAL_DPA: case NAL_DPB: case NAL_DPC: av_log(h->avctx, AV_LOG_WARNING, "Ignoring NAL%d in global header/extradata
", hx->nal_unit_type); // fall through to nextcase case NAL_AUXILIARY_SLICE: hx->nal_unit_type =NAL_FF_IGNORE; } } err = 0; //根据不同的 NALU Type,调用不同的函数 switch (hx->nal_unit_type) { //IDR帧 case NAL_IDR_SLICE: if ((ptr[0] & 0xFC) ==0x98) { av_log(h->avctx,AV_LOG_ERROR, "Invalid inter IDR frame
"); h->next_outputed_poc =INT_MIN; ret = -1; goto end; } if (h->nal_unit_type !=NAL_IDR_SLICE) { av_log(h->avctx,AV_LOG_ERROR, "Invalid mix ofidr and non-idr slices
"); ret = -1; goto end; } if(!idr_cleared) idr(h); // FIXME ensurewe don't lose some frames if there is reordering idr_cleared = 1; h->has_recovery_point = 1; //注意没有break case NAL_SLICE: init_get_bits(&hx->gb,ptr, bit_length); hx->intra_gb_ptr = hx->inter_gb_ptr = &hx->gb; hx->data_partitioning = 0; //解码SliceHeader if ((err =ff_h264_decode_slice_header(hx, h))) break; if(h->sei_recovery_frame_cnt >= 0) { if (h->frame_num !=h->sei_recovery_frame_cnt || hx->slice_type_nos != AV_PICTURE_TYPE_I) h->valid_recovery_point = 1; if ( h->recovery_frame < 0 ||((h->recovery_frame - h->frame_num) & ((1 <
sps.log2_max_frame_num)-1)) > h->sei_recovery_frame_cnt) { h->recovery_frame =(h->frame_num + h->sei_recovery_frame_cnt) & ((1<< h->sps.log2_max_frame_num) - 1); if(!h->valid_recovery_point) h->recovery_frame = h->frame_num; } } h->cur_pic_ptr->f.key_frame |= (hx->nal_unit_type ==NAL_IDR_SLICE); if (hx->nal_unit_type ==NAL_IDR_SLICE || h->recovery_frame ==h->frame_num) { h->recovery_frame = -1; h->cur_pic_ptr->recovered = 1; } // If we have an IDR, allframes after it in decoded order are // "recovered". if (hx->nal_unit_type ==NAL_IDR_SLICE) h->frame_recovered |=FRAME_RECOVERED_IDR; h->frame_recovered |=3*!!(avctx->flags2 & CODEC_FLAG2_SHOW_ALL); h->frame_recovered |=3*!!(avctx->flags & CODEC_FLAG_OUTPUT_CORRUPT);#if 1 h->cur_pic_ptr->recovered|= h->frame_recovered;#else h->cur_pic_ptr->recovered|= !!(h->frame_recovered & FRAME_RECOVERED_IDR);#endif if (h->current_slice == 1) { if (!(avctx->flags2& CODEC_FLAG2_CHUNKS)) decode_postinit(h,nal_index >= nals_needed); if (h->avctx->hwaccel&& (ret =h->avctx->hwaccel->start_frame(h->avctx, NULL, 0)) < 0) return ret; if (CONFIG_H264_VDPAU_DECODER && h->avctx->codec->capabilities & CODEC_CAP_HWACCEL_VDPAU) ff_vdpau_h264_picture_start(h); } if (hx->redundant_pic_count== 0) { if (avctx->hwaccel){ ret =avctx->hwaccel->decode_slice(avctx, &buf[buf_index - consumed], consumed); if (ret < 0) return ret; } else if(CONFIG_H264_VDPAU_DECODER && h->avctx->codec->capabilities & CODEC_CAP_HWACCEL_VDPAU) { ff_vdpau_add_data_chunk(h->cur_pic_ptr->f.data[0], start_code, sizeof(start_code)); ff_vdpau_add_data_chunk(h->cur_pic_ptr->f.data[0], &buf[buf_index - consumed], consumed); } else context_count++; } break; case NAL_DPA: if (h->avctx->flags &CODEC_FLAG2_CHUNKS) { av_log(h->avctx,AV_LOG_ERROR, "Decoding inchunks is not supported for " "partitionedslices.
"); return AVERROR(ENOSYS); } init_get_bits(&hx->gb,ptr, bit_length); hx->intra_gb_ptr = hx->inter_gb_ptr = NULL; //解码SliceHeader if ((err =ff_h264_decode_slice_header(hx, h))) { /* make suredata_partitioning is cleared if it was set * before, so we don't trydecoding a slice without a valid * slice header later */ h->data_partitioning =0; break; } hx->data_partitioning = 1; break; case NAL_DPB: init_get_bits(&hx->intra_gb, ptr, bit_length); hx->intra_gb_ptr =&hx->intra_gb; break; case NAL_DPC: init_get_bits(&hx->inter_gb, ptr, bit_length); hx->inter_gb_ptr =&hx->inter_gb; av_log(h->avctx,AV_LOG_ERROR, "Partitioned H.264 support is incomplete
"); break; if (hx->redundant_pic_count== 0 && hx->intra_gb_ptr&& hx->data_partitioning&& h->cur_pic_ptr&& h->context_initialized && (avctx->skip_frame nal_ref_idc) && (avctx->skip_frame slice_type_nos !=AV_PICTURE_TYPE_B) && (avctx->skip_frame slice_type_nos ==AV_PICTURE_TYPE_I) && avctx->skip_frame gb,ptr, bit_length); //解析SEI补充增强信息单元 ret = ff_h264_decode_sei(h); if (ret < 0 &&(h->avctx->err_recognition & AV_EF_EXPLODE)) goto end; break; case NAL_SPS: init_get_bits(&h->gb,ptr, bit_length); //解析SPS序列参数集 if(ff_h264_decode_seq_parameter_set(h) < 0 && (h->is_avc ? nalsize: 1)) { av_log(h->avctx,AV_LOG_DEBUG, "SPS decodingfailure, trying again with the complete NAL
"); if (h->is_avc) av_assert0(next_avc -buf_index + consumed == nalsize); if ((next_avc - buf_index +consumed - 1) >= INT_MAX/8) break; init_get_bits(&h->gb, &buf[buf_index + 1 - consumed], 8*(next_avc -buf_index + consumed - 1)); ff_h264_decode_seq_parameter_set(h); } break; // case NAL_PPS: init_get_bits(&h->gb,ptr, bit_length); //解析PPS图像参数集 ret = ff_h264_decode_picture_parameter_set(h,bit_length); if (ret < 0 &&(h->avctx->err_recognition & AV_EF_EXPLODE)) goto end; break; case NAL_AUD: case NAL_END_SEQUENCE: case NAL_END_STREAM: case NAL_FILLER_DATA: case NAL_SPS_EXT: case NAL_AUXILIARY_SLICE: break; case NAL_FF_IGNORE: break; default: av_log(avctx, AV_LOG_DEBUG,"Unknown NAL code: %d (%d bits)
", hx->nal_unit_type,bit_length); } if (context_count == h->max_contexts) { ret =ff_h264_execute_decode_slices(h, context_count); if (ret < 0 &&(h->avctx->err_recognition & AV_EF_EXPLODE)) goto end; context_count = 0; } if (err < 0 || err == SLICE_SKIPED) { if (err < 0) av_log(h->avctx,AV_LOG_ERROR, "decode_slice_header error
"); h->ref_count[0] =h->ref_count[1] = h->list_count = 0; } else if (err == SLICE_SINGLETHREAD) { /* Slice could not be decodedin parallel mode, copy down * NAL unit stuff to context 0and restart. Note that * rbsp_buffer is nottransferred, but since we no longer * run in parallel mode thisshould not be an issue. */ h->nal_unit_type =hx->nal_unit_type; h->nal_ref_idc = hx->nal_ref_idc; hx = h; goto again; } } } if (context_count) { //真正的解码 ret = ff_h264_execute_decode_slices(h, context_count); if (ret < 0 && (h->avctx->err_recognition &AV_EF_EXPLODE)) goto end; } ret = 0;end: /* clean up */ if (h->cur_pic_ptr && !h->droppable) { ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX, h->picture_structure == PICT_BOTTOM_FIELD); } return (ret < 0) ? ret : buf_index;}从源代码可以看出,decode_nal_units()首先调用ff_h264_decode_nal()判断NALU的类型,然后根据NALU类型的不同调用了不同的处理函数。这些处理函数可以分为两类——解析函数和解码函数,如下所示。(1)解析函数(获取信息):ff_h264_decode_seq_parameter_set():解析SPS。ff_h264_decode_picture_parameter_set():解析PPS。ff_h264_decode_sei():解析SEI。ff_h264_decode_slice_header():解析Slice Header。(2)解码函数(解码得到图像):ff_h264_execute_decode_slices():解码Slice。解码函数ff_h264_execute_decode_slices()完成了解码Slice的工作,下面看一下该函数的定义。ff_h264_execute_decode_slices()ff_h264_execute_decode_slices()用于解码获取图像信息,定义位于libavcodech264_slice.c,如下所示。/** *Call decode_slice() for each context. * *@param h h264 master context * @paramcontext_count number of contexts to execute *///真正的解码intff_h264_execute_decode_slices(H264Context *h, unsigned context_count){ AVCodecContext *const avctx = h->avctx; H264Context *hx; int i; av_assert0(h->mb_y < h->mb_height); if (h->avctx->hwaccel || h->avctx->codec->capabilities & CODEC_CAP_HWACCEL_VDPAU) return 0; //context_count的数量 if (context_count == 1) { //解码Slice return decode_slice(avctx, &h); }else { av_assert0(context_count > 0); for (i = 1; i < context_count; i++) { hx =h->thread_context[i]; if (CONFIG_ERROR_RESILIENCE) { hx->er.error_count = 0; } hx->x264_build =h->x264_build; } avctx->execute(avctx, decode_slice, h->thread_context, NULL, context_count,sizeof(void *)); /* pull back stuff from slices to master context */ hx = h->thread_context[context_count- 1]; h->mb_x =hx->mb_x; h->mb_y =hx->mb_y; h->droppable =hx->droppable; h->picture_structure = hx->picture_structure; if (CONFIG_ERROR_RESILIENCE) { for (i = 1; i < context_count; i++) h->er.error_count +=h->thread_context[i]->er.error_count; } } return 0;}可以看出ff_h264_execute_decode_slices()调用了decode_slice()函数。在decode_slice()函数中完成了熵解码,宏块解码,环路滤波,错误隐藏等解码的细节工作。由于decode_slice()的内容比较多,本文暂不详细分析该函数,仅简单看一下该函数的定义。decode_slice()decode_slice()完成了熵解码,宏块解码,环路滤波,错误隐藏等解码的细节工作。该函数的定义位于定义位于libavcodech264_slice.c,如下所示。//解码slice//三个主要步骤://1.熵解码(CAVLC/CABAC)//2.宏块解码//3.环路滤波//此外还包含了错误隐藏代码static int decode_slice(structAVCodecContext *avctx, void *arg){ H264Context *h = *(void **)arg; int lf_x_start = h->mb_x; h->mb_skip_run = -1; av_assert0(h->block_offset[15] == (4 * ((scan8[15] - scan8[0]) &7) << h->pixel_shift) + 4 * h->linesize * ((scan8[15] - scan8[0])>> 3)); h->is_complex = FRAME_MBAFF(h) || h->picture_structure !=PICT_FRAME || avctx->codec_id !=AV_CODEC_ID_H264 || (CONFIG_GRAY &&(h->flags & CODEC_FLAG_GRAY)); if(!(h->avctx->active_thread_type & FF_THREAD_SLICE) &&h->picture_structure == PICT_FRAME && h->er.error_status_table) { const int start_i =av_clip(h->resync_mb_x + h->resync_mb_y * h->mb_width, 0, h->mb_num- 1); if (start_i) { int prev_status =h->er.error_status_table[h->er.mb_index2xy[start_i - 1]]; prev_status &= ~ VP_START; if (prev_status != (ER_MV_END | ER_DC_END | ER_AC_END)) h->er.error_occurred = 1; } } //CABAC情况 if (h->pps.cabac) { /* realign */ align_get_bits(&h->gb); /* init cabac */ //初始化CABAC解码器 ff_init_cabac_decoder(&h->cabac, h->gb.buffer +get_bits_count(&h->gb) / 8, (get_bits_left(&h->gb)+ 7) / 8); ff_h264_init_cabac_states(h); //循环处理每个宏块 for (;;) { // START_TIMER //解码CABAC数据 int ret = ff_h264_decode_mb_cabac(h); int eos; // STOP_TIMER("decode_mb_cabac") //解码宏块 if (ret >= 0) ff_h264_hl_decode_mb(h); // FIXME optimal? or let mb_decode decode 16x32 ? //宏块级帧场自适应。很少