你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32H7硬件JPEG编解码基础知识和HAL库API

[复制链接]
STMCU小助手 发布时间:2021-12-21 21:46
57.1 初学者重要提示
  由于硬件JPEG解码后输出的图像格式是YCbCr,所以本章对YCbCr进行了重点介绍。
  测试STM32H7硬件JPEG解码800*480图片性能,全部通过SDRAM缓存数据,解码10ms,显示9ms。
  JPEG涉及到的知识点还是比较多的,如果想深入了解JPEG的话,可以看本章2.6小节给的参考资料。
  本章JPEG相关概念的介绍参考了wiki百科和百度百科。
57.2 硬件JPEG基础知识

对于STM32H7的硬件JPEG了解到以下几点即可:

  支持JPEG解码和编码。
  对每个像素数据进行编解码只需一个时钟周期。
  支持RGB、 YCbCr、YCMK和BW(灰度)图像色彩模型。
  编解码时每图像分量8位深度。

57.2.1 JPEG硬件框图
认识一个外设,最好的方式就是看它的框图,方便我们快速地了解JPEG的基本功能,然后再看手册了解细节。框图如下所示:

aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png


通过这个框图,我们可以得到如下信息:

  JPEG硬件外设支持编码和解码
并且对于输入数据和输出数据都有FIFO支持。

  jpeg_hclk
为JPEG内核和寄存器提供时钟。

  jpeg_it
JPEG全局中断输出。

  jpeg_ift_trg
JPEG输入FIFO阈值信号,可触发MDMA。

  jpeg_ifnf_trg
JPEG输入FIFO未满信号,可触发MDMA。

  jpeg_oft_trg
JPEG输出FIFO阀值信号,可触发MDMA。

  jpeg_ofne_trg
JPEG输出FIFO非空信号,可触发MDMA。

  jpeg_oec_trg
JPEG转换结束信号,可触发MDMA。

57.2.2 YCbCr颜色格式
(注,硬件JPEG解码后输出的图像格式是YCbCr,所以有必要了解下)

正如几何上用坐标空间来描述坐标集,而色彩空间用数学方式来描述颜色集。常见的3种色彩模型是RGB,CMYK和YUV。

YCbCr是YUV经过缩放和修改的翻版,只是在表示方法上不同。其中Y是指亮度分量,Cb指蓝色色度分量,而Cr指红色色度分量。人眼对视频的Y分量更敏感,因此通过对色度分量进行子采样来减少色度分量后,人眼察觉不到的图像质量的变化。

在YUV 家族中,YCbCr 是在计算机系统中应用最多的成员,其应用领域广泛,JPEG、MPEG均采用此格式。一般人们所讲的YUV大多是指YCbCr。

57.2.3 YCbCr采样格式
YCbCr有许多取样格式,如YCbCr 4:4:4,YCbCr 4:2:2,YCbCr 4:1:1 和YCbCr 4:2:0。

  4:2:0
表示每4个像素有4个亮度分量,2个色度分量 (YYYYCbCr),仅采样奇数扫描线,是便携式视频设备(MPEG-4)以及电视会议(H.263)最常用格式。

  4:2:2
表示每4个像素有4个亮度分量,4个色度分量(YYYYCbCrCbCr),是DVD、数字电视、HDTV以及其它消费类视频设备的最常用格式。

  4:4:4
表示全像素点阵(YYYYCbCrCbCrCbCrCbCr),用于高质量视频应用、演播室以及专业视频产品。

具体的采样方式如下图所示,以8个像素为一个单元进行采样:

aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png


由上面的截图可以了解到:

4:4:4表示Y通道,Cb+Cr通道全部采样。

4:2:2表示Y通道全部采样,而Cb+Cr通道两个像素为一组,统一采用第1个颜色值。

4:2:0表示Y通道全部采样,而Cb+Cr通道四个像素为一组,统一采用第1个颜色值。

下面是整体效果,方便大家更好的理解:

aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png




57.2.4 YCbCr的优势
RGB信号作为存储和传输的效率不高,因为它们具有大量冗余信息。而使用YCbCr可以丢弃一些信息以减少带宽,因为人的肉眼对视频的Y分量更敏感,因此通过对色度分量进行子采样来减少色度分量后,肉眼察觉不到的图像质量的变化。了解这种人为缺点,NTSC和PAL等标准大大降低了色度通道的带宽。

