# STM32-HWJpegDecoder **Repository Path**: Jumping99/stm32-hwjpeg-decoder ## Basic Information - **Project Name**: STM32-HWJpegDecoder - **Description**: 基于HAL库、FATFS和FreeRTOS,用C++写的一个STM32F7/H7硬件JPEG解码驱动 - **Primary Language**: C/C++ - **License**: GPL-3.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 3 - **Created**: 2024-02-22 - **Last Updated**: 2025-03-04 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # STM32-HWJpegDecoder ### 介绍 基于HAL库、FATFS和FreeRTOS,用C++写的一个STM32F7/H7硬件JPEG解码驱动。 使用时请先调通FATFS与FreeRTOS,并重载C++的new和delete,避免不必要的问题出现。 关于如何重载new与delete,见下文。 ### 使用说明 #### 1.将驱动加入工程 首先需要准备一个包含FreeRTOS、FATFS且可以正常运行的、支持C++开发的STM32工程,将其中的 *HWJpegDecoder.h*和*HWJpegDecoder.cpp*加入工程中。并确保头文件可以找到。 #### 2.重载C++的new和delete 解码器使用new和delete分配缓冲,且因为解码器的构造函数存在与硬件相关的代码, 因此不可以定义为全局变量,最好是通过new和delete的方式使用解码器。 创建一个.cpp文件并加入new和delete的定义即可,以下为示例: ```c #include #include "FreeRTOS.h" #include "cmsis_os.h" void *operator new(size_t size) { return pvPortMalloc(size); } void *operator new[](size_t size) { return pvPortMalloc(size); } void operator delete(void *p) { vPortFree(p); } void operator delete[](void *p) { vPortFree(p); } void operator delete(void *p, size_t size) { vPortFree(p); } void operator delete[](void *p, size_t size) { vPortFree(p); } ``` **若你参考了以上示例,请注意FreeRTOS的堆空间是否足够大。并且该重载为全局的new重载** **,若一些硬件不支持该内存区域的访问但却使用了new,则可能导致错误,如STM32H7 普通DMA无法访问DTC RAM** #### 3.创建解码器并配置 创建解码器,可以使局部自动变量或使用new实例化解码器,**不可使用静态变量或全局变量。** 创建时,需要一个参数,即HAL库的jpeg句柄。如: ```c jpegDecoder = new HWJpegDecoder(&hjpeg); ``` 创建解码器后根据需求进行配置,包括输入数据源,是否分块输入、输出等。如: ```c jpegDecoder->setFullInput(true); // 不使用分块输入,使用整张图片解码 jpegDecoder->setFullOutput(false); // 使用分块输出,分块处理解码后的数据 // 设置分块输出回调函数,处理解码后的数据 jpegDecoder->setOutputCallback( [](HWJpegDecoder::ImageInfo &info, const void *data, uint32_t line, uint32_t numOfLine) { DMA2D_Copy_YCbCr_To_RGB( // 使用DMA2D将YCbCr转RGB (uint32_t)data, (uint32_t)canvasBuffer, 0, line * info.MCUHeight, info.width, numOfLine * info.MCUHeight, info.chromaSubsampling); }); ``` #### 4.开始解码 调用解码器的decode()方法开启解码,该方法是**非阻塞**的,调用后立即返回。 根据返回值判断是否已启动解码或则错误类型。若该方法指示启动解码成功,则可以调用 waitDecodeFinish()方法阻塞等待解码完成,其内部由信号量实现,会自动休眠调用其的线程。 ```c int ret = jpegDecoder->decode(); if (ret == HWJpegDecoder::NoError) // 启动解码成功 { jpegDecoder->waitDecodeFinish(); // 阻塞等待解码完成 } ``` #### 5.颜色格式转换 解码器输出的图片数据颜色格式为YUV格式(YCbCr),可能是**YUV4:4:4**、**YUV4:2:2**和**YUV4:2:0**,取决于解码的jpeg图片。 - 若芯片为STM32H7系列,则其DMA2D外设可以实现硬件YCbCr转RGB,具体实现请参考*examples*中的示例。 - 若芯片为STM32F7系列,则只能使用软件YCbCr转RGB。 ### 使用限制 - 关于STM32的硬件JPEG解码,仅支持基本式JPEG(Baseline JPEG),不支持渐进式JPEG(Progressive JPEG)等多种JPEG格式, 如果使用了不支持的JPEG格式图片,会导致JPEG解码错误。 - 关于该驱动,目前仅测试了分辨率为8或16整数倍(取决于CbCr采样模式)的JPEG图片,分辨率非8或16整数倍(取决于CbCr采样模式)可能会出现问题。 ### 示例 关于示例请查看*examples*目录下的文件, 包括STM32 JPEG外设的配置jpeg.c、jpeg.h。 ### 扩展 #### 1.注册到lvgl作为图片解码器 在*extend/lv_jpeg_decoder*中,实现了lvgl图片解码器接口,将其注册到lvgl中, 即可实现对JPEG图片的硬件解码。注册后,可以使用lvgl的API解码JPEG图片显示,如: ```c // 使用路径作为输入 lv_img_set_src(img, "0:/jpeg/text.jpg"); // 使用标识为LV_IMG_CF_RAW的lv_img_dsc_t,JPEG源数组作为输入 lv_img_set_src(img, &imgdsc); ``` - 内存需求:除去解码器本身所占内存,额外需要**图片高度 x 图片宽度 x LV_COLOR_DEPTH / 8**字节的内存空间。 - 注册的lvgl解码器中使用new与delete分配内存,与lvgl的内存池无关,当然也可以修改成使用lvgl的内存池。 - 传入的路径使用的是FATFS的路径,与lvgl的文件系统无关,因此不需要注册lvgl的文件系统也可以使用。 - 对与STM32H7系列,使用DMA2D转换YCbCr到RGB,详细在*extend/DMA2D*目录中。