2025-02-18 05:46 AM
Background - TouchGFX based HMI application where I want to display JPEGs I am streaming.
I have setup the bitmap cache for TouchGFX and can confirm it works as expected with raw RGB565/888 bitmaps.
I am trying to integrate the JPEG codec to stream JPEG data instead of the raw bitmaps, to reduce latency.
DMA2D is *not* configured to be used by TouchGFX, so that I can use it to convert the output of the JPEG codec to RGB565 format to store in my bitmap cache, that touchGFX draws. Additionally, I have configured my IOC not to generate the DMA2D init function call.
For JPEG codec and DMA2D code, I have referred to the H7 example project (JPEG_DecodeFromFlashDMA) provided by ST.
When I test with few sample JPEGs, it works as expected and displays accurately, but does not for other samples.
It seems to work with CSS 4:2:0 images only, and not with CSS 4:4:4 or 4:2:2 images - It seems to be the JPEG decode works as expected, and the DMA2D transformation(?) is what is causing issues.
I have attached the relevant snippets of my code below.
HAL_JPEG_Decode(&hjpeg, bitmap_rx, jpeg_size, JPEG_decoded,
BITMAP_BUFFER_SIZE, 100);
HAL_JPEG_GetInfo(&hjpeg, &JPEG_Info);
DMA2D_YCBCR_To_RGB(JPEG_decoded, bitmap->bitmap_pointer,
JPEG_Info.ChromaSubsampling, JPEG_Info.ImageWidth,
JPEG_Info.ImageHeight);
bitmap->bitmap_pointer is the pointer assigned by touchGFX when creating the bitmap cache
bitmap_rx contains the bytestream of a JPEG encoded image, and JPEG_decoded contains the output of the decoded JPEG.
void DMA2D_YCBCR_To_RGB(uint8_t *source_pointer, uint8_t *destination_pointer,
uint32_t chroma_subsampling, uint16_t x_size, uint16_t y_size) {
uint32_t css_mode = DMA2D_CSS_422;
uint32_t input_line_offset = 0;
switch (chroma_subsampling) {
case JPEG_420_SUBSAMPLING:
css_mode = DMA2D_CSS_420;
input_line_offset = x_size % 16;
if (input_line_offset != 0) {
input_line_offset = 16 - input_line_offset;
}
break;
case JPEG_422_SUBSAMPLING:
css_mode = DMA2D_CSS_422;
inputLineOffset = xsize % 16;
if (inputLineOffset != 0) {
inputLineOffset = 16 - inputLineOffset;
}
break;
case JPEG_444_SUBSAMPLING:
css_mode = DMA2D_NO_CSS;
input_line_offset = x_size % 8;
if (input_line_offset != 0) {
input_line_offset = 8 - input_line_offset;
}
break;
default:
break;
}
hdma2d.Instance = DMA2D;
hdma2d.Init.Mode = DMA2D_M2M_PFC;
hdma2d.Init.ColorMode = DMA2D_OUTPUT_RGB565;
hdma2d.Init.OutputOffset = 0;
hdma2d.Init.BytesSwap = DMA2D_BYTES_REGULAR;
hdma2d.Init.LineOffsetMode = DMA2D_LOM_PIXELS;
hdma2d.LayerCfg[1].InputOffset = input_line_offset;
hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_YCBCR;
hdma2d.LayerCfg[1].ChromaSubSampling = css_mode;
hdma2d.LayerCfg[1].AlphaMode = DMA2D_REPLACE_ALPHA;
hdma2d.LayerCfg[1].InputAlpha = 0xFF;
hdma2d.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA;
hdma2d.LayerCfg[1].RedBlueSwap = DMA2D_RB_REGULAR;
if (HAL_DMA2D_Init(&hdma2d) != HAL_OK) {
Error_Handler();
}
if (HAL_DMA2D_ConfigLayer(&hdma2d, 1) != HAL_OK) {
Error_Handler();
}
HAL_DMA2D_Start(&hdma2d, (uint32_t) source_pointer,
(uint32_t) destination_pointer, x_size, y_size);
HAL_DMA2D_PollForTransfer(&hdma2d, 1000);
}
I have also attached sample images for reference of the accurately displayed JPEG (CSS 4:2:0) and incorrectly displayed JPEG, along with pictures of how it is rendered on the display.
Any guidance/assistance would be much appreciated!