57.2.5 YCbCr和RGB互转

为了方便大家更好的了解YCbCr和RGB图像的实际效果,特此搜集整理了两个截图(来自WIKI百科)。下面是图像转YCBCR的效果:四个图,从上到下依次是原始图像,Y通道,Cb通道和Cr通道。

aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png


下面是一幅图像分别以R,G,B通道和Y,CB,CR通道的方式展示:

aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png


57.2.6 JPEG编解码知识
JPEG涉及到的知识点比较多,这里有之前整理的20多个专题知识点,大家有兴趣可以了解下(不了解也没有关系,不影响使用硬件JPEG外设)

57.3 硬件JPEG的HAL库用法
JPEG的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置时钟,并根据需要配置NVIC、中断和MDMA。下面我们逐一展开为大家做个说明。

57.3.1 JPEG寄存器结构体JPEG_TypeDef
JPEG相关的寄存器是通过HAL库中的结构体JPEG_TypeDef定义的,在stm32h743xx.h中可以找到它们的具体定义:

  1. typedef struct
  2. {
  3.   __IO uint32_t CONFR0;         
  4.   __IO uint32_t CONFR1;         
  5.   __IO uint32_t CONFR2;        
  6.   __IO uint32_t CONFR3;        
  7.   __IO uint32_t CONFR4;         
  8.   __IO uint32_t CONFR5;      
  9.   __IO uint32_t CONFR6;      
  10.   __IO uint32_t CONFR7;        
  11.   uint32_t  Reserved20[4];      
  12.   __IO uint32_t CR;            
  13.   __IO uint32_t SR;            
  14.   __IO uint32_t CFR;            
  15.   uint32_t  Reserved3c;        
  16.   __IO uint32_t DIR;         
  17.   __IO uint32_t DOR;            
  18.   uint32_t  Reserved48[2];      
  19.   __IO uint32_t QMEM0[16];     
  20.   __IO uint32_t QMEM1[16];      
  21.   __IO uint32_t QMEM2[16];      
  22.   __IO uint32_t QMEM3[16];      
  23.   __IO uint32_t HUFFMIN[16];   
  24.   __IO uint32_t HUFFBASE[32];   
  25.   __IO uint32_t HUFFSYMB[84];   
  26.   __IO uint32_t DHTMEM[103];   
  27.   uint32_t  Reserved4FC;      
  28.   __IO uint32_t HUFFENC_AC0[88];
  29.   __IO uint32_t HUFFENC_AC1[88];
  30.   __IO uint32_t HUFFENC_DC0[8];  
  31.   __IO uint32_t HUFFENC_DC1[8];
  32. } JPEG_TypeDef;
复制代码

__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:

  1. #define     __O     volatile             /*!< Defines 'write only' permissions */
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码

下面我们再看JPEG的定义,在stm32h743xx.h文件。

  1. #define PERIPH_BASE           ((uint32_t)0x40000000)
  2. #define D1_AHB1PERIPH_BASE    (PERIPH_BASE + 0x12000000)
  3. #define JPEG                  ((JPEG_TypeDef *) JPGDEC_BASE)
  4. #define JPGDEC_BASE           (D1_AHB1PERIPH_BASE + 0x3000) <----- 展开这个宏,(JPEG_TypeDef *) 0x52003000
复制代码

我们访问JPEG的CR寄存器可以采用这种形式:JPEG->CR = 0。

57.3.2 JPEG的编解码参数结构体JPEG_ConfTypeDef
此结构体用于JPEG的编解码参数,具体定义如下:

  1. typedef struct
  2. {
  3.   uint8_t  ColorSpace;               
  4.   uint8_t  ChromaSubsampling;        
  5.   uint32_t ImageHeight;              
  6.   uint32_t ImageWidth;            
  7.   uint8_t  ImageQuality;               
  8. }JPEG_ConfTypeDef;
复制代码

下面将这几个参数逐一为大家做个说明:
  uint8_t  ColorSpace


