骂男人不行的话:基于dm642的H.264的算法改进

来源:百度文库 编辑:中财网 时间:2024/04/27 18:02:25

说到一种编码方式在芯片上作优化,首先要做的事情就是要完全了解这个芯片,在做优化工作之初,我先看了将近一周时间的datasheet, 而且由于我本身属于硬件出身的人, 对这些了解的可能更深入一些, 所以这部分并没有让我吃苦头,简单过了.不过即便如此说,我仍然觉得开始优化前必须了解DM642的基本结构,片内的通用寄存器情况,cache情况,dma情况,指令流水情况.

 

然后重要的就是编码原理了, 在做优化前我从来没接触过编码, 对我来说这个部分很陌生,用了将近一个月时间专门看编码的标准和代码, 也许很多人并没有作这部分工作, 但我觉得这部分时间花的值得, 深入了解一下编码以及要优化的东西对以后的数据结构设计和程序结构设计都有很大的帮助,最起码对我来说这是我做设计的基础,优化工作结束后的我正在写一份自己的编码器和解码器.

 

在然后就是真正的优化工作了,这部分比较枯燥,不过坚持下来收获很大。在这个部分上我的经验就是一直保持PC上的优化先行,DSP跟上的方式。这样对以后程序出现错误时的调试很有帮助,毕竟DSP调试受限于调试速度,而且调试远不如PC方便。

 

我优化的时候始终保持着编码代码的重建帧数据与解码重建数据完全一致,其实这个不是必要的,对很多情况来说,不完全一致也看不出来的问题,这个可能是小bug而不是致命错误,但是为了避免致命bug的出现,我还是一致保持了编解码的一致性。

 

再以后就是具体问题了,下面的章节中具体问题具体分析了。

 

总体而言,我优化工作的流程为:熟悉DSP->熟悉编码->设计程序结构和数据结构->按照设计方式修改PC端代码的->对照PC修改DSP代码。 由于是在TI的DM642上做优化,所以必须先了解DM642,个人认为需要知道的有以下几个方面
1、DM642的通用寄存器,了解了这个部分才能确定每次进出寄存器的数据数量。DM642有2个通用寄存器组(A和B),每个寄存器组包含32个32位寄存器,其中相邻寄存器可以组成寄存器对。
2、DM642有EDMA,可以与CPU并行工作,相当于拥有了一个只能提供搬运功能的协处理器。
3、DM642片内的SRAM(256K)可以配置成为Cache,也可以做为SRAM使用,具体如何使用可以自行配置,常用的配置是配置成为4路cache,占据64k空间,其余空间按照SRAM的方式使用,摆放放在片内的程序和数据。
4、需要了解DM642访问片内和片外的速度的差距。
5、需要了解DM642片内的L1D和L1P的结构,知道DM642是如何处理数据冲突和程序冲突的。
6、需要了解CPU和EDMA同时访问数据产生的同步问题。
7、个人推荐最好了解一些视频驱动方面的知识。 

由于需要做的是H.264编码,那么需要做的大量工作都是围绕编码进行的,需要了解编码的具体细节,也许不了解编码也能做优化,但绝对做不好优化。

编码的原理部分个人比较推荐《新一代视频压缩编码标准H.264》这本书,作者是毕厚杰,这本书里面是有一些错误,但是原理部分的东西讲的比较清楚,看过以后编码框架大致都了解了。

其实就是标准,然后就是一定要花大力气去了解代码,这样才能真的去理解编码的细节。

这里面有两个问题,首先就是网上有很多H.264编码的资料,究竟需不需要。个人认为是因人而异的,从我自己的角度出发,我不是一个喜欢接受别人思想的人,在看编码的初期也去下载了很多资料,结果几乎都没怎么看,直到第一遍优化做过以后再看看才觉得比较有收获。第二个就是编码优化的核心问题——从哪一份代码入手比较方便,通常来说我实在不推荐从JM代码入手,它的功能太强大了,很多东西根本无法在DSP上应用,甚至可以说它根本无法在日常生活中应用,它实现了标准的所有细节,但是太复杂了,使用一般水平的PC编码需要几分钟才能编码一帧,这个速度无法做到实时,它更是一个研究阶段的产物。我是从T642开始看代码的,然后仔细研究了X642,这两份代码差异不大,不过T642维护的不好,所以我的主要参考代码是X264,在理清楚了编码细节以后我看了JM的代码,发现即使有编码的基础了,JM的代码理解起来还是比较麻烦的,不过这时的麻烦主要在代码风格方面和代码冗余方面了。

