从事MTK平台的工作者很多,做高仿机的人也很多,MTK的界面变得越来越花哨,但是对于MTK平台实现进行研究的文章并不多,希望这篇文章和以后的几篇BLOG能为MTK的初学者带来一些帮助。
怎么使用MTK的函数显示图片相信大家都会,但是图片的解码过程就不是人人都去研究了,由于我们做JVM移植层的需要,最近对MTK的图形解码进行了一些研究。
MTK在绘制图形的时候使用的是gdi_image_codec_draw这个函数,在这个函数中,MTK会根据img_type这个参数从gdi_image_codecs这个全局数据结构数组中取得相应绘制回调函数。gdi_image_codecs全局变量在gdi_image.c文件中定义。
(1)BMP解析过程
当img_type为GDI_IMAGE_TYPE_BMP_FILE_OFFSET的时候,MTK会调用gdi_image_bmp_draw_handler作为BMP文件解析的处理函数。在这个函数中,MTK会根据程序员指定的显示大小对bmp文件进行放大或者缩小,由于这里我们只是简单研究一下,就不以图片的放大或者缩小为例子了,如果要研究图片的放大或者缩小,请各位自己研究。我们只研究不对bmp进行放大或者缩小的过程——gdi_image_bmp_draw_file函数。
gdi_image_bmp_draw_file这个函数在gdi_image_bmp.c文件中。这个函数一开始首先建立了一个比特流,在我看来就是把这个BMP文件打开,并把BMP的文件的数据放到gdi_bytestream_buffer这个全局数组中,为以后的解码做准备。接下来大家可能就要迷糊了,MTK使用的是gdi_image_bmp_draw_internal_from_file这样一个函数,这个函数是什么呢!说出来下一条,这个函数是个宏!确切的说这个曾经是函数调用的语句实际上被GDI_IMAGE_BMP_DRAW_INTERNAL这个宏所替代,而这个宏在gdi_image_bmp_codec.h中有一个同名函数,这样gdi_image_bmp_draw_internal_from_file就被指示成了GDI_IMAGE_BMP_DRAW_INTERNAL。我第一次就晕菜了,搞不懂为什么MTK要费这么大劲,绕这么多弯。
GDI_IMAGE_BMP_DRAW_INTERNAL就是解码过程,我们可以看到这里面有1,4,8,16,24,32位BMP的解码函数,如果我们解码的不是这些标准的BMP呢!对不起,MTK会重启!
(2)静态GIF图片的解码过程
当img_type为GDI_IMAGE_TYPE_GIF_FILE_OFFSET的时候,MTK会调用gdi_image_gif_draw_handler函数进行解码。在这个函数中同样分为可变大小和不可变大小,数据来源于文件还是来源与内存资源,这4种情况,我们还是只讨论数据来源于文件而且不进行缩放操作的情况——gdi_image_gif_draw_file。
gdi_image_gif_draw_file这个函数有两个分支。在整个函数的实现中,会有一个do{}while(0)的循环,在定义了硬件解码宏之后,在硬件解码结束以后使用一个break;语句跳出循环。软解码的代码在硬解码的代码后面,没有宏控制。当硬解码宏打开后,完全靠硬解码结束后的break来区分软硬解码。这样,如果硬解码出现问题,可能会造成严重的后果。我不清楚MTK为什么这样做,可能是他们认为硬解码的所有返回都已经处理过了,所以才使用这种方式的吧!
在6226,6228等高端的MTKCPU上,图像都是硬解码的。在这些CPU内部有一组专门的解码电路来对图形进行解码。在硬解码的时候,MTK最终会调用gif_decode_hw这个函数对CPU内部的寄存器进行相关的设置,最后调用GIF_START这个宏函数开始对GIF图形进行解码。
在6225以下的CPU中,所有的图像都是软解码的,这时MTK使用了ret = gdi_image_gif_draw_file_decoders[gdi_act_layer->cf] 这个语句。gdi_image_gif_draw_file_decoders是一个函数指针数组。这个数组定义在gdi_image_gif.c中,这个数组中的元素(例如gdi_image_gif_draw_internal_from_file_8等)其实都指向GDI_IMAGE_GIF_DRAW_INTERNAL这个宏,这个宏又在Gdi_image_gif_codec.h中对应一个同名函数。好像在哪里见过哈!对!BMP就是这样指来指去的。MTK的风格就是这样奇怪而统一。
GDI_IMAGE_GIF_DRAW_INTERNAL就是GIF的解码过程。 一开始,MTK向我们展示了一个catch机制,MTK把最后的2张GIF图片保存在一个gdi_gif_cache的数据结构中,首先检查程序员需要的是不是这两张图片。如果是就不用解析了,不是就要重新解析。解析的算法我们就不讨论了,喜欢研究的可以看看GDI_IMAGE_GIF_CODEC这个函数的实现,GIF由于有动画的设定,所以解析起来要比BMP复杂多了!
(3)JPEG图片解码过程
当img_type为GDI_IMAGE_TYPE_JPG_FILE_OFFSET的时候,MTK会调用gdi_image_jpeg_draw_handler函数进行解码。这个函数最终会调用gdi_image_hwjpeg_draw_internal。MTK把JPEG的软解码和硬解码的接口在这个函数层次统一了起来,gdi_image_hwjpeg_draw_internal会调用gdi_image_hwjpeg_start_decode,gdi_image_hwjpeg_start_decode再调用jpeg_decode_process函数。jpeg_decode_process函数再负责调用JPEG解码核心对JPEG图片进行解码。最后的解码函数为decode_jpeg_file这个函数。无论是软解码还是硬解码都要调用decode_jpeg_file这个函数。在JPEG图形解码这部分,MTK做的还是比较符合中国工程师习惯的。
还有一点,如果我们只想取得JPEG图像的数据,那么我们只要调用gdi_image_jpeg_draw_file_to_buffer或者gdi_image_jpeg_draw_to_buffer这两个函数好了。我们测试过,MTK对这两个函数的封装,封装的比较好。这样就给了我们一个通过JPEG图像传递某种信息的渠道。哦!搞的想干坏事一样,不说了,不说了!
(4)PNG图片解码过程
当img_type为GDI_IMAGE_TYPE_PNG_FILE_OFFSET的时候,MTK会对PNG进行解码,经过了上面的分析,我相信大家都能对MTK的图形解码的流程有了比较深刻的理解了,各位可以自己分析这个过程,我这边就不赘述了!