此参数用于设置输出数据流中的量化表,具体支持的参数如下:
  1. #define JPEG_GRAYSCALE_COLORSPACE     ((uint32_t)0x00000000U)    /* 灰度(1 个量化表)*/
  2. #define JPEG_YCBCR_COLORSPACE         JPEG_CONFR1_COLORSPACE_0   /* YUV(2 个量化表) */
  3. #define JPEG_CMYK_COLORSPACE          JPEG_CONFR1_COLORSPACE     /* CMYK(4 个量化表)*/
复制代码

  uint8_t  ChromaSubsampling
此参数用于色度子采样,具体支持的参数如下:

  1. #define JPEG_444_SUBSAMPLING     ((uint32_t)0x00000000U)   /* 4:4:4 */
  2. #define JPEG_420_SUBSAMPLING     ((uint32_t)0x00000001U)   /* 4:2:0 */
  3. #define JPEG_422_SUBSAMPLING     ((uint32_t)0x00000002U)   /* 4:2:2 */
复制代码

  uint32_t  ImageHeight
此参数用于图像高度。

  uint32_t ImageWidth
此参数用于图像宽度。

  uint8_t  ImageQuality
此参数用于图像质量,参数范围1 – 100,1最差,100最好。

57.3.3 JPEG结构体句柄JPEG_HandleTypeDef
HAL库在JPEG_TypeDef, JPEG_ConfTypeDef的基础上封装了一个结构体JPEG_HandleTypeDef,定义如下:

  1. typedef struct
  2. {
  3.   JPEG_TypeDef             *Instance;        
  4.   JPEG_ConfTypeDef         Conf;            
  5.   uint8_t                  *pJpegInBuffPtr;
  6.   uint8_t                  *pJpegOutBuffPtr;
  7.   __IO uint32_t            JpegInCount;      
  8.   __IO uint32_t            JpegOutCount;     
  9.   uint32_t                 InDataLength;     
  10.   uint32_t                 OutDataLength;     
  11.   MDMA_HandleTypeDef        *hdmain;         
  12.   MDMA_HandleTypeDef        *hdmaout;        
  13.   uint8_t                  CustomQuanTable;
  14.   uint8_t                  *QuantTable0;   
  15.   uint8_t                  *QuantTable1;   
  16.   uint8_t                  *QuantTable2;   
  17.   uint8_t                  *QuantTable3;         
  18.   HAL_LockTypeDef          Lock;            
  19.   __IO  HAL_JPEG_STATETypeDef State;         
  20.   __IO  uint32_t           ErrorCode;      
  21.   __IO uint32_t Context;                    
  22. }JPEG_HandleTypeDef;
复制代码

下面将这几个参数逐一做个说明。

  JPEG_TypeDef   *Instance
这个参数是寄存器的例化,方便操作寄存器,详见本章3.1小节。

  JPEG_ConfTypeDef   Conf
这个参数是用户接触较多的,用于JPEG的编解码参数,详见本章3.2小节。

  uint8_t       *pJpegInBuffPtr
JPEG编解码输入缓冲地址

  uint8_t       *pJpegOutBuffPtr
JPEG编解码输出缓冲地址

  __IO uint32_t   JpegInCount
JPEG内部输入计数。

  __IO uint32_t   JpegOutCount
JPEG内部输出计数。

  uint32_t        InDataLength
JPEG输入缓冲区长度,单位字节

  uint32_t          OutDataLength
JPEG输出缓冲区长度,单位字节。

  MDMA_HandleTypeDef        *hdmain
  MDMA_HandleTypeDef        *hdmaout
MDMA句柄结构体指针变量,用于关联JPEG句柄,方便调用。

  uint8_t       CustomQuanTable
如果此参数设置为1,将使用用户设置的量化表。

  uint8_t      *QuantTable0;   
  uint8_t      *QuantTable1;     
  uint8_t      *QuantTable2;   
  uint8_t      *QuantTable3;
指定量化表地址。   

  HAL_LockTypeDef          Lock           
  __IO  HAL_JPEG_STATETypeDef State           
  __IO  uint32_t           ErrorCode      
这三个变量主要供函数内部使用。Lock用于设置锁状态,State用于设置JPEG状态,而ErrorCode用于配置代码错误。

  __IO uint32_t Context
JPEG上下文。

57.3.4 JPEG初始化流程总结
使用方法由HAL库提供:

  第1步:调用函数HAL_JPEG_Init进行初始化,但这个函数不需要初始化参数。

