使用轻量级图像解码器TJpgDec - 基于MM32F5微控制器和MindSDK

轻量级JPEG解码器TJpgDec移植
介绍TJpgDec组件及其在MM32F5微控制器上的移植过程,包括输入输出数据流回调函数的实现,以及在嵌入式系统中的应用。

使用轻量级图像解码器TJpgDec - 基于MM32F5微控制器和MindSDK

苏勇,suyong_yq@126.com,2022年12月

缘起

移植TJpgDec的文章在我的todo list里躺了快3年,最近关于图像解码的设计需求又被列入到当前的项目当中,趁着这个机会赶紧把移植过程记录下来。隐约记得最早在nxp lpc5500平台上适配TJpgDec的时候遇到过一些问题,并通过研读程序源码找到了解决方案。时至今日,印象逐渐消散,但又不舍得忘却,希望尽早记录下来,给大脑减负。

TJpgDec是难得可以运行在小资源微控制器的解码图片组件,对系统资源要求很少,虽然在作者提供的原版样例工程中使用了动态内存分配的函数(malloc和free),但经过调整源码可以使用静态内存取代动态内存的用法,比较容易集成在微控制器平台的软件中。

编解码这种对算法有一定要求的组件,对开发者的理论水平有相当的要求,同通信类的协议栈更多处理通信交互行为不同,对普通的嵌入式软件开发者有相当高的门槛,自己硬编码一般搞不定。所以,如果开发者能玩一遍TJpgDec,积累一个jpeg图像解码的工具,解锁一项关于多媒体开发的技能,这无疑是一件令人心安的事情。

