/** ****************************************************************************** * @file jpeg_utils.c * @author MCD Application Team * @version V2.0.0 * @date 3-June-2016 * @brief This driver provides JPEG MCU (Minimum Coded Unit) blocks to RGB and RGB to JPEG MCU conversion functions. * * The STM32 HW JPEG decoder/encoder peripheral allows to decode/encode jpeg images. * In decoding, the STM32 HW JPEG data output are organized in blocks called MCU (Minimum Coded Unit) * as specified in the jpeg standard. * In encoding, the STM32 HW JPEG data input must be organized in MCU blocks. * Depending of the image color space and chrominance sampling, an MCU is generally organized in : * N luminance (Y) blocks + a Blue chrominance (Cb) block + a Red chrominance (Cr) block. * Each block size is 8x8 samples. * * The STM32 HW JPEG supports 3 possible color space : * - YCbCr : an MCU is composed of 3 color components : Y , Cb and Cr * - GrayScale : an MCU is composed of 1 single color component : Y * - CMYK : an MCU is composed of 4 color components : Cyan, Magenta, Yellow, and Key (blacK) * * This utility file should be used on top of the STM32 HAL JPEG driver. * In decoding, it allows to convert MCU blocks to RGB888 or ARGB8888 pixels stored to a destination * frame buffer that can be displayed. * In encoding, it allows to convert RGB888 or ARGB8888 pixels to MCU blocks. * * This utility supports following MCU Chroma sampling format and color space : * - YCbCr 4:2:0 : Each MCU is composed of 4 Y 8x8 blocks + 1 Cb 8x8 block + Cr 8x8 block * - YCbCr 4:2:2 : Each MCU is composed of 2 Y 8x8 blocks + 1 Cb 8x8 block + Cr 8x8 block * - YCbCr 4:4:4 : Each MCU is composed of 1 Y 8x8 block + 1 Cb 8x8 block + Cr 8x8 block * - GrayScale : Each MCU is composed of 1 Y 8x8 block * - CMYK : Each MCU is composed of 1 Cyan 8x8 block + 1 Magenta 8x8 block + 1 Yellow 8x8 block + 1 Key 8x8 block. * * * @How to use this driver * * - The configuration file "jpeg_utils_conf_template.h" is used to configure this utility * providing some useful flexibilities. * This file should be copied to the application folder and modified as follows: * - Rename it to "jpeg_utils_conf.h". * - Update the name of the JPEG driver's header file, depending on the EVAL board you are using. * * Example if using the STM32F769I-EVAL board : * - Copy the file "jpeg_utils_conf_template.h" to the application folder and rename it to "jpeg_utils_conf.h" * - Edit the "jpeg_utils_conf.h" and change lines 51 and 52 as follow : * #include "stm32f7xx_hal.h" * #include "stm32f7xx_hal_jpeg.h" * * Using this configuration file, user can change the following settings: * - Use RGB888 or ARGB8888 or RGB565 by setting the constant JPEG_RGB_FORMAT respectively to JPEG_RGB888, JPEG_ARGB8888 JPEG_RGB565. * - Swap RED, and Blue offsets if user needs to change the color order to BGR (instead of RGB) by setting: * #define JPEG_SWAP_RB 1 * - Enable or disable the decoding post-processing functions (YCbCr to RGB conversion functions) by setting the define USE_JPEG_DECODER * respectively to 0 or 1. * - Enable or disable the encoding pre-processing functions (RGB to YCbCr conversion functions) by setting the define USE_JPEG_ENCODER * respectively to 0 or 1. * * * For Decoding: * - First, function "JPEG_InitColorTables" should be called to initialize the YCbCr to RGB color * conversion tables. This function needs to be called only one time at the beginning of the * program whatever the number of jpeg files to be decoded. * * - As soon as the JPEG HW peripheral finished parsing the header of the JPEG input file, * the HAL JPEG callback "HAL_JPEG_InfoReadyCallback" is launched providing the jpeg file * characteristics found in its header. * User can then call the utility function "JPEG_GetDecodeColorConvertFunc" with these * information and retrieve the corresponding color conversion function and number of MCUs. * * Then each time an integer number of MCUs are available (from the HW JPEG output), user * can call the retrieved function to convert these HW JPEG output data to RGB888 or * ARGB8888 pixel stored to the specified destination buffer. * * * For Encoding: * - First, function "JPEG_InitColorTables" should be called to initialize the YCbCr/RGB color * conversion tables. This function needs to be called only one time at the beginning of the * program whatever the number of jpeg files to be encoded or decoded. * * - First Use the utility function "JPEG_GetEncodeColorConvertFunc" with the input image informations * to retrieve the corresponding color conversion function and number of MCUs. * * Then each time an RGB input buffer is available, user can call the retrieved function to convert * RGB data to MCU blocks stored to the specified destination buffer. * * ****************************************************************************** * @attention * *

© COPYRIGHT(c) 2016 STMicroelectronics

* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. Neither the name of STMicroelectronics nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "jpeg_utils.h" /** @addtogroup Utilities * @{ */ /** @defgroup JPEG JPEG * @brief JPEG YCbCr blocks <-> RGB conversion utilties * @{ */ /** @defgroup JPEG_Private_Types JPEG Private Types * @{ */ /* Private typedef -----------------------------------------------------------*/ typedef struct __JPEG_MCU_RGB_ConvertorTypeDef { uint32_t ColorSpace; uint32_t ChromaSubsampling; uint32_t ImageWidth; uint32_t ImageHeight; uint32_t ImageSize_Bytes; uint32_t LineOffset; uint32_t BlockSize; uint32_t H_factor; uint32_t V_factor; uint32_t WidthExtend; uint32_t ScaledWidth; uint32_t MCU_Total_Nb; uint16_t *Y_MCU_LUT; uint16_t *Cb_MCU_LUT; uint16_t *Cr_MCU_LUT; uint16_t *K_MCU_LUT; }JPEG_MCU_RGB_ConvertorTypeDef; /** * @} */ /** @defgroup JPEG_Private_Defines JPEG Private Defines * @{ */ /* Private define ------------------------------------------------------------*/ #define YCBCR_420_BLOCK_SIZE 384 /* YCbCr 4:2:0 MCU : 4 8x8 blocks of Y + 1 8x8 block of Cb + 1 8x8 block of Cr */ #define YCBCR_422_BLOCK_SIZE 256 /* YCbCr 4:2:2 MCU : 2 8x8 blocks of Y + 1 8x8 block of Cb + 1 8x8 block of Cr */ #define YCBCR_444_BLOCK_SIZE 192 /* YCbCr 4:4:4 MCU : 1 8x8 block of Y + 1 8x8 block of Cb + 1 8x8 block of Cr */ #define GRAY_444_BLOCK_SIZE 64 /* GrayScale MCU : 1 8x8 block of Y */ #define CMYK_444_BLOCK_SIZE 256 /* CMYK MCU : 1 8x8 blocks of Cyan + 1 8x8 block Magenta + 1 8x8 block of Yellow and 1 8x8 block of BlacK */ #if (JPEG_RGB_FORMAT == JPEG_ARGB8888) #define JPEG_GREEN_OFFSET 8 /* Offset of the GREEN color in a pixel */ #define JPEG_ALPHA_OFFSET 24 /* Offset of the Transparency Alpha in a pixel */ #define JPEG_BYTES_PER_PIXEL 4 /* Number of bytes in a pixel */ #if (JPEG_SWAP_RB == 0) #define JPEG_RED_OFFSET 16 /* Offset of the RED color in a pixel */ #define JPEG_BLUE_OFFSET 0 /* Offset of the BLUE color in a pixel */ #else #define JPEG_RED_OFFSET 0 /* Offset of the RED color in a pixel */ #define JPEG_BLUE_OFFSET 16 /* Offset of the BLUE color in a pixel */ #endif /* JPEG_SWAP_RB */ #elif(JPEG_RGB_FORMAT == JPEG_RGB888) #define JPEG_GREEN_OFFSET 8 /* Offset of the GREEN color in a pixel */ #define JPEG_BYTES_PER_PIXEL 3 /* Number of bytes in a pixel */ #if (JPEG_SWAP_RB == 0) #define JPEG_RED_OFFSET 16 /* Offset of the RED color in a pixel */ #define JPEG_BLUE_OFFSET 0 /* Offset of the BLUE color in a pixel */ #else #define JPEG_RED_OFFSET 0 /* Offset of the RED color in a pixel */ #define JPEG_BLUE_OFFSET 16 /* Offset of the BLUE color in a pixel */ #endif /* JPEG_SWAP_RB */ #elif (JPEG_RGB_FORMAT == JPEG_RGB565) #define JPEG_GREEN_OFFSET 5 /* Offset of the GREEN color in a pixel */ #define JPEG_BYTES_PER_PIXEL 2 /* Number of bytes in a pixel */ #define JPEG_RGB565_GREEN_MASK 0x07E0 /* Mask of Green component in RGB565 Format */ #if (JPEG_SWAP_RB == 0) #define JPEG_RED_OFFSET 11 /* Offset of the RED color in a pixel */ #define JPEG_BLUE_OFFSET 0 /* Offset of the BLUE color in a pixel */ #define JPEG_RGB565_RED_MASK 0xF800 /* Mask of Red component in RGB565 Format */ #define JPEG_RGB565_BLUE_MASK 0x001F /* Mask of Blue component in RGB565 Format */ #else #define JPEG_RED_OFFSET 0 /* Offset of the RED color in a pixel */ #define JPEG_BLUE_OFFSET 11 /* Offset of the BLUE color in a pixel */ #define JPEG_RGB565_RED_MASK 0x001F /* Mask of Red component in RGB565 Format */ #define JPEG_RGB565_BLUE_MASK 0xF800 /* Mask of Blue component in RGB565 Format */ #endif /* JPEG_SWAP_RB */ #else #error "unknown JPEG_RGB_FORMAT " #endif /* JPEG_RGB_FORMAT */ /** * @} */ /** @defgroup JPEG_Private_Macros JPEG Private Macros * @{ */ /* Private macro -------------------------------------------------------------*/ #if (USE_JPEG_DECODER == 1) #define CLAMP(value) CLAMP_LUT[(value) + 0x100] /* Range limitting macro */ #endif #if (USE_JPEG_ENCODER == 1) #define MAX(val1,val2) ((val1 > val2) ? val1 : val2) #endif /** * @} */ /** @defgroup JPEG_Private_Variables JPEG Private Variables * @{ */ /* Private variables ---------------------------------------------------------*/ static JPEG_MCU_RGB_ConvertorTypeDef JPEG_ConvertorParams; #if (USE_JPEG_DECODER == 1) static int32_t CR_RED_LUT[256]; /* Cr to Red color conversion Look Up Table */ static int32_t CB_BLUE_LUT[256]; /* Cb to Blue color conversion Look Up Table */ static int32_t CR_GREEN_LUT[256]; /* Cr to Green color conversion Look Up Table*/ static int32_t CB_GREEN_LUT[256]; /* Cb to Green color conversion Look Up Table*/ #endif /* USE_JPEG_DECODER == 1 */ #if (USE_JPEG_ENCODER == 1) static int32_t RED_Y_LUT[256]; /* Red to Y color conversion Look Up Table */ static int32_t RED_CB_LUT[256]; /* Red to Cb color conversion Look Up Table */ static int32_t BLUE_CB_RED_CR_LUT[256]; /* Red to Cr and Blue to Cb color conversion Look Up Table */ static int32_t GREEN_Y_LUT[256]; /* Green to Y color conversion Look Up Table*/ static int32_t GREEN_CR_LUT[256]; /* Green to Cr color conversion Look Up Table*/ static int32_t GREEN_CB_LUT[256]; /* Green to Cb color conversion Look Up Table*/ static int32_t BLUE_Y_LUT[256]; /* Blue to Y color conversion Look Up Table */ static int32_t BLUE_CR_LUT[256]; /* Blue to Cr color conversion Look Up Table */ /* Different MCU Look Up Table */ static uint16_t JPEG_Y_MCU_LUT[256]; static uint16_t JPEG_Y_MCU_444_LUT[64]; static uint16_t JPEG_Cb_MCU_420_LUT[256]; static uint16_t JPEG_Cb_MCU_422_LUT[256]; static uint16_t JPEG_Cb_MCU_444_LUT[64]; static uint16_t JPEG_Cr_MCU_420_LUT[256]; static uint16_t JPEG_Cr_MCU_422_LUT[256]; static uint16_t JPEG_Cr_MCU_444_LUT[64]; static uint16_t JPEG_K_MCU_420_LUT[256]; static uint16_t JPEG_K_MCU_422_LUT[256]; static uint16_t JPEG_K_MCU_444_LUT[64]; /* YCCK format blocks */ uint8_t kBlocks[16][16]; #endif /* USE_JPEG_ENCODER == 1 */ #if (USE_JPEG_DECODER == 1) /* color clamp table : used for range limitting */ static const uint8_t CLAMP_LUT[] = { /* clamp range 0xffffffff to 0xffffff00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* clamp range 0x00 to 0xff */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* clamp range 0x100 to 0x1ff */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }; #endif /* USE_JPEG_DECODER == 1 */ /** * @} */ /** @defgroup JPEG_Private_FunctionPrototypes JPEG Private FunctionPrototypes * @{ */ /* Private function prototypes -----------------------------------------------*/ #if (USE_JPEG_ENCODER == 1) static uint32_t JPEG_ARGB_MCU_YCbCr420_ConvertBlocks(uint8_t *pInBuffer, uint8_t *pOutBuffer, uint32_t BlockIndex, uint32_t DataCount, uint32_t *ConvertedDataCount); static uint32_t JPEG_ARGB_MCU_YCbCr422_ConvertBlocks(uint8_t *pInBuffer, uint8_t *pOutBuffer, uint32_t BlockIndex, uint32_t DataCount, uint32_t *ConvertedDataCount); static uint32_t JPEG_ARGB_MCU_YCbCr444_ConvertBlocks(uint8_t *pInBuffer, uint8_t *pOutBuffer, uint32_t BlockIndex, uint32_t DataCount, uint32_t *ConvertedDataCount); static uint32_t JPEG_ARGB_MCU_Gray_ConvertBlocks(uint8_t *pInBuffer, uint8_t *pOutBuffer, uint32_t BlockIndex, uint32_t DataCount, uint32_t *ConvertedDataCount); static uint32_t JPEG_ARGB_MCU_YCCK_ConvertBlocks(uint8_t *pInBuffer, uint8_t *pOutBuffer, uint32_t BlockIndex, uint32_t DataCount, uint32_t *ConvertedDataCount); static void JPEG_Init_MCU_LUT(void); static void JPEG_InitPreProcColorTables(void); static uint8_t *JPEG_Set_K_Blocks(uint8_t *pMCUBuffer, uint8_t pKBlocks[16][16], uint32_t ChromaSampling); #endif /* USE_JPEG_ENCODER == 1 */ #if (USE_JPEG_DECODER == 1) static uint32_t JPEG_MCU_YCbCr420_ARGB_ConvertBlocks(uint8_t *pInBuffer, uint8_t *pOutBuffer, uint32_t BlockIndex, uint32_t DataCount, uint32_t *ConvertedDataCount); static uint32_t JPEG_MCU_YCbCr422_ARGB_ConvertBlocks(uint8_t *pInBuffer, uint8_t *pOutBuffer, uint32_t BlockIndex, uint32_t DataCount, uint32_t *ConvertedDataCount); static uint32_t JPEG_MCU_YCbCr444_ARGB_ConvertBlocks(uint8_t *pInBuffer, uint8_t *pOutBuffer, uint32_t BlockIndex, uint32_t DataCount, uint32_t *ConvertedDataCount); static uint32_t JPEG_MCU_Gray_ARGB_ConvertBlocks(uint8_t *pInBuffer, uint8_t *pOutBuffer, uint32_t BlockIndex, uint32_t DataCount, uint32_t *ConvertedDataCount); static uint32_t JPEG_MCU_YCCK_ARGB_ConvertBlocks(uint8_t *pInBuffer, uint8_t *pOutBuffer, uint32_t BlockIndex, uint32_t DataCount, uint32_t *ConvertedDataCount); static void JPEG_InitPostProcColorTables(void); #endif /* USE_JPEG_DECODER == 1 */ /** * @} */ /** @defgroup JPEG_Private_Functions JPEG Private Functions * @{ */ #if (USE_JPEG_ENCODER == 1) /** * @brief Convert RGB to YCbCr 4:2:0 blocks pixels * @param pInBuffer : pointer to input RGB888/ARGB8888 frame buffer. * @param pOutBuffer : pointer to output YCbCr blocks buffer. * @param BlockIndex : index of the input buffer first block in the final image. * @param DataCount : number of bytes in the input buffer . * @param ConvertedDataCount : number of converted bytes from input buffer. * @retval Number of blcoks converted from RGB to YCbCr */ static uint32_t JPEG_ARGB_MCU_YCbCr420_ConvertBlocks (uint8_t *pInBuffer, uint8_t *pOutBuffer, uint32_t BlockIndex, uint32_t DataCount, uint32_t *ConvertedDataCount) { uint32_t numberMCU; uint32_t i,j, currentMCU, xRef,yRef, colones; uint32_t refline; int32_t ycomp, crcomp, cbcomp, offset; uint32_t red, green, blue; uint8_t *pOutAddr; uint8_t *pInAddr; numberMCU = ((3 * DataCount) / ( 2 * JPEG_BYTES_PER_PIXEL * YCBCR_420_BLOCK_SIZE)); currentMCU = BlockIndex; *ConvertedDataCount = numberMCU * JPEG_ConvertorParams.BlockSize; pOutAddr = &pOutBuffer[0]; while(currentMCU < (numberMCU + BlockIndex)) { xRef = ((currentMCU *JPEG_ConvertorParams.H_factor) / JPEG_ConvertorParams.WidthExtend)*JPEG_ConvertorParams.V_factor; yRef = ((currentMCU *JPEG_ConvertorParams.H_factor) % JPEG_ConvertorParams.WidthExtend); refline = JPEG_ConvertorParams.ScaledWidth * xRef + (JPEG_BYTES_PER_PIXEL*yRef); currentMCU++; if(((currentMCU *JPEG_ConvertorParams.H_factor) % JPEG_ConvertorParams.WidthExtend) == 0) { colones = JPEG_ConvertorParams.H_factor - JPEG_ConvertorParams.LineOffset; } else { colones = JPEG_ConvertorParams.H_factor; } offset = 0; for(i= 0; i < JPEG_ConvertorParams.V_factor; i+=2) { pInAddr = &pInBuffer[0] ; for(j=0; j < colones; j+=2) { /* First Pixel */ #if (JPEG_RGB_FORMAT == JPEG_RGB565) red = (((*(__IO uint16_t *)(pInAddr + refline)) & JPEG_RGB565_RED_MASK) >> JPEG_RED_OFFSET) ; green = (((*(__IO uint16_t *)(pInAddr + refline)) & JPEG_RGB565_GREEN_MASK) >> JPEG_GREEN_OFFSET) ; blue = (((*(__IO uint16_t *)(pInAddr + refline)) & JPEG_RGB565_BLUE_MASK) >> JPEG_BLUE_OFFSET) ; red = (red << 3) | (red >> 2); green = (green << 2) | (green >> 4); blue = (blue << 3) | (blue >> 2); #else red = (*(pInAddr + refline + JPEG_RED_OFFSET/8)) ; green = (*(pInAddr + refline + JPEG_GREEN_OFFSET/8)) ; blue = (*(pInAddr + refline + JPEG_BLUE_OFFSET/8)) ; #endif ycomp = (int32_t)(*(RED_Y_LUT + red)) + (int32_t)(*(GREEN_Y_LUT + green)) + (int32_t)(*(BLUE_Y_LUT + blue)); cbcomp = (int32_t)(*(RED_CB_LUT + red)) + (int32_t)(*(GREEN_CB_LUT + green)) + (int32_t)(*(BLUE_CB_RED_CR_LUT + blue)) + 128; crcomp = (int32_t)(*(BLUE_CB_RED_CR_LUT + red)) + (int32_t)(*(GREEN_CR_LUT + green)) + (int32_t)(*(BLUE_CR_LUT + blue)) + 128; (*(pOutAddr + JPEG_ConvertorParams.Y_MCU_LUT[offset])) = (ycomp); (*(pOutAddr + JPEG_ConvertorParams.Cb_MCU_LUT[offset])) = (cbcomp); (*(pOutAddr + JPEG_ConvertorParams.Cr_MCU_LUT[offset])) = (crcomp); /* Second Pixel */ #if (JPEG_RGB_FORMAT == JPEG_RGB565) red = (((*(__IO uint16_t *)(pInAddr + JPEG_BYTES_PER_PIXEL + refline)) & JPEG_RGB565_RED_MASK) >> JPEG_RED_OFFSET) ; green = (((*(__IO uint16_t *)(pInAddr + JPEG_BYTES_PER_PIXEL + refline)) & JPEG_RGB565_GREEN_MASK) >> JPEG_GREEN_OFFSET) ; blue = (((*(__IO uint16_t *)(pInAddr + JPEG_BYTES_PER_PIXEL + refline)) & JPEG_RGB565_BLUE_MASK) >> JPEG_BLUE_OFFSET) ; red = (red << 3) | (red >> 2); green = (green << 2) | (green >> 4); blue = (blue << 3) | (blue >> 2); #else red = (*(pInAddr + refline + JPEG_BYTES_PER_PIXEL + JPEG_RED_OFFSET/8)) ; green = (*(pInAddr + refline + JPEG_BYTES_PER_PIXEL + JPEG_GREEN_OFFSET/8)) ; blue = (*(pInAddr + refline + JPEG_BYTES_PER_PIXEL + JPEG_BLUE_OFFSET/8)) ; #endif ycomp = (int32_t)(*(RED_Y_LUT + red)) + (int32_t)(*(GREEN_Y_LUT + green)) + (int32_t)(*(BLUE_Y_LUT + blue)); (*(pOutAddr + JPEG_ConvertorParams.Y_MCU_LUT[offset + 1])) = (ycomp); /* Third Pixel */ #if (JPEG_RGB_FORMAT == JPEG_RGB565) red = (((*(__IO uint16_t *)(pInAddr + JPEG_ConvertorParams.ScaledWidth + refline)) & JPEG_RGB565_RED_MASK) >> JPEG_RED_OFFSET) ; green = (((*(__IO uint16_t *)(pInAddr + JPEG_ConvertorParams.ScaledWidth + refline)) & JPEG_RGB565_GREEN_MASK) >> JPEG_GREEN_OFFSET) ; blue = (((*(__IO uint16_t *)(pInAddr + JPEG_ConvertorParams.ScaledWidth + refline)) & JPEG_RGB565_BLUE_MASK) >> JPEG_BLUE_OFFSET) ; red = (red << 3) | (red >> 2); green = (green << 2) | (green >> 4); blue = (blue << 3) | (blue >> 2); #else red = (*(pInAddr + refline + JPEG_ConvertorParams.ScaledWidth + JPEG_RED_OFFSET/8)) ; green = (*(pInAddr + refline + JPEG_ConvertorParams.ScaledWidth + JPEG_GREEN_OFFSET/8)) ; blue = (*(pInAddr + refline + JPEG_ConvertorParams.ScaledWidth + JPEG_BLUE_OFFSET/8)) ; #endif ycomp = (int32_t)(*(RED_Y_LUT + red)) + (int32_t)(*(GREEN_Y_LUT + green)) + (int32_t)(*(BLUE_Y_LUT + blue)); (*(pOutAddr + JPEG_ConvertorParams.Y_MCU_LUT[offset + JPEG_ConvertorParams.H_factor])) = (ycomp); /* Fourth Pixel */ #if (JPEG_RGB_FORMAT == JPEG_RGB565) red = (((*(__IO uint16_t *)(pInAddr + refline + JPEG_ConvertorParams.ScaledWidth + JPEG_BYTES_PER_PIXEL)) & JPEG_RGB565_RED_MASK) >> JPEG_RED_OFFSET) ; green = (((*(__IO uint16_t *)(pInAddr + refline + JPEG_ConvertorParams.ScaledWidth + JPEG_BYTES_PER_PIXEL)) & JPEG_RGB565_GREEN_MASK) >> JPEG_GREEN_OFFSET) ; blue = (((*(__IO uint16_t *)(pInAddr + refline + JPEG_ConvertorParams.ScaledWidth + JPEG_BYTES_PER_PIXEL)) & JPEG_RGB565_BLUE_MASK) >> JPEG_BLUE_OFFSET) ; red = (red << 3) | (red >> 2); green = (green << 2) | (green >> 4); blue = (blue << 3) | (blue >> 2); #else red = (*(pInAddr + refline + JPEG_ConvertorParams.ScaledWidth + JPEG_BYTES_PER_PIXEL + JPEG_RED_OFFSET/8)) ; green = (*(pInAddr + refline + JPEG_ConvertorParams.ScaledWidth + JPEG_BYTES_PER_PIXEL + JPEG_GREEN_OFFSET/8)) ; blue = (*(pInAddr + refline + JPEG_ConvertorParams.ScaledWidth + JPEG_BYTES_PER_PIXEL + JPEG_BLUE_OFFSET/8)) ; #endif ycomp = (int32_t)(*(RED_Y_LUT + red)) + (int32_t)(*(GREEN_Y_LUT + green)) + (int32_t)(*(BLUE_Y_LUT + blue)); (*(pOutAddr + JPEG_ConvertorParams.Y_MCU_LUT[offset + JPEG_ConvertorParams.H_factor + 1])) = (ycomp); /****************/ pInAddr += JPEG_BYTES_PER_PIXEL * 2; offset+=2; } offset += JPEG_ConvertorParams.H_factor + (JPEG_ConvertorParams.H_factor - colones); refline += JPEG_ConvertorParams.ScaledWidth * 2 ; } pOutAddr += JPEG_ConvertorParams.BlockSize ; } return numberMCU; } /** * @brief Convert RGB to YCbCr 4:2:2 blocks pixels * @param pInBuffer : pointer to input RGB888/ARGB8888 frame buffer. * @param pOutBuffer : pointer to output YCbCr blocks buffer. * @param BlockIndex : index of the input buffer first block in the final image. * @param DataCount : number of bytes in the input buffer . * @param ConvertedDataCount : number of converted bytes from input buffer. * @retval Number of blcoks converted from RGB to YCbCr */ static uint32_t JPEG_ARGB_MCU_YCbCr422_ConvertBlocks (uint8_t *pInBuffer, uint8_t *pOutBuffer, uint32_t BlockIndex, uint32_t DataCount, uint32_t *ConvertedDataCount) { uint32_t numberMCU; uint32_t i,j, currentMCU, xRef,yRef, colones; uint32_t refline; int32_t ycomp, crcomp, cbcomp, offset; uint32_t red, green, blue; uint8_t *pOutAddr; uint8_t *pInAddr; numberMCU = ((2 * DataCount) / (JPEG_BYTES_PER_PIXEL * YCBCR_422_BLOCK_SIZE)); currentMCU = BlockIndex; *ConvertedDataCount = numberMCU * JPEG_ConvertorParams.BlockSize; pOutAddr = &pOutBuffer[0]; while(currentMCU < (numberMCU + BlockIndex)) { xRef = ((currentMCU *JPEG_ConvertorParams.H_factor) / JPEG_ConvertorParams.WidthExtend)*JPEG_ConvertorParams.V_factor; yRef = ((currentMCU *JPEG_ConvertorParams.H_factor) % JPEG_ConvertorParams.WidthExtend); refline = JPEG_ConvertorParams.ScaledWidth * xRef + (JPEG_BYTES_PER_PIXEL*yRef); currentMCU++; if(((currentMCU *JPEG_ConvertorParams.H_factor) % JPEG_ConvertorParams.WidthExtend) == 0) { colones = JPEG_ConvertorParams.H_factor - JPEG_ConvertorParams.LineOffset; } else { colones = JPEG_ConvertorParams.H_factor; } offset = 0; for(i= 0; i < JPEG_ConvertorParams.V_factor; i+=1) { pInAddr = &pInBuffer[0] ; for(j=0; j < colones; j+=2) { /* First Pixel */ #if (JPEG_RGB_FORMAT == JPEG_RGB565) red = (((*(__IO uint16_t *)(pInAddr + refline)) & JPEG_RGB565_RED_MASK) >> JPEG_RED_OFFSET) ; green = (((*(__IO uint16_t *)(pInAddr + refline)) & JPEG_RGB565_GREEN_MASK) >> JPEG_GREEN_OFFSET) ; blue = (((*(__IO uint16_t *)(pInAddr + refline)) & JPEG_RGB565_BLUE_MASK) >> JPEG_BLUE_OFFSET) ; red = (red << 3) | (red >> 2); green = (green << 2) | (green >> 4); blue = (blue << 3) | (blue >> 2); #else red = (*(pInAddr + refline + JPEG_RED_OFFSET/8)) ; green = (*(pInAddr + refline + JPEG_GREEN_OFFSET/8)) ; blue = (*(pInAddr + refline + JPEG_BLUE_OFFSET/8)) ; #endif ycomp = (int32_t)(*(RED_Y_LUT + red)) + (int32_t)(*(GREEN_Y_LUT + green)) + (int32_t)(*(BLUE_Y_LUT + blue)); cbcomp = (int32_t)(*(RED_CB_LUT + red)) + (int32_t)(*(GREEN_CB_LUT + green)) + (int32_t)(*(BLUE_CB_RED_CR_LUT + blue)) + 128; crcomp = (int32_t)(*(BLUE_CB_RED_CR_LUT + red)) + (int32_t)(*(GREEN_CR_LUT + green)) + (int32_t)(*(BLUE_CR_LUT + blue)) + 128; (*(pOutAddr + JPEG_ConvertorParams.Y_MCU_LUT[offset])) = ycomp; (*(pOutAddr + JPEG_ConvertorParams.Cb_MCU_LUT[offset])) = cbcomp; (*(pOutAddr + JPEG_ConvertorParams.Cr_MCU_LUT[offset])) = crcomp; /* Second Pixel */ #if (JPEG_RGB_FORMAT == JPEG_RGB565) red = (((*(__IO uint16_t *)(pInAddr + refline + JPEG_BYTES_PER_PIXEL)) & JPEG_RGB565_RED_MASK) >> JPEG_RED_OFFSET) ; green = (((*(__IO uint16_t *)(pInAddr + refline + JPEG_BYTES_PER_PIXEL)) & JPEG_RGB565_GREEN_MASK) >> JPEG_GREEN_OFFSET) ; blue = (((*(__IO uint16_t *)(pInAddr + refline + JPEG_BYTES_PER_PIXEL)) & JPEG_RGB565_BLUE_MASK) >> JPEG_BLUE_OFFSET) ; red = (red << 3) | (red >> 2); green = (green << 2) | (green >> 4); blue = (blue << 3) | (blue >> 2); #else red = (*(pInAddr + refline + JPEG_BYTES_PER_PIXEL + JPEG_RED_OFFSET/8)) ; green = (*(pInAddr + refline + JPEG_BYTES_PER_PIXEL + JPEG_GREEN_OFFSET/8)) ; blue = (*(pInAddr + refline + JPEG_BYTES_PER_PIXEL + JPEG_BLUE_OFFSET/8)) ; #endif ycomp = (int32_t)(*(RED_Y_LUT + red)) + (int32_t)(*(GREEN_Y_LUT + green)) + (int32_t)(*(BLUE_Y_LUT + blue)); (*(pOutAddr + JPEG_ConvertorParams.Y_MCU_LUT[offset + 1])) = ycomp; /****************/ pInAddr += JPEG_BYTES_PER_PIXEL * 2; offset+=2; } offset += (JPEG_ConvertorParams.H_factor - colones); refline += JPEG_ConvertorParams.ScaledWidth ; } pOutAddr += JPEG_ConvertorParams.BlockSize; } return numberMCU; } /** * @brief Convert RGB to YCbCr 4:4:4 blocks pixels * @param pInBuffer : pointer to input RGB888/ARGB8888 frame buffer. * @param pOutBuffer : pointer to output YCbCr blocks buffer. * @param BlockIndex : index of the input buffer first block in the final image. * @param DataCount : number of bytes in the input buffer . * @param ConvertedDataCount : number of converted bytes from input buffer. * @retval Number of blcoks converted from RGB to YCbCr */ static uint32_t JPEG_ARGB_MCU_YCbCr444_ConvertBlocks (uint8_t *pInBuffer, uint8_t *pOutBuffer, uint32_t BlockIndex, uint32_t DataCount, uint32_t *ConvertedDataCount) { uint32_t numberMCU; uint32_t i,j, currentMCU, xRef,yRef, colones; uint32_t refline; int32_t ycomp, crcomp, cbcomp, offset; uint32_t red, green, blue; uint8_t *pOutAddr; uint8_t *pInAddr; numberMCU = ((3 * DataCount) / (JPEG_BYTES_PER_PIXEL * YCBCR_444_BLOCK_SIZE)); currentMCU = BlockIndex; *ConvertedDataCount = numberMCU * JPEG_ConvertorParams.BlockSize; pOutAddr = &pOutBuffer[0]; while(currentMCU < (numberMCU + BlockIndex)) { xRef = ((currentMCU *JPEG_ConvertorParams.H_factor) / JPEG_ConvertorParams.WidthExtend)*JPEG_ConvertorParams.V_factor; yRef = ((currentMCU *JPEG_ConvertorParams.H_factor) % JPEG_ConvertorParams.WidthExtend); refline = JPEG_ConvertorParams.ScaledWidth * xRef + (JPEG_BYTES_PER_PIXEL*yRef); currentMCU++; if(((currentMCU *JPEG_ConvertorParams.H_factor) % JPEG_ConvertorParams.WidthExtend) == 0) { colones = JPEG_ConvertorParams.H_factor - JPEG_ConvertorParams.LineOffset; } else { colones = JPEG_ConvertorParams.H_factor; } offset = 0; for(i= 0; i < JPEG_ConvertorParams.V_factor; i++) { pInAddr = &pInBuffer[0] ; for(j=0; j < colones; j++) { #if (JPEG_RGB_FORMAT == JPEG_RGB565) red = (((*(__IO uint16_t *)(pInAddr + refline)) & JPEG_RGB565_RED_MASK) >> JPEG_RED_OFFSET) ; green = (((*(__IO uint16_t *)(pInAddr + refline)) & JPEG_RGB565_GREEN_MASK) >> JPEG_GREEN_OFFSET) ; blue = (((*(__IO uint16_t *)(pInAddr + refline)) & JPEG_RGB565_BLUE_MASK) >> JPEG_BLUE_OFFSET) ; red = (red << 3) | (red >> 2); green = (green << 2) | (green >> 4); blue = (blue << 3) | (blue >> 2); #else red = (*(pInAddr + refline + JPEG_RED_OFFSET/8)) ; green = (*(pInAddr + refline + JPEG_GREEN_OFFSET/8)) ; blue = (*(pInAddr + refline + JPEG_BLUE_OFFSET/8)) ; #endif ycomp = (int32_t)(*(RED_Y_LUT + red)) + (int32_t)(*(GREEN_Y_LUT + green)) + (int32_t)(*(BLUE_Y_LUT + blue)); cbcomp = (int32_t)(*(RED_CB_LUT + red)) + (int32_t)(*(GREEN_CB_LUT + green)) + (int32_t)(*(BLUE_CB_RED_CR_LUT + blue)) + 128; crcomp = (int32_t)(*(BLUE_CB_RED_CR_LUT + red)) + (int32_t)(*(GREEN_CR_LUT + green)) + (int32_t)(*(BLUE_CR_LUT + blue)) + 128; (*(pOutAddr + JPEG_ConvertorParams.Y_MCU_LUT[offset])) = (ycomp); (*(pOutAddr + JPEG_ConvertorParams.Cb_MCU_LUT[offset])) = (cbcomp); (*(pOutAddr + JPEG_ConvertorParams.Cr_MCU_LUT[offset])) = (crcomp); pInAddr += JPEG_BYTES_PER_PIXEL; offset++; } offset += (JPEG_ConvertorParams.H_factor - colones); refline += JPEG_ConvertorParams.ScaledWidth; } pOutAddr += JPEG_ConvertorParams.BlockSize; } return numberMCU; } /** * @brief Convert RGB to Gray blocks pixels * @param pInBuffer : pointer to input RGB888/ARGB8888 blocks. * @param pOutBuffer : pointer to output Gray blocks buffer. * @param BlockIndex : index of the input buffer first block in the final image. * @param DataCount : number of bytes in the input buffer . * @param ConvertedDataCount : number of converted bytes from input buffer. * @retval Number of blcoks converted from RGB to Gray */ static uint32_t JPEG_ARGB_MCU_Gray_ConvertBlocks(uint8_t *pInBuffer, uint8_t *pOutBuffer, uint32_t BlockIndex, uint32_t DataCount, uint32_t *ConvertedDataCount) { uint32_t numberMCU; uint32_t i,j, currentMCU, xRef,yRef, colones; uint32_t refline; int32_t offset; uint32_t red, green, blue; uint8_t *pOutAddr; uint8_t *pInAddr; uint8_t ycomp; numberMCU = (DataCount / (JPEG_BYTES_PER_PIXEL * GRAY_444_BLOCK_SIZE)); currentMCU = BlockIndex; *ConvertedDataCount = numberMCU * GRAY_444_BLOCK_SIZE; pOutAddr = &pOutBuffer[0]; while(currentMCU < (numberMCU + BlockIndex)) { xRef = ((currentMCU *JPEG_ConvertorParams.H_factor) / JPEG_ConvertorParams.WidthExtend)*JPEG_ConvertorParams.V_factor; yRef = ((currentMCU *JPEG_ConvertorParams.H_factor) % JPEG_ConvertorParams.WidthExtend); refline = JPEG_ConvertorParams.ScaledWidth * xRef + (JPEG_BYTES_PER_PIXEL*yRef); currentMCU++; if(((currentMCU *JPEG_ConvertorParams.H_factor) % JPEG_ConvertorParams.WidthExtend) == 0) { colones = JPEG_ConvertorParams.H_factor - JPEG_ConvertorParams.LineOffset; } else { colones = JPEG_ConvertorParams.H_factor; } offset = 0; for(i= 0; i < JPEG_ConvertorParams.V_factor; i++) { pInAddr = &pInBuffer[0] ; for(j=0; j < colones; j++) { #if (JPEG_RGB_FORMAT == JPEG_RGB565) red = (((*(__IO uint16_t *)(pInAddr + refline)) & JPEG_RGB565_RED_MASK) >> JPEG_RED_OFFSET) ; green = (((*(__IO uint16_t *)(pInAddr + refline)) & JPEG_RGB565_GREEN_MASK) >> JPEG_GREEN_OFFSET) ; blue = (((*(__IO uint16_t *)(pInAddr + refline)) & JPEG_RGB565_BLUE_MASK) >> JPEG_BLUE_OFFSET) ; red = (red << 3) | (red >> 2); green = (green << 2) | (green >> 4); blue = (blue << 3) | (blue >> 2); #else red = (*(pInAddr + refline + JPEG_RED_OFFSET/8)) ; green = (*(pInAddr + refline + JPEG_GREEN_OFFSET/8)) ; blue = (*(pInAddr + refline + JPEG_BLUE_OFFSET/8)) ; #endif ycomp = (uint8_t)((int32_t)(*(RED_Y_LUT + red)) + (int32_t)(*(GREEN_Y_LUT + green)) + (int32_t)(*(BLUE_Y_LUT + blue))); (*(pOutAddr + offset)) = (ycomp); pInAddr += JPEG_BYTES_PER_PIXEL; offset++; } offset += (JPEG_ConvertorParams.H_factor - colones); refline += JPEG_ConvertorParams.ScaledWidth; } pOutAddr += JPEG_ConvertorParams.BlockSize; } return numberMCU; } /** * @brief Convert RGB to YCCK blocks pixels * @param pInBuffer : pointer to input RGB888/ARGB8888 blocks. * @param pOutBuffer : pointer to output YCCK blocks buffer. * @param BlockIndex : index of the input buffer first block in the final image. * @param DataCount : number of bytes in the input buffer . * @param ConvertedDataCount : number of converted bytes from input buffer. * @retval Number of blcoks converted from RGB to YCCK */ static uint32_t JPEG_ARGB_MCU_YCCK_ConvertBlocks(uint8_t *pInBuffer, uint8_t *pOutBuffer, uint32_t BlockIndex, uint32_t DataCount, uint32_t *ConvertedDataCount) { uint32_t numberMCU; uint32_t i,j, currentMCU, xRef,yRef, colones; uint32_t refline; uint32_t offset; int32_t red, green, blue, color_k ; uint8_t *pOutAddr; uint8_t *pInAddr; numberMCU = ((3 * DataCount) / (JPEG_BYTES_PER_PIXEL * CMYK_444_BLOCK_SIZE)); *ConvertedDataCount = numberMCU * CMYK_444_BLOCK_SIZE; currentMCU = BlockIndex; pOutAddr = &pOutBuffer[0]; while(currentMCU < (numberMCU + BlockIndex)) { xRef = ((currentMCU *JPEG_ConvertorParams.H_factor) / JPEG_ConvertorParams.WidthExtend)*JPEG_ConvertorParams.V_factor; yRef = ((currentMCU *JPEG_ConvertorParams.H_factor) % JPEG_ConvertorParams.WidthExtend); refline = JPEG_ConvertorParams.ScaledWidth * xRef + (JPEG_BYTES_PER_PIXEL*yRef); currentMCU++; if(((currentMCU *JPEG_ConvertorParams.H_factor) % JPEG_ConvertorParams.WidthExtend) == 0) { colones = JPEG_ConvertorParams.H_factor - JPEG_ConvertorParams.LineOffset; } else { colones = JPEG_ConvertorParams.H_factor; } offset = 0; for(i= 0; i < JPEG_ConvertorParams.V_factor; i++) { pInAddr = &pInBuffer[refline]; for(j=0; j < colones; j++) { #if (JPEG_RGB_FORMAT == JPEG_RGB565) red = (((*(__IO uint16_t *)(pInAddr + refline)) & JPEG_RGB565_RED_MASK) >> JPEG_RED_OFFSET) ; green = (((*(__IO uint16_t *)(pInAddr + refline)) & JPEG_RGB565_GREEN_MASK) >> JPEG_GREEN_OFFSET) ; blue = (((*(__IO uint16_t *)(pInAddr + refline)) & JPEG_RGB565_BLUE_MASK) >> JPEG_BLUE_OFFSET) ; red = (red << 3) | (red >> 2); green = (green << 2) | (green >> 4); blue = (blue << 3) | (blue >> 2); #else red = (*(pInAddr + JPEG_RED_OFFSET/8)) ; green = (*(pInAddr + JPEG_GREEN_OFFSET/8)) ; blue = (*(pInAddr + JPEG_BLUE_OFFSET/8)) ; #endif color_k = MAX(MAX(red,green),blue); kBlocks[i][j]=color_k; (*(pOutAddr + JPEG_ConvertorParams.Y_MCU_LUT[offset])) = red * 255 / color_k; (*(pOutAddr + JPEG_ConvertorParams.Cb_MCU_LUT[offset])) = green * 255 / color_k; (*(pOutAddr + JPEG_ConvertorParams.Cr_MCU_LUT[offset])) = blue * 255 / color_k; pInAddr += JPEG_BYTES_PER_PIXEL; offset++; } offset += (JPEG_ConvertorParams.H_factor - colones); refline += JPEG_ConvertorParams.ScaledWidth; } JPEG_Set_K_Blocks(pOutAddr, kBlocks, JPEG_ConvertorParams.ChromaSubsampling); pOutAddr += JPEG_ConvertorParams.BlockSize; } return numberMCU; } /** * @brief Retrive Encoding RGB to YCbCr color conversion function and block number * @param pJpegInfo : JPEG_ConfTypeDef that contains the JPEG image informations. * These info are available in the HAL callback "HAL_JPEG_InfoReadyCallback". * @param pFunction : pointer to JPEG_RGBToYCbCr_Convert_Function , used to retrive the color conversion function * depending of the jpeg image color space and chroma sampling info. * @param ImageNbMCUs : pointer to uint32_t, used to retrive the total number of MCU blocks in the jpeg image. * @retval HAL status : HAL_OK or HAL_ERROR. */ HAL_StatusTypeDef JPEG_GetEncodeColorConvertFunc(JPEG_ConfTypeDef *pJpegInfo, JPEG_RGBToYCbCr_Convert_Function *pFunction, uint32_t *ImageNbMCUs) { uint32_t hMCU, vMCU; JPEG_ConvertorParams.ColorSpace = pJpegInfo->ColorSpace; JPEG_ConvertorParams.ChromaSubsampling = pJpegInfo->ChromaSubsampling; if(JPEG_ConvertorParams.ColorSpace == JPEG_YCBCR_COLORSPACE) { if(JPEG_ConvertorParams.ChromaSubsampling == JPEG_420_SUBSAMPLING) { *pFunction = JPEG_ARGB_MCU_YCbCr420_ConvertBlocks; } else if (JPEG_ConvertorParams.ChromaSubsampling == JPEG_422_SUBSAMPLING) { *pFunction = JPEG_ARGB_MCU_YCbCr422_ConvertBlocks; } else if (JPEG_ConvertorParams.ChromaSubsampling == JPEG_444_SUBSAMPLING) { *pFunction = JPEG_ARGB_MCU_YCbCr444_ConvertBlocks; } else { return HAL_ERROR; /* Chroma SubSampling Not supported*/ } } else if(JPEG_ConvertorParams.ColorSpace == JPEG_GRAYSCALE_COLORSPACE) { *pFunction = JPEG_ARGB_MCU_Gray_ConvertBlocks; } else if(JPEG_ConvertorParams.ColorSpace == JPEG_CMYK_COLORSPACE) { *pFunction = JPEG_ARGB_MCU_YCCK_ConvertBlocks; } else { return HAL_ERROR; /* Color space Not supported*/ } JPEG_ConvertorParams.ImageWidth = pJpegInfo->ImageWidth; JPEG_ConvertorParams.ImageHeight = pJpegInfo->ImageHeight; JPEG_ConvertorParams.ImageSize_Bytes = pJpegInfo->ImageWidth * pJpegInfo->ImageHeight * JPEG_BYTES_PER_PIXEL; if((JPEG_ConvertorParams.ChromaSubsampling == JPEG_420_SUBSAMPLING) || (JPEG_ConvertorParams.ChromaSubsampling == JPEG_422_SUBSAMPLING)) { JPEG_ConvertorParams.LineOffset = JPEG_ConvertorParams.ImageWidth % 16; JPEG_ConvertorParams.Y_MCU_LUT = JPEG_Y_MCU_LUT; if(JPEG_ConvertorParams.LineOffset != 0) { JPEG_ConvertorParams.LineOffset = 16 - JPEG_ConvertorParams.LineOffset; } JPEG_ConvertorParams.H_factor = 16; if(JPEG_ConvertorParams.ChromaSubsampling == JPEG_420_SUBSAMPLING) { JPEG_ConvertorParams.V_factor = 16; if(JPEG_ConvertorParams.ColorSpace == JPEG_YCBCR_COLORSPACE) { JPEG_ConvertorParams.BlockSize = YCBCR_420_BLOCK_SIZE; } JPEG_ConvertorParams.Cb_MCU_LUT = JPEG_Cb_MCU_420_LUT; JPEG_ConvertorParams.Cr_MCU_LUT = JPEG_Cr_MCU_420_LUT; JPEG_ConvertorParams.K_MCU_LUT = JPEG_K_MCU_420_LUT; } else /* 4:2:2*/ { JPEG_ConvertorParams.V_factor = 8; if(JPEG_ConvertorParams.ColorSpace == JPEG_YCBCR_COLORSPACE) { JPEG_ConvertorParams.BlockSize = YCBCR_422_BLOCK_SIZE; } JPEG_ConvertorParams.Cb_MCU_LUT = JPEG_Cb_MCU_422_LUT; JPEG_ConvertorParams.Cr_MCU_LUT = JPEG_Cr_MCU_422_LUT; JPEG_ConvertorParams.K_MCU_LUT = JPEG_K_MCU_422_LUT; } } else if(JPEG_ConvertorParams.ChromaSubsampling == JPEG_444_SUBSAMPLING) { JPEG_ConvertorParams.LineOffset = JPEG_ConvertorParams.ImageWidth % 8; JPEG_ConvertorParams.Y_MCU_LUT = JPEG_Y_MCU_444_LUT; JPEG_ConvertorParams.Cb_MCU_LUT = JPEG_Cb_MCU_444_LUT; JPEG_ConvertorParams.Cr_MCU_LUT = JPEG_Cr_MCU_444_LUT; JPEG_ConvertorParams.K_MCU_LUT = JPEG_K_MCU_444_LUT; if(JPEG_ConvertorParams.LineOffset != 0) { JPEG_ConvertorParams.LineOffset = 8 - JPEG_ConvertorParams.LineOffset; } JPEG_ConvertorParams.H_factor = 8; JPEG_ConvertorParams.V_factor = 8; if(JPEG_ConvertorParams.ColorSpace == JPEG_YCBCR_COLORSPACE) { JPEG_ConvertorParams.BlockSize = YCBCR_444_BLOCK_SIZE; } if(JPEG_ConvertorParams.ColorSpace == JPEG_CMYK_COLORSPACE) { JPEG_ConvertorParams.BlockSize = CMYK_444_BLOCK_SIZE; } else if(JPEG_ConvertorParams.ColorSpace == JPEG_GRAYSCALE_COLORSPACE) { JPEG_ConvertorParams.BlockSize = GRAY_444_BLOCK_SIZE; } } else { return HAL_ERROR; /* Not supported*/ } JPEG_ConvertorParams.WidthExtend = JPEG_ConvertorParams.ImageWidth + JPEG_ConvertorParams.LineOffset; JPEG_ConvertorParams.ScaledWidth = JPEG_BYTES_PER_PIXEL * JPEG_ConvertorParams.ImageWidth; hMCU = (JPEG_ConvertorParams.ImageWidth / JPEG_ConvertorParams.H_factor); if((JPEG_ConvertorParams.ImageWidth % JPEG_ConvertorParams.H_factor) != 0) { hMCU++; /*+1 for horizenatl incomplete MCU */ } vMCU = (JPEG_ConvertorParams.ImageHeight / JPEG_ConvertorParams.V_factor); if((JPEG_ConvertorParams.ImageHeight % JPEG_ConvertorParams.V_factor) != 0) { vMCU++; /*+1 for vertical incomplete MCU */ } JPEG_ConvertorParams.MCU_Total_Nb = (hMCU * vMCU); *ImageNbMCUs = JPEG_ConvertorParams.MCU_Total_Nb; return HAL_OK; } #endif /* USE_JPEG_ENCODER == 1 */ #if (USE_JPEG_DECODER == 1) /** * @brief Convert YCbCr 4:2:0 blocks to RGB pixels * @param pInBuffer : pointer to input YCbCr blocks buffer. * @param pOutBuffer : pointer to output RGB888/ARGB8888 frame buffer. * @param BlockIndex : index of the input buffer first block in the final image. * @param DataCount : number of bytes in the input buffer . * @param ConvertedDataCount : number of converted bytes from input buffer. * @retval Number of blcoks converted from YCbCr to RGB */ static uint32_t JPEG_MCU_YCbCr420_ARGB_ConvertBlocks(uint8_t *pInBuffer, uint8_t *pOutBuffer, uint32_t BlockIndex, uint32_t DataCount, uint32_t *ConvertedDataCount) { uint32_t numberMCU; uint32_t i,j,k, currentMCU, xRef,yRef; uint32_t refline; int32_t ycomp, crcomp, cbcomp; int32_t c_red, c_blue, c_green; uint8_t *pOutAddr, *pOutAddr2; uint8_t *pChrom, *pLum; numberMCU = DataCount / YCBCR_420_BLOCK_SIZE; currentMCU = BlockIndex; while(currentMCU < (numberMCU + BlockIndex)) { xRef = ((currentMCU *16) / JPEG_ConvertorParams.WidthExtend)*16; yRef = ((currentMCU *16) % JPEG_ConvertorParams.WidthExtend); refline = JPEG_ConvertorParams.ScaledWidth * xRef + (JPEG_BYTES_PER_PIXEL*yRef); currentMCU++; pChrom = pInBuffer + 256; /* pChroma = pInBuffer + 4*64 */ pLum = pInBuffer; for(i= 0; i < 16; i+=2) { if(i == 8) { pLum = pInBuffer + 128; } if(refline < JPEG_ConvertorParams.ImageSize_Bytes) { pOutAddr = pOutBuffer + refline; pOutAddr2 = pOutAddr + JPEG_ConvertorParams.ScaledWidth; for(k= 0; k<2; k++) { for(j=0; j < 8; j+=2) { cbcomp = (int32_t)(*(pChrom)); c_blue = (int32_t)(*(CB_BLUE_LUT + cbcomp)); crcomp = (int32_t)(*(pChrom + 64)); c_red = (int32_t)(*(CR_RED_LUT + crcomp)); c_green = ((int32_t)(*(CR_GREEN_LUT + crcomp)) + (int32_t)(*(CB_GREEN_LUT + cbcomp))) >> 16; #if (JPEG_RGB_FORMAT == JPEG_ARGB8888) ycomp = (int32_t)(*(pLum +j)); *(__IO uint32_t *)pOutAddr = (CLAMP(ycomp + c_red) << JPEG_RED_OFFSET) | \ (CLAMP( ycomp + c_green) << JPEG_GREEN_OFFSET) | \ (CLAMP(ycomp + c_blue) << JPEG_BLUE_OFFSET); /**********/ ycomp = (int32_t)(*(pLum +j +1)); *((__IO uint32_t *)(pOutAddr + 4)) = (CLAMP(ycomp + c_red) << JPEG_RED_OFFSET) | \ (CLAMP( ycomp + c_green) << JPEG_GREEN_OFFSET) | \ (CLAMP(ycomp + c_blue) << JPEG_BLUE_OFFSET); /**********/ ycomp = (int32_t)(*(pLum +j +8)); *(__IO uint32_t *)pOutAddr2 = (CLAMP(ycomp + c_red) << JPEG_RED_OFFSET) | \ (CLAMP( ycomp + c_green) << JPEG_GREEN_OFFSET) | \ (CLAMP(ycomp + c_blue) << JPEG_BLUE_OFFSET); /**********/ ycomp = (int32_t)(*(pLum +j +8 +1)); *((__IO uint32_t *)(pOutAddr2 +4)) = (CLAMP(ycomp + c_red) << JPEG_RED_OFFSET) | \ (CLAMP( ycomp + c_green) << JPEG_GREEN_OFFSET) | \ (CLAMP(ycomp + c_blue) << JPEG_BLUE_OFFSET); #elif (JPEG_RGB_FORMAT == JPEG_RGB888) ycomp = (int32_t)(*(pLum +j)); pOutAddr[JPEG_RED_OFFSET/8] = CLAMP(ycomp + c_red); pOutAddr[JPEG_GREEN_OFFSET/8] = CLAMP(ycomp + c_green); pOutAddr[JPEG_BLUE_OFFSET/8] = CLAMP(ycomp + c_blue); /**********/ ycomp = (int32_t)(*(pLum +j +1)); pOutAddr[3 + JPEG_RED_OFFSET/8] = CLAMP(ycomp + c_red); pOutAddr[3 + JPEG_GREEN_OFFSET/8] = CLAMP(ycomp + c_green); pOutAddr[3 + JPEG_BLUE_OFFSET/8] = CLAMP(ycomp + c_blue); /**********/ ycomp = (int32_t)(*(pLum +j +8)); pOutAddr2[JPEG_RED_OFFSET/8] = CLAMP(ycomp + c_red); pOutAddr2[JPEG_GREEN_OFFSET/8] = CLAMP(ycomp + c_green); pOutAddr2[JPEG_BLUE_OFFSET/8] = CLAMP(ycomp + c_blue); /**********/ ycomp = (int32_t)(*(pLum +j +8 +1)); pOutAddr2[3+ JPEG_RED_OFFSET/8] = CLAMP(ycomp + c_red); pOutAddr2[3 + JPEG_GREEN_OFFSET/8] = CLAMP(ycomp + c_green); pOutAddr2[3 + JPEG_BLUE_OFFSET/8] = CLAMP(ycomp + c_blue); #elif (JPEG_RGB_FORMAT == JPEG_RGB565) ycomp = (int32_t)(*(pLum +j)); *(__IO uint16_t *)pOutAddr = ((CLAMP(ycomp + c_red) >> 3) << JPEG_RED_OFFSET) | \ ((CLAMP( ycomp + c_green) >> 2) << JPEG_GREEN_OFFSET) | \ ((CLAMP(ycomp + c_blue) >> 3) << JPEG_BLUE_OFFSET); /**********/ ycomp = (int32_t)(*(pLum +j +1)); *((__IO uint16_t *)(pOutAddr + 2)) = ((CLAMP(ycomp + c_red) >> 3) << JPEG_RED_OFFSET) | \ ((CLAMP( ycomp + c_green) >> 2) << JPEG_GREEN_OFFSET) | \ ((CLAMP(ycomp + c_blue) >> 3) << JPEG_BLUE_OFFSET); /**********/ ycomp = (int32_t)(*(pLum +j +8)); *(__IO uint16_t *)pOutAddr2 = ((CLAMP(ycomp + c_red) >> 3) << JPEG_RED_OFFSET) | \ ((CLAMP( ycomp + c_green) >> 2) << JPEG_GREEN_OFFSET) | \ ((CLAMP(ycomp + c_blue) >> 3) << JPEG_BLUE_OFFSET); /**********/ ycomp = (int32_t)(*(pLum +j +8 +1)); *((__IO uint16_t *)(pOutAddr2 +2)) = ((CLAMP(ycomp + c_red) >> 3) << JPEG_RED_OFFSET) | \ ((CLAMP( ycomp + c_green) >> 2) << JPEG_GREEN_OFFSET) | \ ((CLAMP(ycomp + c_blue) >> 3) << JPEG_BLUE_OFFSET); #endif /* JPEG_RGB_FORMAT */ pOutAddr += JPEG_BYTES_PER_PIXEL * 2; pOutAddr2 += JPEG_BYTES_PER_PIXEL * 2; pChrom++; } pLum += 64; } pLum = pLum - 128 + 16; refline += 2*JPEG_ConvertorParams.ScaledWidth; } } pInBuffer += YCBCR_420_BLOCK_SIZE; } return numberMCU; } /** * @brief Convert YCbCr 4:2:2 blocks to RGB pixels * @param pInBuffer : pointer to input YCbCr blocks buffer. * @param pOutBuffer : pointer to output RGB888/ARGB8888 frame buffer. * @param BlockIndex : index of the input buffer first block in the final image. * @param DataCount : number of bytes in the input buffer . * @param ConvertedDataCount : number of converted bytes from input buffer. * @retval Number of blcoks converted from YCbCr to RGB */ static uint32_t JPEG_MCU_YCbCr422_ARGB_ConvertBlocks(uint8_t *pInBuffer, uint8_t *pOutBuffer, uint32_t BlockIndex, uint32_t DataCount, uint32_t *ConvertedDataCount) { uint32_t numberMCU; uint32_t i,j,k, currentMCU, xRef,yRef; uint32_t refline; int32_t ycomp, crcomp, cbcomp; int32_t c_red, c_blue, c_green; uint8_t *pOutAddr; uint8_t *pChrom, *pLum; numberMCU = DataCount / YCBCR_422_BLOCK_SIZE; currentMCU = BlockIndex; while(currentMCU < (numberMCU + BlockIndex)) { xRef = ((currentMCU *16) / JPEG_ConvertorParams.WidthExtend)*8; yRef = ((currentMCU *16) % JPEG_ConvertorParams.WidthExtend); refline = JPEG_ConvertorParams.ScaledWidth * xRef + (JPEG_BYTES_PER_PIXEL*yRef); currentMCU++; pChrom = pInBuffer + 128; /* pChroma = pInBuffer + 2*64 */ pLum = pInBuffer; for(i= 0; i < 8; i++) { if(refline < JPEG_ConvertorParams.ImageSize_Bytes) { pOutAddr = pOutBuffer + refline; for(k= 0; k<2; k++) { for(j=0; j < 8; j+=2) { cbcomp = (int32_t)(*(pChrom)); c_blue = (int32_t)(*(CB_BLUE_LUT + cbcomp)); crcomp = (int32_t)(*(pChrom + 64)); c_red = (int32_t)(*(CR_RED_LUT + crcomp)); c_green = ((int32_t)(*(CR_GREEN_LUT + crcomp)) + (int32_t)(*(CB_GREEN_LUT + cbcomp))) >> 16; #if (JPEG_RGB_FORMAT == JPEG_ARGB8888) ycomp = (int32_t)(*(pLum +j)); *(__IO uint32_t *)pOutAddr = (CLAMP(ycomp + c_red) << JPEG_RED_OFFSET) | \ (CLAMP( ycomp + c_green) << JPEG_GREEN_OFFSET) | \ (CLAMP(ycomp + c_blue) << JPEG_BLUE_OFFSET); /**********/ ycomp = (int32_t)(*(pLum +j +1)); *((__IO uint32_t *)(pOutAddr + 4)) = (CLAMP(ycomp + c_red) << JPEG_RED_OFFSET) | \ (CLAMP( ycomp + c_green) << JPEG_GREEN_OFFSET) | \ (CLAMP(ycomp + c_blue) << JPEG_BLUE_OFFSET); #elif (JPEG_RGB_FORMAT == JPEG_RGB888) ycomp = (int32_t)(*(pLum +j)); pOutAddr[JPEG_RED_OFFSET/8] = CLAMP(ycomp + c_red); pOutAddr[JPEG_GREEN_OFFSET/8] = CLAMP(ycomp + c_green); pOutAddr[JPEG_BLUE_OFFSET/8] = CLAMP(ycomp + c_blue); /**********/ ycomp = (int32_t)(*(pLum +j +1)); pOutAddr[3 + JPEG_RED_OFFSET/8] = CLAMP(ycomp + c_red); pOutAddr[3 + JPEG_GREEN_OFFSET/8] = CLAMP(ycomp + c_green); pOutAddr[3 + JPEG_BLUE_OFFSET/8] = CLAMP(ycomp + c_blue); #elif (JPEG_RGB_FORMAT == JPEG_RGB565) ycomp = (int32_t)(*(pLum +j)); *(__IO uint16_t *)pOutAddr = ((CLAMP(ycomp + c_red) >> 3) << JPEG_RED_OFFSET) | \ ((CLAMP( ycomp + c_green) >> 2) << JPEG_GREEN_OFFSET) | \ ((CLAMP(ycomp + c_blue) >> 3) << JPEG_BLUE_OFFSET); /**********/ ycomp = (int32_t)(*(pLum +j +1)); *((__IO uint16_t *)(pOutAddr + 2)) = ((CLAMP(ycomp + c_red) >> 3) << JPEG_RED_OFFSET) | \ ((CLAMP( ycomp + c_green) >> 2) << JPEG_GREEN_OFFSET) | \ ((CLAMP(ycomp + c_blue) >> 3) << JPEG_BLUE_OFFSET); #endif /* JPEG_RGB_FORMAT*/ pOutAddr += JPEG_BYTES_PER_PIXEL * 2; pChrom++; } pLum += 64; } pLum = pLum - 128 + 8; refline += JPEG_ConvertorParams.ScaledWidth; } } pInBuffer += YCBCR_422_BLOCK_SIZE; } return numberMCU; } /** * @brief Convert YCbCr 4:4:4 blocks to RGB pixels * @param pInBuffer : pointer to input YCbCr blocks buffer. * @param pOutBuffer : pointer to output RGB888/ARGB8888 frame buffer. * @param BlockIndex : index of the input buffer first block in the final image. * @param DataCount : number of bytes in the input buffer . * @param ConvertedDataCount : number of converted bytes from input buffer. * @retval Number of blcoks converted from YCbCr to RGB */ static uint32_t JPEG_MCU_YCbCr444_ARGB_ConvertBlocks(uint8_t *pInBuffer, uint8_t *pOutBuffer, uint32_t BlockIndex, uint32_t DataCount, uint32_t *ConvertedDataCount) { uint32_t numberMCU; uint32_t i,j, currentMCU, xRef,yRef; uint32_t refline; int32_t ycomp, crcomp, cbcomp; int32_t c_red, c_blue, c_green; uint8_t *pOutAddr; uint8_t *pChrom, *pLum; numberMCU = DataCount / YCBCR_444_BLOCK_SIZE; currentMCU = BlockIndex; while(currentMCU < (numberMCU + BlockIndex)) { xRef = ((currentMCU *8) / JPEG_ConvertorParams.WidthExtend)*8; yRef = ((currentMCU *8) % JPEG_ConvertorParams.WidthExtend); refline = JPEG_ConvertorParams.ScaledWidth * xRef + (JPEG_BYTES_PER_PIXEL*yRef); currentMCU++; pChrom = pInBuffer + 64; /* pChroma = pInBuffer + 4*64 */ pLum = pInBuffer; for(i= 0; i < 8; i++) { if(refline < JPEG_ConvertorParams.ImageSize_Bytes) { pOutAddr = pOutBuffer+ refline; for(j=0; j < 8; j++) { cbcomp = (int32_t)(*pChrom); c_blue = (int32_t)(*(CB_BLUE_LUT + cbcomp)); crcomp = (int32_t)(*(pChrom + 64)); c_red = (int32_t)(*(CR_RED_LUT + crcomp)); c_green = ((int32_t)(*(CR_GREEN_LUT + crcomp)) + (int32_t)(*(CB_GREEN_LUT + cbcomp))) >> 16; #if (JPEG_RGB_FORMAT == JPEG_ARGB8888) ycomp = (int32_t)(*(pLum +j)); *(__IO uint32_t *)pOutAddr = (CLAMP(ycomp + c_red) << JPEG_RED_OFFSET) | \ (CLAMP( ycomp + c_green) << JPEG_GREEN_OFFSET) | \ (CLAMP(ycomp + c_blue) << JPEG_BLUE_OFFSET); #elif (JPEG_RGB_FORMAT == JPEG_RGB888) ycomp = (int32_t)(*(pLum +j)); pOutAddr[JPEG_RED_OFFSET/8] = CLAMP(ycomp + c_red); pOutAddr[JPEG_GREEN_OFFSET/8] = CLAMP(ycomp + c_green); pOutAddr[JPEG_BLUE_OFFSET/8] = CLAMP(ycomp + c_blue); #elif (JPEG_RGB_FORMAT == JPEG_RGB565) ycomp = (int32_t)(*(pLum +j)); *(__IO uint16_t *)pOutAddr = ((CLAMP(ycomp + c_red) >> 3) << JPEG_RED_OFFSET) | \ ((CLAMP( ycomp + c_green) >> 2) << JPEG_GREEN_OFFSET) | \ ((CLAMP(ycomp + c_blue) >> 3) << JPEG_BLUE_OFFSET); #endif /* JPEG_RGB_FORMAT */ pOutAddr += JPEG_BYTES_PER_PIXEL; pChrom++; } pLum += 8; refline += JPEG_ConvertorParams.ScaledWidth; } } pInBuffer += YCBCR_444_BLOCK_SIZE; } return numberMCU; } /** * @brief Convert Y Gray blocks to RGB pixels * @param pInBuffer : pointer to input Luminance Y blocks buffer. * @param pOutBuffer : pointer to output RGB888/ARGB8888 frame buffer. * @param BlockIndex : index of the input buffer first block in the final image. * @param DataCount : number of bytes in the input buffer . * @param ConvertedDataCount : number of converted bytes from input buffer. * @retval Number of blcoks converted from YCbCr to RGB */ static uint32_t JPEG_MCU_Gray_ARGB_ConvertBlocks(uint8_t *pInBuffer, uint8_t *pOutBuffer, uint32_t BlockIndex, uint32_t DataCount, uint32_t *ConvertedDataCount) { uint32_t numberMCU; uint32_t currentMCU, xRef,yRef; uint32_t refline; uint32_t i,j, ySample; uint8_t *pOutAddr, *pLum; numberMCU = DataCount / GRAY_444_BLOCK_SIZE; currentMCU = BlockIndex; while(currentMCU < (numberMCU + BlockIndex)) { xRef = ((currentMCU *8) / JPEG_ConvertorParams.WidthExtend)*8; yRef = ((currentMCU *8) % JPEG_ConvertorParams.WidthExtend); refline = JPEG_ConvertorParams.ScaledWidth * xRef + (JPEG_BYTES_PER_PIXEL*yRef); currentMCU++; pLum = pInBuffer; for(i= 0; i < 8; i++) { pOutAddr = pOutBuffer + refline; if(refline < JPEG_ConvertorParams.ImageSize_Bytes) { for(j=0; j < 8; j++) { ySample = (uint32_t)(*pLum); #if (JPEG_RGB_FORMAT == JPEG_ARGB8888) *(__IO uint32_t *)pOutAddr = ySample | (ySample << 8) | (ySample << 16); #elif (JPEG_RGB_FORMAT == JPEG_RGB888) pOutAddr[0] = ySample; pOutAddr[1] = ySample; pOutAddr[2] = ySample; #elif (JPEG_RGB_FORMAT == JPEG_RGB565) *(__IO uint16_t *)pOutAddr = ((ySample >> 3) << 11) | ((ySample >> 2) << 5) | (ySample >> 3); #endif /* JPEG_RGB_FORMAT */ pOutAddr += JPEG_BYTES_PER_PIXEL; pLum++; } refline += JPEG_ConvertorParams.ScaledWidth; } } pInBuffer += GRAY_444_BLOCK_SIZE; } return numberMCU; } /** * @brief Convert CMYK blocks to RGB pixels * @param pInBuffer : pointer to input CMYK blocks buffer. * @param pOutBuffer : pointer to output RGB888/ARGB8888 frame buffer. * @param BlockIndex : index of the input buffer first block in the final image. * @param DataCount : number of bytes in the input buffer . * @param ConvertedDataCount : number of converted bytes from input buffer. * @retval Number of blcoks converted from CMYK to RGB */ static uint32_t JPEG_MCU_YCCK_ARGB_ConvertBlocks(uint8_t *pInBuffer, uint8_t *pOutBuffer, uint32_t BlockIndex, uint32_t DataCount, uint32_t *ConvertedDataCount) { uint32_t numberMCU; uint32_t i,j, currentMCU, xRef,yRef; uint32_t refline; int32_t color_k; int32_t c_red, c_blue, c_green; uint8_t *pOutAddr, *pChrom; numberMCU = DataCount / CMYK_444_BLOCK_SIZE; currentMCU = BlockIndex; while(currentMCU < (numberMCU + BlockIndex)) { xRef = ((currentMCU *8) / JPEG_ConvertorParams.WidthExtend)*8; yRef = ((currentMCU *8) % JPEG_ConvertorParams.WidthExtend); refline = JPEG_ConvertorParams.ScaledWidth * xRef + (JPEG_BYTES_PER_PIXEL*yRef); currentMCU++; pChrom = pInBuffer; for(i= 0; i < 8; i++) { if(refline < JPEG_ConvertorParams.ImageSize_Bytes) { pOutAddr = pOutBuffer+ refline; for(j=0; j < 8; j++) { color_k = (int32_t)(*(pChrom + 192)); c_red = (color_k * ((int32_t)(*pChrom)))/255; c_green = (color_k * (int32_t)(*(pChrom + 64)))/255; c_blue = (color_k * (int32_t)(*(pChrom + 128)))/255; #if (JPEG_RGB_FORMAT == JPEG_ARGB8888) *(__IO uint32_t *)pOutAddr = (c_red << JPEG_RED_OFFSET) | \ (c_green << JPEG_GREEN_OFFSET) | \ (c_blue << JPEG_BLUE_OFFSET); #elif (JPEG_RGB_FORMAT == JPEG_RGB888) pOutAddr[JPEG_RED_OFFSET/8] = c_red; pOutAddr[JPEG_GREEN_OFFSET/8] = c_green; pOutAddr[JPEG_BLUE_OFFSET/8] = c_blue; #elif (JPEG_RGB_FORMAT == JPEG_RGB565) *(__IO uint16_t *)pOutAddr = ((c_red >> 3) << JPEG_RED_OFFSET) | \ ((c_green >> 2) << JPEG_GREEN_OFFSET) | \ ((c_blue >> 3) << JPEG_BLUE_OFFSET); #endif /* JPEG_RGB_FORMAT */ pOutAddr += JPEG_BYTES_PER_PIXEL; pChrom++; } refline += JPEG_ConvertorParams.ScaledWidth; } } pInBuffer += CMYK_444_BLOCK_SIZE; } return numberMCU; } /** * @brief Retrive Decoding YCbCr to RGB color conversion function and block number * @param pJpegInfo : JPEG_ConfTypeDef that contains the JPEG image informations. * These info are available in the HAL callback "HAL_JPEG_InfoReadyCallback". * @param pFunction : pointer to JPEG_YCbCrToRGB_Convert_Function , used to retrive the color conversion function * depending of the jpeg image color space and chroma sampling info. * @param ImageNbMCUs : pointer to uint32_t, used to retrive the total number of MCU blocks in the jpeg image. * @retval HAL status : HAL_OK or HAL_ERROR. */ HAL_StatusTypeDef JPEG_GetDecodeColorConvertFunc(JPEG_ConfTypeDef *pJpegInfo, JPEG_YCbCrToRGB_Convert_Function *pFunction, uint32_t *ImageNbMCUs) { uint32_t hMCU, vMCU; JPEG_ConvertorParams.ColorSpace = pJpegInfo->ColorSpace; JPEG_ConvertorParams.ImageWidth = pJpegInfo->ImageWidth; JPEG_ConvertorParams.ImageHeight = pJpegInfo->ImageHeight; JPEG_ConvertorParams.ImageSize_Bytes = pJpegInfo->ImageWidth * pJpegInfo->ImageHeight * JPEG_BYTES_PER_PIXEL; JPEG_ConvertorParams.ChromaSubsampling = pJpegInfo->ChromaSubsampling; if(JPEG_ConvertorParams.ColorSpace == JPEG_YCBCR_COLORSPACE) { if(JPEG_ConvertorParams.ChromaSubsampling == JPEG_420_SUBSAMPLING) { *pFunction = JPEG_MCU_YCbCr420_ARGB_ConvertBlocks; JPEG_ConvertorParams.LineOffset = JPEG_ConvertorParams.ImageWidth % 16; if(JPEG_ConvertorParams.LineOffset != 0) { JPEG_ConvertorParams.LineOffset = 16 - JPEG_ConvertorParams.LineOffset; } JPEG_ConvertorParams.H_factor = 16; JPEG_ConvertorParams.V_factor = 16; } else if(JPEG_ConvertorParams.ChromaSubsampling == JPEG_422_SUBSAMPLING) { *pFunction = JPEG_MCU_YCbCr422_ARGB_ConvertBlocks; JPEG_ConvertorParams.LineOffset = JPEG_ConvertorParams.ImageWidth % 16; if(JPEG_ConvertorParams.LineOffset != 0) { JPEG_ConvertorParams.LineOffset = 16 - JPEG_ConvertorParams.LineOffset; } JPEG_ConvertorParams.H_factor = 16; JPEG_ConvertorParams.V_factor = 8; } else /*4:4:4*/ { *pFunction = JPEG_MCU_YCbCr444_ARGB_ConvertBlocks; JPEG_ConvertorParams.LineOffset = JPEG_ConvertorParams.ImageWidth % 8; if(JPEG_ConvertorParams.LineOffset != 0) { JPEG_ConvertorParams.LineOffset = 8 - JPEG_ConvertorParams.LineOffset; } JPEG_ConvertorParams.H_factor = 8; JPEG_ConvertorParams.V_factor = 8; } } else if(JPEG_ConvertorParams.ColorSpace == JPEG_GRAYSCALE_COLORSPACE) { *pFunction = JPEG_MCU_Gray_ARGB_ConvertBlocks; JPEG_ConvertorParams.LineOffset = JPEG_ConvertorParams.ImageWidth % 8; if(JPEG_ConvertorParams.LineOffset != 0) { JPEG_ConvertorParams.LineOffset = 8 - JPEG_ConvertorParams.LineOffset; } JPEG_ConvertorParams.H_factor = 8; JPEG_ConvertorParams.V_factor = 8; } else if(JPEG_ConvertorParams.ColorSpace == JPEG_CMYK_COLORSPACE) { *pFunction = JPEG_MCU_YCCK_ARGB_ConvertBlocks; JPEG_ConvertorParams.LineOffset = JPEG_ConvertorParams.ImageWidth % 8; if(JPEG_ConvertorParams.LineOffset != 0) { JPEG_ConvertorParams.LineOffset = 8 - JPEG_ConvertorParams.LineOffset; } JPEG_ConvertorParams.H_factor = 8; JPEG_ConvertorParams.V_factor = 8; } else { return HAL_ERROR; /* Color space Not supported*/ } JPEG_ConvertorParams.WidthExtend = JPEG_ConvertorParams.ImageWidth + JPEG_ConvertorParams.LineOffset; JPEG_ConvertorParams.ScaledWidth = JPEG_BYTES_PER_PIXEL * JPEG_ConvertorParams.ImageWidth; hMCU = (JPEG_ConvertorParams.ImageWidth / JPEG_ConvertorParams.H_factor); if((JPEG_ConvertorParams.ImageWidth % JPEG_ConvertorParams.H_factor) != 0) { hMCU++; /*+1 for horizenatl incomplete MCU */ } vMCU = (JPEG_ConvertorParams.ImageHeight / JPEG_ConvertorParams.V_factor); if((JPEG_ConvertorParams.ImageHeight % JPEG_ConvertorParams.V_factor) != 0) { vMCU++; /*+1 for vertical incomplete MCU */ } JPEG_ConvertorParams.MCU_Total_Nb = (hMCU * vMCU); *ImageNbMCUs = JPEG_ConvertorParams.MCU_Total_Nb; return HAL_OK; } /** * @brief Initializes the YCbCr -> RGB colors conversion Look Up Tables * @param None * @retval None */ void JPEG_InitPostProcColorTables(void) { int32_t index, i; for (i = 0; i <= 255; i++) { index = (i * 2) - 256; CR_RED_LUT[i] = ( (((int32_t) ((1.40200 / 2) * (1L << 16))) * index) + ((int32_t) 1 << (16 - 1))) >> 16; CB_BLUE_LUT[i] = ( (((int32_t) ((1.77200 / 2) * (1L << 16))) * index) + ((int32_t) 1 << (16 - 1))) >> 16; CR_GREEN_LUT[i] = (-((int32_t) ((0.71414 / 2) * (1L << 16)))) * index; CB_GREEN_LUT[i] = (-((int32_t) ((0.34414 / 2) * (1L << 16)))) * index; } } #endif /* USE_JPEG_DECODER == 1 */ /** * @brief Initializes the colors conversion Look Up Tables * @param None * @retval None */ void JPEG_InitColorTables(void) { #if (USE_JPEG_ENCODER == 1) JPEG_InitPreProcColorTables(); JPEG_Init_MCU_LUT(); #endif #if (USE_JPEG_DECODER == 1) JPEG_InitPostProcColorTables(); #endif } #if (USE_JPEG_ENCODER == 1) /** * @brief Initializes the RGB -> YCbCr colors conversion Look Up Tables * @param None * @retval None */ void JPEG_InitPreProcColorTables(void) { int32_t i; for (i = 0; i <= 255; i++) { RED_Y_LUT[i] = (( ((int32_t) ((0.299 ) * (1L << 16))) * i) + ((int32_t) 1 << (16 - 1))) >> 16 ; GREEN_Y_LUT[i] = (( ((int32_t) ((0.587 ) * (1L << 16))) * i) + ((int32_t) 1 << (16 - 1))) >> 16 ; BLUE_Y_LUT[i] = (( ((int32_t) ((0.114 ) * (1L << 16))) * i) + ((int32_t) 1 << (16 - 1))) >> 16 ; RED_CB_LUT[i] = (((-((int32_t) ((0.1687 ) * (1L << 16)))) * i) + ((int32_t) 1 << (16 - 1))) >> 16 ; GREEN_CB_LUT[i] = (((-((int32_t) ((0.3313 ) * (1L << 16)))) * i) + ((int32_t) 1 << (16 - 1))) >> 16 ; /* BLUE_CB_LUT and RED_CR_LUT are identical */ BLUE_CB_RED_CR_LUT[i] = (( ((int32_t) ((0.5 ) * (1L << 16))) * i) + ((int32_t) 1 << (16 - 1))) >> 16 ; GREEN_CR_LUT[i] = (((-((int32_t) ((0.4187 ) * (1L << 16)))) * i) + ((int32_t) 1 << (16 - 1))) >> 16 ; BLUE_CR_LUT[i] = (((-((int32_t) ((0.0813 ) * (1L << 16)))) * i) + ((int32_t) 1 << (16 - 1))) >> 16 ; } } /** * @brief Initializes the MCU Look Up Tables * @param None * @retval None */ void JPEG_Init_MCU_LUT(void) { uint32_t i, j, offset; /*Y LUT */ for(i = 0; i < 16; i++) { for(j = 0; j < 16; j++) { offset = j + (i*8); if((j>=8) && (i>=8)) offset+= 120; else if((j>=8) && (i<8)) offset+= 56; else if((j<8) && (i>=8)) offset+= 64; JPEG_Y_MCU_LUT[i*16 + j] = offset; } } /*Cb Cr K LUT*/ for(i = 0; i < 16; i++) { for(j = 0; j < 16; j++) { offset = i*16 + j; JPEG_Cb_MCU_420_LUT[offset] = (j/2) + ((i/2)*8) + 256; JPEG_Cb_MCU_422_LUT[offset] = (j/2) + (i*8) + 128; JPEG_Cr_MCU_420_LUT[offset] = (j/2) + ((i/2)*8) + 320; JPEG_Cr_MCU_422_LUT[offset] = (j/2) + (i*8) + 192; JPEG_K_MCU_420_LUT[offset] = (j/2) + ((i/2)*8) + 384; JPEG_K_MCU_422_LUT[offset] = (j/2) + ((i/2)*8) + 256; } } for(i = 0; i < 8; i++) { for(j = 0; j < 8; j++) { offset = i*8 + j; JPEG_Y_MCU_444_LUT[offset] = offset; JPEG_Cb_MCU_444_LUT[offset] = offset + 64 ; JPEG_Cr_MCU_444_LUT[offset] = offset + 128 ; JPEG_K_MCU_444_LUT[offset] = offset + 192 ; } } } /** * @brief Initializes the YCCK format K Blocks * @param ChromaSampling * @retval pMCUBuffer */ static uint8_t *JPEG_Set_K_Blocks(uint8_t *pMCUBuffer, uint8_t pKBlocks[16][16], uint32_t ChromaSampling) { uint32_t i,j; if(ChromaSampling == JPEG_420_SUBSAMPLING) { /* 4:2:0 4Y + Cb + Cr + K*/ pMCUBuffer = pMCUBuffer + 384; /* K block */ for(i=0;i<16;i+=2) { for(j=0;j<16;j+=2) { *pMCUBuffer = pKBlocks[i][j]; pMCUBuffer++; } } } else if(ChromaSampling == JPEG_422_SUBSAMPLING) { /* 4:2:2 2Y horizental + Cb + Cr + K*/ pMCUBuffer = pMCUBuffer + 256; /* K block */ for(i=0;i<8;i++) { for(j=0;j<16;j+=2) { *pMCUBuffer = pKBlocks[i][j]; pMCUBuffer++; } } } else if(ChromaSampling == JPEG_444_SUBSAMPLING) { /* 4:4:4 Y + Cb + Cr + K*/ /* K block */ pMCUBuffer = pMCUBuffer + 192; for(i=0;i<8;i++) { for(j=0;j<8;j++) { *pMCUBuffer = pKBlocks[i][j]; pMCUBuffer++; } } } return pMCUBuffer; } #endif /* USE_JPEG_ENCODER == 1 */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/