如果是JPEG编码,可以通过函数HAL_JPEG_ConfigEncoding设置JPEG图像的质量参数,质量越高,生成的JPEG文件越大、

  第2步:调用编解码函数

  查询式编解码函数
HAL_JPEG_Encode

HAL_JPEG_Decode



  中断方式
HAL_JPEG_Encode_IT

HAL_JPEG_Decode_IT



  DMA方式
HAL_JPEG_Encode_DMA

HAL_JPEG_Decode_DMA

  第4步:如果用户之前的数据已经处理完毕,需要插入新数据,会调用函数HAL_JPEG_GetDataCallback

(1)如果新的数据已经准备好,需要调用函数HAL_JPEG_ConfigInputBuffer。如果新的数据没有准备好,需要等待插入新数据时,可以调用函数HAL_JPEG_Pause(参数XferSelection被设置为JPEG_PAUSE_RESUME_INPUT),待数据准备好后,可以调用HAL_JPEG_ConfigInputBuffer设置新的输入缓冲和大小,然后调用函数HAL_JPEG_Resume恢复JPEG编解码。

如果编解码的数据已经处理完毕,可以调用函数HAL_JPEG_ConfigInputBuffer设置InDataLength参数为0(此函数是在回调函数HAL_JPEG_GetDataCallback里面被调用的)。


(2)函数HAL_JPEG_ConfigInputBuffer/HAL_JPEG_Pause/HAL_JPEG_Resume的工作机制允许应用程序以块为单位提供输入数据。如果新的数据块未准备好,可以调用函数HAL_JPEG_Pause暂停输入,待数据准备好后,可以调用HAL_JPEG_ConfigInputBuffer设置新的输入缓冲和大小,然后调用函数HAL_JPEG_Resume恢复JPEG编解码。


(3)新的数据块准备好后,可以在回调函数HAL_JPEG_GetDataCallback外面调用HAL_JPEG_ConfigInputBuffer 和 HAL_JPEG_Resume,但是为了保持数据一致性问题,务必在回调函数HAL_JPEG_GetDataCallback里面调用HAL_JPEG_Resume。


  第5步:输出缓冲区填充了给定大小的数据后,会调用回调函数HAL_JPEG_DataReadyCallback

(1)如果有数据空间存储新数据块,需要调用函数HAL_JPEG_ConfigOutputBuffer配置新存储位置。如果没有数据空间存储新数据块,需要等待有数据空间可用时,可以调用函数HAL_JPEG_Pause(参数XferSelection被设置为JPEG_PAUSE_RESUME_INPUT),待有数据空间可用时,可以调用HAL_JPEG_ConfigOutputBuffe设置新的输出缓冲,然后调用函数HAL_JPEG_Resume恢复JPEG编解码。

(2)函数HAL_JPEG_ConfigOutputBuffe/HAL_JPEG_Pause/HAL_JPEG_Resume的工作机制允许应用程序以块为单位接收数据。当接收到数据块时,应用程序可以暂停JPEG输出来处理这些数据,比如解码时YCbCr转RGB或者编码时数据存储。

(3)新的数据空间准备好后,可以在回调函数HAL_JPEG_DataReadyCallback外面调用HAL_JPEG_ConfigOutputBuffer和 HAL_JPEG_Resume,但是为了保持数据一致性问题,务必在回调函数HAL_JPEG_DataReadyCallback里面调用HAL_JPEG_Resume。


  第6步:其它相关函数

  JPEG解码时,如果解码成功,会调用回调函数HAL_JPEG_InfoReadyCallback。
  JPEG编码操作结束后会调用回调函数HAL_JPEG_EncodeCpltCallback。
  JPEG解码操作结束后,会调用回调函数HAL_JPEG_DecodeCpltCallback。
  操作过程中出现错误,会调用回调函数HAL_JPEG_ErrorCallback,用户可以调用函数HAL_JPEG_GetError获取错误类型。
  HAL JPEG默认使用的是ISO/IEC 10918-1规格量化表,如果要修改,可以调用函数HAL_JPEG_SetUserQuantTables实现。
  通过函数HAL_JPEG_GetState可以获取JPEG状态。


