打印
[STM32H7]

【STM32H745I-DISCO试用】JPEG解码实验

[复制链接]
27|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 南来之风 于 2025-3-10 11:05 编辑

本实验展示了如何使用硬件JPEG解码器解码存储在内部Flash中的JPGE图片,解码后的图片格式为YCbCr。然后使用DMA2D把这种格式转换为ARGB888,之后显示在LCD上。
首先配置系统时钟:
static void SystemClock_Config(void)
{
  RCC_ClkInitTypeDef RCC_ClkInitStruct;
  RCC_OscInitTypeDef RCC_OscInitStruct;
  HAL_StatusTypeDef ret = HAL_OK;

  /* The voltage scaling allows optimizing the power consumption when the device is
     clocked below the maximum system frequency, to update the voltage scaling value
     regarding system frequency refer to product datasheet.  */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
  
  /* Enable HSE Oscillator and activate PLL with HSE as source */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
  RCC_OscInitStruct.CSIState = RCC_CSI_OFF;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;

  RCC_OscInitStruct.PLL.PLLM = 5;
  RCC_OscInitStruct.PLL.PLLN = 160;
  RCC_OscInitStruct.PLL.PLLFRACN = 0;
  RCC_OscInitStruct.PLL.PLLP = 2;
  RCC_OscInitStruct.PLL.PLLR = 2;
  RCC_OscInitStruct.PLL.PLLQ = 4;

  RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
  RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;
  ret = HAL_RCC_OscConfig(&RCC_OscInitStruct);
  if(ret != HAL_OK)
  {
    Error_Handler();
  }
  
/* Select PLL as system clock source and configure  bus clocks dividers */
  RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_D1PCLK1 | RCC_CLOCKTYPE_PCLK1 | \
                                 RCC_CLOCKTYPE_PCLK2  | RCC_CLOCKTYPE_D3PCLK1);

  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;  
  RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
  RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
  ret = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4);
  if(ret != HAL_OK)
  {
    Error_Handler();
  }

