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;