至于对h.264了解多少以后再开始做优化的数据结构设计和程序结构设计,我觉得至少要保证在脑海里想一下帧内和帧间编码的过程、每个过程需要的数据以及写出数据的格式能够完全不卡,这样就可以开始做设计了  在做程序和数据设计前要弄清楚几个基本问题
1、编码方式采用哪一种?是cavlc还是cabac,我使用的是cavlc,cabac的压缩性能更强,但是相对复杂度更高,为了多压缩10% ~ 20%的码率而增加50%左右的复杂度是得不偿失,尤其我的优化目标是8路cif,使用cabac不可能做得到。
2、如何减少判断,这个对编码速度影响非常大,且不说每条判断语句需要5个周期,单是每次遇到判断就打断软件流水,这大大影响了编码速度
3、要理解软件流水的概念。
4、要利用好dma。
5、cache命中率非常重要。
针对以上的问题,我的程序和数据结构设计如下
1、每次从片外读取一个宏块进行编码而不是常用的读取一行宏块进行编码,这样提高了cache的命中率。
2、使用乒乓结构,即在编码乒宏块数据的时候开始从片外dma进来乓宏块数据,做到dma和cpu并行操作。
3、采用了x264的那个cache结构体,将每个宏块编码过程中需要的数据完全写入了这个cache结构体中,便于写cavlc数据使用。
4、扩大了每个宏块对应的重建宏块的大小,并使用这个重建宏块多的部分写入I帧预测需要的数据。
5、搜索窗范围为48x48并同时使用dma的乒乓结构,这样dma的压力不大,而且搜索数据在片内, 提高了数据命中率。
6、设计结构体保存了插值数据,避免反复插值的过程。
7、所有宏块需要的判断尽量在同一个函数内完成,避免影响以后的程序效率。
其实我觉得最重要的就是要是用好cache结构体,如果能理解x264的cache结构体,那么对自己做程序和数据设计大有好处。  数据和程序结构体设计完成后就要开始在PC是用VC++去实现了,为什么使用VC++实现,其实这并不是一个必须的,只是我比较习惯VC++而且觉得它比较好调试罢了。这部分工作我用了将近两个月的时间,不过这两个月过后编码的过程我几乎已经了解的差不多了,在DSP上作优化也就顺手了,所以我觉得这部分时间花的值得。同时再这部分中确定了编码器所支持的功能和使用的具体技术细节。由于有高人指导,没走多少弯路,搜索范围确定为48x48,P帧使用半像素搜索,不采用1/4像素搜索,B帧中只使用整像素搜索。滤波方面不使用环路滤波,采用简单的滤波方法,这个问题上指导我的人不让我多说,他说比较丢人,呵呵,不过加上环路滤波的话整体速度会有1ms的下降。使用了零块预判算法,不过这个算法不是我加上的,所以我了解不多,不过据说这个已经是公开的秘密了,打算过段时间研究一下。这些工作做完后PC端的事情也就差不多了。  

当PC端实现了预期设计后就可以开始着手DSP端的代码实现了,DSP端可以完全使用PC端的代码,不过DSP端还是会遇到不少问题,所以我建议可以先做一个小的测试工程,也就是先别把视频采集部分的代码合到一起去,可以通过读文件的方式编码测试序列,然后与PC端的做对比,然后在这个小工程下进行优化,等到一切结束后再整合代码也来得及。

下一步工作就是真的开始优化代码了,首先去掉一切冗余计算,然后开始处理具体数据了,第一个需要处理的就是片内寄存器的数据量问题,编码最终是对4x4块进行操作,4x4的数据可以直接在寄存器内完成所有计算,所以做DCT、量化、zigzag、IDCT、 反量化最好能在一个函数中完成,这样就不会涉及到寄存器数据重复导入和导出的问题了。第二个就是线性汇编的问题了,关于线性汇编这里就不重复了,其实大多时间都是一些基本操作,在TI的文档中讲的比较清楚,而且我本人线性汇编写的实在是不多,怕误人子弟啊。最后就是抠抠边角了,原则就是不需要的不计算,尽量不用判断,有些时候 “? :”这个组合也比if  else强。