Tag Archives: Lab

苦力笔记

还是写点流水账记一下吧。

到今天中午,手上的mbaff项目终于能够仿真通过一个mbaff编码的视频码流了,这是自从今年3月份我接手以来的第一次。虽然对于最终结果来说,这样的阶段成果距离最后结束还是太遥远了,我们还有很多其他各种各样比如,paff、普通的帧编码、普通的场编码,大尺寸、小尺寸,单帧多slice,high profile、baseline profile等等等等测试视频需要仿,我们最终的指标QFHD尺寸的mbaff视频还完全没有踪影,仿真以后能不能成功综合成满足时序没有意外latch还是个未知数,综合之后放在fpga上面能不能配合firmware继续跑一圈QA Video更是遥远的事情。

即便这样,手里的代码也是经过反复折腾才长成如此规模的。3月时刚从上一届学长那里拿到原始的代码,首先要做的就是与现有的QFHD解码器合并代码。问题是,这两个版本之间的差距差不多有两年多,两年前,他们各自在各自的工作空间里添加流水线或者MBAFF,然后随着时间推移一届传一届的又分别长成了自成一格的两个项目。我从软件开始到后来的RTL合并,光读懂前辈和前辈的前辈们的代码就已经很痛苦了,何况双份,更何况他们持续多年的人肉版本管理终于让一份能战的Soft Model都淹没在各种各样命名的目录之内消失不见。作为什么都不懂的笨蛋,每天开着Beyond Compare作文字处理也会惶惶恐恐,哪些是新的架构更改,哪些是MBAFF特有的计算模块我那时还一概不知。后来的提交也会引起上司们的抱怨:“你怎么可以如此merge” “你弄错了,现在这些信号都不用了”

可是,新的系统架构,新的模块组织什么的,你都没教我,你只是这么一句话:看代码,一切都很清楚。

整个3月和半个4月我都在做这种其实算是打字和文字处理的事情,迷迷茫茫。也不知道该吐槽哪边的代码风格更加令人费解才好。也不是没有注释或者设计文档,只是,我才见识原来到注释可以不写一行文字却纯用符号表达,好似甲骨文占卜,而设计文档老旧的无法和现在主流的Project Tree兼容。光RTL部分来说我并没有全包这种合并工作,只是整个系统的前端部分,解码器的FrontEnd模块——这已经是五人两代的劳动结晶了(笑),具体的说有这么几块MBAFF支持比较集中的地方:算数编解码CAVLC与CABAC[未完成]、预测运动矢量readMotion、显示图像缓存DPB、去块滤波参数DBP以及其他宏块前期处理的过程。 至于作为模型的C Model,在一个很偶然的情况下发现已经合并结束的工程并不能正确的解码.264的视频,别说mbaff编码,普通的码流输出的yuv序列都无法和参考对应。这时面对混乱的工程和项目,上司们显得比我还要焦躁。最后我在硬盘深处找到一个号称QA测试结果最优的版本,反向合并(也就是在中古项目里加QFHD支持),通过大部分QA码流的解码测试。这才稳住了摇摇欲坠的软件模型,而此时已经5月过半了。

两个月以来干的事情其实仍然很杂并且效率低下,而且自己一方面新丁上场不懂的地方实在多到影响工作效率(不懂mbaff原理、不懂项目里的一些设计结构、甚至不懂稍微具体的解码流程),一方面给前辈本应完成而未完成的事情扫尾自然会状况百出。这种情况直到自己开始调试,开始做功能仿真时才得到改善。其实,还有一点不得不说的是春季的三四月,也是公司和大佬双双push得最厉害的时候,leader经常在要开会或者要用我的时候发现我不在,而相似的大佬每次来打水也会出现上午明明看到下午就不见踪影的事情。这段日子两边让我都觉得压力好大,每天也很疲劳,四月还有自己私人交际上的第三方压力。我没有崩溃,却大病一场体温窜到39度如同泄气皮球一样释放出来了。五月用了一周时间和父母在一起,之后就自然而然的辞职quit,专心做事。

这段我先前曾拼命隐瞒——起码想和三次元的交际圈里面千方百计隐瞒的经历想了想还是坦诚写在这里吧,我憋了也有好几月了,一直没处说,虽然经常经常依赖Twitter来抱怨生活上的不如意,但出现在人家的Timeline上毕竟是与大家相关不大的事情,虽然安全却有着些些陌生的落寂感。过去这么长时间,即便三次元的、身边的、甚至就是敏感的大佬本人如果google到这篇,我也觉得无所谓了,哪怕域名被墙,尽管来看好了,来看看你身边的人是混的多么的苦逼——当你有着另一半陪着看电影或者完全不用为晚饭的食物操心的时候你身边的人有多么的苦逼。

—————有多少爱,可以重来;有多少人,愿意等待—————

