【平头哥RVB2601创意应用开发】动态加载MBRE JPEG解码器移植源码与测试结果
[复制链接]
JPEG是数字图像的有损压缩的常用方法,特别是对于由数码摄影产生的图像。JPEG(Joint Photographic Experts Group)是在国际标准化组织(ISO)领导之下制定静态图像压缩标准的委员会,第一套国际静态图像压缩标准ISO 10918-1(JPEG)就是该委员会制定的。由于JPEG优良的品质,使他在短短几年内获得了成功,被广泛应用于互联网和数码相机领域,网站上80%的图像都采用了JPEG压缩标准。相比无损压缩的PNG, GIF等格式, JPEG提供了可控质量损失下高压缩比的存储能力。
TJpgDec是一个专门为小型嵌入式系统高度优化PEG图像的解码模块,具有几个非常明显的特点:
TJpgDec的作者Bodmer就是TFT-espi的作者,所以两者的结合更是天衣无缝,使用起来非常简单。
本次MBRE测试动态加载的过程中, JPG作为小电视项目的支撑库之一, 也做了移植和测试。 因为RVB2601没有直接提供spiffs,所以只做了内存数组解码的原理测试(从文件系统中操作本质其实相同,只需要增加对文件系统的访问接口即可)。移植过程主要是修改一些包含的头文件已保证编译通过即可,解码器源代码请参考附件,
TJpg_Decoder.rar
(15.01 KB, 下载次数: 2)
基本上没有遇到任何问题。
解码器配合TFT-ESPI使用起来就非常简单了,因为解码器配置成了RGB 565的输出,和实验用的ILI9341的输出格式一致,因此只需在初始化时指定好输出回调函数,并在回调函数中将解码得到的位图贴到TFT上即可。这里给出一个小例子:
//JPG Decoder的初始化设置
TJpgDec.thisPtr = &TJpgDec; //移植版本去掉了构造函数,手工处理原构造函数中的指针赋值操作
TJpgDec.setJpgScale(1); //缩放比例,设置为1
TJpgDec.setSwapBytes(false); //565标准格式,无需交换RGB bytes
TJpgDec.setCallback(tft_output); //解码输出回调,每解码一部分,产生小块位图,就会回调一次
//以下解码RAM中的JPG数组,并计算解码,刷新时间显示在屏幕中
time_t t0 = millis();
TJpgDec.drawJpg(0, 0, testjpg_data, sizeof(testjpg_data));
time_t t1 = millis();
char buf[128];
sprintf(buf, "JPG解码测试 %dms", t1 - t0);
//使用TFT-espi的API显示文字
gpTft->drawString(buf, 8, 10, MBRE_FIXED_FONT);
上述代码中的tft_output是回调函数,JPG解码器是一小块一小块的解码(这样可以控制RAM占用),解码一个块之后就会调用设置好的回调函数进行实际的绘制处理。给一个使用tft_espi的tft_output参考实现:
// TFT屏幕输出函数
bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap)
{
//简单的裁剪保护,超过屏幕Y最大值不用绘制了
//并返回0,通知解码器不用再进行后续解码
if(y >= gpTft->height()) return 0;
//将位图通过Tft-espi绘制到屏幕上, tft-espi会对位图做基本的裁剪保护
gpTft->pushImage(x, y, w, h, bitmap);
// 返回1告诉解码器继续解码
return 1;
}
最后上图,在RVB2601上解码320x240 QVGA分辨率 jpeg的实测结果。 图示的JPEG解码和刷屏时间大概190MS,考虑到单刷屏时间在60-100ms之间, 解码时间大概是90-130ms,是一个可以接受的指标。更多关于JPG DECODER的实际使用,建议大家参考MBRE前次分享中提及的小电视项目的开源代码学习。其中的太空人飞行动画就是采用JPG连续解码+TSprite离屏缓冲实现的平滑动画效果。
|