Skip to content

Commit d402e9c

Browse files
Merge pull request #444 from espressif/feature/esp_jpeg_configurable_pool
feat(esp_jpeg): Add configuration option for working buffer size
2 parents d3e5a00 + a24c4bc commit d402e9c

File tree

7 files changed

+126
-18
lines changed

7 files changed

+126
-18
lines changed

esp_jpeg/CHANGELOG.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
## 1.2.0
2+
3+
- Added option to for passing user defined working buffer
4+
5+
## 1.1.0
6+
7+
- Added support for decoding images without Huffman tables
8+
- Fixed undefined configuration options from Kconfig
9+
10+
## 1.0.5~3
11+
12+
- Added option to swap output color bytes regardless of JD_FORMAT
13+
14+
## 1.0.4
15+
16+
- Added ROM implementation support for ESP32-C6
17+
18+
## 1.0.2
19+
20+
- Fixed compiler warnings
21+
22+
## 1.0.1
23+
24+
- Fixed: exclude ESP32-C2 from list of ROM implementations
25+
26+
## 1.0.0
27+
28+
- Initial version

esp_jpeg/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# JPEG Decoder: TJpgDec - Tiny JPEG Decompressor
22

33
[![Component Registry](https://components.espressif.com/components/espressif/esp_jpeg/badge.svg)](https://components.espressif.com/components/espressif/esp_jpeg)
4+
![maintenance-status](https://img.shields.io/badge/maintenance-actively--developed-brightgreen.svg)
45

56
TJpgDec is a lightweight JPEG image decompressor optimized for embedded systems with minimal memory consumption.
67

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# This file was generated using idf.py save-defconfig. It can be edited manually.
2+
# Espressif IoT Development Framework (ESP-IDF) 5.5.0 Project Minimal Configuration
3+
#
4+
CONFIG_TOUCH_SUPPRESS_DEPRECATE_WARN=y

esp_jpeg/idf_component.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version: "1.1.0"
1+
version: "1.2.0"
22
description: "JPEG Decoder: TJpgDec"
33
url: https://github.com/espressif/idf-extra-components/tree/master/esp_jpeg/
44
dependencies:

esp_jpeg/include/jpeg_decoder.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@ typedef struct esp_jpeg_image_cfg_s {
4848
uint8_t swap_color_bytes: 1; /*!< Swap first and last color bytes */
4949
} flags;
5050

51+
struct {
52+
void *working_buffer; /*!< If set to NULL, a working buffer will be allocated in esp_jpeg_decode().
53+
Tjpgd does not use dynamic allocation, se we pass this buffer to Tjpgd that uses it as scratchpad */
54+
size_t working_buffer_size; /*!< Size of the working buffer. Must be set it working_buffer != NULL.
55+
Default size is 3.1kB or 65kB if JD_FASTDECODE == 2 */
56+
} advanced;
57+
5158
struct {
5259
uint32_t read; /*!< Internal count of read bytes */
5360
} priv;

esp_jpeg/jpeg_decoder.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,21 @@ esp_err_t esp_jpeg_decode(esp_jpeg_image_cfg_t *cfg, esp_jpeg_image_output_t *im
7979
assert(cfg != NULL);
8080
assert(img != NULL);
8181

82-
workbuf = heap_caps_malloc(JPEG_WORK_BUF_SIZE, MALLOC_CAP_DEFAULT);
83-
ESP_GOTO_ON_FALSE(workbuf, ESP_ERR_NO_MEM, err, TAG, "no mem for JPEG work buffer");
82+
const bool allocate_buffer = (cfg->advanced.working_buffer == NULL);
83+
const size_t workbuf_size = allocate_buffer ? JPEG_WORK_BUF_SIZE : cfg->advanced.working_buffer_size;
84+
if (allocate_buffer) {
85+
workbuf = heap_caps_malloc(JPEG_WORK_BUF_SIZE, MALLOC_CAP_DEFAULT);
86+
ESP_GOTO_ON_FALSE(workbuf, ESP_ERR_NO_MEM, err, TAG, "no mem for JPEG work buffer");
87+
} else {
88+
workbuf = cfg->advanced.working_buffer;
89+
ESP_RETURN_ON_FALSE(workbuf_size != 0, ESP_ERR_INVALID_ARG, TAG, "Working buffer size not defined!");
90+
}
91+
8492

8593
cfg->priv.read = 0;
8694

8795
/* Prepare image */
88-
res = jd_prepare(&JDEC, jpeg_decode_in_cb, workbuf, JPEG_WORK_BUF_SIZE, cfg);
96+
res = jd_prepare(&JDEC, jpeg_decode_in_cb, workbuf, workbuf_size, cfg);
8997
ESP_GOTO_ON_FALSE((res == JDR_OK), ESP_FAIL, err, TAG, "Error in preparing JPEG image! %d", res);
9098

9199
uint8_t scale_div = jpeg_get_div_by_scale(cfg->out_scale);
@@ -104,7 +112,7 @@ esp_err_t esp_jpeg_decode(esp_jpeg_image_cfg_t *cfg, esp_jpeg_image_output_t *im
104112
ESP_GOTO_ON_FALSE((res == JDR_OK), ESP_FAIL, err, TAG, "Error in decoding JPEG image! %d", res);
105113

106114
err:
107-
if (workbuf) {
115+
if (workbuf && allocate_buffer) {
108116
free(workbuf);
109117
}
110118

esp_jpeg/test_apps/main/tjpgd_test.c

Lines changed: 73 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Unlicense OR CC0-1.0
55
*/
@@ -18,16 +18,29 @@
1818
#define TESTW 46
1919
#define TESTH 46
2020

21-
TEST_CASE("Test JPEG decompression library", "[esp_jpeg]")
21+
void esp_jpeg_print_ascii(unsigned char *rgb888, esp_jpeg_image_output_t *outimg)
2222
{
2323
char aapix[] = " .:;+=xX$$";
24+
unsigned char *p = rgb888 + 2;
25+
26+
for (int y = 0; y < outimg->width; y++) {
27+
for (int x = 0; x < outimg->height; x++) {
28+
int v = ((*p) * (sizeof(aapix) - 2) * 2) / 256;
29+
printf("%c%c", aapix[v / 2], aapix[(v + 1) / 2]);
30+
p += 3;
31+
}
32+
printf("%c%c", ' ', '\n');
33+
}
34+
}
35+
36+
TEST_CASE("Test JPEG decompression library", "[esp_jpeg]")
37+
{
2438
unsigned char *decoded, *p;
2539
const unsigned char *o;
26-
int x, y, v;
2740
int decoded_outsize = TESTW * TESTH * 3;
2841

2942
decoded = malloc(decoded_outsize);
30-
for (x = 0; x < decoded_outsize; x += 2) {
43+
for (int x = 0; x < decoded_outsize; x += 2) {
3144
decoded[x] = 0;
3245
decoded[x + 1] = 0xff;
3346
}
@@ -54,7 +67,7 @@ TEST_CASE("Test JPEG decompression library", "[esp_jpeg]")
5467

5568
p = decoded;
5669
o = logo_rgb888;
57-
for (x = 0; x < outimg.width * outimg.height; x++) {
70+
for (int x = 0; x < outimg.width * outimg.height; x++) {
5871
/* The color can be +- 2 */
5972
TEST_ASSERT_UINT8_WITHIN(2, o[0], p[0]);
6073
TEST_ASSERT_UINT8_WITHIN(2, o[1], p[1]);
@@ -64,17 +77,64 @@ TEST_CASE("Test JPEG decompression library", "[esp_jpeg]")
6477
o += 3;
6578
}
6679

67-
p = decoded + 2;
68-
for (y = 0; y < outimg.width; y++) {
69-
for (x = 0; x < outimg.height; x++) {
70-
v = ((*p) * (sizeof(aapix) - 2) * 2) / 256;
71-
printf("%c%c", aapix[v / 2], aapix[(v + 1) / 2]);
72-
p += 3;
73-
}
74-
printf("%c%c", ' ', '\n');
80+
esp_jpeg_print_ascii(decoded, &outimg);
81+
82+
free(decoded);
83+
}
84+
85+
#define WORKING_BUFFER_SIZE 4096
86+
TEST_CASE("Test JPEG decompression library: User defined working buffer", "[esp_jpeg]")
87+
{
88+
unsigned char *decoded, *p;
89+
const unsigned char *o;
90+
int decoded_outsize = TESTW * TESTH * 3;
91+
92+
decoded = malloc(decoded_outsize);
93+
uint8_t *working_buf = malloc(WORKING_BUFFER_SIZE);
94+
assert(decoded);
95+
assert(working_buf);
96+
97+
for (int x = 0; x < decoded_outsize; x += 2) {
98+
decoded[x] = 0;
99+
decoded[x + 1] = 0xff;
75100
}
76101

102+
/* JPEG decode */
103+
esp_jpeg_image_cfg_t jpeg_cfg = {
104+
.indata = (uint8_t *)logo_jpg,
105+
.indata_size = logo_jpg_len,
106+
.outbuf = decoded,
107+
.outbuf_size = decoded_outsize,
108+
.out_format = JPEG_IMAGE_FORMAT_RGB888,
109+
.out_scale = JPEG_IMAGE_SCALE_0,
110+
.flags = {
111+
.swap_color_bytes = 0,
112+
},
113+
.advanced = {
114+
.working_buffer = working_buf,
115+
.working_buffer_size = WORKING_BUFFER_SIZE,
116+
},
117+
};
118+
esp_jpeg_image_output_t outimg;
119+
esp_err_t err = esp_jpeg_decode(&jpeg_cfg, &outimg);
120+
TEST_ASSERT_EQUAL(err, ESP_OK);
77121

122+
/* Decoded image size */
123+
TEST_ASSERT_EQUAL(outimg.width, TESTW);
124+
TEST_ASSERT_EQUAL(outimg.height, TESTH);
125+
126+
p = decoded;
127+
o = logo_rgb888;
128+
for (int x = 0; x < outimg.width * outimg.height; x++) {
129+
/* The color can be +- 2 */
130+
TEST_ASSERT_UINT8_WITHIN(2, o[0], p[0]);
131+
TEST_ASSERT_UINT8_WITHIN(2, o[1], p[1]);
132+
TEST_ASSERT_UINT8_WITHIN(2, o[2], p[2]);
133+
134+
p += 3;
135+
o += 3;
136+
}
137+
free(working_buf);
78138
free(decoded);
79139
}
80140

0 commit comments

Comments
 (0)