经过大约一个月左右的业余时间,终于初步完成一个H.265/HEVC码流分析工具。时间包括平时的周末、晚上,以及调休的集中时间。当然,中秋回家过节不写代码。截至今天,经过多种H.265序列测试,也有各种工具对比,基本上无大问题,v2.0版本终于释放出来。v1.x版本是去年年初做的,弹指间一年多的今天又继续做。但后面也不知道有没有时间和心情完善,随缘吧。
按惯例,每年年中的时候,公司都要讲新平台预研,但不等预研结束,公司高层就开会举手敲定一个新平台,而使得“预研”结束。今年主题之一是上H.265。第一个H.265标准在2013年1月出来,至今不够3年时间,有很多公司盯上了这领域,势头很好,但毕竟只是开始的几年,还是有待发展。
这种宣传性的东西,估计产品经理、行业总监们要关注,咱们这些写代码的其实不用关心太多。但对于技术的研究、探索,还是很有必要的。网上已经有很多商用的工具开发出来了,在文章《初识HEVC/H.265》中提到一些。鉴于以前也写了H264码流分析工具,从这方面入手会好一些,一来练练手,保持代码熟悉度,二来在写的过程对照标准手册学习,效果比单看手册好很多。于是就在原来工具基础上,继续做H265的分析。
在文章《完成一个分析H264码流的工具》中大概写了一些思路,但不是很系统。这里再写一下。核心代码为h264bitstream开源库,它提供了一个很好的H.264码流读、写的方案,而且开源。它提供了基本的读写码流的接口。比如查找NAL,指数哥伦布编码等。因此,使用该开源库,只需根据标准手册里的语法规定去一一解析即可。关于这个库,不在此处详细展开描述。
0、根据标准手册语法,建立全局结构体,每个字段都单独存储。所有结构体归属于h264_stream_t和h265_stream_t结构体。对于数量不确定的字段,统一使用vector存储。
1、用户打开文件时,先判断文件类型,目前只支持H.264和H.265两种格式,如有后缀名,优先使用后缀名判定,否则读取文件开始处的NAL头,查看手册,两种码流的NAL头有差异,故可以使用该种方法。
2、按字节读取文件,根据start code解析NAL,得到NAL偏移量、长度、类型(如果是slice,还会解析出slice的类型,如I帧、P帧、B帧),存储于vector中,同时,为了得到如视频分辨率,帧率、YUV空间等信息,在解析NAL时,一并进行。做这些工作,是为了在界面的列表中列出各个NAL信息以及视频的概要信息。详见下文的界面截图。
3、鼠标双击某一个NAL时,根据前面得到NAL索引、偏移,读取文件并解析,从而得到该NAL详细信息,这里使用的方法,就是根据手册,逐一读取码流。
此处讲述一下在编码、学习过程的经验。
未动手写代码时,去下载商业工具玩玩,但只有几天的试用期,就把几个关键的NAL截图保存起来,方便日后对比。后面过期了,就拿HM的工程做对比,该工程打开几个宏就可以把运行过程的信息打印出来,包括解析码流的各个字段。
然后按手册的语法,参考h264bitstream代码,建立H.265的对应结构体,基本上语法大的方面保持一致,但H.265多了一个VPS结构体,还有ptl(profile tier level)。添加这些语法,耗时很多,一来语法字段本来就多,二来要对着手册看——即使这样,后面还是发现有个别错误、疏漏的。H.264/H.265有很多字段是属于数组类型,根据某一数值来确定范围。起初参考h264bitstream,数组统一使用255,但后来想想还是用Vector好一些,就改了。
读取码流完成了,打印字段也完成了,再从宏观上看整个工程,发现写有乱。这次是在去年写的工具上进行的,其实改善空间很大,只是自己懒,不去做。于是趁机会把代码重构了,重构后条理性好了很多。
之后就进行调试。在这个过程,还是有不少问题。
有些是细节问题,比如有个地方判断B帧,结果把“==”写成“=”,查了半天才发现。还有一个地方是pred_weight_table的判断,判断P和B帧的条件不同,但代码复制时不注意,没搞对,又花了很久排查。还有一个是读取slice头部的num_ref_idx_l1_active_minus1字段,同样是代码复制,没有注意是ue(),在和HM代码运行结果对比时,花了很多时间才确定问题。
打印NAL字段函数里,有些不按语法上写,导致个别字段和其它工具的不一致,于是又对着手册改——开始时就应该如此,又是懒没用心写。
下面说说其它的问题。
解析NAL,是要将码流转换成RBSP,代码工程统一使用h264bitstream提供的nal_to_rbsp函数,但该函数只针对只有一个字节的H.264码流的,而H.265的NAL头有2个字节。在转换时是不包括NAL头的,于是就手动修改该函数的参数。
关于SEI,h264bitstream库并没有做过多解析。或许是SEI信息重要程度不高吧。还有一个问题。在PPS中,more_rbsp_data的判断不正确。导致后面的字段不再解析。几经搜索,最终使用FFMPEG代码的判断方法,似乎是正常的了,就不再深究。
而至于其它的修改、完善,我在另一篇文章《关于h264bitstream的bug修正及完善》里写了,这里不再写出了。
无论怎样,还是完成了。此事务算告一段落。界面如下:
源代码仓库地址为:https://github.com/latelee/H264BSAnalyzer。后续不确定是否要继续维护、更新,以仓库代码为准。
后记:调休期间,有传言说大大boss拍板停止调研某国产的支持H.265的芯片平台,但我没有在正式场合得到信息,不懂是否真实。在不确定是否上H.265时,我决定搞这个工具,在不确定是否停止H.265时,完成这个工具。有始有终。
2015.11.21的更新:
发布v2.1版本。使用树形控件显示码流语法元素。增加界面的缩放功能。离上个版本有差不多2个月了,理论上搞这么个小功能不用花那么久的,主要还是因为自己懒,一到周末就完全不想写代码了。新版本界面如下(一眼看上去,顿时觉得高端好多):
李迟 时值中华人民共和国成立66周年,祖国万岁