57.4 源文件stm32h7xx_hal_jpeg.c
这里把我们把如下几个常用到的函数做个说明:

  HAL_JPEG_Init
  HAL_JPEG_GetInfo
  HAL_JPEG_Decode_DMA
  HAL_JPEG_ConfigInputBuffer
  HAL_JPEG_ConfigOutputBuffer

57.4.1 函数HAL_JPEG_Init
函数原型:

  1. HAL_StatusTypeDef HAL_JPEG_Init(JPEG_HandleTypeDef *hjpeg)
  2. {
  3.   uint32_t acLum_huffmanTableAddr = (uint32_t)(&JPEG_ACLUM_HuffTable);
  4.   uint32_t dcLum_huffmanTableAddr = (uint32_t)(&JPEG_DCLUM_HuffTable);
  5.   uint32_t acChrom_huffmanTableAddr = (uint32_t)(&JPEG_ACCHROM_HuffTable);
  6.   uint32_t dcChrom_huffmanTableAddr = (uint32_t)(&JPEG_DCCHROM_HuffTable);

  7.   /* 检测句柄是否有效 */
  8.   if(hjpeg == NULL)
  9.   {
  10.     return HAL_ERROR;
  11.   }

  12.   if(hjpeg->State == HAL_JPEG_STATE_RESET)
  13.   {
  14.     hjpeg->Lock = HAL_UNLOCKED;

  15.      /* 初始化GPIO,NVIC等 */
  16.     HAL_JPEG_MspInit(hjpeg);
  17.   }

  18.   /* 设置JPEG状态 */
  19.   hjpeg->State = HAL_JPEG_STATE_BUSY;

  20.   /* 使能JPEG  */
  21.   __HAL_JPEG_ENABLE(hjpeg);

  22.   /* 关闭JPEG编解码处理 */
  23.   hjpeg->Instance->CONFR0 &=  ~JPEG_CONFR0_START;

  24.   /* 关闭JPEG所有中断 */
  25.   __HAL_JPEG_DISABLE_IT(hjpeg,JPEG_INTERRUPT_MASK);

  26.   /* 清空输入输入FIFO缓冲 */
  27.   hjpeg->Instance->CR |= JPEG_CR_IFF;
  28.   hjpeg->Instance->CR |= JPEG_CR_OFF;  

  29.   /* 清除所有标志 */
  30.   __HAL_JPEG_CLEAR_FLAG(hjpeg,JPEG_FLAG_ALL);

  31.   /* 初始化默认的量化表 */
  32.   hjpeg->QuantTable0 = (uint8_t *)((uint32_t)JPEG_LUM_QuantTable);
  33.   hjpeg->QuantTable1 = (uint8_t *)((uint32_t)JPEG_CHROM_QuantTable);
  34.   hjpeg->QuantTable2 = NULL;
  35.   hjpeg->QuantTable3 = NULL;

  36.   /* 初始化默认的霍夫曼表 */
  37.   if(JPEG_Set_HuffEnc_Mem(hjpeg, (JPEG_ACHuffTableTypeDef *)acLum_huffmanTableAddr, (JPEG_DCHuffTableTypeDef *)dcLum_huffmanTableAddr, (JPEG_ACHuffTableTypeDef *)acChrom_huffmanTableAddr, (JPEG_DCHuffTableTypeDef *)dcChrom_huffmanTableAddr) != HAL_OK)
  38.   {
  39.     hjpeg->ErrorCode = HAL_JPEG_ERROR_HUFF_TABLE;

  40.     return HAL_ERROR;
  41.   }

  42.   /* 使能文件头处理 */
  43.   hjpeg->Instance->CONFR1 |= JPEG_CONFR1_HDR;

  44.   /* 复位JPEG输入输出计数 */
  45.   hjpeg->JpegInCount = 0;
  46.   hjpeg->JpegOutCount = 0;

  47.   /* 设置JPEG就绪 */
  48.   hjpeg->State = HAL_JPEG_STATE_READY;

  49.   /* 设置无错误 Reset the JPEG ErrorCode */
  50.   hjpeg->ErrorCode = HAL_JPEG_ERROR_NONE;

  51.   /* 清除上下文 */
  52.   hjpeg->Context = 0;

  53.   /* 返回HAL_OK */
  54.   return HAL_OK;
  55. }