/*
  Note : The activation of the I/O Compensation Cell is recommended with communication  interfaces
          (GPIO, SPI, FMC, QSPI ...)  when  operating at  high frequencies(please refer to product datasheet)      
          The I/O Compensation Cell activation  procedure requires :
        - The activation of the CSI clock
        - The activation of the SYSCFG clock
        - Enabling the I/O Compensation Cell : setting bit[0] of register SYSCFG_CCCSR
*/

  /*activate CSI clock mondatory for I/O Compensation Cell*/  
  __HAL_RCC_CSI_ENABLE() ;
   
  /* Enable SYSCFG clock mondatory for I/O Compensation Cell */
  __HAL_RCC_SYSCFG_CLK_ENABLE() ;
  
  /* Enables the I/O Compensation Cell */   
  HAL_EnableCompensationCell();  
}
初始化JPEG解码器:HAL_JPEG_Init(&JPEG_Handle);
HAL_StatusTypeDef HAL_JPEG_Init(JPEG_HandleTypeDef *hjpeg)
{
  /* These are the sample quantization tables given in JPEG spec ISO/IEC 10918-1 standard , section K.1. */
  static const uint8_t JPEG_LUM_QuantTable[JPEG_QUANT_TABLE_SIZE] =
  {
    16,  11,  10,  16,  24,  40,  51,  61,
    12,  12,  14,  19,  26,  58,  60,  55,
    14,  13,  16,  24,  40,  57,  69,  56,
    14,  17,  22,  29,  51,  87,  80,  62,
    18,  22,  37,  56,  68, 109, 103,  77,
    24,  35,  55,  64,  81, 104, 113,  92,
    49,  64,  78,  87, 103, 121, 120, 101,
    72,  92,  95,  98, 112, 100, 103,  99
  };
  static const uint8_t JPEG_CHROM_QuantTable[JPEG_QUANT_TABLE_SIZE] =
  {
    17,  18,  24,  47,  99,  99,  99,  99,
    18,  21,  26,  66,  99,  99,  99,  99,
    24,  26,  56,  99,  99,  99,  99,  99,
    47,  66,  99,  99,  99,  99,  99,  99,
    99,  99,  99,  99,  99,  99,  99,  99,
    99,  99,  99,  99,  99,  99,  99,  99,
    99,  99,  99,  99,  99,  99,  99,  99,
    99,  99,  99,  99,  99,  99,  99,  99
  };

  /* Check the JPEG handle allocation */
  if (hjpeg == NULL)
  {
    return HAL_ERROR;
  }

#if (USE_HAL_JPEG_REGISTER_CALLBACKS == 1)
  if (hjpeg->State == HAL_JPEG_STATE_RESET)
  {
    /* Allocate lock resource and initialize it */
    hjpeg->Lock = HAL_UNLOCKED;

    hjpeg->InfoReadyCallback  = HAL_JPEG_InfoReadyCallback;  /* Legacy weak InfoReadyCallback  */
    hjpeg->EncodeCpltCallback = HAL_JPEG_EncodeCpltCallback; /* Legacy weak EncodeCpltCallback */
    hjpeg->DecodeCpltCallback = HAL_JPEG_DecodeCpltCallback; /* Legacy weak DecodeCpltCallback */
    hjpeg->ErrorCallback      = HAL_JPEG_ErrorCallback;      /* Legacy weak ErrorCallback      */
    hjpeg->GetDataCallback    = HAL_JPEG_GetDataCallback;    /* Legacy weak GetDataCallback    */
    hjpeg->DataReadyCallback  = HAL_JPEG_DataReadyCallback;  /* Legacy weak DataReadyCallback  */

    if (hjpeg->MspInitCallback == NULL)
    {
      hjpeg->MspInitCallback = HAL_JPEG_MspInit; /* Legacy weak MspInit  */
    }

    /* Init the low level hardware */
    hjpeg->MspInitCallback(hjpeg);
  }
#else
  if (hjpeg->State == HAL_JPEG_STATE_RESET)
  {
    /* Allocate lock resource and initialize it */
    hjpeg->Lock = HAL_UNLOCKED;

    /* Init the low level hardware : GPIO, CLOCK */
    HAL_JPEG_MspInit(hjpeg);
  }
#endif /* USE_HAL_JPEG_REGISTER_CALLBACKS */

  /* Change the JPEG state */
  hjpeg->State = HAL_JPEG_STATE_BUSY;

  /* Start the JPEG Core*/
  __HAL_JPEG_ENABLE(hjpeg);

  /* Stop the JPEG encoding/decoding process*/
  hjpeg->Instance->CONFR0 &=  ~JPEG_CONFR0_START;

  /* Disable All Interrupts */
  __HAL_JPEG_DISABLE_IT(hjpeg, JPEG_INTERRUPT_MASK);


  /* Flush input and output FIFOs*/
  hjpeg->Instance->CR |= JPEG_CR_IFF;
  hjpeg->Instance->CR |= JPEG_CR_OFF;

  /* Clear all flags */
  __HAL_JPEG_CLEAR_FLAG(hjpeg, JPEG_FLAG_ALL);

  /* init default quantization tables*/
  hjpeg->QuantTable0 = (uint8_t *)((uint32_t)JPEG_LUM_QuantTable);
  hjpeg->QuantTable1 = (uint8_t *)((uint32_t)JPEG_CHROM_QuantTable);
  hjpeg->QuantTable2 = NULL;
  hjpeg->QuantTable3 = NULL;

  /* init the default Huffman tables*/
  if (JPEG_Set_HuffEnc_Mem(hjpeg) != HAL_OK)
  {
    hjpeg->ErrorCode = HAL_JPEG_ERROR_HUFF_TABLE;

    return HAL_ERROR;
  }

  /* Enable header processing*/
  hjpeg->Instance->CONFR1 |= JPEG_CONFR1_HDR;

  /* Reset JpegInCount and JpegOutCount */
  hjpeg->JpegInCount = 0;
  hjpeg->JpegOutCount = 0;

  /* Change the JPEG state */
  hjpeg->State = HAL_JPEG_STATE_READY;

  /* Reset the JPEG ErrorCode */
  hjpeg->ErrorCode = HAL_JPEG_ERROR_NONE;

  /*Clear the context filelds*/
  hjpeg->Context = 0;

  /* Return function status */
  return HAL_OK;
}



初始化配置LCD  BSP_LCD_Init(0, LCD_ORIENTATION_LANDSCAPE);
/**
  * [url=home.php?mod=space&uid=247401]@brief[/url]  Initializes the LCD in default mode.
  * @param  Instance    LCD Instance
  * @param  Orientation LCD_ORIENTATION_LANDSCAPE
  * @retval BSP status
  */
int32_t BSP_LCD_Init(uint32_t Instance, uint32_t Orientation)
{
  return BSP_LCD_InitEx(Instance, Orientation, LTDC_PIXEL_FORMAT_ARGB8888, LCD_DEFAULT_WIDTH, LCD_DEFAULT_HEIGHT);
}



