C

Qt Quick Ultralite imagedecoder Example

/****************************************************************************** ** ** Copyright (C) 2023 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Quick Ultralite module. ** ** $QT_BEGIN_LICENSE:COMM$ ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see http://www.qt.io/terms-conditions. For further ** information use the contact form at http://www.qt.io/contact-us. ** ** $QT_END_LICENSE$ ** ******************************************************************************/
#include "stmimagedecoder.h" #include "stm32_mcu_specific.h" #include "buffer_config.h" #include <platforminterface/imagedecoder.h> #include <platforminterface/log.h> extern "C" { #include "jpeg_utils.h" } void JPEG_InputHandler(JPEG_HandleTypeDef *hjpeg, Qul::PlatformInterface::ImageDecoder::RequestDataCallback &callback); uint32_t JPEG_OutputHandler(JPEG_HandleTypeDef *hjpeg); bool jpegInformation(Qul::PlatformInterface::ImageDecoder::RequestDataCallback &callback, int16_t *width, int16_t *height, Qul::PixelFormat *actualPixelFormat, Qul::PixelFormat optimalOpaquePixelFormat, Qul::PixelFormat optimalAlphaPixelFormat); StmImageDecoder::StmImageDecoder() {} StmImageDecoder::~StmImageDecoder() {} extern JPEG_HandleTypeDef JPEG_Handle; JPEG_YCbCrToRGB_Convert_Function pConvert_Function = NULL; bool StmImageDecoder::imageInformation(RequestDataCallback &callback, int16_t *width, int16_t *height, Qul::PixelFormat *actualPixelFormat, Qul::PixelFormat optimalOpaquePixelFormat, Qul::PixelFormat optimalAlphaPixelFormat) { return jpegInformation(callback, width, height, actualPixelFormat, optimalOpaquePixelFormat, optimalAlphaPixelFormat); } uint32_t MCU_TotalNb = 0; uint32_t MCU_BlockIndex; uint32_t Jpeg_HWDecodingEnd = 0; uint32_t JPEG_OUT_Read_BufferIndex = 0; uint32_t JPEG_OUT_Write_BufferIndex = 0; __IO uint32_t Output_Is_Paused = 0; uint32_t JPEG_IN_Read_BufferIndex = 0; uint32_t JPEG_IN_Write_BufferIndex = 0; __IO uint32_t Input_Is_Paused = 0; uint8_t *FrameBufferAddress; uint32_t fileOffset = 0; static void resetDecoderContext(void) { uint16_t i; fileOffset = 0; pConvert_Function = NULL; MCU_TotalNb = 0; MCU_BlockIndex = 0; Jpeg_HWDecodingEnd = 0; JPEG_OUT_Read_BufferIndex = 0; JPEG_OUT_Write_BufferIndex = 0; Output_Is_Paused = 0; JPEG_IN_Read_BufferIndex = 0; JPEG_IN_Write_BufferIndex = 0; Input_Is_Paused = 0; for (i = 0; i < NB_OUTPUT_DATA_BUFFERS; i++) { Jpeg_OUT_BufferTab[i].State = JPEG_BUFFER_EMPTY; Jpeg_OUT_BufferTab[i].DataBufferSize = 0; } } int StmImageDecoder::decodeImage(RequestDataCallback &callback, unsigned char *outbuffer, uint32_t outbufferSize, Qul::PixelFormat pixelFormat, uint32_t requiredBytesPerLine) { QUL_UNUSED(outbufferSize); QUL_UNUSED(pixelFormat); QUL_UNUSED(requiredBytesPerLine); /*##-6- JPEG decoding with DMA (Not Blocking ) Method ################*/ uint32_t i; FrameBufferAddress = outbuffer; resetDecoderContext(); /* Read from JPG file and fill input buffers */ for (i = 0; i < NB_INPUT_DATA_BUFFERS; i++) { Jpeg_IN_BufferTab[i].DataBufferSize = callback.readData(Jpeg_IN_BufferTab[i].DataBuffer, fileOffset, CHUNK_SIZE_IN); if (Jpeg_IN_BufferTab[i].DataBufferSize % 4 != 0) Qul::PlatformInterface::log("size is not 4 bytes\n"); if (uint32_t(Jpeg_IN_BufferTab[i].DataBuffer) % 4 != 0) Qul::PlatformInterface::log("buffer is not 4 bytes aligned\n"); if (Jpeg_IN_BufferTab[i].DataBufferSize > 0) { Jpeg_IN_BufferTab[i].State = JPEG_BUFFER_FULL; fileOffset += Jpeg_IN_BufferTab[i].DataBufferSize; } else { Qul::PlatformInterface::log("Read fail\n"); return -1; } } /* Start JPEG decoding with DMA method */ HAL_StatusTypeDef status; #ifdef USE_DMA_BASED_JPEG_DECODING //Using DMA based jpeg decoding status = HAL_JPEG_Decode_DMA(&JPEG_Handle, Jpeg_IN_BufferTab[0].DataBuffer, Jpeg_IN_BufferTab[0].DataBufferSize, Jpeg_OUT_BufferTab[0].DataBuffer, CHUNK_SIZE_OUT); #else //Using Interrupt based jpeg decoding status = HAL_JPEG_Decode_IT(&JPEG_Handle, Jpeg_IN_BufferTab[0].DataBuffer, Jpeg_IN_BufferTab[0].DataBufferSize, Jpeg_OUT_BufferTab[0].DataBuffer, CHUNK_SIZE_OUT); #endif if (status != HAL_OK) { Qul::PlatformInterface::log("HAL_JPEG_Decode_DMA failed\n"); return 1; } /*##-7- Wait till end of JPEG decoding and perfom Input/Output Processing in BackGround #*/ uint32_t JpegProcessing_End = 0; do { JPEG_InputHandler(&JPEG_Handle, callback); JpegProcessing_End = JPEG_OutputHandler(&JPEG_Handle); } while (JpegProcessing_End == 0); while (!Jpeg_HWDecodingEnd) { #if (PLATFORM_OS == baremetal) //Sleep until HAL_JPEG_DecodeCpltCallback __WFI(); #else //FreeRTOS based platforms can wait on semaphore to yield to other tasks. //Semaphore can be given up in HAL_JPEG_DecodeCpltCallback #endif } Jpeg_HWDecodingEnd = 0; return 0; } /** * @brief JPEG Ouput Data BackGround Postprocessing . * @param hjpeg: JPEG handle pointer * @retval 1 : if JPEG processing has finished, 0 : if JPEG processing still ongoing */ uint32_t JPEG_OutputHandler(JPEG_HandleTypeDef *hjpeg) { uint32_t ConvertedDataCount; // Looks like not being used by the STM32 implementation for decoding if (Jpeg_OUT_BufferTab[JPEG_OUT_Read_BufferIndex].State == JPEG_BUFFER_FULL) { MCU_BlockIndex += pConvert_Function(Jpeg_OUT_BufferTab[JPEG_OUT_Read_BufferIndex].DataBuffer, FrameBufferAddress, MCU_BlockIndex, Jpeg_OUT_BufferTab[JPEG_OUT_Read_BufferIndex].DataBufferSize, &ConvertedDataCount); Jpeg_OUT_BufferTab[JPEG_OUT_Read_BufferIndex].State = JPEG_BUFFER_EMPTY; Jpeg_OUT_BufferTab[JPEG_OUT_Read_BufferIndex].DataBufferSize = 0; JPEG_OUT_Read_BufferIndex++; if (JPEG_OUT_Read_BufferIndex >= NB_OUTPUT_DATA_BUFFERS) { JPEG_OUT_Read_BufferIndex = 0; } if (MCU_BlockIndex == MCU_TotalNb) { return 1; } } else if ((Output_Is_Paused == 1) && (JPEG_OUT_Write_BufferIndex == JPEG_OUT_Read_BufferIndex) && (Jpeg_OUT_BufferTab[JPEG_OUT_Read_BufferIndex].State == JPEG_BUFFER_EMPTY)) { Output_Is_Paused = 0; HAL_JPEG_Resume(hjpeg, JPEG_PAUSE_RESUME_OUTPUT); } return 0; } /** * @brief JPEG Input Data BackGround processing . * @param hjpeg: JPEG handle pointer * @retval None */ void JPEG_InputHandler(JPEG_HandleTypeDef *hjpeg, Qul::PlatformInterface::ImageDecoder::RequestDataCallback &callback) { if (Jpeg_IN_BufferTab[JPEG_IN_Write_BufferIndex].State == JPEG_BUFFER_EMPTY) { if (fileOffset == callback.totalAvailableDataSize()) return; // No more data to read Jpeg_IN_BufferTab[JPEG_IN_Write_BufferIndex].DataBufferSize = callback.readData(Jpeg_IN_BufferTab[JPEG_IN_Write_BufferIndex].DataBuffer, fileOffset, CHUNK_SIZE_IN); if (Jpeg_IN_BufferTab[JPEG_IN_Write_BufferIndex].DataBufferSize > 0) { fileOffset += Jpeg_IN_BufferTab[JPEG_IN_Write_BufferIndex].DataBufferSize; Jpeg_IN_BufferTab[JPEG_IN_Write_BufferIndex].State = JPEG_BUFFER_FULL; } else { Qul::PlatformInterface::log("EOF reached, (or read failed)\n"); return; } if ((Input_Is_Paused == 1) && (JPEG_IN_Write_BufferIndex == JPEG_IN_Read_BufferIndex)) { Input_Is_Paused = 0; HAL_JPEG_ConfigInputBuffer(hjpeg, Jpeg_IN_BufferTab[JPEG_IN_Read_BufferIndex].DataBuffer, Jpeg_IN_BufferTab[JPEG_IN_Read_BufferIndex].DataBufferSize); HAL_StatusTypeDef status = HAL_JPEG_Resume(hjpeg, JPEG_PAUSE_RESUME_INPUT); if (status != HAL_OK) Qul::PlatformInterface::log("HAL_JPEG_Resume failed\n"); } JPEG_IN_Write_BufferIndex++; if (JPEG_IN_Write_BufferIndex >= NB_INPUT_DATA_BUFFERS) { JPEG_IN_Write_BufferIndex = 0; } } } extern "C" { /** * @brief JPEG Info ready callback * @param hjpeg: JPEG handle pointer * @param pInfo: JPEG Info Struct pointer * @retval None */ void HAL_JPEG_InfoReadyCallback(JPEG_HandleTypeDef *hjpeg, JPEG_ConfTypeDef *pInfo) { QUL_UNUSED(hjpeg); if (JPEG_GetDecodeColorConvertFunc(pInfo, &pConvert_Function, &MCU_TotalNb) != HAL_OK) { return; } } /** * @brief JPEG Get Data callback * @param hjpeg: JPEG handle pointer * @param NbDecodedData: Number of decoded (consummed) bytes from input buffer * @retval None */ void HAL_JPEG_GetDataCallback(JPEG_HandleTypeDef *hjpeg, uint32_t NbDecodedData) { if (NbDecodedData == Jpeg_IN_BufferTab[JPEG_IN_Read_BufferIndex].DataBufferSize) { Jpeg_IN_BufferTab[JPEG_IN_Read_BufferIndex].State = JPEG_BUFFER_EMPTY; Jpeg_IN_BufferTab[JPEG_IN_Read_BufferIndex].DataBufferSize = 0; JPEG_IN_Read_BufferIndex++; if (JPEG_IN_Read_BufferIndex >= NB_INPUT_DATA_BUFFERS) { JPEG_IN_Read_BufferIndex = 0; } if (Jpeg_IN_BufferTab[JPEG_IN_Read_BufferIndex].State == JPEG_BUFFER_EMPTY) { HAL_JPEG_Pause(hjpeg, JPEG_PAUSE_RESUME_INPUT); Input_Is_Paused = 1; } else { HAL_JPEG_ConfigInputBuffer(hjpeg, Jpeg_IN_BufferTab[JPEG_IN_Read_BufferIndex].DataBuffer, Jpeg_IN_BufferTab[JPEG_IN_Read_BufferIndex].DataBufferSize); } } else { HAL_JPEG_ConfigInputBuffer(hjpeg, Jpeg_IN_BufferTab[JPEG_IN_Read_BufferIndex].DataBuffer + NbDecodedData, Jpeg_IN_BufferTab[JPEG_IN_Read_BufferIndex].DataBufferSize - NbDecodedData); } } /** * @brief JPEG Data Ready callback * @param hjpeg: JPEG handle pointer * @param pDataOut: pointer to the output data buffer * @param OutDataLength: length of output buffer in bytes * @retval None */ void HAL_JPEG_DataReadyCallback(JPEG_HandleTypeDef *hjpeg, uint8_t *pDataOut, uint32_t OutDataLength) { QUL_UNUSED(pDataOut); Jpeg_OUT_BufferTab[JPEG_OUT_Write_BufferIndex].State = JPEG_BUFFER_FULL; Jpeg_OUT_BufferTab[JPEG_OUT_Write_BufferIndex].DataBufferSize = OutDataLength; JPEG_OUT_Write_BufferIndex++; if (JPEG_OUT_Write_BufferIndex >= NB_OUTPUT_DATA_BUFFERS) { JPEG_OUT_Write_BufferIndex = 0; } if (Jpeg_OUT_BufferTab[JPEG_OUT_Write_BufferIndex].State != JPEG_BUFFER_EMPTY) { HAL_JPEG_Pause(hjpeg, JPEG_PAUSE_RESUME_OUTPUT); Output_Is_Paused = 1; } HAL_JPEG_ConfigOutputBuffer(hjpeg, Jpeg_OUT_BufferTab[JPEG_OUT_Write_BufferIndex].DataBuffer, CHUNK_SIZE_OUT); } void HAL_JPEG_ErrorCallback(JPEG_HandleTypeDef *hjpeg) { Qul::PlatformInterface::log("HAL_JPEG_ErrorCallback\n"); QUL_UNUSED(hjpeg); } void HAL_JPEG_DecodeCpltCallback(JPEG_HandleTypeDef *hjpeg) { QUL_UNUSED(hjpeg); Jpeg_HWDecodingEnd = 1; } }