复制代码

函数描述:

此函数用于初始化JPEG。

函数参数:

  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
注意事项:

函数HAL_JPEG_MspInit用于初始化JPEG的底层时钟、NVIC等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
如果形参hjpeg的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量JPEG_HandleTypeDef JpegHandle。
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_JPEG_STATE_RESET  = 0x00U。

解决办法有三

方法1:用户自己初始JPEG底层。

方法2:定义JPEG_HandleTypeDef JpegHandle为全局变量。

方法3:下面的方法

  1. if(HAL_JPEG_DeInit(&JpegHandle) != HAL_OK)
  2. {
  3.     Error_Handler();
  4. }  
  5. if(HAL_JPEG_Init(&Dma2dHandle) != HAL_OK)
  6. {
  7.     Error_Handler();
  8. }
复制代码

使用举例:
  1. JPEG_HandleTypeDef    JPEG_Handle;
  2. JPEG_Handle.Instance = JPEG;
  3. HAL_JPEG_Init(&JPEG_Handle);
复制代码

57.4.2 函数HAL_JPEG_GetInfo
函数原型:

  1. HAL_StatusTypeDef HAL_JPEG_GetInfo(JPEG_HandleTypeDef *hjpeg, JPEG_ConfTypeDef *pInfo)
  2. {
  3.   uint32_t yblockNb, cBblockNb, cRblockNb;

  4.   /* 检测句柄是否有效 */
  5.   if((hjpeg == NULL) || (pInfo == NULL))
  6.   {
  7.     return HAL_ERROR;
  8.   }

  9.   /* 读取配置参数 */
  10.   if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == JPEG_CONFR1_NF_1)
  11.   {
  12.     pInfo->ColorSpace = JPEG_YCBCR_COLORSPACE;   
  13.   }   
  14.   else if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == 0)
  15.   {
  16.     pInfo->ColorSpace = JPEG_GRAYSCALE_COLORSPACE;
  17.   }
  18.   else if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == JPEG_CONFR1_NF)
  19.   {
  20.     pInfo->ColorSpace = JPEG_CMYK_COLORSPACE;   
  21.   }

  22.   pInfo->ImageHeight = (hjpeg->Instance->CONFR1 & 0xFFFF0000U) >> 16;
  23.   pInfo->ImageWidth  = (hjpeg->Instance->CONFR3 & 0xFFFF0000U) >> 16;

  24.   if((pInfo->ColorSpace == JPEG_YCBCR_COLORSPACE) || (pInfo->ColorSpace == JPEG_CMYK_COLORSPACE))
  25.   {
  26.     yblockNb  = (hjpeg->Instance->CONFR4 & JPEG_CONFR4_NB) >> 4;
  27.     cBblockNb = (hjpeg->Instance->CONFR5 & JPEG_CONFR5_NB) >> 4;
  28.     cRblockNb = (hjpeg->Instance->CONFR6 & JPEG_CONFR6_NB) >> 4;

  29.     if((yblockNb == 1) && (cBblockNb == 0) && (cRblockNb == 0))
  30.     {
  31.       pInfo->ChromaSubsampling = JPEG_422_SUBSAMPLING; /*16x8 block*/
  32.     }
  33.     else if((yblockNb == 0) && (cBblockNb == 0) && (cRblockNb == 0))
  34.     {
  35.       pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;
  36.     }
  37.     else if((yblockNb == 3) && (cBblockNb == 0) && (cRblockNb == 0))
  38.     {
  39.       pInfo->ChromaSubsampling = JPEG_420_SUBSAMPLING;
  40.     }
  41.     else /* 默认是 4:4:4*/
  42.     {
  43.       pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;
  44.     }
  45.   }
  46.   else
  47.   {
  48.     pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;
  49.   }

  50.   pInfo->ImageQuality = JPEG_GetQuality(hjpeg);

  51.   /* 返回HAL_OK */
  52.   return HAL_OK;
  53. }
复制代码

函数描述:

此函数主要用于解码JPEG时获取相关图像信息,比如图像质量,图像长宽等。

函数参数:

  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。
  第2个参数是JPEG_ConfTypeDef类型结构体指针变量,用于获取JPEG的配置信息,结构体变量成员的详细介绍看本章3.2小
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。