6月到来,带来的魔都夏日却一直挺凉爽的,我早早的铺上麻将席却时时冻得鸡皮疙瘩发抖。6月以来的项目就进入了真正的调试阶段,接触了许多项目里的设计概念,学到了不少。在此期间我有好几次中二发作,作为什么资历都没有的小虾米愣是不爽研究所里山寨小作坊一般的工作环境。于是先从自己用的EDA软件入手,搞定了license,搞定了linux版本的novas,接着搞定了linux下一套Soft Model+RTL Model的工作调试环境,最后搞定了自用的版本管理svn,因为讨厌在老的掉牙的RHEL4里面无论装个什么都发愁库与库之间依赖性,索性自己做了个新的debian amd64虚拟机偷偷塞进去(起码deb包和apt-get可以迅速的装上从gcc到svn再到vim一切常用工具);而windows平台下成功说服同僚扔掉VC6,起码debug时用vs2008看你的变量和条件断点比较不那么反人类吧。中二的自己也没法把自己这一套习惯向外推广,一直只是这么自个儿坚持的。我不能说外面无论大小公司基本工作环境都是*nix基础动辄vim或emacs你们还死守UltraEdit32破解版怎么行啊,也不能劝服说放弃你自己的bat批处理吧那么多脚本可以写。总之,在三次元的同僚眼里或许我就是这么个格格不入甚至有时很装逼的二愣子吧,没差啦。也许你可以忍受win7下面debussy 5.4 for win的频频崩溃而我不能;也许你认为双击bat文件比起敲make命令方便而我讨厌虚拟机内外切来切去——我要插一句话,我们的仿真流程一般是这样的:如果更新过C代码的话接下来要到虚拟机里使用Makefile编译打包用于or1200 cpu的firmware,接下来使用GenTestBench.bat调用vc编译的软件模型解出待仿真的码流的YUV序列,之后调用一些C写的数据处理小工具制作二进制文件为仿真做准备——为什么这些不能一股脑在linux环境下做完?反正仿真肯定没法在win下面跑了。所以我凭借这么一股中二的热情用若干Makefile嵌套补完了整个project tree(看上去像模像样),也照着《鸟哥的linux私房菜》(感谢我的第一个leader)写了点shell脚本,这么着不仅把仿真环境,更是把项目的树状结构理清楚了,也能给建立版本库做准备。在这里我要感谢曾经实习的DesignCAD team,这些树状项目和IP组件管理的概念都是在组里做CDS移植的时候学习到的。

说回项目本身,实地仿真出了许多错误,而这些错误都作为改进文本合并或是了解项目中系统结构与数据、时序处理细节的小小经验积累。起初为了保证文本合并之后代码功能正常,挑选的都是非mbaff编码格式的码流,我印象最深的是CVPA_TOSHIBA_D这个(也许命名记忆有偏差),同僚跟我说是作为非mbaff码流来说最考验去块滤波的一个QA码流,作为图像级帧场自适应编码的视频考验了去块滤波本来就足够复杂的各种可能情况。解决了这一类问题(主要是当初合并时对现有的架构和流水线机制并不太清楚)已经差不多到了7月的关头。此时距离传说中的暑假只剩下一个月,实验室内的大家也陆陆续续大体完成了属于自己那份的活计,各自忙着写小论文投简历面试找实习如何如何,可是我还什么都没个头绪,再去找寻个肯给工资的雇主我也怕自己手上东西没有做好,去哪里都是半调子继续自我厌恶的这种循环。但毕竟要加快自己进度了,当时决定否决再调一些“传统”非mbaff码流的建议,直接挑选mbaff编码中图像尺寸最小、帧数也最少的CVQP3_Sony_D,开始了没日没夜没有周末没有夜间休息的昏天暗地生活。实际上我解决问题最多最集中的也就是7月这么20来天,多到没法回想起一些充满成就令人回味的改动。我只能说,自从邯郸学步地把svn版本库建好到现在整个码流跑通,现在的revision已经到r37了(抱歉大佬,r不是release的意思)。从茫茫的错误中我知道了前端FrontEnd里关于流水线的设计动机和原理,也知道SRAM配合流水线进行读写的机制,软硬件配合甚至firmware编写与调试,也算修改过总数达到二十五六个状态的状态机,修正过细小模块的时序错误,此外还有软件内铺张浪费的数组声明到硬件里只能处处以吝啬节省为主的时候只好用相当扭曲消耗脑细胞的表达方式组织数据,诸如此类。

我并不是一个爱看书和会读书的人,很多好书系统的讲解了某方面的知识我最多当作字典或者参考书一样用到的时候随手翻翻,用完就丢脑后忘掉。这些零零碎碎的东西竟然都能作为自己经验,那我这样的得多么不学无术才行啊——很多细节都是书里详细讲解的典型案例才对。呵呵,作为从小到大被人骂做笨蛋的人也只能做到这种程度了,摊手。睡觉了,真的懒得在wp后台给blog插图,对于软件对于web对于基于这一切的技术来说我就是个什么都不懂的小白。

