解决h264bitstream的一个bug | 迟思堂工作室
A-A+

解决h264bitstream的一个bug

2014-09-10 13:56 Windows程序, 开源项目 暂无评论 阅读 3,706 次

上个月着手写的那个H264码流分析工具基本完成基本的功能,为了显摆,还在部门公布了,不过使用效果不及几十刀的正牌分析工具那样功能强大,速度快。但是,自己从这里面学到了一些东西,还是不错的。当然,肯定是向着更高更强的层次看齐。——所以那个工具还在完善中。

上周同事拿了一下他自己录的视频给我,我用那个工具打开,发现界面显示的宽、高显示不对,SPS中的分析的字段不正确(对,就是工具分析后的参数不正确)。对比正牌工具的分析结果,毫无悬念地怀疑是自己工具的问题,于是叫同事截图给我(正牌工具只能在一台电脑上安装,在他电脑上),当天晚上回去调试代码,终于解决了这个问题,原来是h264bitstream本身的bug。本来想向h264bitstream项目提意见的,但人家好几年没更新了,于是就不了了之了。

说回bug本身,经过调试,发现只要是sps_t的seq_scaling_matrix_present_flag字段为1,分析的结果就不正确。于是定位到下面的代码:

if( sps->seq_scaling_matrix_present_flag ) { for( i = 0; i < 8; i++ ) { sps->seq_scaling_list_present_flag[ i ] = bs_read_u1(b); if( sps->seq_scaling_list_present_flag[ i ] ) { if( i < 6 ) { read_scaling_list( b, sps->ScalingList4x4[ i ], 16, sps->UseDefaultScalingMatrix4x4Flag[ i ]); } else { read_scaling_list( b, sps->ScalingList8x8[ i - 6 ], 64, sps->UseDefaultScalingMatrix8x8Flag[ i - 6 ] ); } } } }

对比分析正确截图的对应的字段,seq_scaling_list_present_flag数组的值不符合,继续定位到bs_read_u1和read_scaling_list函数以及代码里面的判断条件。bs_read_u1其实没有什么好怀疑的,单步看结果是正确的,继续看read_scaling_list,发现该函数有一个判断:

void read_scaling_list(bs_t* b, int* scalingList, int sizeOfScalingList, int useDefaultScalingMatrixFlag ) { int j; if(scalingList == NULL) { return; } }

这里会不会有问题呢?比如,传递了NULL,直接返回,不再执行下去。因为就是从这里开始错误的,有理由作出合理的怀疑,于是打印出传递给scalingList的参数,发现是0,竟然是NULL!!!也就是说,sps->ScalingList4x4[]数组的元素是0,再看前面的代码,赫然有下面的语句:

memset(sps, 0, sizeof(sps_t));

——后面又没有对这个数组进行操作,不是0才怪!

再看对应的成员参数的声明:

int* ScalingList4x4[6]; int* ScalingList8x8[2];

声明了指针,感觉上没有问题,但是在调用上却误将ScalingList4x4和ScalingList8x8的元素的值(即0)传递进去了。知道了原因,修改就容易了。将两者的声明去掉“*”,不要用指针。下面是修改后的代码

if( sps->seq_scaling_matrix_present_flag ) { for( i = 0; i < ((sps->chroma_format_idc!=3) ? 8 : 12); i++ ) { sps->seq_scaling_list_present_flag[ i ] = bs_read_u1(b); if( sps->seq_scaling_list_present_flag[ i ] ) { if( i < 6 ) { read_scaling_list( b, &sps->ScalingList4x4[ i ], 16, sps->UseDefaultScalingMatrix4x4Flag[ i ]); } else { read_scaling_list( b, &sps->ScalingList8x8[ i - 6 ], 64, sps->UseDefaultScalingMatrix8x8Flag[ i - 6 ] ); } } } }

综上所述,最终的修改就是去掉两个“*”,加上两个“&”。

修改很简单,但知道修改的原因却要经过一番努力——而这,就是不为人知的背后的辛酸。

PS:最近领导找我谈了加薪问题,无意间听到一些事,想了两宿,觉得以后还是少显摆自己的水平比较好,有时间有心情搞点东西,还是直接在网络上发表文章的好。

李迟记于2014年3月22日



如果本文对阁下有帮助,不妨赞助笔者以输出更多好文章,谢谢!
donate




给我留言