使用举例:
  1. JPEG_HandleTypeDef    JPEG_Handle;
  2. JPEG_ConfTypeDef      JPEG_Info;

  3. HAL_JPEG_GetInfo(&JPEG_Handle, &JPEG_Info);  
复制代码

57.4.3 函数HAL_JPEG_Decode_DMA
函数原型:

  1. HAL_StatusTypeDef  HAL_JPEG_Decode_DMA(JPEG_HandleTypeDef *hjpeg ,uint8_t *pDataIn ,uint32_t InDataLength ,uint8_t *pDataOutMCU ,uint32_t OutDataLength)
  2. {
  3.   /* 检测参数 */
  4.   assert_param((InDataLength >= 4));
  5.   assert_param((OutDataLength >= 4));

  6.   /* 检测参数 */
  7.   if((hjpeg == NULL) || (pDataIn == NULL) || (pDataOutMCU == NULL))
  8.   {
  9.     return HAL_ERROR;
  10.   }

  11.   /* 上锁 */
  12.   __HAL_LOCK(hjpeg);

  13.   if(hjpeg->State == HAL_JPEG_STATE_READY)
  14.   {
  15.     /* 设置JPEG忙 */
  16.     hjpeg->State = HAL_JPEG_STATE_BUSY_DECODING;

  17.     /* 设置JPEG上下文,工作在DMA界面状态 */
  18.     hjpeg->Context &= ~(JPEG_CONTEXT_OPERATION_MASK | JPEG_CONTEXT_METHOD_MASK);
  19.     hjpeg->Context |= (JPEG_CONTEXT_DECODE | JPEG_CONTEXT_DMA);         

  20.     /* 设置输入输出缓冲地址和大小 */
  21.     hjpeg->pJpegInBuffPtr = pDataIn;
  22.     hjpeg->pJpegOutBuffPtr = pDataOutMCU;
  23.     hjpeg->InDataLength = InDataLength;
  24.     hjpeg->OutDataLength = OutDataLength;

  25.     /* 复位输入输出缓冲计数 */
  26.     hjpeg->JpegInCount = 0;   
  27.     hjpeg->JpegOutCount = 0;   

  28.     /* 初始化解码处理 */
  29.     JPEG_Init_Process(hjpeg);

  30.     /* 启动JPEG解码处理,使用DMA方式 */
  31.     JPEG_DMA_StartProcess(hjpeg);

  32.   }
  33.   else
  34.   {
  35.     /* 解锁 */
  36.     __HAL_UNLOCK(hjpeg);

  37.     return HAL_BUSY;
  38.   }

  39.   /* 返回HAL_OK */
  40.   return HAL_OK;
  41. }
复制代码


函数描述:

此函数用于启动JPEG的DMA方式解码。

函数参数:

  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。
  第2个参数是输入数据缓冲地址。
  第3个参数输入数据大小,单位字节。
  第4个参数是输出缓冲地址。
  第5个参数是输出缓冲大小,单位字节。
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。

使用举例:

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: JPEG_Decode_DMA
  4. *    功能说明: JPEG解码
  5. *    形    参: hjpeg               JPEG_HandleTypeDef句柄指针
  6. *             FrameSourceAddress  数据地址
  7. *             FrameSize           数据大小
  8. *             DestAddress         目的数据地址
  9. *    返 回 值: HAL_ERROR表示配置失败,HAL_OK表示配置成功
  10. *             HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出
  11. *********************************************************************************************************
  12. */
  13. uint32_t JPEG_Decode_DMA(JPEG_HandleTypeDef *hjpeg, uint32_t FrameSourceAddress ,uint32_t FrameSize, uint32_t DestAddress)
  14. {
  15.     JPEGSourceAddress =  FrameSourceAddress ;
  16.     FrameBufferAddress = DestAddress;
  17.     Input_frameIndex = 0;
  18.     Input_frameSize = FrameSize;

  19.     /* 设置标志,0表示开始解码,1表示解码完成 */
  20.     Jpeg_HWDecodingEnd = 0;

  21.     /* 启动JPEG解码 */
  22.     HAL_JPEG_Decode_DMA(hjpeg ,(uint8_t *)JPEGSourceAddress ,CHUNK_SIZE_IN ,
  23. (uint8_t *)FrameBufferAddress ,CHUNK_SIZE_OUT);

  24.     return HAL_OK;
  25. }
