【DSP开发】利用CCS5.4开发基于DSP6455的JPEG2000图像解压缩过程
声明:引用请注明出处http://blog.csdn.net/lg1259156776/
说明:前端是时间基于VS2010工程,在windows上实现了对openjpeg2000的改写,实现了从内存中读取数据进行解压缩的工作。由于某些技术储备需要,将其移植到DSP6455中进行解压缩。本文记录的就是整个移植过程。
0. 异想天开:试图在CCS上直接使用VS2010生成好的编译库
这个想法是一直就有的,在调试VS2010下的openjpeg2000并改写的时候,由于费的功夫比较多,所以才生出了这种一次编译,到处运行的想法(这不是Java的招牌吗)。后来还专门对这方面的内容进行了了解和消化,最终得出结论,最多能实现一次编写,到处编译,这样源码级别的跨平台。以后就直接把静态链接库看作是目标文件obj的归档,在linux下,使用命令ar t xx.lib可以分析出对应的obj文件,也可以通过ar -v -x xx.lib将目标文件解出来。所以都知道obj文件是经过了预编译,编译和汇编,已经算是针对硬件平台上的机器码了,所以根本不可能在不同的平台上被链接执行。
所以,only way就是利用目标处理器上或者操作系统上的开发环境进行编译生成对应的库,然后再用该开发环境利用该生成的库,进行编译链接,这是唯一的方法,对于这种源码级别的跨平台语言来说。所以,还是比较喜欢JVM,虽然在不同的平台上需要安装不同的JVM,但是配置好之后,在任何平台上可能都能实现运行。
1. 利用CCS3.3进行移植
直接将VS2020工程下openjpeg的依赖源文件全部拷贝入CCS3.3工程目录下,然后选择的是输出静态链接库(注意DSP的应用没有所谓的动态链接库,因为不可能像windows那样,在运行的时候载入dll等方式),进行编译,当然会出现很多错误。逐个排查,主要的错误是平台相关的部分,因为openjpeg通过CMake生成,使用cmake指令对CMakeLists解析生成makefile,或者是直接对应的目标工程文件,经测试在windows下VS2010和Linux下的makefile都可以顺利的编译通过,并生成可执行文件,顺利实现解压缩。但是对于能否在windows下,使用cmake实现对CCS工程的生成,在网上并没有找到相关的资料文档,也就放弃使用这种最为简单的方法了。实际上后来想想,cmake对于生成嵌入式开发平台的工程可能有点太异想天开了,或许在以后能实现也说不准。所以言归正传,刚开始出现的一堆错误,全被我被我注释掉了,后来才证明,给我自己挖了一个巨大坑,花了5个小时才把坑找出来,修正过来。终于可以生成了静态链接库。然后准备类似VS2010下的那种方法,再建一个工程,使用这个生成的静态链接库来进行解压缩。
同样开始编译源文件会出现一些错误,同样使用了上面的方法,直接蔑视掉,注释了,最后终于编译可以通过,生成了对应的obj文件,但是在链接的时候出现了一堆错误,都是各种函数被声明了,被引用了,但是却没有定义,不仅是obj中找不到,lib文件中的那些函数也找不到。
到现在应该明白了吧,生成静态链接库,不需要进行链接,只需要将对应的obj文件进行打包归档即可。所以,这也是在上一个生成lib的工程中没有报错的原因,但是在这个解压缩的工程中,因为生成的是可执行文件,需要经过链接,重定位等之后才能生成,故所有的错误都是在这个链接过程。
注意到很多错误是来自一些printf,malloc等这些标准库中的函数发生了链接错误,所以感觉这个ccs3.3可能不够先进,或者相关的参数没有设置好【目前猜测是运行时库没有找到,或者链接发生了错误】,但是一时间又找不到相应的解决办法,于是决定利用CCS5.4进行开发,希望这个比较新的开发环境能够提供更为丰富的运行时库吧。
2. 利用CCS5.4进行移植
因为有了上面的基础,在CCS5.4上进行测试就比较快了,直接拷贝,直接生成工程,配置环境为DSK6455的目标板卡,首先选择的还是生成静态链接库。调试通过后生成了相应的静态链接库,然后同样的配置解压缩的工程,注意输出为可执行文件,然后输入对应的库。
这时候问题就来了,刚开始还是没有注意,依然用注释的方式去掉了出现的错误,然后终于生成了可执行文件。这个时候类似在CCS3.3中出现的链接错误不再出现,对应malloc,alloc,fopen等都能找到。
工程配置中的那个运行时库选择为自动,所以可能是这个原因,对应的函数都能找到定义。也就没出现链接错误,所以还是推荐使用更高版本的CCS进行开发,(虽然在CCS5.4上开发DSK6455的网口总是会出现网络无法连接的问题,而在CCS3.3下则能正常网络连接,但利用同样的NDK开发6678的网口却没有错误)。
一开始并没有急着直接下载到板卡上调试,因为在DSP等嵌入式平台上一个最大的问题就是内存有限,6455的片内RAM只有2M多。
在进行解压缩的时候,工程的工作流程是这样的:从电脑F盘中读取j2c格式的JPEG2000压缩源文件,存入内存中,然后将内存送入修改后的LIB内部的函数中进行从内存中读取数据以解压,并最后在F盘上输出BMP文件的图像。
这个流程看似很简单,在DSP上实现却破费思量,首先LIB库中的函数和变量数据的内存是由LIB库自己管理的,这样就说明LIB库中大部分的内存管理都是通过malloc或者alloc等进行动态申请的,因此,需要DSP运行环境中有较大的堆栈,所以,需要在工程CMD文件或者是工程配置的Linker基本选项中设置堆栈的大小,为了保险起见,最好设置大一些,这里直接设置为0x2000000,太大了,在片内ram中根本无法申请的下。考虑到这么大的内存消耗,及DSK6455片外挂载的512MB的DDR2,考虑将所有的程序和数据都放入DDR2中进行执行,这样就需要配置CMD中的.text段,.stack段,.bss段等映射到DDR2的地址空间,这样就解决了内存不够用的问题,但是要明白DDR2的时钟速率只有600MHZ左右吧,加上一定的访问延迟,所以不要期望执行速率较高,不过在调试阶段还是能够接受的。
后续如果调试通过,还可以再反过来对LIB内存的使用进行优化,中间肯定好多地方的内存是不需要的,因为LIB中有一个地方好像是申请最大支持图像的内存,这是有一定量的内存浪费的,后续优化时要注意这一点。
在完成了上面的内存配置后,开始进行下载到板卡的测试,开始全速运行,发现输出的信息中decode出现了错误,只能解码前面的header,然后稍微调试了下,能够正确得到图像的尺寸。但是由于输入的是库文件,调试的时候不能进入库文件中的函数定义,于是又重新建立的一个工程,这回不使用库,而是直接把所有生成库de工程中的源文件全部添加到这个工程中以方便调试用。等调试好了,在将修改后的文件拷贝到库工程下,编译生成库,然后再输入使用库的工程下进行测试库是否可用。
所以,后面的调试可以说是暗无天日,各种加断点,各种找出现问题的原因,估计花了有三个小时,终于让我在经过十个函数连续的调用后发现了一个返回值的false,就是它导致的后面的一些参数读取然后判断出问题,而输出的错误调试信息。然后进入到这个函数中,我惊喜的发现了这个问题实际上就是我前面为了排除编译错误华丽丽注释掉的那行代码。实际上就是一个关于变量内存申请的函数,由于在win32下,有相应的宏定义,所以预编译指令控制编译的是win32平台的代码段,而在CCS下,没有这个宏定义,而且相关的函数确实没有。而我注释掉的内容确实是在没有找到任何平台的时候调用的函数,当时记得输出的编译错误就是对应的函数没有定义。该死的为了求快导致的后果就是用3个小时去查找错误的原因。
然后修正了这个错误,并同时检查了是不是还有因为这个原因导致的错误,同时还注意了在具体的试用了win32宏定义进行编译的代码段,看看在ccs上对应的代码段是否缺失等。总之,又进行了一系列的排查,最终真的找不到问题所在时,才进行了再次调试,并真的输出了对应的bmp文件,但是真是一阵窃喜,本来在上一个问题上已经被磨得没有了耐心,如果搞不定,估计就放弃了。还好,还好!
但是问题又来了,发现输出的图片无法打开,然后用UltraEdit打开对比VS2010下进行解压的图片数据,发现好像就头一样,对应的BM字样,然后十六进制编辑后,发现也就头一样(当时也真是昏了头脑,居然没有认真的比对,因为后来发现两者的差别只是ccs的输出文件中缺少了00而已,其他的大致都一样。主要是UltraEdit分屏看,后面8个数字看不到,被遮挡了,导致比对上的错位【粗心总是会坏大事】)。后来居然返回去怀疑是不是解压出现了问题,很忧心是不是算法出现了问题,因为如果是算法的问题的话,这就很难办了。后来很难说服自己解压数据是正确的,但是仍去考虑了是不是保存数据出的错,反反复复好像花了1个多小时吧。最后还是通过比对两者的输出结果,发现了原来真的是ccs利用fprintf(“%c”,0)输出ASCII码为0的字符时,根本输不出来。【可恶极了】。
当发现了解码得到的数据是对的时候,我的心才放下来,对于fprintf输出的问题,是比较好解决的,直接换成fwrite算了,后来当然是先通过新建一个CCSFileTest仿真工程来测试是不是真的输不出0,进行了验证后,决定直接用fwrite来输出。后来的事情就比较简单了,不表。
实际上我早就发现了输出的文件大小不一样,而且连前面的固定格式的文件头都不一样,但是就应该怀疑了,但是并没有深入查看,导致后面花费一个小时来解决这个问题。真是有点浪费声明了。
2015-10-23调试记录 张朋艺