基于ARM的MPEG4视频解码器
1 引 言 本文旨在研究基于ARM微处理器的MPEG-4视频解码技术,主要应用在手持移动设备中。利用嵌入式系统实现MPEG-4视频解码,处理器的选择是关键。在嵌入式系统中常用的RISC处理器是ARM核,主要是因为它具有体积小,功耗低,成本低,性价比高的特点,这对于移动应用领域非常重要。ARM7系列微处理器为低功耗的32位RISC处理器,最适合于对价位和功耗要求较高的消费类应用。本解码器定位于低分辨率和低帧率的应用场合,因此选择在ARM7TDMI核上实现解码功能。要实现更高帧率和分辨率的解码,可将软件直接应用在更高端的处理器上。 2 MPEG-4视频解码算法的优化与实现 MPEG-4标准可以划分为一套子标准,标准的每一部分都有各自最适合的应用场合。MPEG-4 SVP就是一种特殊的、简单的MPEG-4实现,SVP代表Simple Visual Profile。这部分是专门针对手持式产品中无线视频传输应用场合而制定的。由于本解码器应用在手持移动设备视频解码的场合,因此选用MPEG-4 SVP作为解码算法。 本文选用ARM7TDMI作为核心处理器进行MPEG-4视频解码器的开发。在实际开发过程中,针对ARM7TDMI的结构和MPEG-4的算法特点,做了大量优化工作,保证了解码的精度,大幅度提高了解码的速度。解码器的具体功能如表1所列。 2.1 解码器算法 解码过程实际上就是从视频编码码流中恢复出VOP数据的过程。图1描述了一个视频解码过程。解码器主要包含两部分: 运动解码和纹理解码。I帧中只含有纹理信息,因此只须解码纹理信息即可恢复I帧。而P帧中不仅包含纹理信息,还包含运动信息,所以须解码运动信息,获得运动矢量并进行运动补偿。另外,还须进行纹理解码获得残差值,将这两部分组合起来才能重建P帧。 解码器的实现主要是提供一个简单的接口函数,供解码时调用。该接口函数根据解码的不同需要和不同阶段提供了5个入口。5个接口函数中: 4个供初始化、预处理及后续处理时调用;剩余1个是帧解码的实现函数。 解码过程的计算主要集中在如下几个模块:IDCT、运动补偿MC、逆量化、逆扫描、逆预测以及变长解码VLD。表2给出了优化前解码过程的特征信息。 2.2 ARM平台下算法的优化
ARM结构是基于RISC原理的,指令集和相关的解码机制都比CISC要简单得多。它能高效地输出指令,快速送出实时中断响应;它还进行了管道设置,处理和存储系统的所有部分可以持续地运转。在典型的情况下,当一条指令被执行时,其后续指令正在被解码;而第三条指令便从存储器中取出。ARM7TDMI并不具有指令或数据的高速缓存,主要被用于控制核心,而非数据处理。但通过对其特性的灵活运用,可以使其非常容易地应用于视频解码过程。对MPEG4视频解码器的算法优化主要从以下几方面入手:
(1) 算法的优化
这里是指高级C语言转化算法以简化计算量, 用最佳算法实现解码中的各模块。
① IDCT算法的选择
IDCT运行次数多,运算量很大,其变换的快慢直接影响解码的速度。本文采用一种称为AAN的快速算法。其一维8点的DCT变换通过16点DFT来实现,而16点DFT又可通过FFT实现;二维8×8的DCT运算仅需80次乘法和464次加法操作,大大减小了这部分的运算量。用AAN算法实现IDCT运算时,实际上是用IDFT取代IDCT,所以首先要得到DFT系数。方法是逆量化后直接将DCT系数分别乘以尺度因子,也就是说将尺度变换与逆量化结合。 ② 除法运算的消除
一个除法操作须花费60~120个周期进行处理,而一个乘法操作最多需要4个周期。在除法可以被乘法代替而不丧失准确性的计算中,这样做是非常有好处的。在反向DC系数预测过程中,DC系数重构后,立即对其进行逆量化,从而消除除法运算。 ③ 存储访问的减少
在任何实现中尽可能减少存储访问都是非常有价值的。由于ARM7TDMI内没有缓存,每次访问都是对外部存储器进行的,所以这样做尤为重要。通过在任何可能的地方结合解码过程,访问的次数即可减少。I帧中反向DC系数预测与DC系数逆量化的结合、逆扫描与变长解码的结合,以及逆量化与IDCT的结合,P帧中变长解码、逆扫描与反量化的结合,对于每个非零系数只需一次读入和一次存储。同时,像素重建也在IDCT之后立即进行。这样对每个系数来说,又减少了一次读入和存储。 (2) 根据ARM7TDMI芯片结构的优化 这里的优化主要体现在节约寄存器资源。任何一种芯片的寄存器资源都是有限的,ARM7TDMI的通用寄存器总数为31个,对于小规模应用程序是足够了,但在MPEG4解码过程中往往会用到较多的寄存器,所以仍须节俭。方法如下: 其一,在可能的情况下尽量少用寄存器,比如可对一个寄存器多次使用。其二,根据具体情况选择最优的变量类型,在局部变量中,使用int类型效率最高;而对于全局变量,使用short类型,则可减小Flash的使用量。 (3) 汇编/结构层的优化 尽管编译器可以产生汇编代码,但为了使代码效率更高,根据ARM7TDMI的特性对模块IDCT、IQ、VLD、DC/AC预测和MC进行手工汇编编码。下面详细阐述不同的优化方法及其所使用的模块。
① 内部循环的解开 循环的解开其实也是为了增强程序中的并行处理能力。对于解循环,不能在解开的循环中保留线性过程,即指令在执行过程中的结果不能作为后续指令的输入数据;否则也就失去了并行处理能力,解循环也就失去了意义。 ② 乘法和除法尽量用移位运算来完成\ 对于2的幂次乘法或除法使用移位将会提高不少效率,一条除法指令使用的周期数远远多于移位指令。 ③ 尽可能将循环内部的负荷放到循环外面 这点很重要,因为许多循环内部包括一条或几条运算语句,这些语句将被重复运算,因此如果事先设定一个变量,然后赋上那几条运算语句的值,并替换到循环外部,则会极大地节省芯片资源,特别是对于循环中含有除法运算的情况。在逆量化循环运算中,存在着大量冗余计算,原因在于逆量化运算中参数的重复计算,而对于每帧解码VOP,这些参数是唯一的。因此,可将这些参数的计算放到逆量化循环外面,则每帧只须计算一次。这样即可节约大量的指令周期。 ④ 功能参数的优化数量 在ARM编译的过程中,子程序的参数是通过寄存器R0~R3来传递的。如果所传递的参数多于4个,那么超出的参数将被压入栈内;当它们在函数中被第一次访问时,便会从栈中弹出。通过把参数的数量减少到4个或者少于4个,则可直接使用,而无需任何的调入,因为这些值都可从寄存器中获得。 ⑤ 利用LDM和STM减少存储器的访问 批量加载/存储指令可以实现在一组寄存器和一块连续的内存单元之间传输数据。LDM为加载多个寄存器;STM为存储多个寄存器。这种特性非常有用,因为与单字加载/存储相比,它在执行周期上花费更少。因此它在IDCT中得到了有效的利用,用于同一时刻取出一行的所有系数。同样在运动补偿过程中,一组数据字在指令的一次执行中获得,并且暂时存储在多个寄存器中以便日后使用。 ⑥ 指令的有条件执行 有条件执行的特性被ARM7TDMI的所有算法和数据移位指令支持。这是一项可选的特性。它在指令被执行时设置标记。有条件执行通常用于循环退出条件和饱和条件,可以节省退出循环中的一个指令CMP。对于循环次数很多的情况,即使是一个指令的减少也有很大的好处。在变长解码中就很好地利用了这种特性。 ⑦ 一种用于运动补偿的有效优化方法 解码过程中处理的像素是8位。如果运动补偿是在字节或像素的基础上执行,那么字节加载和存储将被使用,它是存储器访问中代价最高的操作。因为ARM7TDMI是32位微处理器,存储器可以按字读取数据,因此设计出一种有效的运动补偿方法,即在字数据的基础上进行操作。利用这种方法,便可以用一种非常有效的方式同时对4像素进行运动补偿。 |