偶然发现TJpgDec,源头还是多年前捣鼓FatFs文件系统时发现了同一个作者搞了Petty FatFs(一个FatFs小资源版本),通过网站域名找到原作者的主页上向看看还有什么有趣的软件,其实我对这种在小资源微控制器上实现的功能组件还是非常感兴趣的。结果发现作者ChaN也是一个2B青年,他的项目主页(http://www.elm-chan.org/)竟然是二次元风格的。如图x所示。

在这里插入图片描述

图x ChaN的项目网站主页

其中软件分类的页面(http://www.elm-chan.org/fsw_e.html)中罗列了ChaN在持续维护的若干项目,除了文件系统组件之外,原本期望可能会有一个基于文件系统的shell,结果shell软件没找到,倒是找到了一个JPEG图像解码器。如图x所示。

在这里插入图片描述

图x ChaN软件项目清单的网页

从网页上看,ChaN最近又在微控制器平台上搞了一些新的软件,例如Clopboard Saver。对FatFs和TJpgDec软件也进行了更新。当时看到TJpgDec的项目简介中专门提到专为小型嵌入式系统进行了高度优化,嗯,有熟悉的味道,就点进TJpgDec的项目主页(http://www.elm-chan.org/fsw/tjpgd/00index.html)里看了看。果不奇然,同FatFs类似的简单明了的风格,嗯,看起来是个不错的软件。因为刚好手头上在调的板子上有个屏,就花了一些时间就调了起来,真香。TJpgDec的项目主页,如图x所示。

在这里插入图片描述

图x TJpgDec项目网站主页

本文简单介绍了TJpgDec组件的情况,以及汇总了关于TJpgDec组件的所有必要的资料,然后对原作者描述的移植接口进行了详细的解释,补充一部分原作者在网页中简要带过的内容,最后在使用国产灵动微电子的MM32F5277E9P(Arm Cortex-MC1处理器)的plus-f5270开发板上进行具体移植,使用静态内存分配的方式换掉动态内存的用法。这个样例工程已经加入到灵动微电子官方的软件开发平台MindSDK的开发分支,即将在下一次release将面向公众发布。

TJpgDec简介

TJpgDec是一个为小型嵌入式系统高度优化的创建JPEG图像的解码软件。它工作时占用的内存非常低,以便它可以集成到微控芯片,如AVR, 8051, PIC, Z80, Cortex-M0等。不依赖于具体的硬件平台,使用ANSI-C编写,易于使用的操作模式,完全可重入的体系结构,非常小的内存占用(独立于图像尺寸的3KB SRAM。3.5-8.5KB的代码空间)。输出格式可以是缩放比例为1/1、1/2、1/4或1/8可选,像素格式可以是RGB888或RGB565。

TJpgDec组件是一个免费开放的软件,可用于教育、科研和商业开发。用户可以在包含TJpgDec的个人项目和商业产品中改写和重新发布该组件。

TJpgDec组件在用户的应用中仅需要调用2个API。

jd_prepare() - 准备解码JPEG图像

jd_prepare 分析JPEG数据并创建一个解码对象用于随后的解码过程。

jd_prepare函数是JPEG解码过程的第一阶段。它接收用户传入的数据流(需要通过传入的回调函数操作数据流),分析JPEG图像和创建解码参数表。函数成功后,会话准备好在jd_decomp函数解码JPEG图像。应用程序可以参考JPEG解码对象中存储的尺寸大小。这个信息将用于在后续的解码阶段配置输出设备和参数。

JRESULT jd_prepare (
			JDEC* jdec,            /* Pointer to blank decompression object */
			UINT(*infunc)(JDEC*,BYTE*,UINT), /* Pointer to input function */
			void* work,            /* Pointer to work area */
			UINT sz_work,          /* Size of the work area */
			void* device           /* Device identifier for the session */
			);

输入参数:

  • jdec - 输出,一个空的JDEC结构体对象,初始化一个解码对象。需要用户先创建JPEC对象的内存,然后本函数在执行过程中会向其中填充有效信息,这个解码对象也将用于后续的解码操作。
  • infunc - 输入,指定一个为解码算法提供输入数据的回调函数。实际上,这个方法也是关联具体平台的,不仅仅是提供一个读数的方法,更确切是提供一个具体的数据流。这个infunc函数也是需要在具体平台适配过程中需要用户自行实现的。具体写法可以看原作者给的应用说明,也可以参见本文中的基于具体微控制器平台的实现。
  • work - 输入,指定一个内存块,给解码器内部运行算法的工作空间。
  • sz_work - 输入,指定work参数指定工作空间的 size,以字节为单位。TJpgDec至多需要3092字节的工作区域,这依赖于JPEG图像的内置参数表。通常情况下是3092字节工作区域。
  • device - 输入,指定用户自定义的会话设备标识。它保存在解码对象jdec的字段device中。它可以用于I/O函数去识别当前会话。当I/O device固定在project或者不需要这个功能,设置为NULL并忽略它。device参数可以作为回调函数中访问绑定硬件的传参。

返回值:

  • JDR_OK - 函数执行成功,且编码对象是有效的。
  • JDR_INP - 一个错误发生在input函数,由于硬件错误或者流终止。
  • JDR_MEM1 - 工作空间不足解码这个JPEG图像。
  • JDR_MEM2 - 工作空间不足解码这个JPEG图像。可能更小。
  • JDR_PAR - 参数错误。传入工作空间的指针为NULL。
  • JDR_FMT1 - 数据格式错误。JPEG数据损坏。
  • JDR_FMT2 - 格式正确,但不支持。也许是一个灰度图像。
  • JDR_FMT3 - 不支持JPEG标准,也许是一个后续版本的JPEG图像。

jd_decomp() - 执行解码JPEG图像

jd_decomp()函数解码JPEG图像并输出RGB数据。

jd_decomp()是JPEG解码过程的第二阶段。它进一步执行解码JPEG图像的过程,并通过用户定义的输出函数输出数据,但同时也继续使用在jd_prepare()传入的输入数据流的函数。在它之后,解码对象将不在有效。

在解码时指定的比例因子,它将JPEG图像按1/2、1/4或1/8比例缩放尺寸。例如,当解码一个1024x768大小JPEG图像在1/4比例,它将输出256x192大小。相比不缩放,1/2和1/4的缩放由于求均值,解码速度略有下降。但是1/8缩放相比不缩放是2-3倍的速度输出,因为每个块IDCT和求均值可以跳过,这一特点适合创建缩略图。

JRESULT jd_decomp (
			JDEC* jdec,             /* Pointer to valid decompressor object */
			UINT(*outfunc)(JDEC*,void*,JRECT*), /* Pointer to output function */
			BYTE scale              /* Scaling factor */
			);

输入参数:

  • jdec - 输入,指定有效的解码对象。其实就是之前在jd_prepare()函数中准备好的JDEC对象。
  • outfunc - 输入,指定用户定义的JPEG解码过程输出数据流的回调函数。jd_decomp()调用这个函数去输出解码JPEG图像的RGB形式数据流。具体写法可以看原作者给的应用说明,也可以参见本文中的基于具体微控制器平台的实现。
  • scale - 输入,指定输出缩放值N。输出图像的缩小比例为1/2^N(N = 0 to 3)。当不使用缩放功能时(JD_USE_SCALE == 0),可以指定为0。

返回值

  • JDR_OK - 函数执行成功。
  • JDR_INTR - 解码过程在输出函数中断。
  • JDR_INP - 一个错误发生在input函数,由于硬件错误或者流终止。
  • JDR_PAR - 参数错误。给定的缩放值无效。
  • JDR_FMT1 - 数据格式错误。JPEG数据损坏。

tjpgdcnf.h - 配置文件

早期版本的TjpgDec源码中并没有tjpgdcnf.h文件。我试着找了一下tjpgdec项目的changelog,没有直接找到关于版本更新的详情内容,但是遍历了到目前为止tjpgd所有发布版本的软件包,确定了tjpgdcnf.h首次出现的版本是2021年5月8日发布的R0.02版本。在这个文件中,更细化地提取了一些对TJpgDec软件配置和裁剪的一些选项,在当前最新的R0.03版本中源码如下(原作者非常贴心地注释了可用的选项和对应的解释):

/*----------------------------------------------*/
/* TJpgDec System Configurations R0.03          */
/*----------------------------------------------*/

#define	JD_SZBUF		512
/* 指定在输入数据流中每次读取的字节数,512、1024、2048等等均可。 */

#define JD_FORMAT		0
/* Specifies output pixel format.
/  0: RGB888 (24-bit/pix)
/  1: RGB565 (16-bit/pix)
/  2: Grayscale (8-bit/pix)
*/

#define	JD_USE_SCALE	1
/* Switches output descaling feature.
/  0: Disable
/  1: Enable
*/

#define JD_TBLCLIP		1
/* Use table conversion for saturation arithmetic. A bit faster, but increases 1 KB of code size.
/  0: Disable
/  1: Enable
*/

#define JD_FASTDECODE	0
/* Optimization level
/  0: Basic optimization. Suitable for 8/16-bit MCUs.
/  1: + 32-bit barrel shifter. Suitable for 32-bit MCUs.
/  2: + Table conversion for huffman decoding (wants 6 << HUFF_BIT bytes of RAM)
*/

针对使用ARM Cortex-MC1处理器内核和FSMC驱动的16位并口屏幕的MM32F5微控制器,这里需要改写:

#define JD_FORMAT     1 /* 1: RGB565 (16-bit/pix) */
#define JD_FASTDECODE 1 /* 1: + 32-bit barrel shifter. Suitable for 32-bit MCUs. */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值