调用JPEGE_Decode_DMA解码JPEG图片
JPEG_Decode_DMA(&JPEG_Handle, (uint32_t)image_320_240_jpg, IMAGE_320_240_JPG_SIZE , JPEG_OUTPUT_DATA_BUFFER);
/**
  * [url=home.php?mod=space&uid=247401]@brief[/url]  Decode_DMA
  * @param hjpeg: JPEG handle pointer
  * @param  FrameSourceAddress    : video buffer address.
  * @param  DestAddress : YCbCr destination Frame Buffer Address.
  * @retval None
  */
uint32_t JPEG_Decode_DMA(JPEG_HandleTypeDef *hjpeg, uint32_t FrameSourceAddress ,uint32_t FrameSize, uint32_t DestAddress)
{
  JPEGSourceAddress =  FrameSourceAddress ;
  FrameBufferAddress = DestAddress;
  Input_frameIndex=0;
  Input_frameSize = FrameSize;
  
  Jpeg_HWDecodingEnd = 0;
  
  /* Start JPEG decoding with DMA method */
  HAL_JPEG_Decode_DMA(hjpeg ,(uint8_t *)JPEGSourceAddress ,CHUNK_SIZE_IN ,(uint8_t *)FrameBufferAddress ,CHUNK_SIZE_OUT);
  
  
  return 0;
  
}


