1993 lines
77 KiB
C
1993 lines
77 KiB
C
/**
|
|
******************************************************************************
|
|
* @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
|
|
*
|
|
* <h2><center>© COPYRIGHT(c) 2016 STMicroelectronics</center></h2>
|
|
*
|
|
* 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****/
|