在和研究所里的项目抗争之余,我那一个周末缝补起来的脚本知识全部忘光了,现在肯定没什么人要我的吧(笑。

PowerPoint才代表最先进的生产力

轮到我给下一届的学弟学妹们做暑期培训,讲到实验室项目里用到的流水先设计。把仿真波形拎出来讲,他们一脸茫然:

再用powerpoint随手画的那种SmartArt插画当示意图,讲这里有两级流水线,前一级有什么模块做了什么什么事,后一级又是如何如何,两级并行时对图像宏块处理是错开一个进行的……云云。

结果孩子们还是一脸茫然,不过似乎听懂了点,可回到仿真波形又表示看不懂了。唉,我无能为力。

十月计划

下午prof过来,把我们统一划分到了解码组。所里的安排计划如下:
decoder:
纠错——C mode已完善,需要迁移至RTL实现。
MBAFF——模块调试工作完成进度,包括DBST接口(马王张)
多路decoding——整体架构大改动,目的实现4路FullHD/8路720p/16路480p实时解码
encoder:
RTL模型空白

我接手MBAFF的部分,需要了解Macroblock的预测/DDR数据分配。等这些做完则转入encoder实现。

花十个月做这些事情,希望自己早点完成提前出去多多实习。

也许实习5个月,休2个月,再出去5个月是个不错的折衷,但似乎我们更加忙碌一些。

y4m to yuv conversion note

1. YUV4MPEG2 format

YUV4MPEG2这种文件格式是一种以头文件存储视频规格的未压缩视频序列。简单来说,在原始的yuv序列的起始和每一帧的头部都加入了纯文字形式的视频参数信息,包括分辨率、帧率、逐行/隔行扫描方式、高宽比(aspect ratio),以及每一帧起始的”FRAME ”标志位。具体的定义可以参考这里的wiki。也可以下载相应的.y4m序列样本观察。

2. y4m序列的播放

太笨,除了mplayer没有找到更好的播放器(单独的yuv序列可以用基本的yuvviewerplus,到处都可以找到)。因为主流的桌面linux发行版安装mplayer以及GUI界面smplayer都很方便,所以就不在windows下面折腾了。

在终端输入

$ mplayer xxxx.y4m

会自动调用y4m的demuxer和decoder之类的东西,因为头文件信息包含了帧率和分辨率因此无须手动指定。一些常见的快捷键在mplayer的man里面都有说明,比如p暂停,左右键快速前进后退等等。对比来看下yuv序列播放,在终端输入:

$ mplayer sample-720x576.yuv -demuxer rawvideo -rawvideo w=720:h=576

因为yuv序列只有luma分量和chroma分量的生肉(raw)数据所以必须指定宽高参数。

3. y4m到yuv的转换

了解了y4m的封装形式后,我们的工作就变得相当机械。只要把头文件和每帧的标志位去除即可,剩下的生肉既是原封不动的yuv数据,如果是4:2:0也不需要进一步的转换修整工作。这次的练习是将一个3840*2160的500帧y4m转换成yuv序列,进行接下来的jm和j264编码练习。转换的思路

pFile跳过头文件
 for frame=0, frame<500, frame++
 (
 pFile跳过FRAME 标志位
 for (line=0;line;Heigth;line++)
 (读Width字节的Y分量数据并写到yuv中)
 for (line=Height;line<2*Heigth;line++)
 (读0.5Width字节UV分量数据并写到yuv中)
 )

照这样写的y4m2yuv.c工作有一个问题,生成的.yuv序列使用yuvviewerplus到#172帧的时候直接报错退出,而用mplayer播放会出现跳变、色彩大幅偏移的现象。我们开始怀疑.y4m源在172-175帧的头文件标记不那么规整,于是做了一个头文件抽取函数head_drawer(char filename[18])。把上一段算法小小改动跳过大段的像素值只提取header生成header.dat。来看看header.dat里面都是什么(notepad++,vi,emacs都行)

100419    func head_drawer() to show how does the header data stored in file. Issue found.
 Line 1:YUV4MPEG2 W3840 H2160 F50:1 Ip A1:1
 Line 2:FRAME
 ...
 Line 174:FRAME
 see->    Line 175:蔼报抱饭腐亢房文.....
 That would be the reason why .yuv sequence found error when playing through #172 frame.
 Next step, discussing the problem.
 Keypoint found:fopen() cannot past 2GB file size limit.

这样的header更让人怀疑是.y4m源的问题了。但boss指导说看看是不是文件操作有2GB限制,因为长整形最大2^32-1。找了一圈,又是要用Win API又是要用内存地址映射又是在linux环境下define BIT_OFFSET 64之类的……浪费了很多时间才想起来MSDN,终于扒出了有用的东西。fseek()->_fseeki64(),编译,问题解决。

C文件放在这里备忘。可能要被嘲笑的吧哈哈

新的问题是,实验室内网(物理隔离)的机器只有vc6,vc6的stdio库里似乎没有定义_fseeki64这个函数。啊啊好烦。然后又被老板批了,因为vc6不支持就不去想办法解决只会伸手要高版本的vs2005。。。可,可是vc6也有一些东西不是通用的ANSI C阿真是的……

bonus:在心烦大文件操作时候找到了个好用的工具,emacs的hex view插件,瞬间打开5G大文件不是问题。猛击-> 这里