/**
******************************************************************************
* @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****/