调用HAL_JPEG_GetInfo(&JPEG_Handle, &JPEG_Info); 来获取JPEG图片信息。
/**
  * @brief  Extract the image configuration from the JPEG header during the decoding
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @param  pInfo pointer to a JPEG_ConfTypeDef structure that contains
  *         The JPEG decoded header information
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_JPEG_GetInfo(JPEG_HandleTypeDef *hjpeg, JPEG_ConfTypeDef *pInfo)
{
  uint32_t yblockNb;
  uint32_t cBblockNb;
  uint32_t cRblockNb;

  /* Check the JPEG handle allocation */
  if ((hjpeg == NULL) || (pInfo == NULL))
  {
    return HAL_ERROR;
  }

  /*Read the conf parameters */
  if ((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == JPEG_CONFR1_NF_1)
  {
    pInfo->ColorSpace = JPEG_YCBCR_COLORSPACE;
  }
  else if ((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == 0UL)
  {
    pInfo->ColorSpace = JPEG_GRAYSCALE_COLORSPACE;
  }
  else if ((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == JPEG_CONFR1_NF)
  {
    pInfo->ColorSpace = JPEG_CMYK_COLORSPACE;
  }
  else
  {
    return HAL_ERROR;
  }

  pInfo->ImageHeight = (hjpeg->Instance->CONFR1 & 0xFFFF0000UL) >> 16;
  pInfo->ImageWidth  = (hjpeg->Instance->CONFR3 & 0xFFFF0000UL) >> 16;

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

    if ((yblockNb == 1UL) && (cBblockNb == 0UL) && (cRblockNb == 0UL))
    {
      pInfo->ChromaSubsampling = JPEG_422_SUBSAMPLING; /*16x8 block*/
    }
    else if ((yblockNb == 0UL) && (cBblockNb == 0UL) && (cRblockNb == 0UL))
    {
      pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;
    }
    else if ((yblockNb == 3UL) && (cBblockNb == 0UL) && (cRblockNb == 0UL))
    {
      pInfo->ChromaSubsampling = JPEG_420_SUBSAMPLING;
    }
    else /*Default is 4:4:4*/
    {
      pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;
    }
  }
  else
  {
    pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;
  }

  pInfo->ImageQuality = JPEG_GetQuality(hjpeg);

  /* Return function status */
  return HAL_OK;
}




[size=13.3333px]调用DMA2D转换图片格式:   DMA2D_CopyBuffer((uint32_t *)JPEG_OUTPUT_DATA_BUFFER, (uint32_t *)LCD_FRAME_BUFFER, xPos , yPos, JPEG_Info.ImageWidth, JPEG_Info.ImageHeight, JPEG_Info.ChromaSubsampling);



[size=13.3333px]

/**
  * @brief  Copy the Decoded image to the display Frame buffer.
  * @param  pSrc: Pointer to source buffer
  * @param  pDst: Pointer to destination buffer
  * @param  x: destination Horizontal offset.
  * @param  y: destination Vertical offset.
  * @param  xsize: image width
  * @param  ysize: image Height
  * @param  ChromaSampling : YCbCr Chroma sampling : 4:2:0, 4:2:2 or 4:4:4  
  * @retval None
  */
static void DMA2D_CopyBuffer(uint32_t *pSrc, uint32_t *pDst, uint16_t x, uint16_t y, uint16_t xsize, uint16_t ysize, uint32_t ChromaSampling)
{   
  
  uint32_t cssMode = DMA2D_CSS_420, inputLineOffset = 0;  
  uint32_t destination = 0;
  
  if(ChromaSampling == JPEG_420_SUBSAMPLING)
  {
    cssMode = DMA2D_CSS_420;
   
    inputLineOffset = xsize % 16;
    if(inputLineOffset != 0)
    {
      inputLineOffset = 16 - inputLineOffset;
    }   
  }
  else if(ChromaSampling == JPEG_444_SUBSAMPLING)
  {
    cssMode = DMA2D_NO_CSS;
   
    inputLineOffset = xsize % 8;
    if(inputLineOffset != 0)
    {
      inputLineOffset = 8 - inputLineOffset;
    }   
  }
  else if(ChromaSampling == JPEG_422_SUBSAMPLING)
  {
    cssMode = DMA2D_CSS_422;
   
    inputLineOffset = xsize % 16;
    if(inputLineOffset != 0)
    {
      inputLineOffset = 16 - inputLineOffset;
    }      
  }  
  
  /*##-1- Configure the DMA2D Mode, Color Mode and output offset #############*/
  DMA2D_Handle.Init.Mode         = DMA2D_M2M_PFC;
  DMA2D_Handle.Init.ColorMode    = DMA2D_OUTPUT_ARGB8888;
  DMA2D_Handle.Init.OutputOffset = LCD_X_Size - xsize;
  DMA2D_Handle.Init.AlphaInverted = DMA2D_REGULAR_ALPHA;  /* No Output Alpha Inversion*/  
  DMA2D_Handle.Init.RedBlueSwap   = DMA2D_RB_REGULAR;     /* No Output Red & Blue swap */  
  
  /*##-2- DMA2D Callbacks Configuration ######################################*/
  DMA2D_Handle.XferCpltCallback  = NULL;
  
  /*##-3- Foreground Configuration ###########################################*/
  DMA2D_Handle.LayerCfg[1].AlphaMode = DMA2D_REPLACE_ALPHA;
  DMA2D_Handle.LayerCfg[1].InputAlpha = 0xFF;
  DMA2D_Handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_YCBCR;
  DMA2D_Handle.LayerCfg[1].ChromaSubSampling = cssMode;
  DMA2D_Handle.LayerCfg[1].InputOffset = inputLineOffset;
  DMA2D_Handle.LayerCfg[1].RedBlueSwap = DMA2D_RB_REGULAR; /* No ForeGround Red/Blue swap */
  DMA2D_Handle.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA; /* No ForeGround Alpha inversion */  
  
  DMA2D_Handle.Instance          = DMA2D;
  
  /*##-4- DMA2D Initialization     ###########################################*/
  HAL_DMA2D_Init(&DMA2D_Handle);
  HAL_DMA2D_ConfigLayer(&DMA2D_Handle, 1);
  
  /*##-5-  copy the new decoded frame to the LCD Frame buffer ################*/
  BSP_LCD_GetXSize(0, &LCD_X_Size);
  destination = (uint32_t)pDst + ((y * LCD_X_Size) + x) * 4;

  HAL_DMA2D_Start(&DMA2D_Handle, (uint32_t)pSrc, destination, xsize, ysize);
  HAL_DMA2D_PollForTransfer(&DMA2D_Handle, 25);  /* wait for the previous DMA2D transfer to ends */
}


[size=13.3333px]解码后的图片展示:
[size=13.3333px]



附python代码把本地jpeg图片转换成hex格式:
from PIL import Image
import binascii

import re

def jpg_to_hex(file_path):
    # 打开图像
    with open(file_path, 'rb') as image_file:
        # 读取文件的二进制数据
        binary_data = image_file.read()
        # 将二进制数据转换为十六进制
        hex_data = binascii.hexlify(binary_data)
        #return hex_data
        # 转换为字符串
        hex_string = hex_data.decode('utf-8')
        return hex_string

# 示例用法
file_path = 'IMG320240.jpg'
hex_representation = jpg_to_hex(file_path)
#print(hex_representation)

split_str = [hex_representation[i:i+2] for i in range(0, len(hex_representation), 2)]
print(split_str)





























使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

59

主题

272

帖子

2

粉丝