diff --git a/components/esp_rom/CMakeLists.txt b/components/esp_rom/CMakeLists.txt index 04d5cc0cd9..5938c3a823 100644 --- a/components/esp_rom/CMakeLists.txt +++ b/components/esp_rom/CMakeLists.txt @@ -18,7 +18,6 @@ else() "patches/esp_rom_sys.c" "patches/esp_rom_uart.c" "patches/esp_rom_spiflash.c" - "patches/esp_rom_tjpgd.c" "patches/esp_rom_regi2c.c" "patches/esp_rom_efuse.c") list(APPEND private_required_comp soc hal) diff --git a/components/esp_rom/esp32/ld/esp32.rom.api.ld b/components/esp_rom/esp32/ld/esp32.rom.api.ld index bc6fa83390..911cc17292 100644 --- a/components/esp_rom/esp32/ld/esp32.rom.api.ld +++ b/components/esp_rom/esp32/ld/esp32.rom.api.ld @@ -1,12 +1,6 @@ /** * ROM APIs */ - -/* user may provide newer version of tjpgd */ -/* so here directly assign the symbols with the ROM API address to make sure one from rom is correctly linked */ -PROVIDE ( esp_rom_tjpgd_decomp = 0x400613e8 ); -PROVIDE ( esp_rom_tjpgd_prepare = 0x40060fa8 ); - PROVIDE ( esp_rom_crc32_le = crc32_le ); PROVIDE ( esp_rom_crc16_le = crc16_le ); PROVIDE ( esp_rom_crc8_le = crc8_le ); diff --git a/components/esp_rom/esp32c3/ld/esp32c3.rom.api.ld b/components/esp_rom/esp32c3/ld/esp32c3.rom.api.ld index 9c7d0903c1..d223ff6a95 100644 --- a/components/esp_rom/esp32c3/ld/esp32c3.rom.api.ld +++ b/components/esp_rom/esp32c3/ld/esp32c3.rom.api.ld @@ -1,11 +1,6 @@ -/** ROM APIs +/** + * ROM APIs */ - -/* user may provide newer version of tjpgd */ -/* so here directly assign the symbols with the ROM API address to make sure one from rom is correctly linked */ -PROVIDE ( esp_rom_tjpgd_decomp = 0x40000108 ); -PROVIDE ( esp_rom_tjpgd_prepare = 0x40000104 ); - PROVIDE ( esp_rom_crc32_le = crc32_le ); PROVIDE ( esp_rom_crc16_le = crc16_le ); PROVIDE ( esp_rom_crc8_le = crc8_le ); diff --git a/components/esp_rom/esp32h2/ld/rev1/esp32h2.rom.api.ld b/components/esp_rom/esp32h2/ld/rev1/esp32h2.rom.api.ld index 2bc1ceb462..7945722adc 100644 --- a/components/esp_rom/esp32h2/ld/rev1/esp32h2.rom.api.ld +++ b/components/esp_rom/esp32h2/ld/rev1/esp32h2.rom.api.ld @@ -6,9 +6,6 @@ /** ROM APIs */ -PROVIDE ( esp_rom_tjpgd_decomp = 0x40000104 ); -PROVIDE ( esp_rom_tjpgd_prepare = 0x40000100 ); - PROVIDE ( esp_rom_crc32_le = crc32_le ); PROVIDE ( esp_rom_crc16_le = crc16_le ); PROVIDE ( esp_rom_crc8_le = crc8_le ); diff --git a/components/esp_rom/esp32h2/ld/rev2/esp32h2.rom.api.ld b/components/esp_rom/esp32h2/ld/rev2/esp32h2.rom.api.ld index 2bc1ceb462..7945722adc 100644 --- a/components/esp_rom/esp32h2/ld/rev2/esp32h2.rom.api.ld +++ b/components/esp_rom/esp32h2/ld/rev2/esp32h2.rom.api.ld @@ -6,9 +6,6 @@ /** ROM APIs */ -PROVIDE ( esp_rom_tjpgd_decomp = 0x40000104 ); -PROVIDE ( esp_rom_tjpgd_prepare = 0x40000100 ); - PROVIDE ( esp_rom_crc32_le = crc32_le ); PROVIDE ( esp_rom_crc16_le = crc16_le ); PROVIDE ( esp_rom_crc8_le = crc8_le ); diff --git a/components/esp_rom/esp32s3/ld/esp32s3.rom.api.ld b/components/esp_rom/esp32s3/ld/esp32s3.rom.api.ld index 72156b74c2..22425ce3bb 100644 --- a/components/esp_rom/esp32s3/ld/esp32s3.rom.api.ld +++ b/components/esp_rom/esp32s3/ld/esp32s3.rom.api.ld @@ -1,12 +1,6 @@ /** * ROM APIs */ - -/* user may provide newer version of tjpgd */ -/* so here directly assign the symbols with the ROM API address to make sure one from rom is correctly linked */ -PROVIDE ( esp_rom_tjpgd_decomp = 0x40000864 ); -PROVIDE ( esp_rom_tjpgd_prepare = 0x40000858 ); - PROVIDE ( esp_rom_crc32_le = crc32_le ); PROVIDE ( esp_rom_crc16_le = crc16_le ); PROVIDE ( esp_rom_crc8_le = crc8_le ); diff --git a/components/esp_rom/include/esp_rom_tjpgd.h b/components/esp_rom/include/esp_rom_tjpgd.h deleted file mode 100644 index 318519ba74..0000000000 --- a/components/esp_rom/include/esp_rom_tjpgd.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/*-----------------------------------------------------------------------------/ -/ TJpgDec - Tiny JPEG Decompressor R0.01b (C)ChaN, 2012 -/-----------------------------------------------------------------------------/ -/ The TJpgDec is a generic JPEG decompressor module for tiny embedded systems. -/ This is a free software that opened for education, research and commercial -/ developments under license policy of following terms. -/ -/ Copyright (C) 2012, ChaN, all right reserved. -/ -/ * The TJpgDec module is a free software and there is NO WARRANTY. -/ * No restriction on use. You can use, modify and redistribute it for -/ personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY. -/ * Redistributions of source code must retain the above copyright notice. -/ -/-----------------------------------------------------------------------------*/ - -#pragma once - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* Error code */ -typedef enum { - JDR_OK = 0, /* 0: Succeeded */ - JDR_INTR, /* 1: Interrupted by output function */ - JDR_INP, /* 2: Device error or wrong termination of input stream */ - JDR_MEM1, /* 3: Insufficient memory pool for the image */ - JDR_MEM2, /* 4: Insufficient stream input buffer */ - JDR_PAR, /* 5: Parameter error */ - JDR_FMT1, /* 6: Data format error (may be damaged data) */ - JDR_FMT2, /* 7: Right format but not supported */ - JDR_FMT3 /* 8: Not supported JPEG standard */ -} esp_rom_tjpgd_result_t; - -/* Rectangular structure */ -typedef struct { - uint16_t left; /* Left end */ - uint16_t right; /* Right end */ - uint16_t top; /* Top end */ - uint16_t bottom;/* Bottom end */ -} esp_rom_tjpgd_rect_t; - -typedef struct JDEC_s esp_rom_tjpgd_dec_t; - -/** - * @brief Type of user defined input function to read data from input stream - * @param dec Specifies the decompression object of the decompression session - * @param buffer Specifies the pointer to the read buffer to store the read data. A NULL specifies to remove the data from input stream - * @param ndata Specifies number of bytes to read/remove from the input stream - * - * @return number of bytes read/removed. When a zero is returned, the esp_rom_tjpgd_prepare and esp_rom_tjpgd_decomp function aborts with JDR_INP - */ -typedef uint32_t (*esp_rom_tjpgd_input_function_t)(esp_rom_tjpgd_dec_t *dec, uint8_t *buffer, uint32_t ndata); - -/** - * @brief User defined output function to write decompressed pixels to the output device - * - * This function is the data output interface of the TJpgDec module. - * The corresponding decompression session can be identified by the pointer to the device identifier jdec->device passed to the 5th argument of jd_prepare function. - * The bitmap is sent to the frame buffer or display device in this function. - * The first pixel in the bitmap is the left-top of the rectangular, the second one is next right and last pixel is the bottom-right of the rectangular. - * The size of rectangular varies from 1x1 to 16x16 depends on clipping, scaling and sampling factor of the image. - * If the rectangular is out of the frame buffer, it should be clipped in this function. - * - * The pixel format is currently configured to RGB888 - * - * @param dec Specifies the decompression object of the decompression session - * @param bitmap Specifies the RGB bitmap to be output - * @param rect Specifies rectangular region in the image to output the RGB bitmap - * - * @return Normally returns 1. It lets TJpgDec to continue the decompressing process. - * When a 0 is returned, the esp_rom_tjpgd_decomp function aborts with JDR_INTR. - * This is useful to interrupt the decompression process - */ -typedef uint32_t (*esp_rom_tjpgd_output_function_t)(esp_rom_tjpgd_dec_t *dec, void *bitmap, esp_rom_tjpgd_rect_t *rect); - -struct JDEC_s { - uint32_t dctr; /* Number of bytes available in the input buffer */ - uint8_t *dptr; /* Current data read ptr */ - uint8_t *inbuf; /* Bit stream input buffer */ - uint8_t dmsk; /* Current bit in the current read byte */ - uint8_t scale; /* Output scaling ratio */ - uint8_t msx, msy; /* MCU size in unit of block (width, height) */ - uint8_t qtid[3]; /* Quantization table ID of each component */ - int16_t dcv[3]; /* Previous DC element of each component */ - uint16_t nrst; /* Restart inverval */ - uint32_t width, height; /* Size of the input image (pixel) */ - uint8_t *huffbits[2][2]; /* Huffman bit distribution tables [id][dcac] */ - uint16_t *huffcode[2][2]; /* Huffman code word tables [id][dcac] */ - uint8_t *huffdata[2][2]; /* Huffman decoded data tables [id][dcac] */ - int32_t *qttbl[4]; /* Dequaitizer tables [id] */ - void *workbuf; /* Working buffer for IDCT and RGB output */ - uint8_t *mcubuf; /* Working buffer for the MCU */ - void *pool; /* Pointer to available memory pool */ - uint32_t sz_pool; /* Size of momory pool (bytes available) */ - esp_rom_tjpgd_input_function_t infunc; /* Pointer to jpeg stream input function */ - void *device; /* Pointer to I/O device identifiler for the session */ -}; - -/* TJpgDec API functions */ - -/** - * @brief Analyzes the JPEG data and create a decompression object for subsequent decompression process. - * @param dec Specifies the decompression object to be initialized. The decompression object is used for subsequent decompression process. - * @param infunc Specifies the user defined data input function. - * @param work Specifies pointer to the work area for this session. It should be aligned to word boundary or it can result an exception. - * @param sz_work Specifies size of the work area in unit of byte. - * TJpgDec requires upto 3092 bytes of work area depends on the built-in parameter tables of the JPEG image. - * Thus 3092 bytes of work area is sufficient for most case. - * @param dev Specifies pointer to the user defined device identifier for this session. - * It is stored to the member device in the decompression object. It can be referred by I/O functions to identify the current session. - * When I/O device is fixed in the project or this feature is not needed, set NULL and do not care about this. - * - * @return - * - JDR_OK Function succeeded and decompression object is valid. - * - JDR_INP An error occurred in input function due to hard error or wrong stream termination. - * - JDR_MEM1 Insufficient work area for this JPEG image. - * - JDR_MEM2 Insufficient input buffer for this JPEG image. JD_SZBUF may be too small. - * - JDR_PAR Parameter error. Given pointer to the work area is NULL. - * - JDR_FMT1 Data format error. The JPEG data can be collapsed. - * - JDR_FMT2 Right format but not supported. May be a grayscale image. - * - JDR_FMT3 Not supported JPEG standard. May be a progressive JPEG image. - */ -esp_rom_tjpgd_result_t esp_rom_tjpgd_prepare(esp_rom_tjpgd_dec_t *dec, esp_rom_tjpgd_input_function_t infunc, void *work, uint32_t sz_work, void *dev); - -/** - * @brief Decompress the JPEG image and output it as RGB data. - * @param dec Specifies the valid decompressor object. - * @param outfunc Specifies the user defined data output function. The esp_rom_tjpgd_decomp function calls this function to output the decompressed JPEG image in RGB form. - * @param scale Specifies scaling factor N for output. The output image is descaled to 1 / 2 ^ N (N = 0 to 3). - * - * @return - * - JDR_OK Function succeeded. - * - JDR_INTR The decompression process is interrupted by output function. - * - JDR_INP An error occured in input function due to hard error or wrong stream termination. - * - JDR_PAR Parameter error. Given scale factor is invalid. - * - JDR_FMT1 Data format error. The JPEG data can be collapted. - */ -esp_rom_tjpgd_result_t esp_rom_tjpgd_decomp(esp_rom_tjpgd_dec_t *dec, esp_rom_tjpgd_output_function_t outfunc, uint8_t scale); - -#ifdef __cplusplus -} -#endif diff --git a/components/esp_rom/patches/esp_rom_tjpgd.c b/components/esp_rom/patches/esp_rom_tjpgd.c deleted file mode 100644 index 8e0b8d2713..0000000000 --- a/components/esp_rom/patches/esp_rom_tjpgd.c +++ /dev/null @@ -1,976 +0,0 @@ -/*----------------------------------------------------------------------------/ -/ TJpgDec - Tiny JPEG Decompressor R0.01b (C)ChaN, 2012 -/-----------------------------------------------------------------------------/ -/ The TJpgDec is a generic JPEG decompressor module for tiny embedded systems. -/ This is a free software that opened for education, research and commercial -/ developments under license policy of following terms. -/ -/ Copyright (C) 2012, ChaN, all right reserved. -/ -/ * The TJpgDec module is a free software and there is NO WARRANTY. -/ * No restriction on use. You can use, modify and redistribute it for -/ personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY. -/ * Redistributions of source code must retain the above copyright notice. -/ -/-----------------------------------------------------------------------------/ -/ Oct 04,'11 R0.01 First release. -/ Feb 19,'12 R0.01a Fixed decompression fails when scan starts with an escape seq. -/ Sep 03,'12 R0.01b Added JD_TBLCLIP option. -/----------------------------------------------------------------------------*/ - -#include "esp_rom_caps.h" - -#if !ESP_ROM_HAS_JPEG_DECODE - -#include "esp_rom_tjpgd.h" - -#define JD_SZBUF 512 /* Size of stream input buffer */ -#define JD_FORMAT 0 /* Output pixel format 0:RGB888 (3 BYTE/pix), 1:RGB565 (1 WORD/pix) */ -#define JD_USE_SCALE 1 /* Use descaling feature for output */ -#define JD_TBLCLIP 1 /* Use table for saturation (might be a bit faster but increases 1K bytes of code size) */ - - -/*-----------------------------------------------*/ -/* Zigzag-order to raster-order conversion table */ -/*-----------------------------------------------*/ - -#define ZIG(n) Zig[n] - -static -const uint8_t Zig[64] = { /* Zigzag-order to raster-order conversion table */ - 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, - 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, - 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, - 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 -}; - - - -/*-------------------------------------------------*/ -/* Input scale factor of Arai algorithm */ -/* (scaled up 16 bits for fixed point operations) */ -/*-------------------------------------------------*/ - -#define IPSF(n) Ipsf[n] - -static -const uint16_t Ipsf[64] = { /* See also aa_idct.png */ - (uint16_t)(1.00000*8192), (uint16_t)(1.38704*8192), (uint16_t)(1.30656*8192), (uint16_t)(1.17588*8192), (uint16_t)(1.00000*8192), (uint16_t)(0.78570*8192), (uint16_t)(0.54120*8192), (uint16_t)(0.27590*8192), - (uint16_t)(1.38704*8192), (uint16_t)(1.92388*8192), (uint16_t)(1.81226*8192), (uint16_t)(1.63099*8192), (uint16_t)(1.38704*8192), (uint16_t)(1.08979*8192), (uint16_t)(0.75066*8192), (uint16_t)(0.38268*8192), - (uint16_t)(1.30656*8192), (uint16_t)(1.81226*8192), (uint16_t)(1.70711*8192), (uint16_t)(1.53636*8192), (uint16_t)(1.30656*8192), (uint16_t)(1.02656*8192), (uint16_t)(0.70711*8192), (uint16_t)(0.36048*8192), - (uint16_t)(1.17588*8192), (uint16_t)(1.63099*8192), (uint16_t)(1.53636*8192), (uint16_t)(1.38268*8192), (uint16_t)(1.17588*8192), (uint16_t)(0.92388*8192), (uint16_t)(0.63638*8192), (uint16_t)(0.32442*8192), - (uint16_t)(1.00000*8192), (uint16_t)(1.38704*8192), (uint16_t)(1.30656*8192), (uint16_t)(1.17588*8192), (uint16_t)(1.00000*8192), (uint16_t)(0.78570*8192), (uint16_t)(0.54120*8192), (uint16_t)(0.27590*8192), - (uint16_t)(0.78570*8192), (uint16_t)(1.08979*8192), (uint16_t)(1.02656*8192), (uint16_t)(0.92388*8192), (uint16_t)(0.78570*8192), (uint16_t)(0.61732*8192), (uint16_t)(0.42522*8192), (uint16_t)(0.21677*8192), - (uint16_t)(0.54120*8192), (uint16_t)(0.75066*8192), (uint16_t)(0.70711*8192), (uint16_t)(0.63638*8192), (uint16_t)(0.54120*8192), (uint16_t)(0.42522*8192), (uint16_t)(0.29290*8192), (uint16_t)(0.14932*8192), - (uint16_t)(0.27590*8192), (uint16_t)(0.38268*8192), (uint16_t)(0.36048*8192), (uint16_t)(0.32442*8192), (uint16_t)(0.27590*8192), (uint16_t)(0.21678*8192), (uint16_t)(0.14932*8192), (uint16_t)(0.07612*8192) -}; - - - -/*---------------------------------------------*/ -/* Conversion table for fast clipping process */ -/*---------------------------------------------*/ - -#if JD_TBLCLIP - -#define BYTECLIP(v) Clip8[(uint32_t)(v) & 0x3FF] - -static -const uint8_t Clip8[1024] = { - /* 0..255 */ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, - 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, - /* 256..511 */ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - /* -512..-257 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* -256..-1 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -#else /* JD_TBLCLIP */ - -inline -uint8_t BYTECLIP ( - int32_t val -) -{ - if (val < 0) val = 0; - if (val > 255) val = 255; - - return (uint8_t)val; -} - -#endif - - - -/*-----------------------------------------------------------------------*/ -/* Allocate a memory block from memory pool */ -/*-----------------------------------------------------------------------*/ - -static -void* alloc_pool ( /* Pointer to allocated memory block (NULL:no memory available) */ - esp_rom_tjpgd_dec_t* jd, /* Pointer to the decompressor object */ - uint32_t nd /* Number of bytes to allocate */ -) -{ - char *rp = 0; - - - nd = (nd + 3) & ~3; /* Align block size to the word boundary */ - - if (jd->sz_pool >= nd) { - jd->sz_pool -= nd; - rp = (char*)jd->pool; /* Get start of available memory pool */ - jd->pool = (void*)(rp + nd); /* Allocate requierd bytes */ - } - - return (void*)rp; /* Return allocated memory block (NULL:no memory to allocate) */ -} - - - - -/*-----------------------------------------------------------------------*/ -/* Create de-quantization and prescaling tables with a DQT segment */ -/*-----------------------------------------------------------------------*/ - -static -uint32_t create_qt_tbl ( /* 0:OK, !0:Failed */ - esp_rom_tjpgd_dec_t* jd, /* Pointer to the decompressor object */ - const uint8_t* data, /* Pointer to the quantizer tables */ - uint32_t ndata /* Size of input data */ -) -{ - uint32_t i; - uint8_t d, z; - int32_t *pb; - - - while (ndata) { /* Process all tables in the segment */ - if (ndata < 65) return JDR_FMT1; /* Err: table size is unaligned */ - ndata -= 65; - d = *data++; /* Get table property */ - if (d & 0xF0) return JDR_FMT1; /* Err: not 8-bit resolution */ - i = d & 3; /* Get table ID */ - pb = alloc_pool(jd, 64 * sizeof (int32_t));/* Allocate a memory block for the table */ - if (!pb) return JDR_MEM1; /* Err: not enough memory */ - jd->qttbl[i] = pb; /* Register the table */ - for (i = 0; i < 64; i++) { /* Load the table */ - z = ZIG(i); /* Zigzag-order to raster-order conversion */ - pb[z] = (int32_t)((uint32_t)*data++ * IPSF(z)); /* Apply scale factor of Arai algorithm to the de-quantizers */ - } - } - - return JDR_OK; -} - - - - -/*-----------------------------------------------------------------------*/ -/* Create huffman code tables with a DHT segment */ -/*-----------------------------------------------------------------------*/ - -static -uint32_t create_huffman_tbl ( /* 0:OK, !0:Failed */ - esp_rom_tjpgd_dec_t* jd, /* Pointer to the decompressor object */ - const uint8_t* data, /* Pointer to the packed huffman tables */ - uint32_t ndata /* Size of input data */ -) -{ - uint32_t i, j, b, np, cls, num; - uint8_t d, *pb, *pd; - uint16_t hc, *ph; - - - while (ndata) { /* Process all tables in the segment */ - if (ndata < 17) return JDR_FMT1; /* Err: wrong data size */ - ndata -= 17; - d = *data++; /* Get table number and class */ - cls = (d >> 4); num = d & 0x0F; /* class = dc(0)/ac(1), table number = 0/1 */ - if (d & 0xEE) return JDR_FMT1; /* Err: invalid class/number */ - pb = alloc_pool(jd, 16); /* Allocate a memory block for the bit distribution table */ - if (!pb) return JDR_MEM1; /* Err: not enough memory */ - jd->huffbits[num][cls] = pb; - for (np = i = 0; i < 16; i++) { /* Load number of patterns for 1 to 16-bit code */ - pb[i] = b = *data++; - np += b; /* Get sum of code words for each code */ - } - - ph = alloc_pool(jd, np * sizeof (uint16_t));/* Allocate a memory block for the code word table */ - if (!ph) return JDR_MEM1; /* Err: not enough memory */ - jd->huffcode[num][cls] = ph; - hc = 0; - for (j = i = 0; i < 16; i++) { /* Re-build huffman code word table */ - b = pb[i]; - while (b--) ph[j++] = hc++; - hc <<= 1; - } - - if (ndata < np) return JDR_FMT1; /* Err: wrong data size */ - ndata -= np; - pd = alloc_pool(jd, np); /* Allocate a memory block for the decoded data */ - if (!pd) return JDR_MEM1; /* Err: not enough memory */ - jd->huffdata[num][cls] = pd; - for (i = 0; i < np; i++) { /* Load decoded data corresponds to each code ward */ - d = *data++; - if (!cls && d > 11) return JDR_FMT1; - *pd++ = d; - } - } - - return JDR_OK; -} - - - - -/*-----------------------------------------------------------------------*/ -/* Extract N bits from input stream */ -/*-----------------------------------------------------------------------*/ - -static -int32_t bitext ( /* >=0: extracted data, <0: error code */ - esp_rom_tjpgd_dec_t* jd, /* Pointer to the decompressor object */ - uint32_t nbit /* Number of bits to extract (1 to 11) */ -) -{ - uint8_t msk, s, *dp; - uint32_t dc, v, f; - - - msk = jd->dmsk; dc = jd->dctr; dp = jd->dptr; /* Bit mask, number of data available, read ptr */ - s = *dp; v = f = 0; - do { - if (!msk) { /* Next byte? */ - if (!dc) { /* No input data is available, re-fill input buffer */ - dp = jd->inbuf; /* Top of input buffer */ - dc = jd->infunc(jd, dp, JD_SZBUF); - if (!dc) return 0 - (int32_t)JDR_INP; /* Err: read error or wrong stream termination */ - } else { - dp++; /* Next data ptr */ - } - dc--; /* Decrement number of available bytes */ - if (f) { /* In flag sequence? */ - f = 0; /* Exit flag sequence */ - if (*dp != 0) return 0 - (int32_t)JDR_FMT1; /* Err: unexpected flag is detected (may be collapted data) */ - *dp = s = 0xFF; /* The flag is a data 0xFF */ - } else { - s = *dp; /* Get next data byte */ - if (s == 0xFF) { /* Is start of flag sequence? */ - f = 1; continue; /* Enter flag sequence */ - } - } - msk = 0x80; /* Read from MSB */ - } - v <<= 1; /* Get a bit */ - if (s & msk) v++; - msk >>= 1; - nbit--; - } while (nbit); - jd->dmsk = msk; jd->dctr = dc; jd->dptr = dp; - - return (int32_t)v; -} - - - - -/*-----------------------------------------------------------------------*/ -/* Extract a huffman decoded data from input stream */ -/*-----------------------------------------------------------------------*/ - -static -int32_t huffext ( /* >=0: decoded data, <0: error code */ - esp_rom_tjpgd_dec_t* jd, /* Pointer to the decompressor object */ - const uint8_t* hbits, /* Pointer to the bit distribution table */ - const uint16_t* hcode, /* Pointer to the code word table */ - const uint8_t* hdata /* Pointer to the data table */ -) -{ - uint8_t msk, s, *dp; - uint32_t dc, v, f, bl, nd; - - - msk = jd->dmsk; dc = jd->dctr; dp = jd->dptr; /* Bit mask, number of data available, read ptr */ - s = *dp; v = f = 0; - bl = 16; /* Max code length */ - do { - if (!msk) { /* Next byte? */ - if (!dc) { /* No input data is available, re-fill input buffer */ - dp = jd->inbuf; /* Top of input buffer */ - dc = jd->infunc(jd, dp, JD_SZBUF); - if (!dc) return 0 - (int32_t)JDR_INP; /* Err: read error or wrong stream termination */ - } else { - dp++; /* Next data ptr */ - } - dc--; /* Decrement number of available bytes */ - if (f) { /* In flag sequence? */ - f = 0; /* Exit flag sequence */ - if (*dp != 0) - return 0 - (int32_t)JDR_FMT1; /* Err: unexpected flag is detected (may be collapted data) */ - *dp = s = 0xFF; /* The flag is a data 0xFF */ - } else { - s = *dp; /* Get next data byte */ - if (s == 0xFF) { /* Is start of flag sequence? */ - f = 1; continue; /* Enter flag sequence, get trailing byte */ - } - } - msk = 0x80; /* Read from MSB */ - } - v <<= 1; /* Get a bit */ - if (s & msk) v++; - msk >>= 1; - - for (nd = *hbits++; nd; nd--) { /* Search the code word in this bit length */ - if (v == *hcode++) { /* Matched? */ - jd->dmsk = msk; jd->dctr = dc; jd->dptr = dp; - return *hdata; /* Return the decoded data */ - } - hdata++; - } - bl--; - } while (bl); - - return 0 - (int32_t)JDR_FMT1; /* Err: code not found (may be collapted data) */ -} - - - - -/*-----------------------------------------------------------------------*/ -/* Apply Inverse-DCT in Arai Algorithm (see also aa_idct.png) */ -/*-----------------------------------------------------------------------*/ - -static -void block_idct ( - int32_t* src, /* Input block data (de-quantized and pre-scaled for Arai Algorithm) */ - uint8_t* dst /* Pointer to the destination to store the block as byte array */ -) -{ - const int32_t M13 = (int32_t)(1.41421*4096), M2 = (int32_t)(1.08239*4096), M4 = (int32_t)(2.61313*4096), M5 = (int32_t)(1.84776*4096); - int32_t v0, v1, v2, v3, v4, v5, v6, v7; - int32_t t10, t11, t12, t13; - uint32_t i; - - /* Process columns */ - for (i = 0; i < 8; i++) { - v0 = src[8 * 0]; /* Get even elements */ - v1 = src[8 * 2]; - v2 = src[8 * 4]; - v3 = src[8 * 6]; - - t10 = v0 + v2; /* Process the even elements */ - t12 = v0 - v2; - t11 = (v1 - v3) * M13 >> 12; - v3 += v1; - t11 -= v3; - v0 = t10 + v3; - v3 = t10 - v3; - v1 = t11 + t12; - v2 = t12 - t11; - - v4 = src[8 * 7]; /* Get odd elements */ - v5 = src[8 * 1]; - v6 = src[8 * 5]; - v7 = src[8 * 3]; - - t10 = v5 - v4; /* Process the odd elements */ - t11 = v5 + v4; - t12 = v6 - v7; - v7 += v6; - v5 = (t11 - v7) * M13 >> 12; - v7 += t11; - t13 = (t10 + t12) * M5 >> 12; - v4 = t13 - (t10 * M2 >> 12); - v6 = t13 - (t12 * M4 >> 12) - v7; - v5 -= v6; - v4 -= v5; - - src[8 * 0] = v0 + v7; /* Write-back transformed values */ - src[8 * 7] = v0 - v7; - src[8 * 1] = v1 + v6; - src[8 * 6] = v1 - v6; - src[8 * 2] = v2 + v5; - src[8 * 5] = v2 - v5; - src[8 * 3] = v3 + v4; - src[8 * 4] = v3 - v4; - - src++; /* Next column */ - } - - /* Process rows */ - src -= 8; - for (i = 0; i < 8; i++) { - v0 = src[0] + (128L << 8); /* Get even elements (remove DC offset (-128) here) */ - v1 = src[2]; - v2 = src[4]; - v3 = src[6]; - - t10 = v0 + v2; /* Process the even elements */ - t12 = v0 - v2; - t11 = (v1 - v3) * M13 >> 12; - v3 += v1; - t11 -= v3; - v0 = t10 + v3; - v3 = t10 - v3; - v1 = t11 + t12; - v2 = t12 - t11; - - v4 = src[7]; /* Get odd elements */ - v5 = src[1]; - v6 = src[5]; - v7 = src[3]; - - t10 = v5 - v4; /* Process the odd elements */ - t11 = v5 + v4; - t12 = v6 - v7; - v7 += v6; - v5 = (t11 - v7) * M13 >> 12; - v7 += t11; - t13 = (t10 + t12) * M5 >> 12; - v4 = t13 - (t10 * M2 >> 12); - v6 = t13 - (t12 * M4 >> 12) - v7; - v5 -= v6; - v4 -= v5; - - dst[0] = BYTECLIP((v0 + v7) >> 8); /* Descale the transformed values 8 bits and output */ - dst[7] = BYTECLIP((v0 - v7) >> 8); - dst[1] = BYTECLIP((v1 + v6) >> 8); - dst[6] = BYTECLIP((v1 - v6) >> 8); - dst[2] = BYTECLIP((v2 + v5) >> 8); - dst[5] = BYTECLIP((v2 - v5) >> 8); - dst[3] = BYTECLIP((v3 + v4) >> 8); - dst[4] = BYTECLIP((v3 - v4) >> 8); - dst += 8; - - src += 8; /* Next row */ - } -} - - - - -/*-----------------------------------------------------------------------*/ -/* Load all blocks in the MCU into working buffer */ -/*-----------------------------------------------------------------------*/ - -static -esp_rom_tjpgd_result_t mcu_load ( - esp_rom_tjpgd_dec_t* jd /* Pointer to the decompressor object */ -) -{ - int32_t *tmp = (int32_t*)jd->workbuf; /* Block working buffer for de-quantize and IDCT */ - uint32_t blk, nby, nbc, i, z, id, cmp; - int32_t b, d, e; - uint8_t *bp; - const uint8_t *hb, *hd; - const uint16_t *hc; - const int32_t *dqf; - - - nby = jd->msx * jd->msy; /* Number of Y blocks (1, 2 or 4) */ - nbc = 2; /* Number of C blocks (2) */ - bp = jd->mcubuf; /* Pointer to the first block */ - - for (blk = 0; blk < nby + nbc; blk++) { - cmp = (blk < nby) ? 0 : blk - nby + 1; /* Component number 0:Y, 1:Cb, 2:Cr */ - id = cmp ? 1 : 0; /* Huffman table ID of the component */ - - /* Extract a DC element from input stream */ - hb = jd->huffbits[id][0]; /* Huffman table for the DC element */ - hc = jd->huffcode[id][0]; - hd = jd->huffdata[id][0]; - b = huffext(jd, hb, hc, hd); /* Extract a huffman coded data (bit length) */ - if (b < 0) return 0 - b; /* Err: invalid code or input */ - d = jd->dcv[cmp]; /* DC value of previous block */ - if (b) { /* If there is any difference from previous block */ - e = bitext(jd, b); /* Extract data bits */ - if (e < 0) return 0 - e; /* Err: input */ - b = 1 << (b - 1); /* MSB position */ - if (!(e & b)) e -= (b << 1) - 1; /* Restore sign if needed */ - d += e; /* Get current value */ - jd->dcv[cmp] = (int16_t)d; /* Save current DC value for next block */ - } - dqf = jd->qttbl[jd->qtid[cmp]]; /* De-quantizer table ID for this component */ - tmp[0] = d * dqf[0] >> 8; /* De-quantize, apply scale factor of Arai algorithm and descale 8 bits */ - - /* Extract following 63 AC elements from input stream */ - for (i = 1; i < 64; i++) tmp[i] = 0; /* Clear rest of elements */ - hb = jd->huffbits[id][1]; /* Huffman table for the AC elements */ - hc = jd->huffcode[id][1]; - hd = jd->huffdata[id][1]; - i = 1; /* Top of the AC elements */ - do { - b = huffext(jd, hb, hc, hd); /* Extract a huffman coded value (zero runs and bit length) */ - if (b == 0) break; /* EOB? */ - if (b < 0) return 0 - b; /* Err: invalid code or input error */ - z = (uint32_t)b >> 4; /* Number of leading zero elements */ - if (z) { - i += z; /* Skip zero elements */ - if (i >= 64) return JDR_FMT1; /* Too long zero run */ - } - if (b &= 0x0F) { /* Bit length */ - d = bitext(jd, b); /* Extract data bits */ - if (d < 0) return 0 - d; /* Err: input device */ - b = 1 << (b - 1); /* MSB position */ - if (!(d & b)) d -= (b << 1) - 1;/* Restore negative value if needed */ - z = ZIG(i); /* Zigzag-order to raster-order converted index */ - tmp[z] = d * dqf[z] >> 8; /* De-quantize, apply scale factor of Arai algorithm and descale 8 bits */ - } - } while (++i < 64); /* Next AC element */ - - if (JD_USE_SCALE && jd->scale == 3) - *bp = (*tmp / 256) + 128; /* If scale ratio is 1/8, IDCT can be ommited and only DC element is used */ - else - block_idct(tmp, bp); /* Apply IDCT and store the block to the MCU buffer */ - - bp += 64; /* Next block */ - } - - return JDR_OK; /* All blocks have been loaded successfully */ -} - - - - -/*-----------------------------------------------------------------------*/ -/* Output an MCU: Convert YCrCb to RGB and output it in RGB form */ -/*-----------------------------------------------------------------------*/ - -static -esp_rom_tjpgd_result_t mcu_output ( - esp_rom_tjpgd_dec_t* jd, /* Pointer to the decompressor object */ - uint32_t (*outfunc)(esp_rom_tjpgd_dec_t*, void*, esp_rom_tjpgd_rect_t*), /* RGB output function */ - uint32_t x, /* MCU position in the image (left of the MCU) */ - uint32_t y /* MCU position in the image (top of the MCU) */ -) -{ - const int32_t CVACC = (sizeof (int32_t) > 2) ? 1024 : 128; - uint32_t ix, iy, mx, my, rx, ry; - int32_t yy, cb, cr; - uint8_t *py, *pc, *rgb24; - esp_rom_tjpgd_rect_t rect; - - - mx = jd->msx * 8; my = jd->msy * 8; /* MCU size (pixel) */ - rx = (x + mx <= jd->width) ? mx : jd->width - x; /* Output rectangular size (it may be clipped at right/bottom end) */ - ry = (y + my <= jd->height) ? my : jd->height - y; - if (JD_USE_SCALE) { - rx >>= jd->scale; ry >>= jd->scale; - if (!rx || !ry) return JDR_OK; /* Skip this MCU if all pixel is to be rounded off */ - x >>= jd->scale; y >>= jd->scale; - } - rect.left = x; rect.right = x + rx - 1; /* Rectangular area in the frame buffer */ - rect.top = y; rect.bottom = y + ry - 1; - - - if (!JD_USE_SCALE || jd->scale != 3) { /* Not for 1/8 scaling */ - - /* Build an RGB MCU from discrete comopnents */ - rgb24 = (uint8_t*)jd->workbuf; - for (iy = 0; iy < my; iy++) { - pc = jd->mcubuf; - py = pc + iy * 8; - if (my == 16) { /* Double block height? */ - pc += 64 * 4 + (iy >> 1) * 8; - if (iy >= 8) py += 64; - } else { /* Single block height */ - pc += mx * 8 + iy * 8; - } - for (ix = 0; ix < mx; ix++) { - cb = pc[0] - 128; /* Get Cb/Cr component and restore right level */ - cr = pc[64] - 128; - if (mx == 16) { /* Double block width? */ - if (ix == 8) py += 64 - 8; /* Jump to next block if double block heigt */ - pc += ix & 1; /* Increase chroma pointer every two pixels */ - } else { /* Single block width */ - pc++; /* Increase chroma pointer every pixel */ - } - yy = *py++; /* Get Y component */ - - /* Convert YCbCr to RGB */ - *rgb24++ = /* R */ BYTECLIP(yy + ((int32_t)(1.402 * CVACC) * cr) / CVACC); - *rgb24++ = /* G */ BYTECLIP(yy - ((int32_t)(0.344 * CVACC) * cb + (int32_t)(0.714 * CVACC) * cr) / CVACC); - *rgb24++ = /* B */ BYTECLIP(yy + ((int32_t)(1.772 * CVACC) * cb) / CVACC); - } - } - - /* Descale the MCU rectangular if needed */ - if (JD_USE_SCALE && jd->scale) { - uint32_t x, y, r, g, b, s, w, a; - uint8_t *op; - - /* Get averaged RGB value of each square correcponds to a pixel */ - s = jd->scale * 2; /* Bumber of shifts for averaging */ - w = 1 << jd->scale; /* Width of square */ - a = (mx - w) * 3; /* Bytes to skip for next line in the square */ - op = (uint8_t*)jd->workbuf; - for (iy = 0; iy < my; iy += w) { - for (ix = 0; ix < mx; ix += w) { - rgb24 = (uint8_t*)jd->workbuf + (iy * mx + ix) * 3; - r = g = b = 0; - for (y = 0; y < w; y++) { /* Accumulate RGB value in the square */ - for (x = 0; x < w; x++) { - r += *rgb24++; - g += *rgb24++; - b += *rgb24++; - } - rgb24 += a; - } /* Put the averaged RGB value as a pixel */ - *op++ = (uint8_t)(r >> s); - *op++ = (uint8_t)(g >> s); - *op++ = (uint8_t)(b >> s); - } - } - } - - } else { /* For only 1/8 scaling (left-top pixel in each block are the DC value of the block) */ - - /* Build a 1/8 descaled RGB MCU from discrete comopnents */ - rgb24 = (uint8_t*)jd->workbuf; - pc = jd->mcubuf + mx * my; - cb = pc[0] - 128; /* Get Cb/Cr component and restore right level */ - cr = pc[64] - 128; - for (iy = 0; iy < my; iy += 8) { - py = jd->mcubuf; - if (iy == 8) py += 64 * 2; - for (ix = 0; ix < mx; ix += 8) { - yy = *py; /* Get Y component */ - py += 64; - - /* Convert YCbCr to RGB */ - *rgb24++ = /* R */ BYTECLIP(yy + ((int32_t)(1.402 * CVACC) * cr / CVACC)); - *rgb24++ = /* G */ BYTECLIP(yy - ((int32_t)(0.344 * CVACC) * cb + (int32_t)(0.714 * CVACC) * cr) / CVACC); - *rgb24++ = /* B */ BYTECLIP(yy + ((int32_t)(1.772 * CVACC) * cb / CVACC)); - } - } - } - - /* Squeeze up pixel table if a part of MCU is to be truncated */ - mx >>= jd->scale; - if (rx < mx) { - uint8_t *s, *d; - uint32_t x, y; - - s = d = (uint8_t*)jd->workbuf; - for (y = 0; y < ry; y++) { - for (x = 0; x < rx; x++) { /* Copy effective pixels */ - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - } - s += (mx - rx) * 3; /* Skip truncated pixels */ - } - } - - /* Convert RGB888 to RGB565 if needed */ - if (JD_FORMAT == 1) { - uint8_t *s = (uint8_t*)jd->workbuf; - uint16_t w, *d = (uint16_t*)s; - uint32_t n = rx * ry; - - do { - w = (*s++ & 0xF8) << 8; /* RRRRR----------- */ - w |= (*s++ & 0xFC) << 3; /* -----GGGGGG----- */ - w |= *s++ >> 3; /* -----------BBBBB */ - *d++ = w; - } while (--n); - } - - /* Output the RGB rectangular */ - return outfunc(jd, jd->workbuf, &rect) ? JDR_OK : JDR_INTR; -} - - - - -/*-----------------------------------------------------------------------*/ -/* Process restart interval */ -/*-----------------------------------------------------------------------*/ - -static -esp_rom_tjpgd_result_t restart ( - esp_rom_tjpgd_dec_t* jd, /* Pointer to the decompressor object */ - uint16_t rstn /* Expected restert sequense number */ -) -{ - uint32_t i, dc; - uint16_t d; - uint8_t *dp; - - - /* Discard padding bits and get two bytes from the input stream */ - dp = jd->dptr; dc = jd->dctr; - d = 0; - for (i = 0; i < 2; i++) { - if (!dc) { /* No input data is available, re-fill input buffer */ - dp = jd->inbuf; - dc = jd->infunc(jd, dp, JD_SZBUF); - if (!dc) return JDR_INP; - } else { - dp++; - } - dc--; - d = (d << 8) | *dp; /* Get a byte */ - } - jd->dptr = dp; jd->dctr = dc; jd->dmsk = 0; - - /* Check the marker */ - if ((d & 0xFFD8) != 0xFFD0 || (d & 7) != (rstn & 7)) - return JDR_FMT1; /* Err: expected RSTn marker is not detected (may be collapted data) */ - - /* Reset DC offset */ - jd->dcv[2] = jd->dcv[1] = jd->dcv[0] = 0; - - return JDR_OK; -} - - - - -/*-----------------------------------------------------------------------*/ -/* Analyze the JPEG image and Initialize decompressor object */ -/*-----------------------------------------------------------------------*/ - -#define LDB_WORD(ptr) (uint16_t)(((uint16_t)*((uint8_t*)(ptr))<<8)|(uint16_t)*(uint8_t*)((ptr)+1)) - - -esp_rom_tjpgd_result_t esp_rom_tjpgd_prepare ( - esp_rom_tjpgd_dec_t* jd, /* Blank decompressor object */ - uint32_t (*infunc)(esp_rom_tjpgd_dec_t*, uint8_t*, uint32_t), /* JPEG strem input function */ - void* pool, /* Working buffer for the decompression session */ - uint32_t sz_pool, /* Size of working buffer */ - void* dev /* I/O device identifier for the session */ -) -{ - uint8_t *seg, b; - uint16_t marker; - uint32_t ofs; - uint32_t n, i, j, len; - esp_rom_tjpgd_result_t rc; - - - if (!pool) return JDR_PAR; - - jd->pool = pool; /* Work memroy */ - jd->sz_pool = sz_pool; /* Size of given work memory */ - jd->infunc = infunc; /* Stream input function */ - jd->device = dev; /* I/O device identifier */ - jd->nrst = 0; /* No restart interval (default) */ - - for (i = 0; i < 2; i++) { /* Nulls pointers */ - for (j = 0; j < 2; j++) { - jd->huffbits[i][j] = 0; - jd->huffcode[i][j] = 0; - jd->huffdata[i][j] = 0; - } - } - for (i = 0; i < 4; i++) jd->qttbl[i] = 0; - - jd->inbuf = seg = alloc_pool(jd, JD_SZBUF); /* Allocate stream input buffer */ - if (!seg) return JDR_MEM1; - - if (jd->infunc(jd, seg, 2) != 2) return JDR_INP;/* Check SOI marker */ - if (LDB_WORD(seg) != 0xFFD8) return JDR_FMT1; /* Err: SOI is not detected */ - ofs = 2; - - for (;;) { - /* Get a JPEG marker */ - if (jd->infunc(jd, seg, 4) != 4) return JDR_INP; - marker = LDB_WORD(seg); /* Marker */ - len = LDB_WORD(seg + 2); /* Length field */ - if (len <= 2 || (marker >> 8) != 0xFF) return JDR_FMT1; - len -= 2; /* Content size excluding length field */ - ofs += 4 + len; /* Number of bytes loaded */ - - switch (marker & 0xFF) { - case 0xC0: /* SOF0 (baseline JPEG) */ - /* Load segment data */ - if (len > JD_SZBUF) return JDR_MEM2; - if (jd->infunc(jd, seg, len) != len) return JDR_INP; - - jd->width = LDB_WORD(seg+3); /* Image width in unit of pixel */ - jd->height = LDB_WORD(seg+1); /* Image height in unit of pixel */ - if (seg[5] != 3) return JDR_FMT3; /* Err: Supports only Y/Cb/Cr format */ - - /* Check three image components */ - for (i = 0; i < 3; i++) { - b = seg[7 + 3 * i]; /* Get sampling factor */ - if (!i) { /* Y component */ - if (b != 0x11 && b != 0x22 && b != 0x21)/* Check sampling factor */ - return JDR_FMT3; /* Err: Supports only 4:4:4, 4:2:0 or 4:2:2 */ - jd->msx = b >> 4; jd->msy = b & 15; /* Size of MCU [blocks] */ - } else { /* Cb/Cr component */ - if (b != 0x11) return JDR_FMT3; /* Err: Sampling factor of Cr/Cb must be 1 */ - } - b = seg[8 + 3 * i]; /* Get dequantizer table ID for this component */ - if (b > 3) return JDR_FMT3; /* Err: Invalid ID */ - jd->qtid[i] = b; - } - break; - - case 0xDD: /* DRI */ - /* Load segment data */ - if (len > JD_SZBUF) return JDR_MEM2; - if (jd->infunc(jd, seg, len) != len) return JDR_INP; - - /* Get restart interval (MCUs) */ - jd->nrst = LDB_WORD(seg); - break; - - case 0xC4: /* DHT */ - /* Load segment data */ - if (len > JD_SZBUF) return JDR_MEM2; - if (jd->infunc(jd, seg, len) != len) return JDR_INP; - - /* Create huffman tables */ - rc = create_huffman_tbl(jd, seg, len); - if (rc) return rc; - break; - - case 0xDB: /* DQT */ - /* Load segment data */ - if (len > JD_SZBUF) return JDR_MEM2; - if (jd->infunc(jd, seg, len) != len) return JDR_INP; - - /* Create de-quantizer tables */ - rc = create_qt_tbl(jd, seg, len); - if (rc) return rc; - break; - - case 0xDA: /* SOS */ - /* Load segment data */ - if (len > JD_SZBUF) return JDR_MEM2; - if (jd->infunc(jd, seg, len) != len) return JDR_INP; - - if (!jd->width || !jd->height) return JDR_FMT1; /* Err: Invalid image size */ - - if (seg[0] != 3) return JDR_FMT3; /* Err: Supports only three color components format */ - - /* Check if all tables corresponding to each components have been loaded */ - for (i = 0; i < 3; i++) { - b = seg[2 + 2 * i]; /* Get huffman table ID */ - if (b != 0x00 && b != 0x11) return JDR_FMT3; /* Err: Different table number for DC/AC element */ - b = i ? 1 : 0; - if (!jd->huffbits[b][0] || !jd->huffbits[b][1]) /* Check huffman table for this component */ - return JDR_FMT1; /* Err: Huffman table not loaded */ - if (!jd->qttbl[jd->qtid[i]]) return JDR_FMT1; /* Err: Dequantizer table not loaded */ - } - - /* Allocate working buffer for MCU and RGB */ - n = jd->msy * jd->msx; /* Number of Y blocks in the MCU */ - if (!n) return JDR_FMT1; /* Err: SOF0 has not been loaded */ - len = n * 64 * 2 + 64; /* Allocate buffer for IDCT and RGB output */ - if (len < 256) len = 256; /* but at least 256 byte is required for IDCT */ - jd->workbuf = alloc_pool(jd, len); /* and it may occupy a part of following MCU working buffer for RGB output */ - if (!jd->workbuf) return JDR_MEM1; /* Err: not enough memory */ - jd->mcubuf = alloc_pool(jd, (n + 2) * 64); /* Allocate MCU working buffer */ - if (!jd->mcubuf) return JDR_MEM1; /* Err: not enough memory */ - - /* Pre-load the JPEG data to extract it from the bit stream */ - jd->dptr = seg; jd->dctr = 0; jd->dmsk = 0; /* Prepare to read bit stream */ - if (ofs %= JD_SZBUF) { /* Align read offset to JD_SZBUF */ - jd->dctr = jd->infunc(jd, seg + ofs, JD_SZBUF - (uint32_t)ofs); - jd->dptr = seg + ofs - 1; - } - - return JDR_OK; /* Initialization succeeded. Ready to decompress the JPEG image. */ - - case 0xC1: /* SOF1 */ - case 0xC2: /* SOF2 */ - case 0xC3: /* SOF3 */ - case 0xC5: /* SOF5 */ - case 0xC6: /* SOF6 */ - case 0xC7: /* SOF7 */ - case 0xC9: /* SOF9 */ - case 0xCA: /* SOF10 */ - case 0xCB: /* SOF11 */ - case 0xCD: /* SOF13 */ - case 0xCE: /* SOF14 */ - case 0xCF: /* SOF15 */ - case 0xD9: /* EOI */ - return JDR_FMT3; /* Unsuppoted JPEG standard (may be progressive JPEG) */ - - default: /* Unknown segment (comment, exif or etc..) */ - /* Skip segment data */ - if (jd->infunc(jd, 0, len) != len) /* Null pointer specifies to skip bytes of stream */ - return JDR_INP; - } - } -} - - - - -/*-----------------------------------------------------------------------*/ -/* Start to decompress the JPEG picture */ -/*-----------------------------------------------------------------------*/ - -esp_rom_tjpgd_result_t esp_rom_tjpgd_decomp ( - esp_rom_tjpgd_dec_t* jd, /* Initialized decompression object */ - uint32_t (*outfunc)(esp_rom_tjpgd_dec_t*, void*, esp_rom_tjpgd_rect_t*), /* RGB output function */ - uint8_t scale /* Output de-scaling factor (0 to 3) */ -) -{ - uint32_t x, y, mx, my; - uint16_t rst, rsc; - esp_rom_tjpgd_result_t rc; - - - if (scale > (JD_USE_SCALE ? 3 : 0)) return JDR_PAR; - jd->scale = scale; - - mx = jd->msx * 8; my = jd->msy * 8; /* Size of the MCU (pixel) */ - - jd->dcv[2] = jd->dcv[1] = jd->dcv[0] = 0; /* Initialize DC values */ - rst = rsc = 0; - - rc = JDR_OK; - for (y = 0; y < jd->height; y += my) { /* Vertical loop of MCUs */ - for (x = 0; x < jd->width; x += mx) { /* Horizontal loop of MCUs */ - if (jd->nrst && rst++ == jd->nrst) { /* Process restart interval if enabled */ - rc = restart(jd, rsc++); - if (rc != JDR_OK) return rc; - rst = 1; - } - rc = mcu_load(jd); /* Load an MCU (decompress huffman coded stream and apply IDCT) */ - if (rc != JDR_OK) return rc; - rc = mcu_output(jd, outfunc, x, y); /* Output the MCU (color space conversion, scaling and output) */ - if (rc != JDR_OK) return rc; - } - } - - return rc; -} - -#endif // ESP_ROM_HAS_JPEG_DECODE diff --git a/components/esp_rom/test/test_tjpgd.c b/components/esp_rom/test/test_tjpgd.c deleted file mode 100644 index 673d91a358..0000000000 --- a/components/esp_rom/test/test_tjpgd.c +++ /dev/null @@ -1,89 +0,0 @@ -#include -#include -#include -#include -#include "sdkconfig.h" -#include "unity.h" - -#include "esp_rom_tjpgd.h" -#include "test_tjpgd_logo.h" - -typedef struct { - const unsigned char *inData; - int inPos; - unsigned char *outData; - int outW; - int outH; -} JpegDev; - -static uint32_t infunc(esp_rom_tjpgd_dec_t *decoder, uint8_t *buf, uint32_t len) -{ - JpegDev *jd = (JpegDev *)decoder->device; - printf("Reading %d bytes from pos %d\n", len, jd->inPos); - if (buf != NULL) { - memcpy(buf, jd->inData + jd->inPos, len); - } - jd->inPos += len; - return len; -} - -static uint32_t outfunc(esp_rom_tjpgd_dec_t *decoder, void *bitmap, esp_rom_tjpgd_rect_t *rect) -{ - unsigned char *in = (unsigned char *)bitmap; - unsigned char *out; - int y; - printf("Rect %d,%d - %d,%d\n", rect->top, rect->left, rect->bottom, rect->right); - JpegDev *jd = (JpegDev *)decoder->device; - for (y = rect->top; y <= rect->bottom; y++) { - out = jd->outData + ((jd->outW * y) + rect->left) * 3; - memcpy(out, in, ((rect->right - rect->left) + 1) * 3); - in += ((rect->right - rect->left) + 1) * 3; - } - return 1; -} - -#define TESTW 48 -#define TESTH 48 -#define WORKSZ 3100 - -TEST_CASE("Test JPEG decompression library", "[rom][tjpgd]") -{ - char aapix[] = " .:;+=xX$$"; - unsigned char *decoded, *p; - char *work; - int r; - int x, y, v; - esp_rom_tjpgd_dec_t decoder; - JpegDev jd; - decoded = malloc(TESTW * TESTH * 3); - for (x = 0; x < TESTW * TESTH * 3; x += 2) { - decoded[x] = 0; - decoded[x + 1] = 0xff; - } - work = malloc(WORKSZ); - memset(work, 0, WORKSZ); - - jd.inData = logo_jpg; - jd.inPos = 0; - jd.outData = decoded; - jd.outW = TESTW; - jd.outH = TESTH; - - r = esp_rom_tjpgd_prepare(&decoder, infunc, work, WORKSZ, (void *)&jd); - TEST_ASSERT_EQUAL(r, JDR_OK); - r = esp_rom_tjpgd_decomp(&decoder, outfunc, 0); - TEST_ASSERT_EQUAL(r, JDR_OK); - - p = decoded + 2; - for (y = 0; y < TESTH; y++) { - for (x = 0; x < TESTH; x++) { - v = ((*p) * (sizeof(aapix) - 2) * 2) / 256; - printf("%c%c", aapix[v / 2], aapix[(v + 1) / 2]); - p += 3; - } - printf("%c%c", ' ', '\n'); - } - - free(work); - free(decoded); -} diff --git a/docs/en/migration-guides/release-5.x/removed-components.rst b/docs/en/migration-guides/release-5.x/removed-components.rst index 7d32006a84..9506d0b38a 100644 --- a/docs/en/migration-guides/release-5.x/removed-components.rst +++ b/docs/en/migration-guides/release-5.x/removed-components.rst @@ -20,6 +20,7 @@ Following components are removed from ESP-IDF and moved to `IDF Component Regist * `coap `_ * `esp-cryptoauthlib `_ * `qrcode `_ +* `tjpgd `_ .. note:: Please note that http parser functionality which was previously part of ``nghttp`` component is now part of :component:`http_parser ` component. diff --git a/docs/zh_CN/migration-guides/release-5.x/removed-components.rst b/docs/zh_CN/migration-guides/release-5.x/removed-components.rst index 1050593192..47adafd2cf 100644 --- a/docs/zh_CN/migration-guides/release-5.x/removed-components.rst +++ b/docs/zh_CN/migration-guides/release-5.x/removed-components.rst @@ -18,6 +18,7 @@ * `sh2lib `_ * `expat `_ * `coap `_ +* `tjpgd `_ .. note:: 请注意,http 解析功能以前属于 ``nghttp`` 组件一部分,但现在属于 :component:`http_parser ` 组件。 diff --git a/examples/peripherals/lcd/tjpgd/main/decode_image.c b/examples/peripherals/lcd/tjpgd/main/decode_image.c index f7182a32cb..3a02a04862 100644 --- a/examples/peripherals/lcd/tjpgd/main/decode_image.c +++ b/examples/peripherals/lcd/tjpgd/main/decode_image.c @@ -15,132 +15,54 @@ format if you want to use a different image file. */ #include "decode_image.h" -#include "esp_rom_tjpgd.h" +#include "jpeg_decoder.h" #include "esp_log.h" +#include "esp_check.h" #include +#include "freertos/FreeRTOS.h" //Reference the binary-included jpeg file extern const uint8_t image_jpg_start[] asm("_binary_image_jpg_start"); extern const uint8_t image_jpg_end[] asm("_binary_image_jpg_end"); //Define the height and width of the jpeg file. Make sure this matches the actual jpeg //dimensions. -#define IMAGE_W 336 -#define IMAGE_H 256 const char *TAG = "ImageDec"; -//Data that is passed from the decoder function to the infunc/outfunc functions. -typedef struct { - const unsigned char *inData; //Pointer to jpeg data - uint16_t inPos; //Current position in jpeg data - uint16_t **outData; //Array of IMAGE_H pointers to arrays of IMAGE_W 16-bit pixel values - int outW; //Width of the resulting file - int outH; //Height of the resulting file -} JpegDev; - -//Input function for jpeg decoder. Just returns bytes from the inData field of the JpegDev structure. -static uint32_t infunc(esp_rom_tjpgd_dec_t *decoder, uint8_t *buf, uint32_t len) -{ - //Read bytes from input file - JpegDev *jd = (JpegDev *)decoder->device; - if (buf != NULL) { - memcpy(buf, jd->inData + jd->inPos, len); - } - jd->inPos += len; - return len; -} - -//Output function. Re-encodes the RGB888 data from the decoder as big-endian RGB565 and -//stores it in the outData array of the JpegDev structure. -static uint32_t outfunc(esp_rom_tjpgd_dec_t *decoder, void *bitmap, esp_rom_tjpgd_rect_t *rect) -{ - JpegDev *jd = (JpegDev *)decoder->device; - uint8_t *in = (uint8_t *)bitmap; - for (int y = rect->top; y <= rect->bottom; y++) { - for (int x = rect->left; x <= rect->right; x++) { - //We need to convert the 3 bytes in `in` to a rgb565 value. - uint16_t v = 0; - v |= ((in[0] >> 3) << 11); - v |= ((in[1] >> 2) << 5); - v |= ((in[2] >> 3) << 0); - //The LCD wants the 16-bit value in big-endian, so swap bytes - v = (v >> 8) | (v << 8); - jd->outData[y][x] = v; - in += 3; - } - } - return 1; -} - -//Size of the work space for the jpeg decoder. -#define WORKSZ 3100 - //Decode the embedded image into pixel lines that can be used with the rest of the logic. -esp_err_t decode_image(uint16_t ***pixels) +esp_err_t decode_image(uint16_t **pixels) { - char *work = NULL; - int r; - esp_rom_tjpgd_dec_t decoder; - JpegDev jd; *pixels = NULL; esp_err_t ret = ESP_OK; //Alocate pixel memory. Each line is an array of IMAGE_W 16-bit pixels; the `*pixels` array itself contains pointers to these lines. - *pixels = calloc(IMAGE_H, sizeof(uint16_t *)); - if (*pixels == NULL) { - ESP_LOGE(TAG, "Error allocating memory for lines"); - ret = ESP_ERR_NO_MEM; - goto err; - } - for (int i = 0; i < IMAGE_H; i++) { - (*pixels)[i] = malloc(IMAGE_W * sizeof(uint16_t)); - if ((*pixels)[i] == NULL) { - ESP_LOGE(TAG, "Error allocating memory for line %d", i); - ret = ESP_ERR_NO_MEM; - goto err; + *pixels = calloc(IMAGE_H * IMAGE_W, sizeof(uint16_t)); + ESP_GOTO_ON_FALSE((*pixels), ESP_ERR_NO_MEM, err, TAG, "Error allocating memory for lines"); + + //JPEG decode config + esp_jpeg_image_cfg_t jpeg_cfg = { + .indata = (uint8_t *)image_jpg_start, + .indata_size = image_jpg_end - image_jpg_start, + .outbuf = (uint8_t*)(*pixels), + .outbuf_size = IMAGE_W * IMAGE_H * sizeof(uint16_t), + .out_format = JPEG_IMAGE_FORMAT_RGB565, + .out_scale = JPEG_IMAGE_SCALE_0, + .flags = { + .swap_color_bytes = 1, } - } + }; - //Allocate the work space for the jpeg decoder. - work = calloc(WORKSZ, 1); - if (work == NULL) { - ESP_LOGE(TAG, "Cannot allocate workspace"); - ret = ESP_ERR_NO_MEM; - goto err; - } + //JPEG decode + esp_jpeg_image_output_t outimg; + esp_jpeg_decode(&jpeg_cfg, &outimg); - //Populate fields of the JpegDev struct. - jd.inData = image_jpg_start; - jd.inPos = 0; - jd.outData = *pixels; - jd.outW = IMAGE_W; - jd.outH = IMAGE_H; + ESP_LOGI(TAG, "JPEG image decoded! Size of the decoded image is: %dpx x %dpx", outimg.width, outimg.height); - //Prepare and decode the jpeg. - r = esp_rom_tjpgd_prepare(&decoder, infunc, work, WORKSZ, (void *)&jd); - if (r != JDR_OK) { - ESP_LOGE(TAG, "Image decoder: jd_prepare failed (%d)", r); - ret = ESP_ERR_NOT_SUPPORTED; - goto err; - } - r = esp_rom_tjpgd_decomp(&decoder, outfunc, 0); - if (r != JDR_OK && r != JDR_FMT1) { - ESP_LOGE(TAG, "Image decoder: jd_decode failed (%d)", r); - ret = ESP_ERR_NOT_SUPPORTED; - goto err; - } - - //All done! Free the work area (as we don't need it anymore) and return victoriously. - free(work); return ret; err: //Something went wrong! Exit cleanly, de-allocating everything we allocated. if (*pixels != NULL) { - for (int i = 0; i < IMAGE_H; i++) { - free((*pixels)[i]); - } free(*pixels); } - free(work); return ret; } diff --git a/examples/peripherals/lcd/tjpgd/main/decode_image.h b/examples/peripherals/lcd/tjpgd/main/decode_image.h index 8fa1155005..44800b17ba 100644 --- a/examples/peripherals/lcd/tjpgd/main/decode_image.h +++ b/examples/peripherals/lcd/tjpgd/main/decode_image.h @@ -8,6 +8,9 @@ #include #include "esp_err.h" +#define IMAGE_W 320 +#define IMAGE_H 240 + /** * @brief Decode the jpeg ``image.jpg`` embedded into the program file into pixel data. * @@ -17,4 +20,4 @@ * - ESP_ERR_NO_MEM if out of memory * - ESP_OK on succesful decode */ -esp_err_t decode_image(uint16_t ***pixels); +esp_err_t decode_image(uint16_t **pixels); diff --git a/examples/peripherals/lcd/tjpgd/main/idf_component.yml b/examples/peripherals/lcd/tjpgd/main/idf_component.yml new file mode 100644 index 0000000000..a2167bf4c2 --- /dev/null +++ b/examples/peripherals/lcd/tjpgd/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + idf: ">=4.4" + esp_jpeg: ">=1.0.2" diff --git a/examples/peripherals/lcd/tjpgd/main/image.jpg b/examples/peripherals/lcd/tjpgd/main/image.jpg index 803ca2cdca..cacad09050 100644 Binary files a/examples/peripherals/lcd/tjpgd/main/image.jpg and b/examples/peripherals/lcd/tjpgd/main/image.jpg differ diff --git a/examples/peripherals/lcd/tjpgd/main/lcd_tjpgd_example_main.c b/examples/peripherals/lcd/tjpgd/main/lcd_tjpgd_example_main.c index 99231c8568..6a27dce742 100644 --- a/examples/peripherals/lcd/tjpgd/main/lcd_tjpgd_example_main.c +++ b/examples/peripherals/lcd/tjpgd/main/lcd_tjpgd_example_main.c @@ -28,7 +28,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////// Please update the following configuration according to your LCD spec ////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#define EXAMPLE_LCD_PIXEL_CLOCK_HZ (10 * 1000 * 1000) +#define EXAMPLE_LCD_PIXEL_CLOCK_HZ (20 * 1000 * 1000) #define EXAMPLE_LCD_BK_LIGHT_ON_LEVEL 0 #define EXAMPLE_LCD_BK_LIGHT_OFF_LEVEL !EXAMPLE_LCD_BK_LIGHT_ON_LEVEL #define EXAMPLE_PIN_NUM_DATA0 23 /*!< for 1-line SPI, this also refered as MOSI */ diff --git a/examples/peripherals/lcd/tjpgd/main/pretty_effect.c b/examples/peripherals/lcd/tjpgd/main/pretty_effect.c index 3aa8ac03c9..b7e557f990 100644 --- a/examples/peripherals/lcd/tjpgd/main/pretty_effect.c +++ b/examples/peripherals/lcd/tjpgd/main/pretty_effect.c @@ -9,15 +9,13 @@ #include "sdkconfig.h" #include "decode_image.h" -uint16_t **pixels; +uint16_t *pixels; //Grab a rgb16 pixel from the esp32_tiles image static inline uint16_t get_bgnd_pixel(int x, int y) { - //Image has an 8x8 pixel margin, so we can also resolve e.g. [-3, 243] - x+=8; - y+=8; - return pixels[y][x]; + //Get color of the pixel on x,y coords + return (uint16_t) *(pixels + (y * IMAGE_W) + x); } //This variable is used to detect the next frame. diff --git a/examples/peripherals/spi_master/lcd/main/decode_image.c b/examples/peripherals/spi_master/lcd/main/decode_image.c index a9a460bc39..bedaf4334d 100644 --- a/examples/peripherals/spi_master/lcd/main/decode_image.c +++ b/examples/peripherals/spi_master/lcd/main/decode_image.c @@ -18,132 +18,54 @@ format if you want to use a different image file. */ #include "decode_image.h" -#include "esp_rom_tjpgd.h" +#include "jpeg_decoder.h" #include "esp_log.h" +#include "esp_check.h" #include +#include "freertos/FreeRTOS.h" //Reference the binary-included jpeg file extern const uint8_t image_jpg_start[] asm("_binary_image_jpg_start"); extern const uint8_t image_jpg_end[] asm("_binary_image_jpg_end"); //Define the height and width of the jpeg file. Make sure this matches the actual jpeg //dimensions. -#define IMAGE_W 336 -#define IMAGE_H 256 const char *TAG = "ImageDec"; -//Data that is passed from the decoder function to the infunc/outfunc functions. -typedef struct { - const unsigned char *inData; //Pointer to jpeg data - uint16_t inPos; //Current position in jpeg data - uint16_t **outData; //Array of IMAGE_H pointers to arrays of IMAGE_W 16-bit pixel values - int outW; //Width of the resulting file - int outH; //Height of the resulting file -} JpegDev; - -//Input function for jpeg decoder. Just returns bytes from the inData field of the JpegDev structure. -static uint32_t infunc(esp_rom_tjpgd_dec_t *decoder, uint8_t *buf, uint32_t len) -{ - //Read bytes from input file - JpegDev *jd = (JpegDev *)decoder->device; - if (buf != NULL) { - memcpy(buf, jd->inData + jd->inPos, len); - } - jd->inPos += len; - return len; -} - -//Output function. Re-encodes the RGB888 data from the decoder as big-endian RGB565 and -//stores it in the outData array of the JpegDev structure. -static uint32_t outfunc(esp_rom_tjpgd_dec_t *decoder, void *bitmap, esp_rom_tjpgd_rect_t *rect) -{ - JpegDev *jd = (JpegDev *)decoder->device; - uint8_t *in = (uint8_t *)bitmap; - for (int y = rect->top; y <= rect->bottom; y++) { - for (int x = rect->left; x <= rect->right; x++) { - //We need to convert the 3 bytes in `in` to a rgb565 value. - uint16_t v = 0; - v |= ((in[0] >> 3) << 11); - v |= ((in[1] >> 2) << 5); - v |= ((in[2] >> 3) << 0); - //The LCD wants the 16-bit value in big-endian, so swap bytes - v = (v >> 8) | (v << 8); - jd->outData[y][x] = v; - in += 3; - } - } - return 1; -} - -//Size of the work space for the jpeg decoder. -#define WORKSZ 3100 - //Decode the embedded image into pixel lines that can be used with the rest of the logic. -esp_err_t decode_image(uint16_t ***pixels) +esp_err_t decode_image(uint16_t **pixels) { - char *work = NULL; - int r; - esp_rom_tjpgd_dec_t decoder; - JpegDev jd; *pixels = NULL; esp_err_t ret = ESP_OK; //Alocate pixel memory. Each line is an array of IMAGE_W 16-bit pixels; the `*pixels` array itself contains pointers to these lines. - *pixels = calloc(IMAGE_H, sizeof(uint16_t *)); - if (*pixels == NULL) { - ESP_LOGE(TAG, "Error allocating memory for lines"); - ret = ESP_ERR_NO_MEM; - goto err; - } - for (int i = 0; i < IMAGE_H; i++) { - (*pixels)[i] = malloc(IMAGE_W * sizeof(uint16_t)); - if ((*pixels)[i] == NULL) { - ESP_LOGE(TAG, "Error allocating memory for line %d", i); - ret = ESP_ERR_NO_MEM; - goto err; + *pixels = calloc(IMAGE_H * IMAGE_W, sizeof(uint16_t)); + ESP_GOTO_ON_FALSE((*pixels), ESP_ERR_NO_MEM, err, TAG, "Error allocating memory for lines"); + + //JPEG decode config + esp_jpeg_image_cfg_t jpeg_cfg = { + .indata = (uint8_t *)image_jpg_start, + .indata_size = image_jpg_end - image_jpg_start, + .outbuf = (uint8_t*)(*pixels), + .outbuf_size = IMAGE_W * IMAGE_H * sizeof(uint16_t), + .out_format = JPEG_IMAGE_FORMAT_RGB565, + .out_scale = JPEG_IMAGE_SCALE_0, + .flags = { + .swap_color_bytes = 1, } - } + }; - //Allocate the work space for the jpeg decoder. - work = calloc(WORKSZ, 1); - if (work == NULL) { - ESP_LOGE(TAG, "Cannot allocate workspace"); - ret = ESP_ERR_NO_MEM; - goto err; - } + //JPEG decode + esp_jpeg_image_output_t outimg; + esp_jpeg_decode(&jpeg_cfg, &outimg); - //Populate fields of the JpegDev struct. - jd.inData = image_jpg_start; - jd.inPos = 0; - jd.outData = *pixels; - jd.outW = IMAGE_W; - jd.outH = IMAGE_H; + ESP_LOGI(TAG, "JPEG image decoded! Size of the decoded image is: %dpx x %dpx", outimg.width, outimg.height); - //Prepare and decode the jpeg. - r = esp_rom_tjpgd_prepare(&decoder, infunc, work, WORKSZ, (void *)&jd); - if (r != JDR_OK) { - ESP_LOGE(TAG, "Image decoder: jd_prepare failed (%d)", r); - ret = ESP_ERR_NOT_SUPPORTED; - goto err; - } - r = esp_rom_tjpgd_decomp(&decoder, outfunc, 0); - if (r != JDR_OK && r != JDR_FMT1) { - ESP_LOGE(TAG, "Image decoder: jd_decode failed (%d)", r); - ret = ESP_ERR_NOT_SUPPORTED; - goto err; - } - - //All done! Free the work area (as we don't need it anymore) and return victoriously. - free(work); return ret; err: //Something went wrong! Exit cleanly, de-allocating everything we allocated. if (*pixels != NULL) { - for (int i = 0; i < IMAGE_H; i++) { - free((*pixels)[i]); - } free(*pixels); } - free(work); return ret; } diff --git a/examples/peripherals/spi_master/lcd/main/decode_image.h b/examples/peripherals/spi_master/lcd/main/decode_image.h index 1e31e3d1cd..c9aaf0cd02 100644 --- a/examples/peripherals/spi_master/lcd/main/decode_image.h +++ b/examples/peripherals/spi_master/lcd/main/decode_image.h @@ -10,6 +10,9 @@ #include #include "esp_err.h" +#define IMAGE_W 320 +#define IMAGE_H 240 + #ifdef __cplusplus extern "C" { #endif @@ -23,7 +26,7 @@ extern "C" { * - ESP_ERR_NO_MEM if out of memory * - ESP_OK on succesful decode */ -esp_err_t decode_image(uint16_t ***pixels); +esp_err_t decode_image(uint16_t **pixels); #ifdef __cplusplus } diff --git a/examples/peripherals/spi_master/lcd/main/idf_component.yml b/examples/peripherals/spi_master/lcd/main/idf_component.yml new file mode 100644 index 0000000000..a2167bf4c2 --- /dev/null +++ b/examples/peripherals/spi_master/lcd/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + idf: ">=4.4" + esp_jpeg: ">=1.0.2" diff --git a/examples/peripherals/spi_master/lcd/main/image.jpg b/examples/peripherals/spi_master/lcd/main/image.jpg index 803ca2cdca..cacad09050 100644 Binary files a/examples/peripherals/spi_master/lcd/main/image.jpg and b/examples/peripherals/spi_master/lcd/main/image.jpg differ diff --git a/examples/peripherals/spi_master/lcd/main/pretty_effect.c b/examples/peripherals/spi_master/lcd/main/pretty_effect.c index 2923b7cf6f..9c6887977e 100644 --- a/examples/peripherals/spi_master/lcd/main/pretty_effect.c +++ b/examples/peripherals/spi_master/lcd/main/pretty_effect.c @@ -14,16 +14,15 @@ #include "sdkconfig.h" #include "decode_image.h" -uint16_t **pixels; +uint16_t *pixels; //Grab a rgb16 pixel from the esp32_tiles image static inline uint16_t get_bgnd_pixel(int x, int y) { - //Image has an 8x8 pixel margin, so we can also resolve e.g. [-3, 243] - x+=8; - y+=8; - return pixels[y][x]; + //Get color of the pixel on x,y coords + return (uint16_t) *(pixels + (y * IMAGE_W) + x); } + //This variable is used to detect the next frame. static int prev_frame=-1; diff --git a/tools/idf_py_actions/hints.yml b/tools/idf_py_actions/hints.yml index 5651c4a2db..f03f2e0d0c 100644 --- a/tools/idf_py_actions/hints.yml +++ b/tools/idf_py_actions/hints.yml @@ -191,3 +191,8 @@ re: "Failed to resolve component '(?!esp_ipc)(\\w+)'" hint: "The component {} has been moved to the IDF component manager or has been removed and refactored into some other component.\nPlease look out for component in 'https://components.espressif.com' and add using 'idf.py add-dependency' command.\nRefer to the migration guide for more details." match_to_output: True + +- + re: "fatal error: (esp_rom_tjpgd.h): No such file or directory" + hint: "{} was removed. Please use esp_jpeg component from IDF component manager instead.\nPlease look out for component in 'https://components.espressif.com' and add using 'idf.py add-dependency' command.\nRefer to the migration guide for more details." + match_to_output: True