最近公司想测试一下ESP32S3的屏幕刷gif图片,将这个预研项目分派给我,我再论坛里面学习到很多,也来总结一下经验
硬件平台:ESP32S3
LCD:ILI9341
SPI:60Mbps
图片总数:400张
像素240*240
最简单的方式当然是不解码直接刷屏,速度肯定很快,动画速率就是刷屏速率,但是需要将所有的图片保存在flash中,有点离谱,总大小为40MB左右,显然不现实
然后又测试了gif解码器,单独移植了lvgl自带的gif三方库,这个gif解码器拉跨得很,特别占用RAM与时间,解码时间的长度和图像复杂度相关,最慢一帧可以来到350ms,简直没法使用,RAM占用情况:仅仅是缓存内外部就需要7*(像素点数量),240的放图大约占用400KB,esp32S3直接跑不起来,降低了分辨率才能跑起来
gif解码器我感觉再优化也不会有什么好的结果了,直接放弃
然后又想到jpg解码器,将所有的图片导出为jpg格式,总大小才3MB,比gif占用内存还小
第一次尝试了idf自带的ipg解码,名字叫做 tiny jpegdec,速度一张图大约消耗48ms,感觉不太好优化了
然后又移植了另一个解码器 JPEGDEC,同样的图片实测只要22ms,并且这个库对ESP32S3平台进行了SIMD优化,也就是运行一个指令支持修改多个数据,需要启动DSP,时间消耗来到了13ms,我对这个时间长度已经很满意了
开启双核心,用双缓存技术,一个核心解码 另一个核心刷屏,jpg的刷图速度就是刷屏速率
大佬们还有什么更有效的优化方式
不妨一起讨论讨论
离线
【ESP32S3_3.5寸QSPI屏_播放avi视频-哔哩哔哩】 https://b23.tv/P34oCJm
这个视频就是用的带SIMD的jpeg解码
莫工,我还在你的视频留言了,那个‘树莓好倒霉’就是我
你也可以尝试一下 esp_new_jpeg这个库,是乐鑫他们官方优化的,效果也很好
离线
@waku_dac
```
int ui_jpeg_decode(uint8_t *input_buf, int len, uint8_t *output_buf, int *out_len)
{
int ret = JPEG_ERR_OK;
jpeg_dec_io_t jpeg_io = {0};
jpeg_dec_header_info_t out_info = {0};
// Generate default configuration
jpeg_dec_config_t config = DEFAULT_JPEG_DEC_CONFIG();
config.output_type = JPEG_PIXEL_FORMAT_RGB565_BE;
config.rotate = JPEG_ROTATE_0D;
// config.scale.width = 0;
// config.scale.height = 0;
// config.clipper.width = 0;
// config.clipper.height = 0;
// Create jpeg_dec handle
jpeg_dec_handle_t jpeg_dec = NULL;
ret = jpeg_dec_open(&config, &jpeg_dec);
if (ret != JPEG_ERR_OK)
{
return ret;
}
// Set input buffer and buffer len to io_callback
jpeg_io.inbuf = input_buf;
jpeg_io.inbuf_len = len;
// Parse jpeg picture header and get picture for user and decoder
ret = jpeg_dec_parse_header(jpeg_dec, &jpeg_io, &out_info);
if (ret != JPEG_ERR_OK)
{
goto jpeg_dec_failed;
}
*out_len = out_info.width * out_info.height * 3;
// Calloc out_put data buffer and update inbuf ptr and inbuf_len
if (config.output_type == JPEG_PIXEL_FORMAT_RGB565_LE || config.output_type == JPEG_PIXEL_FORMAT_RGB565_BE || config.output_type == JPEG_PIXEL_FORMAT_CbYCrY)
{
*out_len = out_info.width * out_info.height * 2;
}
else if (config.output_type == JPEG_PIXEL_FORMAT_RGB888)
{
*out_len = out_info.width * out_info.height * 3;
}
else
{
ret = JPEG_ERR_INVALID_PARAM;
goto jpeg_dec_failed;
}
jpeg_io.outbuf = output_buf;
// Start decode jpeg
ret = jpeg_dec_process(jpeg_dec, &jpeg_io);
if (ret != JPEG_ERR_OK)
{
goto jpeg_dec_failed;
}
// Decoder deinitialize
jpeg_dec_failed:
jpeg_dec_close(jpeg_dec);
return ret;
}
```
这是我的解码封装函数,其中,output_buf必须16字节对齐:
```
static uint8_t canvas_gram[IMG_WIDTH * IMG_HEIGHT * 2] __attribute__((aligned(16)));
```
你可以参考一下
离线