最近学习HEVC,参考h264bitstream开源库重新写代码解析码流。在观察H264码流的分析结果时,发现该库分析的结果与商业工具有些不同。以前也遇到过,还写了篇文章《解决h264bitstream的一个bug 》,经调试发现h264bitstream库实现上有些小问题,于是就修改修改,形成此文。
一、头文件 1、改名及新加 将sps_t结构体的residual_colour_transform_flag改名为separate_colour_plane_flag。根据最新文档,sps_t结构体新加ChromaArrayType。slice_header_t结构体添加colour_plane_id成员。
2、新加vector 去掉extern “C”的限制,添加std的vector。
1 2 #include <vector> using std::vector;
3、分离部分结构体 将slice_header_t结构体的pwt、rplr和drpm独立出来。因为这些字段的数量不固定,使用了vector存储,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 // predictive weight table typedef struct { int luma_log2_weight_denom; int chroma_log2_weight_denom; int luma_weight_l0_flag[64]; int luma_weight_l0[64]; int luma_offset_l0[64]; int chroma_weight_l0_flag[64]; int chroma_weight_l0[64][2]; int chroma_offset_l0[64][2]; int luma_weight_l1_flag[64]; int luma_weight_l1[64]; int luma_offset_l1[64]; int chroma_weight_l1_flag[64]; int chroma_weight_l1[64][2]; int chroma_offset_l1[64][2]; } pwt_t; // ref pic list modification typedef struct { int modification_of_pic_nums_idc; int abs_diff_pic_num_minus1; int long_term_pic_num; } rplm_tt; typedef struct { int ref_pic_list_modification_flag_l0; int ref_pic_list_modification_flag_l1; vector rplm; } rplm_t; // decoded ref pic marking typedef struct { int memory_management_control_operation; int difference_of_pic_nums_minus1; int long_term_pic_num; int long_term_frame_idx; int max_long_term_frame_idx_plus1; } drpm_tt; typedef struct { int no_output_of_prior_pics_flag; int long_term_reference_flag; int adaptive_ref_pic_marking_mode_flag; vector drpm; } drpm_t;
slice_header_t对应的变更如下:
1 2 3 pwt_t pwt; rplm_t rplm; drpm_t drpm;
二、实现文件 1、 将read_ref_pic_list_reordering函数改名为read_ref_pic_list_modification。根据不同的数值添加到vector中。实现变更如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 //7.3.3.1 Reference picture list modification syntax void read_ref_pic_list_modification(h264_stream_t* h, bs_t* b) { slice_header_t* sh = h->sh; rplm_tt rplmtt; if( ! is_slice_type( sh->slice_type, SH_SLICE_TYPE_I ) && ! is_slice_type( sh->slice_type, SH_SLICE_TYPE_SI ) ) { sh->rplm.ref_pic_list_modification_flag_l0 = bs_read_u1(b); if( sh->rplm.ref_pic_list_modification_flag_l0 ) { do { rplmtt.modification_of_pic_nums_idc = bs_read_ue(b); if( rplmtt.modification_of_pic_nums_idc == 0 || rplmtt.modification_of_pic_nums_idc == 1 ) { rplmtt.abs_diff_pic_num_minus1 = bs_read_ue(b); } else if( rplmtt.modification_of_pic_nums_idc == 2 ) { rplmtt.long_term_pic_num = bs_read_ue(b); } sh->rplm.rplm.push_back(rplmtt); } while( rplmtt.modification_of_pic_nums_idc != 3 && ! bs_eof(b) ); } } if( is_slice_type( sh->slice_type, SH_SLICE_TYPE_B ) ) { sh->rplm.ref_pic_list_modification_flag_l1 = bs_read_u1(b); if( sh->rplm.ref_pic_list_modification_flag_l1 ) { do { rplmtt.modification_of_pic_nums_idc = bs_read_ue(b); if( rplmtt.modification_of_pic_nums_idc == 0 || rplmtt.modification_of_pic_nums_idc == 1 ) { rplmtt.abs_diff_pic_num_minus1 = bs_read_ue(b); } else if( rplmtt.modification_of_pic_nums_idc == 2 ) { rplmtt.long_term_pic_num = bs_read_ue(b); } sh->rplm.rplm.push_back(rplmtt); } while( rplmtt.modification_of_pic_nums_idc != 3 && ! bs_eof(b) ); } } }
2、 与上类似,read_dec_ref_pic_marking函数变更如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 //7.3.3.3 Decoded reference picture marking syntax void read_dec_ref_pic_marking(h264_stream_t* h, bs_t* b) { slice_header_t* sh = h->sh; drpm_tt drpmtt; if( h->nal->nal_unit_type == 5 ) { sh->drpm.no_output_of_prior_pics_flag = bs_read_u1(b); sh->drpm.long_term_reference_flag = bs_read_u1(b); } else { sh->drpm.adaptive_ref_pic_marking_mode_flag = bs_read_u1(b); if( sh->drpm.adaptive_ref_pic_marking_mode_flag ) { do { drpmtt.memory_management_control_operation = bs_read_ue(b); if( drpmtt.memory_management_control_operation == 1 || drpmtt.memory_management_control_operation == 3 ) { drpmtt.difference_of_pic_nums_minus1 = bs_read_ue(b); } if(drpmtt.memory_management_control_operation == 2 ) { drpmtt.long_term_pic_num = bs_read_ue(b); } if( drpmtt.memory_management_control_operation == 3 || drpmtt.memory_management_control_operation == 6 ) { drpmtt.long_term_frame_idx = bs_read_ue(b); } if( drpmtt.memory_management_control_operation == 4 ) { drpmtt.max_long_term_frame_idx_plus1 = bs_read_ue(b); } sh->drpm.drpm.push_back(drpmtt); } while( drpmtt.memory_management_control_operation != 0 && ! bs_eof(b) ); } } }
3、 read_pred_weight_table函数中使用的num_ref_idx_l0_active_minus1为pps_t结构体的,这是错误的。正确的是使用slice_header_t结构体的num_ref_idx_l0_active_minus1。
1 for( i = 0; i <= pps->num_ref_idx_l0_active_minus1; i++ )
要更改为
1 for( i = 0; i <= sh->num_ref_idx_l0_active_minus1; i++ )
其它一些细小的修改不在此文列出。源代码见github仓库:https://github.com/latelee/H264BSAnalyzer 的Branch_dev分支。 具体如下:https://github.com/latelee/H264BSAnalyzer/blob/Branch_dev/H264BSAnalyzer/h264_stream.h https://github.com/latelee/H264BSAnalyzer/blob/Branch_dev/H264BSAnalyzer/h264_stream.cpp
李迟 2015.9.28 晚