mirror of
https://github.com/espressif/esp-idf.git
synced 2025-07-30 18:57:19 +02:00
feat(jpeg_decode): Add support for default Huffman tables
- In case of a missing Huffman table, while decoding a JPEG image - Define a default Huff table and add it to JPEG image header
This commit is contained in:
@ -39,6 +39,7 @@ static const char *TAG = "jpeg.decoder";
|
|||||||
static void s_decoder_error_log_print(uint32_t status);
|
static void s_decoder_error_log_print(uint32_t status);
|
||||||
static esp_err_t jpeg_dec_config_dma_descriptor(jpeg_decoder_handle_t decoder_engine);
|
static esp_err_t jpeg_dec_config_dma_descriptor(jpeg_decoder_handle_t decoder_engine);
|
||||||
static esp_err_t jpeg_parse_marker(jpeg_decoder_handle_t decoder_engine, const uint8_t *in_buf, uint32_t inbuf_len);
|
static esp_err_t jpeg_parse_marker(jpeg_decoder_handle_t decoder_engine, const uint8_t *in_buf, uint32_t inbuf_len);
|
||||||
|
static esp_err_t jpeg_check_marker(jpeg_decoder_handle_t decoder_engine);
|
||||||
static esp_err_t jpeg_parse_header_info_to_hw(jpeg_decoder_handle_t decoder_engine);
|
static esp_err_t jpeg_parse_header_info_to_hw(jpeg_decoder_handle_t decoder_engine);
|
||||||
static bool jpeg_dec_transaction_on_picked(uint32_t channel_num, const dma2d_trans_channel_info_t *dma2d_chans, void *users_config);
|
static bool jpeg_dec_transaction_on_picked(uint32_t channel_num, const dma2d_trans_channel_info_t *dma2d_chans, void *users_config);
|
||||||
|
|
||||||
@ -225,6 +226,7 @@ esp_err_t jpeg_decoder_process(jpeg_decoder_handle_t decoder_engine, const jpeg_
|
|||||||
decoder_engine->decoded_buf = decode_outbuf;
|
decoder_engine->decoded_buf = decode_outbuf;
|
||||||
|
|
||||||
ESP_GOTO_ON_ERROR(jpeg_parse_marker(decoder_engine, bit_stream, stream_size), err2, TAG, "jpeg parse marker failed");
|
ESP_GOTO_ON_ERROR(jpeg_parse_marker(decoder_engine, bit_stream, stream_size), err2, TAG, "jpeg parse marker failed");
|
||||||
|
ESP_GOTO_ON_ERROR(jpeg_check_marker(decoder_engine), err2, TAG, "jpeg check marker failed");
|
||||||
ESP_GOTO_ON_ERROR(jpeg_parse_header_info_to_hw(decoder_engine), err2, TAG, "write header info to hw failed");
|
ESP_GOTO_ON_ERROR(jpeg_parse_header_info_to_hw(decoder_engine), err2, TAG, "write header info to hw failed");
|
||||||
ESP_GOTO_ON_ERROR(jpeg_dec_config_dma_descriptor(decoder_engine), err2, TAG, "config dma descriptor failed");
|
ESP_GOTO_ON_ERROR(jpeg_dec_config_dma_descriptor(decoder_engine), err2, TAG, "config dma descriptor failed");
|
||||||
|
|
||||||
@ -726,6 +728,38 @@ static esp_err_t jpeg_parse_marker(jpeg_decoder_handle_t decoder_engine, const u
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static esp_err_t jpeg_default_huff_table(jpeg_dec_header_info_t *header_info)
|
||||||
|
{
|
||||||
|
// Copy default Huffman table parameters to JPEG header
|
||||||
|
// DC Coefficients
|
||||||
|
memcpy(header_info->huffbits[0][0], luminance_dc_coefficients, JPEG_HUFFMAN_BITS_LEN_TABLE_LEN);
|
||||||
|
memcpy(header_info->huffbits[0][1], chrominance_dc_coefficients, JPEG_HUFFMAN_BITS_LEN_TABLE_LEN);
|
||||||
|
// AC Coefficients
|
||||||
|
memcpy(header_info->huffbits[1][0], luminance_ac_coefficients, JPEG_HUFFMAN_BITS_LEN_TABLE_LEN);
|
||||||
|
memcpy(header_info->huffbits[1][1], chrominance_ac_coefficients, JPEG_HUFFMAN_BITS_LEN_TABLE_LEN);
|
||||||
|
// DC Values
|
||||||
|
memcpy(header_info->huffcode[0][0], luminance_dc_values, JPEG_HUFFMAN_DC_VALUE_TABLE_LEN);
|
||||||
|
memcpy(header_info->huffcode[0][1], chrominance_dc_values, JPEG_HUFFMAN_DC_VALUE_TABLE_LEN);
|
||||||
|
// AC Values
|
||||||
|
memcpy(header_info->huffcode[1][0], luminance_ac_values, JPEG_HUFFMAN_AC_VALUE_TABLE_LEN);
|
||||||
|
memcpy(header_info->huffcode[1][1], chrominance_ac_values, JPEG_HUFFMAN_AC_VALUE_TABLE_LEN);
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t jpeg_check_marker(jpeg_decoder_handle_t decoder_engine)
|
||||||
|
{
|
||||||
|
// Check if Huffman table is present in JPEG image
|
||||||
|
if (!decoder_engine->header_info->dht_marker) {
|
||||||
|
|
||||||
|
// Huffman table not present, define a default one
|
||||||
|
// This is common for USB Cameras, not to include the table into the JPEG image to save a bandwidth on a USB bus
|
||||||
|
jpeg_default_huff_table(decoder_engine->header_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static void s_decoder_error_log_print(uint32_t status)
|
static void s_decoder_error_log_print(uint32_t status)
|
||||||
{
|
{
|
||||||
if (status & JPEG_LL_INTR_CID_ERR) {
|
if (status & JPEG_LL_INTR_CID_ERR) {
|
||||||
|
@ -162,6 +162,8 @@ esp_err_t jpeg_parse_dht_marker(jpeg_dec_header_info_t *header_info)
|
|||||||
num_left -= (1 + JPEG_HUFFMAN_BITS_LEN_TABLE_LEN + np);
|
num_left -= (1 + JPEG_HUFFMAN_BITS_LEN_TABLE_LEN + np);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Record, that Huffman table present in JPEG header
|
||||||
|
header_info->dht_marker = true;
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,6 +86,7 @@ typedef struct {
|
|||||||
uint8_t huffbits[2][2][JPEG_HUFFMAN_BITS_LEN_TABLE_LEN]; // Huffman bit distribution tables [id][dcac]
|
uint8_t huffbits[2][2][JPEG_HUFFMAN_BITS_LEN_TABLE_LEN]; // Huffman bit distribution tables [id][dcac]
|
||||||
uint8_t huffcode[2][2][JPEG_HUFFMAN_AC_VALUE_TABLE_LEN]; // Huffman decoded data tables [id][dcac]
|
uint8_t huffcode[2][2][JPEG_HUFFMAN_AC_VALUE_TABLE_LEN]; // Huffman decoded data tables [id][dcac]
|
||||||
uint32_t tmp_huff[JPEG_HUFFMAN_AC_VALUE_TABLE_LEN]; // temp buffer to store huffman code
|
uint32_t tmp_huff[JPEG_HUFFMAN_AC_VALUE_TABLE_LEN]; // temp buffer to store huffman code
|
||||||
|
bool dht_marker; // If we have Huffman table present in header
|
||||||
uint16_t ri; // Restart interval
|
uint16_t ri; // Restart interval
|
||||||
} jpeg_dec_header_info_t;
|
} jpeg_dec_header_info_t;
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ project(jpeg_test)
|
|||||||
|
|
||||||
target_add_binary_data(jpeg_test.elf "${IDF_PATH}/examples/peripherals/jpeg/jpeg_decode/resources/esp720.jpg" BINARY)
|
target_add_binary_data(jpeg_test.elf "${IDF_PATH}/examples/peripherals/jpeg/jpeg_decode/resources/esp720.jpg" BINARY)
|
||||||
target_add_binary_data(jpeg_test.elf "${IDF_PATH}/examples/peripherals/jpeg/jpeg_decode/resources/esp1080.jpg" BINARY)
|
target_add_binary_data(jpeg_test.elf "${IDF_PATH}/examples/peripherals/jpeg/jpeg_decode/resources/esp1080.jpg" BINARY)
|
||||||
|
target_add_binary_data(jpeg_test.elf "resources/no_huff.jpg" BINARY)
|
||||||
target_add_binary_data(jpeg_test.elf "resources/esp480.rgb" BINARY)
|
target_add_binary_data(jpeg_test.elf "resources/esp480.rgb" BINARY)
|
||||||
|
|
||||||
message(STATUS "Checking jpeg registers are not read-write by half-word")
|
message(STATUS "Checking jpeg registers are not read-write by half-word")
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||||
*/
|
*/
|
||||||
@ -21,6 +21,9 @@
|
|||||||
extern const uint8_t image_esp1080_jpg_start[] asm("_binary_esp1080_jpg_start");
|
extern const uint8_t image_esp1080_jpg_start[] asm("_binary_esp1080_jpg_start");
|
||||||
extern const uint8_t image_esp1080_jpg_end[] asm("_binary_esp1080_jpg_end");
|
extern const uint8_t image_esp1080_jpg_end[] asm("_binary_esp1080_jpg_end");
|
||||||
|
|
||||||
|
extern const uint8_t image_no_huff_jpg_start[] asm("_binary_no_huff_jpg_start");
|
||||||
|
extern const uint8_t image_no_huff_jpg_end[] asm("_binary_no_huff_jpg_end");
|
||||||
|
|
||||||
TEST_CASE("JPEG decode driver memory leaking check", "[jpeg]")
|
TEST_CASE("JPEG decode driver memory leaking check", "[jpeg]")
|
||||||
{
|
{
|
||||||
jpeg_decoder_handle_t jpgd_handle;
|
jpeg_decoder_handle_t jpgd_handle;
|
||||||
@ -87,3 +90,46 @@ TEST_CASE("JPEG decode performance test for 1080*1920 YUV->RGB picture", "[jpeg]
|
|||||||
free(tx_buf_1080p);
|
free(tx_buf_1080p);
|
||||||
TEST_ESP_OK(jpeg_del_decoder_engine(jpgd_handle));
|
TEST_ESP_OK(jpeg_del_decoder_engine(jpgd_handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("JPEG decode image without Huffman table JPEG->RGB picture", "[jpeg]")
|
||||||
|
{
|
||||||
|
jpeg_decoder_handle_t jpgd_handle;
|
||||||
|
|
||||||
|
jpeg_decode_engine_cfg_t decode_eng_cfg = {
|
||||||
|
.intr_priority = 0,
|
||||||
|
.timeout_ms = 40,
|
||||||
|
};
|
||||||
|
|
||||||
|
jpeg_decode_cfg_t decode_cfg = {
|
||||||
|
.output_format = JPEG_DECODE_OUT_FORMAT_RGB565,
|
||||||
|
};
|
||||||
|
|
||||||
|
jpeg_decode_memory_alloc_cfg_t rx_mem_cfg = {
|
||||||
|
.buffer_direction = JPEG_DEC_ALLOC_OUTPUT_BUFFER,
|
||||||
|
};
|
||||||
|
|
||||||
|
jpeg_decode_memory_alloc_cfg_t tx_mem_cfg = {
|
||||||
|
.buffer_direction = JPEG_DEC_ALLOC_INPUT_BUFFER,
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t rx_buffer_size;
|
||||||
|
uint8_t *rx_buf_no_huff = (uint8_t*)jpeg_alloc_decoder_mem(120 * 160 * 3, &rx_mem_cfg, &rx_buffer_size);
|
||||||
|
uint32_t out_size_no_huff = 0;
|
||||||
|
|
||||||
|
size_t bit_stream_length = (size_t)image_no_huff_jpg_end - (size_t)image_no_huff_jpg_start;
|
||||||
|
|
||||||
|
size_t tx_buffer_size;
|
||||||
|
uint8_t *tx_buf_no_huff = (uint8_t*)jpeg_alloc_decoder_mem(bit_stream_length, &tx_mem_cfg, &tx_buffer_size);
|
||||||
|
// Copy bit stream to psram
|
||||||
|
memcpy(tx_buf_no_huff, image_no_huff_jpg_start, bit_stream_length);
|
||||||
|
TEST_ESP_OK(jpeg_new_decoder_engine(&decode_eng_cfg, &jpgd_handle));
|
||||||
|
|
||||||
|
// Decode a picture without Huffman table only once, to ensure that the default Huffman table is defined correctly
|
||||||
|
TEST_ESP_OK(jpeg_decoder_process(jpgd_handle, &decode_cfg, tx_buf_no_huff, bit_stream_length, rx_buf_no_huff, rx_buffer_size, &out_size_no_huff));
|
||||||
|
// JPEG image resolution is 120 x 160, output format is RGB565: expected decoded size is 120 * 160 * 2
|
||||||
|
TEST_ASSERT_EQUAL(out_size_no_huff, 120 * 160 * 2);
|
||||||
|
|
||||||
|
free(rx_buf_no_huff);
|
||||||
|
free(tx_buf_no_huff);
|
||||||
|
TEST_ESP_OK(jpeg_del_decoder_engine(jpgd_handle));
|
||||||
|
}
|
||||||
|
Binary file not shown.
After Width: | Height: | Size: 655 B |
Reference in New Issue
Block a user