复制代码

57.4.4 函数HAL_JPEG_ConfigInputBuffer
函数原型:

  1. void HAL_JPEG_ConfigInputBuffer(JPEG_HandleTypeDef *hjpeg, uint8_t *pNewInputBuffer, uint32_t InDataLength)
  2. {
  3.   hjpeg->pJpegInBuffPtr =  pNewInputBuffer;
  4.   hjpeg->InDataLength = InDataLength;
  5. }
复制代码

函数描述:

此函数用于配置编解码输入缓冲地址和数据大小。

函数参数:

  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。
  第2个参数是输入缓冲地址。
  第3个参数是输入缓冲大小,单位字节。
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
使用举例:

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: HAL_JPEG_GetDataCallback
  4. *    功能说明: JPEG回调函数,用于从输入地址获取新数据继续解码
  5. *    形    参: hjpeg          JPEG_HandleTypeDef 句柄指针
  6. *             NbDecodedData  上一轮已经解码的数据大小,单位字节  
  7. *    返 回 值: 无
  8. *********************************************************************************************************
  9. */
  10. void HAL_JPEG_GetDataCallback(JPEG_HandleTypeDef *hjpeg, uint32_t NbDecodedData)
  11. {
  12.     uint32_t inDataLength;

  13.     /* 更新已经解码的数据大小 */
  14.     Input_frameIndex += NbDecodedData;

  15.     /* 如果当前已经解码的数据小于总文件大小,继续解码 */
  16.     if( Input_frameIndex < Input_frameSize)
  17.     {
  18.         /* 更新解码数据位置 */
  19.         JPEGSourceAddress = JPEGSourceAddress + NbDecodedData;

  20.         /* 更新下一轮要解码的数据大小 */
  21.         if((Input_frameSize - Input_frameIndex) >= CHUNK_SIZE_IN)
  22.         {
  23.             inDataLength = CHUNK_SIZE_IN;
  24.         }
  25.         else
  26.         {
  27.             inDataLength = Input_frameSize - Input_frameIndex;
  28.         }   
  29.     }
  30.     else
  31.     {
  32.         inDataLength = 0;
  33.     }

  34.     /* 更新输入缓冲 */
  35.     HAL_JPEG_ConfigInputBuffer(hjpeg,(uint8_t *)JPEGSourceAddress, inDataLength);   
  36. }
复制代码


57.4.5 函数HAL_JPEG_ConfigOutputBuffer
函数原型:

  1. void HAL_JPEG_ConfigOutputBuffer(JPEG_HandleTypeDef *hjpeg, uint8_t *pNewOutputBuffer, uint32_t OutDataLength)
  2. {
  3.   hjpeg->pJpegOutBuffPtr = pNewOutputBuffer;
  4.   hjpeg->OutDataLength = OutDataLength;  
  5. }
复制代码


函数描述:

此函数用于配置编解码输出缓冲地址和数据大小。

函数参数:

  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。
  第2个参数是输出缓冲地址。
  第3个参数是输出缓冲大小,单位字节。
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
使用举例:

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: HAL_JPEG_DataReadyCallback
  4. *    功能说明: JPEG回调函数,用于输出缓冲地址更新
  5. *    形    参: hjpeg         JPEG_HandleTypeDef 句柄指针
  6. *             pDataOut      输出数据缓冲
  7. *             OutDataLength 输出数据大小,单位字节
  8. *    返 回 值: 无
  9. *********************************************************************************************************
  10. */
  11. void HAL_JPEG_DataReadyCallback (JPEG_HandleTypeDef *hjpeg, uint8_t *pDataOut, uint32_t OutDataLength)
  12. {
  13.     /* 更新JPEG输出地址 */  
  14.     FrameBufferAddress += OutDataLength;

  15.     HAL_JPEG_ConfigOutputBuffer(hjpeg, (uint8_t *)FrameBufferAddress, CHUNK_SIZE_OUT);
  16. }
复制代码

57.5 总结
本章节就为大家讲解这么多,JPEG功能用到的地方还是比较多的,建议熟练使用。



收藏 评论0 发布时间:2021-12-21 21:46

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版