feat(jpeg_encoder): Add the basic support for jpeg encoder

This commit is contained in:
Cao Sen Miao 2024-04-01 19:58:07 +08:00
parent b02a2eaf1a
commit 22ec65adef
19 changed files with 1371 additions and 10 deletions

View File

@ -1,4 +1,4 @@
[codespell]
skip = build,*.yuv,components/fatfs/src/*,alice.txt
skip = build,*.yuv,components/fatfs/src/*,alice.txt,*.rgb
ignore-words-list = ser,dout,rsource,fram,inout
write-changes = true

View File

@ -22,7 +22,8 @@ repos:
.*_pb2.py|
.*.pb-c.h|
.*.pb-c.c|
.*.yuv
.*.yuv|
.*.rgb
)$
- id: end-of-file-fixer
exclude: *whitespace_excludes

View File

@ -13,6 +13,12 @@ if(CONFIG_SOC_JPEG_CODEC_SUPPORTED)
"jpeg_decode.c"
)
endif()
if(CONFIG_SOC_JPEG_ENCODE_SUPPORTED)
list(APPEND srcs
"jpeg_emit_marker.c"
"jpeg_encode.c"
)
endif()
endif()
idf_component_register(SRCS ${srcs}

View File

@ -126,7 +126,7 @@ esp_err_t jpeg_del_decoder_engine(jpeg_decoder_handle_t decoder_engine);
* @param[out] allocated_size Actual allocated buffer size.
* @return Pointer to the allocated memory space, or NULL if allocation fails.
*/
void *jpeg_alloc_decoder_mem(size_t size, jpeg_decode_memory_alloc_cfg_t *mem_cfg, size_t *allocated_size);
void *jpeg_alloc_decoder_mem(size_t size, const jpeg_decode_memory_alloc_cfg_t *mem_cfg, size_t *allocated_size);
#ifdef __cplusplus
}

View File

@ -0,0 +1,103 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "esp_err.h"
#include "jpeg_types.h"
#include "hal/jpeg_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief JPEG encoder configure structure
*/
typedef struct {
uint32_t height; /*!< Number of pixels in the horizontal direction */
uint32_t width; /*!< Number of pixels in the vertical direction */
jpeg_enc_input_format_t src_type; /*!< Source type of raw image to be encoded, see `jpeg_enc_src_type_t` */
jpeg_down_sampling_type_t sub_sample; /*!< JPEG subsampling method */
uint32_t image_quality; /*!< JPEG compressing quality, value from 1-100 */
} jpeg_encode_cfg_t;
/**
* @brief Configuration parameters for the JPEG encode engine.
*/
typedef struct {
int intr_priority; /*!< JPEG interrupt priority, if set to 0, driver will select the default priority (1,2,3). */
int timeout_ms; /*!< JPEG timeout threshold for handling a picture, should larger than valid decode time in ms. For example, for 30fps decode, this value must larger than 34. -1 means wait forever */
} jpeg_encode_engine_cfg_t;
/**
* @brief JPEG encoder memory allocation config
*/
typedef struct {
jpeg_enc_buffer_alloc_direction_t buffer_direction; /*!< Buffer direction for jpeg decoder memory allocation */
} jpeg_encode_memory_alloc_cfg_t;
/**
* @brief Allocate JPEG encoder
*
* @param[in] enc_eng_cfg config for jpeg encoder
* @param[out] ret_encoder handle for jpeg encoder
* @return
* - ESP_OK: JPEG encoder initialized successfully.
* - ESP_ERR_INVALID_ARG: JPEG encoder initialization failed because of invalid argument.
* - ESP_ERR_NO_MEM: Create JPEG encoder failed because of out of memory.
*/
esp_err_t jpeg_new_encoder_engine(const jpeg_encode_engine_cfg_t *enc_eng_cfg, jpeg_encoder_handle_t *ret_encoder);
/**
* @brief Process encoding of JPEG data using the specified encoder engine.
*
* This function processes the encoding of JPEG data using the provided encoder engine
* and configuration. It takes an input buffer containing the raw image data, performs
* encoding based on the configuration settings, and outputs the compressed bitstream.
*
* @param[in] encoder_engine Handle to the JPEG encoder engine to be used for encoding.
* @param[in] encode_cfg Pointer to the configuration structure for the JPEG encoding process.
* @param[in] encode_inbuf Pointer to the input buffer containing the raw image data.
* @param[in] inbuf_size Size of the input buffer in bytes.
* @param[in] encode_outbuf Pointer to the output buffer where the compressed bitstream will be stored.
* @param[in] outbuf_size The size of output buffer.
* @param[out] out_size Pointer to a variable where the size of the output bitstream will be stored.
*
* @return
* - ESP_OK: JPEG encoder process successfully.
* - ESP_ERR_INVALID_ARG: JPEG encoder process failed because of invalid argument.
* - ESP_ERR_TIMEOUT: JPEG encoder process timeout.
*/
esp_err_t jpeg_encoder_process(jpeg_encoder_handle_t encoder_engine, const jpeg_encode_cfg_t *encode_cfg, const uint8_t *encode_inbuf, uint32_t inbuf_size, uint8_t *encode_outbuf, uint32_t outbuf_size, uint32_t *out_size);
/**
* @brief Release resources used by a JPEG encoder instance.
*
* This function releases the resources used by the specified JPEG encoder instance. The encoder instance is
* specified by the `encoder_engine` parameter.
*
* @param[in] encoder_engine Handle of the JPEG encoder instance to release resources for.
* @return
* - ESP_OK: Delete JPEG encoder successfully.
* - ESP_ERR_INVALID_ARG: Delete JPEG encoder failed because of invalid argument.
*/
esp_err_t jpeg_del_encoder_engine(jpeg_encoder_handle_t encoder_engine);
/**
* @brief A helper function to allocate memory space for JPEG encoder.
*
* @param[in] size The size of memory to allocate.
* @param[in] mem_cfg Memory configuration for memory allocation
* @param[out] allocated_size Actual allocated buffer size.
* @return Pointer to the allocated memory space, or NULL if allocation fails.
*/
void *jpeg_alloc_encoder_mem(size_t size, const jpeg_encode_memory_alloc_cfg_t *mem_cfg, size_t *allocated_size);
#ifdef __cplusplus
}
#endif

View File

@ -46,11 +46,38 @@ typedef enum {
JPEG_DEC_ALLOC_OUTPUT_BUFFER = 1, /*!< Alloc the picture output buffer, (decompressed format in decoder) */
} jpeg_dec_buffer_alloc_direction_t;
/**
* @brief Enumeration for jpeg input format.
*/
typedef enum {
JPEG_ENCODE_IN_FORMAT_RGB888 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB888), /*!< input RGB888 format */
JPEG_ENCODE_IN_FORMAT_RGB565 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB565), /*!< input RGB565 format */
JPEG_ENCODE_IN_FORMAT_GRAY = COLOR_TYPE_ID(COLOR_SPACE_GRAY, COLOR_PIXEL_GRAY8), /*!< input GRAY format */
} jpeg_enc_input_format_t;
/**
* @brief Enumeration for jpeg encoder alloc buffer direction.
*/
typedef enum {
JPEG_ENC_ALLOC_INPUT_BUFFER = 0, /*!< Alloc the picture input buffer, (decompressed format in encoder) */
JPEG_ENC_ALLOC_OUTPUT_BUFFER = 1, /*!< Alloc the picture output buffer, (compressed format in encoder) */
} jpeg_enc_buffer_alloc_direction_t;
/**
* @brief Type of jpeg decoder handle
*/
typedef struct jpeg_decoder_t *jpeg_decoder_handle_t;
/**
* @brief Type of jpeg codec handle
*/
typedef struct jpeg_codec_t *jpeg_codec_handle_t;
/**
* @brief Type of jpeg encoder handle
*/
typedef struct jpeg_encoder_t *jpeg_encoder_handle_t;
#ifdef __cplusplus
}
#endif

View File

@ -36,8 +36,6 @@
static const char *TAG = "jpeg.decoder";
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
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_parse_marker(jpeg_decoder_handle_t decoder_engine, const uint8_t *in_buf, uint32_t inbuf_len);
@ -77,7 +75,7 @@ esp_err_t jpeg_new_decoder_engine(const jpeg_decode_engine_cfg_t *dec_eng_cfg, j
uint32_t cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA);
uint32_t alignment = cache_line_size;
size_t dma_desc_mem_size = ALIGN_UP(sizeof(dma2d_descriptor_t), cache_line_size);
size_t dma_desc_mem_size = JPEG_ALIGN_UP(sizeof(dma2d_descriptor_t), cache_line_size);
decoder_engine->rxlink = (dma2d_descriptor_t*)heap_caps_aligned_calloc(alignment, 1, dma_desc_mem_size, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | JPEG_MEM_ALLOC_CAPS);
ESP_GOTO_ON_FALSE(decoder_engine->rxlink, ESP_ERR_NO_MEM, err, TAG, "no memory for jpeg decode rxlink");
@ -279,7 +277,7 @@ esp_err_t jpeg_del_decoder_engine(jpeg_decoder_handle_t decoder_engine)
return ESP_OK;
}
void *jpeg_alloc_decoder_mem(size_t size, jpeg_decode_memory_alloc_cfg_t *mem_cfg, size_t *allocated_size)
void *jpeg_alloc_decoder_mem(size_t size, const jpeg_decode_memory_alloc_cfg_t *mem_cfg, size_t *allocated_size)
{
/*
Principle of buffer align.
@ -289,7 +287,7 @@ void *jpeg_alloc_decoder_mem(size_t size, jpeg_decode_memory_alloc_cfg_t *mem_cf
size_t cache_align = 0;
esp_cache_get_alignment(ESP_CACHE_MALLOC_FLAG_PSRAM, &cache_align);
if (mem_cfg->buffer_direction == JPEG_DEC_ALLOC_OUTPUT_BUFFER) {
size = ALIGN_UP(size, cache_align);
size = JPEG_ALIGN_UP(size, cache_align);
*allocated_size = size;
return heap_caps_aligned_calloc(cache_align, 1, size, MALLOC_CAP_SPIRAM);
} else {

View File

@ -0,0 +1,243 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "esp_log.h"
#include "jpeg_private.h"
#include "private/jpeg_param.h"
#include "private/jpeg_emit_marker.h"
#include "hal/jpeg_defs.h"
#include "esp_private/esp_cache_private.h"
#define JPEG_MAX(a, b) (((a) > (b)) ? (a) : (b))
#define JPEG_MIN(a, b) (((a) < (b)) ? (a) : (b))
static void emit_byte(jpeg_enc_header_info_t *header_info, uint8_t i)
{
header_info->header_buf[header_info->header_len] = i;
header_info->header_len = header_info->header_len + 1;
}
static void emit_word(jpeg_enc_header_info_t *header_info, uint16_t i)
{
emit_byte(header_info, i >> 8);
emit_byte(header_info, i & 0xFF);
}
static void emit_marker(jpeg_enc_header_info_t *header_info, uint8_t marker)
{
emit_byte(header_info, 0xFF);
emit_byte(header_info, marker);
}
static void emit_dht(jpeg_enc_header_info_t *header_info, uint8_t *bits, uint8_t *val, int index, bool ac_flag)
{
emit_marker(header_info, JPEG_M_DHT & 0xff);
int length = 0;
for (int i = 0; i < 16; i++) {
length += bits[i];
}
emit_word(header_info, length + 2 + 1 + 16);
emit_byte(header_info, index + (ac_flag << 4));
for (int i = 0; i < 16; i++) {
emit_byte(header_info, bits[i]);
}
for (int i = 0; i < length; i++) {
emit_byte(header_info, val[i]);
}
}
static void compute_quant_table(uint32_t *quant_table, const uint32_t *basic_table, uint32_t quality)
{
int scaling_factor = 0;
if (quality < 50) {
scaling_factor = 5000 / quality;
} else {
scaling_factor = 200 - quality * 2;
}
for (int i = 0; i < 64; i++) {
int temp = *basic_table++;
temp = (temp * scaling_factor + 50L) / 100L;
*quant_table++ = JPEG_MIN(JPEG_MAX(temp, 1), 255);
}
}
esp_err_t emit_soi_marker(jpeg_enc_header_info_t *header_info)
{
emit_marker(header_info, JPEG_M_SOI & 0xff);
return ESP_OK;
}
esp_err_t emit_app0_marker(jpeg_enc_header_info_t *header_info)
{
emit_marker(header_info, JPEG_M_APP0 & 0xff);
emit_word(header_info, 2 + 4 + 1 + 2 + 1 + 2 + 2 + 1 + 1);
// 0x4A46494600 for JIF0
emit_byte(header_info, 0x4A);
emit_byte(header_info, 0x46);
emit_byte(header_info, 0x49);
emit_byte(header_info, 0x46);
emit_byte(header_info, 0x00);
// Major version
emit_byte(header_info, 1);
// Minor version
emit_byte(header_info, 1);
// Density unit (0: no unit, 1: inch 2: cm)
emit_byte(header_info, 0);
// X direction density
emit_word(header_info, 1);
// Y direction density
emit_word(header_info, 1);
// No thumbnail image
emit_byte(header_info, 0);
emit_byte(header_info, 0);
return ESP_OK;
}
esp_err_t emit_dqt_marker(jpeg_enc_header_info_t *header_info)
{
compute_quant_table(header_info->m_quantization_tables[0], luminance_quantization_table, header_info->quality);
compute_quant_table(header_info->m_quantization_tables[1], chrominance_quantization_table, header_info->quality);
for (int i = 0; i < ((header_info->num_components == 3) ? 2 : 1); i++) {
emit_marker(header_info, JPEG_M_DQT & 0xff);
emit_word(header_info, 64 + 1 + 2);
emit_byte(header_info, (i));
for (int j = 0; j < 64; j++) {
emit_byte(header_info, (uint8_t)(header_info->m_quantization_tables[i][zigzag_arr[j]]));
}
}
return ESP_OK;
}
esp_err_t emit_sof_marker(jpeg_enc_header_info_t *header_info)
{
uint8_t comp_h_samp[3] = {0};
uint8_t comp_v_samp[3] = {0};
switch (header_info->sub_sample) {
case JPEG_DOWN_SAMPLING_YUV444: {
comp_h_samp[0] = 1;
comp_v_samp[0] = 1;
comp_h_samp[1] = 1;
comp_v_samp[1] = 1;
comp_h_samp[2] = 1;
comp_v_samp[2] = 1;
break;
}
case JPEG_DOWN_SAMPLING_YUV422: {
comp_h_samp[0] = 2;
comp_v_samp[0] = 1;
comp_h_samp[1] = 1;
comp_v_samp[1] = 1;
comp_h_samp[2] = 1;
comp_v_samp[2] = 1;
break;
}
case JPEG_DOWN_SAMPLING_YUV420: {
comp_h_samp[0] = 2;
comp_v_samp[0] = 2;
comp_h_samp[1] = 1;
comp_v_samp[1] = 1;
comp_h_samp[2] = 1;
comp_v_samp[2] = 1;
break;
}
case JPEG_DOWN_SAMPLING_GRAY: {
comp_h_samp[0] = 1;
comp_v_samp[0] = 1;
comp_h_samp[1] = 1;
comp_v_samp[1] = 1;
comp_h_samp[2] = 1;
comp_v_samp[2] = 1;
break;
}
default:
break;
}
emit_marker(header_info, JPEG_M_SOF0 & 0xff); /* baseline */
emit_word(header_info, 3 * header_info->num_components + 2 + 5 + 1);
emit_byte(header_info, 8); /* precision */
emit_word(header_info, header_info->origin_v);
emit_word(header_info, header_info->origin_h);
emit_byte(header_info, header_info->num_components);
for (int i = 0; i < header_info->num_components; i++) {
emit_byte(header_info, (i + 1));
emit_byte(header_info, (comp_h_samp[i] << 4) + comp_v_samp[i]);
emit_byte(header_info, (i > 0));
}
return ESP_OK;
}
esp_err_t emit_dht_marker(jpeg_enc_header_info_t *header_info)
{
uint8_t m_huff_bits[2][2][JPEG_HUFFMAN_BITS_LEN_TABLE_LEN] = {0};
uint8_t m_huff_val[2][2][JPEG_HUFFMAN_AC_VALUE_TABLE_LEN] = {0};
memcpy(m_huff_bits[0][0], luminance_dc_coefficients, JPEG_HUFFMAN_DC_VALUE_TABLE_LEN);
memcpy(m_huff_val[0][0], luminance_dc_values, JPEG_HUFFMAN_DC_VALUE_TABLE_LEN);
memcpy(m_huff_bits[0][1], luminance_ac_coefficients, JPEG_HUFFMAN_DC_VALUE_TABLE_LEN);
memcpy(m_huff_val[0][1], luminance_ac_values, JPEG_HUFFMAN_AC_VALUE_TABLE_LEN);
memcpy(m_huff_bits[1][0], chrominance_dc_coefficients, JPEG_HUFFMAN_DC_VALUE_TABLE_LEN);
memcpy(m_huff_val[1][0], chrominance_dc_values, JPEG_HUFFMAN_DC_VALUE_TABLE_LEN);
memcpy(m_huff_bits[1][1], chrominance_ac_coefficients, JPEG_HUFFMAN_DC_VALUE_TABLE_LEN);
memcpy(m_huff_val[1][1], chrominance_ac_values, JPEG_HUFFMAN_AC_VALUE_TABLE_LEN);
emit_dht(header_info, m_huff_bits[0][0], m_huff_val[0][0], 0, false);
emit_dht(header_info, m_huff_bits[0][1], m_huff_val[0][1], 0, true);
if (header_info->num_components == 3) {
emit_dht(header_info, m_huff_bits[1][0], m_huff_val[1][0], 1, false);
emit_dht(header_info, m_huff_bits[1][1], m_huff_val[1][1], 1, true);
}
return ESP_OK;
}
esp_err_t emit_sos_marker(jpeg_enc_header_info_t *header_info)
{
emit_marker(header_info, JPEG_M_SOS & 0xff);
emit_word(header_info, 2 * header_info->num_components + 2 + 1 + 3);
emit_byte(header_info, header_info->num_components);
for (int i = 0; i < header_info->num_components; i++) {
emit_byte(header_info, i + 1);
if (i == 0) {
emit_byte(header_info, (0 << 4) + 0);
} else {
emit_byte(header_info, (1 << 4) + 1);
}
}
emit_byte(header_info, 0); /* spectral selection */
emit_byte(header_info, 63);
emit_byte(header_info, 0);
return ESP_OK;
}
esp_err_t emit_com_marker(jpeg_enc_header_info_t *header_info)
{
// Calculate how many bytes should be compensate to make it byte aligned.
size_t cache_align = 0;
esp_cache_get_alignment(ESP_CACHE_MALLOC_FLAG_PSRAM, &cache_align);
// compensate_size = aligned_size - SOS marker size(2 * header_info->num_components + 2 + 1 + 3 + 2) - COM marker size(4).
uint32_t compensate_size = ((header_info->header_len / cache_align + 1) * cache_align) - header_info->header_len - (2 * header_info->num_components + 2 + 1 + 3 + 2) - 4;
emit_marker(header_info, JPEG_M_COM & 0xff);
emit_word(header_info, compensate_size);
for (int i = 0; i < compensate_size; i++) {
emit_byte(header_info, 0);
}
return ESP_OK;
}

View File

@ -0,0 +1,491 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "esp_heap_caps.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#if CONFIG_JPEG_ENABLE_DEBUG_LOG
// The local log level must be defined before including esp_log.h
// Set the maximum log level for this source file
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
#endif
#include "esp_log.h"
#include "esp_attr.h"
#include "hal/jpeg_ll.h"
#include "hal/cache_hal.h"
#include "hal/cache_ll.h"
#include "esp_private/dma2d.h"
#include "jpeg_private.h"
#include "driver/jpeg_encode.h"
#include "private/jpeg_param.h"
#include "private/jpeg_emit_marker.h"
#include "esp_check.h"
#include "esp_cache.h"
#include "esp_private/esp_cache_private.h"
#include "esp_intr_alloc.h"
#include "soc/dma2d_channel.h"
static const char *TAG = "jpeg.encoder";
static esp_err_t s_jpeg_set_header_info(jpeg_encoder_handle_t encoder_engine);
static uint32_t s_dma_desc_get_len(dma2d_descriptor_t *dsc);
static bool s_jpeg_rx_eof(dma2d_channel_handle_t dma2d_chan, dma2d_event_data_t *event_data, void *user_data);
static bool s_jpeg_enc_transaction_on_job_picked(uint32_t channel_num, const dma2d_trans_channel_info_t *dma2d_chans, void *user_config);
static void s_cfg_desc(jpeg_encoder_handle_t encoder_engine, dma2d_descriptor_t *dsc, uint8_t en_2d, uint8_t mode, uint16_t vb, uint16_t hb, uint8_t eof, uint32_t pbyte, uint8_t owner, uint16_t va, uint16_t ha, uint8_t *buf, dma2d_descriptor_t *next_dsc);
static void s_jpeg_enc_config_picture_color_space(jpeg_encoder_handle_t encoder_engine);
static void s_jpeg_enc_select_sample_mode(jpeg_encoder_handle_t encoder_engine);
static void s_encoder_error_log_print(uint32_t status);
static void jpeg_encoder_isr_handle_default(void *arg)
{
jpeg_encoder_handle_t encoder_engine = (jpeg_encoder_handle_t) arg;
portBASE_TYPE HPTaskAwoken = pdFALSE;
jpeg_hal_context_t *hal = &encoder_engine->codec_base->hal;
jpeg_enc_dma2d_evt_t s_event = {
.dma_evt = 0,
.encoder_status = 0,
};
uint32_t value = jpeg_ll_get_intr_status(hal->dev);
jpeg_ll_clear_intr_mask(hal->dev, value);
s_event.encoder_status = value;
xQueueSendFromISR(encoder_engine->evt_queue, &s_event, &HPTaskAwoken);
if (HPTaskAwoken == pdTRUE) {
portYIELD_FROM_ISR();
}
}
static esp_err_t s_jpeg_set_header_info(jpeg_encoder_handle_t encoder_engine)
{
encoder_engine->header_info->header_len = 0;
ESP_RETURN_ON_ERROR(emit_soi_marker(encoder_engine->header_info), TAG, "marker emit failed");
ESP_RETURN_ON_ERROR(emit_app0_marker(encoder_engine->header_info), TAG, "marker emit failed");
ESP_RETURN_ON_ERROR(emit_dqt_marker(encoder_engine->header_info), TAG, "marker emit failed");
ESP_RETURN_ON_ERROR(emit_sof_marker(encoder_engine->header_info), TAG, "marker emit failed");
ESP_RETURN_ON_ERROR(emit_dht_marker(encoder_engine->header_info), TAG, "marker emit failed");
ESP_RETURN_ON_ERROR(emit_com_marker(encoder_engine->header_info), TAG, "marker emit failed");
ESP_RETURN_ON_ERROR(emit_sos_marker(encoder_engine->header_info), TAG, "marker emit failed");
return ESP_OK;
}
esp_err_t jpeg_new_encoder_engine(const jpeg_encode_engine_cfg_t *enc_eng_cfg, jpeg_encoder_handle_t *ret_encoder)
{
#if CONFIG_JPEG_ENABLE_DEBUG_LOG
esp_log_level_set(TAG, ESP_LOG_DEBUG);
#endif
esp_err_t ret = ESP_OK;
jpeg_encoder_handle_t encoder_engine = NULL;
ESP_RETURN_ON_FALSE(enc_eng_cfg, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
encoder_engine = (jpeg_encoder_handle_t)heap_caps_calloc(1, sizeof(jpeg_encoder_t), MALLOC_CAP_8BIT);
ESP_RETURN_ON_FALSE(encoder_engine, ESP_ERR_NO_MEM, TAG, "no memory for jpeg encoder");
uint32_t cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA);
uint32_t alignment = cache_line_size;
size_t dma_desc_mem_size = JPEG_ALIGN_UP(sizeof(dma2d_descriptor_t), cache_line_size);
encoder_engine->rxlink = (dma2d_descriptor_t*)heap_caps_aligned_calloc(alignment, 1, sizeof(dma2d_descriptor_t), MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | JPEG_MEM_ALLOC_CAPS);
ESP_GOTO_ON_FALSE(encoder_engine->rxlink, ESP_ERR_NO_MEM, err, TAG, "no memory for jpeg encoder rxlink");
encoder_engine->txlink = (dma2d_descriptor_t*)heap_caps_aligned_calloc(alignment, 1, sizeof(dma2d_descriptor_t), MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | JPEG_MEM_ALLOC_CAPS);
ESP_GOTO_ON_FALSE(encoder_engine->txlink, ESP_ERR_NO_MEM, err, TAG, "no memory for jpeg encoder txlink");
encoder_engine->dma_desc_size = dma_desc_mem_size;
ESP_GOTO_ON_ERROR(jpeg_acquire_codec_handle(&encoder_engine->codec_base), err, TAG, "JPEG encoder acquires codec handle failed");
jpeg_hal_context_t *hal = &encoder_engine->codec_base->hal;
encoder_engine->evt_queue = xQueueCreateWithCaps(2, sizeof(jpeg_enc_dma2d_evt_t), JPEG_MEM_ALLOC_CAPS);
ESP_GOTO_ON_FALSE(encoder_engine->evt_queue, ESP_ERR_NO_MEM, err, TAG, "No memory for event queue");
encoder_engine->timeout_tick = (enc_eng_cfg->timeout_ms == -1) ? portMAX_DELAY : pdMS_TO_TICKS(enc_eng_cfg->timeout_ms);
jpeg_ll_clear_intr_mask(hal->dev, JPEG_LL_ENCODER_EVENT_INTR);
ESP_GOTO_ON_ERROR(jpeg_check_intr_priority(encoder_engine->codec_base, enc_eng_cfg->intr_priority), err, TAG, "set group interrupt priority failed");
if (enc_eng_cfg->intr_priority) {
ESP_RETURN_ON_FALSE(1 << (enc_eng_cfg->intr_priority) & JPEG_ALLOW_INTR_PRIORITY_MASK, ESP_ERR_INVALID_ARG, TAG, "invalid interrupt priority:%d", enc_eng_cfg->intr_priority);
}
int isr_flags = JPEG_INTR_ALLOC_FLAG;
if (enc_eng_cfg->intr_priority) {
isr_flags |= 1 << (enc_eng_cfg->intr_priority);
}
ret = jpeg_isr_register(encoder_engine->codec_base, jpeg_encoder_isr_handle_default, encoder_engine, JPEG_LL_ENCODER_EVENT_INTR, isr_flags, &encoder_engine->intr_handle);
ESP_GOTO_ON_ERROR(ret, err, TAG, "install jpeg decode interrupt failed");
dma2d_pool_config_t dma2d_group_config = {
.pool_id = 0,
};
ESP_ERROR_CHECK(dma2d_acquire_pool(&dma2d_group_config, &encoder_engine->dma2d_group_handle));
encoder_engine->trans_desc = (dma2d_trans_t *)heap_caps_calloc(1, SIZEOF_DMA2D_TRANS_T, JPEG_MEM_ALLOC_CAPS);
ESP_GOTO_ON_FALSE(encoder_engine->trans_desc, ESP_ERR_NO_MEM, err, TAG, "No memory for dma2d descriptor");
encoder_engine->header_info = (jpeg_enc_header_info_t*)heap_caps_calloc(1, sizeof(jpeg_enc_header_info_t), JPEG_MEM_ALLOC_CAPS);
ESP_GOTO_ON_FALSE(encoder_engine->header_info, ESP_ERR_NO_MEM, err, TAG, "no memory for jpeg header information structure");
*ret_encoder = encoder_engine;
return ESP_OK;
err:
if (encoder_engine) {
jpeg_del_encoder_engine(encoder_engine);
}
return ret;
}
esp_err_t jpeg_encoder_process(jpeg_encoder_handle_t encoder_engine, const jpeg_encode_cfg_t *encode_cfg, const uint8_t *encode_inbuf, uint32_t inbuf_size, uint8_t *bit_stream, uint32_t outbuf_size, uint32_t *out_size)
{
ESP_RETURN_ON_FALSE(encoder_engine, ESP_ERR_INVALID_ARG, TAG, "jpeg encode handle is null");
ESP_RETURN_ON_FALSE(encode_cfg, ESP_ERR_INVALID_ARG, TAG, "jpeg encode config is null");
ESP_RETURN_ON_FALSE(encode_inbuf, ESP_ERR_INVALID_ARG, TAG, "jpeg encode picture buffer is null");
ESP_RETURN_ON_FALSE(out_size, ESP_ERR_INVALID_ARG, TAG, "jpeg encode picture out_size is null");
ESP_RETURN_ON_FALSE(((uintptr_t)bit_stream % cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA)) == 0, ESP_ERR_INVALID_ARG, TAG, "jpeg encode bit stream is not aligned, please use jpeg_alloc_encoder_mem to malloc your buffer");
esp_err_t ret = ESP_OK;
if (encoder_engine->codec_base->pm_lock) {
ESP_RETURN_ON_ERROR(esp_pm_lock_acquire(encoder_engine->codec_base->pm_lock), TAG, "acquire pm_lock failed");
}
jpeg_hal_context_t *hal = &encoder_engine->codec_base->hal;
uint8_t *raw_buffer = (uint8_t*)encode_inbuf;
uint32_t compressed_size;
xSemaphoreTake(encoder_engine->codec_base->codec_mutex, portMAX_DELAY);
jpeg_ll_soft_rst(hal->dev);
jpeg_ll_set_codec_mode(hal->dev, JPEG_CODEC_ENCODER);
/* Reset queue */
xQueueReset(encoder_engine->evt_queue);
jpeg_enc_format_hb_t best_hb_idx = 0;
encoder_engine->picture_format = encode_cfg->src_type;
color_space_pixel_format_t picture_format;
picture_format.color_type_id = encoder_engine->picture_format;
switch (encode_cfg->src_type) {
case JPEG_ENCODE_IN_FORMAT_RGB888:
encoder_engine->color_space = JPEG_ENC_SRC_RGB888;
best_hb_idx = JPEG_ENC_SRC_RGB888_HB;
break;
case JPEG_ENCODE_IN_FORMAT_RGB565:
encoder_engine->color_space = JPEG_ENC_SRC_RGB565;
best_hb_idx = JPEG_ENC_SRC_RGB565_HB;
break;
case JPEG_ENCODE_IN_FORMAT_GRAY:
encoder_engine->color_space = JPEG_ENC_SRC_GRAY;
best_hb_idx = JPEG_ENC_SRC_GRAY_HB;
break;
default:
ESP_LOGE(TAG, "wrong, we don't support encode from such format.");
ret = ESP_ERR_NOT_SUPPORTED;
goto err;
}
encoder_engine->header_info->sub_sample = encode_cfg->sub_sample;
encoder_engine->header_info->quality = encode_cfg->image_quality;
encoder_engine->header_info->origin_h = encode_cfg->width;
encoder_engine->header_info->origin_v = encode_cfg->height;
encoder_engine->header_info->header_buf = bit_stream;
s_jpeg_enc_config_picture_color_space(encoder_engine);
s_jpeg_enc_select_sample_mode(encoder_engine);
jpeg_ll_set_picture_height(hal->dev, encoder_engine->header_info->origin_v);
jpeg_ll_set_picture_width(hal->dev, encoder_engine->header_info->origin_h);
jpeg_ll_pixel_reverse(hal->dev, false);
jpeg_ll_add_tail(hal->dev, true);
jpeg_ll_enable_ff_check(hal->dev, true);
jpeg_ll_set_qnr_presition(hal->dev, 0);
ESP_GOTO_ON_ERROR(s_jpeg_set_header_info(encoder_engine), err, TAG, "set header failed");
jpeg_hal_set_quantization_coefficient(hal, encoder_engine->header_info->m_quantization_tables[0], encoder_engine->header_info->m_quantization_tables[1]);
uint32_t dma_hb = enc_hb_tbl[best_hb_idx][encoder_engine->header_info->sub_sample];
uint32_t dma_vb = encoder_engine->mcuy;
ESP_GOTO_ON_FALSE((encoder_engine->header_info->header_len % cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA)) == 0, ESP_ERR_INVALID_STATE, err, TAG, "The header is not cache line aligned, please check");
// 1D direction
memset(encoder_engine->rxlink, 0, sizeof(dma2d_descriptor_t));
s_cfg_desc(encoder_engine, encoder_engine->rxlink, JPEG_DMA2D_2D_DISABLE, DMA2D_DESCRIPTOR_BLOCK_RW_MODE_MULTIPLE, outbuf_size & JPEG_DMA2D_MAX_SIZE, 0, JPEG_DMA2D_EOF_NOT_LAST, 1, DMA2D_DESCRIPTOR_BUFFER_OWNER_DMA, outbuf_size >> JPEG_DMA2D_1D_HIGH_14BIT, 0, bit_stream + encoder_engine->header_info->header_len, NULL);
// 2D direction
memset(encoder_engine->txlink, 0, sizeof(dma2d_descriptor_t));
s_cfg_desc(encoder_engine, encoder_engine->txlink, JPEG_DMA2D_2D_ENABLE, DMA2D_DESCRIPTOR_BLOCK_RW_MODE_MULTIPLE, dma_vb, dma_hb, JPEG_DMA2D_EOF_NOT_LAST, dma2d_desc_pixel_format_to_pbyte_value(picture_format), DMA2D_DESCRIPTOR_BUFFER_OWNER_DMA, encoder_engine->header_info->origin_v, encoder_engine->header_info->origin_h, raw_buffer, NULL);
ret = esp_cache_msync((void*)raw_buffer, encoder_engine->header_info->origin_v * encoder_engine->header_info->origin_h * encoder_engine->bytes_per_pixel, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED);
assert(ret == ESP_OK);
dma2d_trans_config_t trans_desc = {
.tx_channel_num = 1,
.rx_channel_num = 1,
.channel_flags = DMA2D_CHANNEL_FUNCTION_FLAG_TX_REORDER,
.user_config = encoder_engine,
.on_job_picked = s_jpeg_enc_transaction_on_job_picked,
};
ESP_GOTO_ON_ERROR(dma2d_enqueue(encoder_engine->dma2d_group_handle, &trans_desc, encoder_engine->trans_desc), err, TAG, "DMA2D enqueue failed");
while (1) {
jpeg_enc_dma2d_evt_t s_rcv_event;
BaseType_t ret_val = xQueueReceive(encoder_engine->evt_queue, &s_rcv_event, encoder_engine->timeout_tick);
ESP_GOTO_ON_FALSE(ret_val == pdTRUE, ESP_ERR_TIMEOUT, err, TAG, "jpeg-dma2d handle jpeg decode timeout, please check `timeout_ms`");
if (s_rcv_event.encoder_status != 0) {
s_encoder_error_log_print(s_rcv_event.encoder_status);
ret = ESP_ERR_INVALID_STATE;
goto err;
}
if (s_rcv_event.dma_evt & JPEG_DMA2D_RX_EOF) {
compressed_size = s_dma_desc_get_len(encoder_engine->rxlink);
compressed_size = JPEG_ALIGN_UP(compressed_size, cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA));
ESP_GOTO_ON_ERROR(esp_cache_msync((void*)(bit_stream + encoder_engine->header_info->header_len), compressed_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C), err, TAG, "sync memory to cache failed");
break;
}
}
compressed_size += encoder_engine->header_info->header_len;
*out_size = compressed_size;
err:
xSemaphoreGive(encoder_engine->codec_base->codec_mutex);
if (encoder_engine->codec_base->pm_lock) {
ESP_RETURN_ON_ERROR(esp_pm_lock_release(encoder_engine->codec_base->pm_lock), TAG, "release pm_lock failed");
}
return ret;
}
esp_err_t jpeg_del_encoder_engine(jpeg_encoder_handle_t encoder_engine)
{
ESP_RETURN_ON_FALSE(encoder_engine, ESP_ERR_INVALID_ARG, TAG, "jpeg encoder handle is null");
ESP_RETURN_ON_ERROR(jpeg_release_codec_handle(encoder_engine->codec_base), TAG, "release codec failed");
if (encoder_engine) {
if (encoder_engine->rxlink) {
free(encoder_engine->rxlink);
}
if (encoder_engine->txlink) {
free(encoder_engine->txlink);
}
if (encoder_engine->header_info) {
free(encoder_engine->header_info);
}
if (encoder_engine->trans_desc) {
free(encoder_engine->trans_desc);
}
if (encoder_engine->evt_queue) {
vQueueDeleteWithCaps(encoder_engine->evt_queue);
}
if (encoder_engine->dma2d_group_handle) {
dma2d_release_pool(encoder_engine->dma2d_group_handle);
}
if (encoder_engine->intr_handle) {
jpeg_isr_deregister(encoder_engine->codec_base, encoder_engine->intr_handle);
}
free(encoder_engine);
}
return ESP_OK;
}
void *jpeg_alloc_encoder_mem(size_t size, const jpeg_encode_memory_alloc_cfg_t *mem_cfg, size_t *allocated_size)
{
/*
Principle of buffer align.
For output buffer(for decoder is 2DDMA write to PSRAM), both address and size should be aligned according to cache invalidate.
For input buffer(for decoder is PSRAM write to 2DDMA), no restriction for any align (both cache writeback and requirement from 2DDMA).
*/
size_t cache_align = 0;
esp_cache_get_alignment(ESP_CACHE_MALLOC_FLAG_PSRAM, &cache_align);
if (mem_cfg->buffer_direction == JPEG_ENC_ALLOC_OUTPUT_BUFFER) {
size = JPEG_ALIGN_UP(size, cache_align);
*allocated_size = size;
return heap_caps_aligned_calloc(cache_align, 1, size, MALLOC_CAP_SPIRAM);
} else {
*allocated_size = size;
return heap_caps_calloc(1, size, MALLOC_CAP_SPIRAM);
}
}
/****************************************************************
* DMA related functions
****************************************************************/
static uint32_t s_dma_desc_get_len(dma2d_descriptor_t *dsc)
{
uint32_t len = 0;
len |= dsc->ha_length;
len = len << 14;
len |= dsc->hb_length;
return len;
}
static bool s_jpeg_rx_eof(dma2d_channel_handle_t dma2d_chan, dma2d_event_data_t *event_data, void *user_data)
{
jpeg_encoder_handle_t encoder_engine = (jpeg_encoder_handle_t) user_data;
portBASE_TYPE higher_priority_task_awoken = pdFALSE;
jpeg_enc_dma2d_evt_t s_event = {
.dma_evt = 0,
.encoder_status = 0,
};
s_event.dma_evt = JPEG_DMA2D_RX_EOF;
xQueueSendFromISR(encoder_engine->evt_queue, &s_event, &higher_priority_task_awoken);
return higher_priority_task_awoken;
}
static void jpeg_enc_config_dma_trans_ability(jpeg_encoder_handle_t encoder_engine)
{
// set transfer ability
dma2d_transfer_ability_t transfer_ability_config_tx = {
.data_burst_length = DMA2D_DATA_BURST_LENGTH_128,
.desc_burst_en = true,
.mb_size = DMA2D_MACRO_BLOCK_SIZE_NONE,
};
dma2d_transfer_ability_t transfer_ability_config_rx = {
.data_burst_length = DMA2D_DATA_BURST_LENGTH_128,
.desc_burst_en = true,
.mb_size = DMA2D_MACRO_BLOCK_SIZE_NONE,
};
switch (encoder_engine->header_info->sub_sample) {
case JPEG_DOWN_SAMPLING_YUV444:
transfer_ability_config_tx.mb_size = DMA2D_MACRO_BLOCK_SIZE_8_8;
break;
case JPEG_DOWN_SAMPLING_YUV422:
transfer_ability_config_tx.mb_size = DMA2D_MACRO_BLOCK_SIZE_8_16;
break;
case JPEG_DOWN_SAMPLING_YUV420:
transfer_ability_config_tx.mb_size = DMA2D_MACRO_BLOCK_SIZE_16_16;
break;
case JPEG_DOWN_SAMPLING_GRAY:
transfer_ability_config_tx.mb_size = DMA2D_MACRO_BLOCK_SIZE_8_8;
break;
default:
break;
}
dma2d_set_transfer_ability(encoder_engine->dma2d_tx_channel, &transfer_ability_config_tx);
dma2d_set_transfer_ability(encoder_engine->dma2d_rx_channel, &transfer_ability_config_rx);
}
static bool s_jpeg_enc_transaction_on_job_picked(uint32_t channel_num, const dma2d_trans_channel_info_t *dma2d_chans, void *user_config)
{
assert(channel_num == 2);
jpeg_encoder_handle_t encoder_engine = (jpeg_encoder_handle_t) user_config;
jpeg_hal_context_t *hal = &encoder_engine->codec_base->hal;
uint32_t rx_idx = 0;
uint32_t tx_idx = 0;
if (dma2d_chans[0].dir == DMA2D_CHANNEL_DIRECTION_TX) {
rx_idx = 1;
tx_idx = 0;
} else {
rx_idx = 0;
tx_idx = 1;
}
dma2d_channel_handle_t tx_chan = dma2d_chans[tx_idx].chan;
dma2d_channel_handle_t rx_chan = dma2d_chans[rx_idx].chan;
encoder_engine->dma2d_tx_channel = tx_chan;
encoder_engine->dma2d_rx_channel = rx_chan;
// 2ddma connect
dma2d_trigger_t trig_periph = {
.periph = DMA2D_TRIG_PERIPH_JPEG_ENCODER,
.periph_sel_id = SOC_DMA2D_TRIG_PERIPH_JPEG_TX,
};
dma2d_connect(tx_chan, &trig_periph);
trig_periph.periph_sel_id = SOC_DMA2D_TRIG_PERIPH_JPEG_RX;
dma2d_connect(rx_chan, &trig_periph);
jpeg_enc_config_dma_trans_ability(encoder_engine);
dma2d_csc_config_t tx_csc = {
.tx_csc_option = DMA2D_CSC_TX_NONE,
};
dma2d_configure_color_space_conversion(tx_chan, &tx_csc);
static dma2d_rx_event_callbacks_t jpeg_dec_cbs = {
.on_recv_eof = s_jpeg_rx_eof,
};
dma2d_register_rx_event_callbacks(rx_chan, &jpeg_dec_cbs, encoder_engine);
dma2d_set_desc_addr(tx_chan, (intptr_t)encoder_engine->txlink);
dma2d_set_desc_addr(rx_chan, (intptr_t)encoder_engine->rxlink);
dma2d_start(tx_chan);
dma2d_start(rx_chan);
jpeg_ll_enable_intr_mask(hal->dev, JPEG_LL_ENCODER_EVENT_INTR);
jpeg_ll_process_start(hal->dev);
return false;
}
static void s_cfg_desc(jpeg_encoder_handle_t encoder_engine, dma2d_descriptor_t *dsc, uint8_t en_2d, uint8_t mode, uint16_t vb, uint16_t hb, uint8_t eof, uint32_t pbyte, uint8_t owner, uint16_t va, uint16_t ha, uint8_t *buf, dma2d_descriptor_t *next_dsc)
{
dsc->dma2d_en = en_2d;
dsc->mode = mode;
dsc->vb_size = vb;
dsc->hb_length = hb;
dsc->pbyte = pbyte;
dsc->suc_eof = eof;
dsc->owner = owner;
dsc->va_size = va;
dsc->ha_length = ha;
dsc->buffer = buf;
dsc->next = next_dsc;
esp_err_t ret = esp_cache_msync((void*)dsc, encoder_engine->dma_desc_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE);
assert(ret == ESP_OK);
}
static void s_jpeg_enc_config_picture_color_space(jpeg_encoder_handle_t encoder_engine)
{
jpeg_hal_context_t *hal = &encoder_engine->codec_base->hal;
color_space_pixel_format_t picture_format;
jpeg_ll_config_picture_color_space(hal->dev, encoder_engine->color_space);
picture_format.color_type_id = encoder_engine->picture_format;
encoder_engine->bytes_per_pixel = color_hal_pixel_format_get_bit_depth(picture_format);
if (encoder_engine->color_space == JPEG_ENC_SRC_GRAY) {
encoder_engine->header_info->num_components = 1;
} else {
encoder_engine->header_info->num_components = 3;
}
}
static void s_jpeg_enc_select_sample_mode(jpeg_encoder_handle_t encoder_engine)
{
jpeg_hal_context_t *hal = &encoder_engine->codec_base->hal;
switch (encoder_engine->header_info->sub_sample) {
case JPEG_DOWN_SAMPLING_YUV444:
encoder_engine->mcux = 8;
encoder_engine->mcuy = 8;
break;
case JPEG_DOWN_SAMPLING_YUV422:
encoder_engine->mcux = 16;
encoder_engine->mcuy = 8;
break;
case JPEG_DOWN_SAMPLING_YUV420:
encoder_engine->mcux = 16;
encoder_engine->mcuy = 16;
break;
case JPEG_DOWN_SAMPLING_GRAY:
encoder_engine->mcux = 8;
encoder_engine->mcuy = 8;
break;
default:
break;
}
if (encoder_engine->header_info->sub_sample != JPEG_DOWN_SAMPLING_GRAY) {
// Not needed to call this function if 1 channel color down sampling
jpeg_ll_sample_mode_select(hal->dev, encoder_engine->header_info->sub_sample);
}
}
static void s_encoder_error_log_print(uint32_t status)
{
if (status & JPEG_LL_RLE_PARALLEL_ERR) {
ESP_LOGE(TAG, "Run length encoding error occurs");
}
if (status & JPEG_LL_EN_FRAME_EOF_ERR) {
ESP_LOGE(TAG, "The number of data units obtained after decoding a frame of image is different from the number of data units calculated based on the image resolution configured by the software");
}
}

View File

@ -45,3 +45,161 @@ const uint32_t dec_hb_tbl[JPEG_DOWN_SAMPLING_MAX][JPEG_DEC_BEST_HB_MAX] = {
{48, 32, 32, 48, 0},
{96, 0, 0, 0, 96},
};
/**
* @brief DMA2D best hb value table for JPEG compression.
*
* This two-dimensional array represents a Huffman encoding table for JPEG
* compression. It is used to decode the Huffman-coded symbols in the compressed
* data stream during the encoding process.
*/
const uint32_t enc_hb_tbl[JPEG_ENC_BEST_HB_MAX][JPEG_DOWN_SAMPLING_MAX] = {
{40, 32, 32, 0},
{0, 64, 0, 0},
{64, 64, 48, 0},
{0, 0, 0, 128}
};
/**
* @brief Setup the standard Huffman tables (JPEG standard sections K.3.3)
* For table K.3 (for luminance DC coefficients), the 16 bytes which specify the list of code lengths for the table are
* X'00 01 05 01 01 01 01 01 01 00 00 00 00 00 00 00'
*/
const uint8_t luminance_dc_coefficients[JPEG_HUFFMAN_BITS_LEN_TABLE_LEN] = {
0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
};
/**
* @brief Setup the standard Huffman tables (JPEG standard sections K.3.3)
* For table K.3 (for luminance DC coefficients), the set of values following this list is
* X'00 01 02 03 04 05 06 07 08 09 0A 0B'
*/
const uint8_t luminance_dc_values[JPEG_HUFFMAN_DC_VALUE_TABLE_LEN] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
};
/**
* @brief Setup the standard Huffman tables (JPEG standard sections K.3.3)
* For table K.5 (for luminance AC coefficients), the 16 bytes which specify the list of code lengths for the table are
* X'00 02 01 03 03 02 04 03 05 05 04 04 00 00 01 7D'
*/
const uint8_t luminance_ac_coefficients[JPEG_HUFFMAN_BITS_LEN_TABLE_LEN] = {
0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
};
/**
* @brief Setup the standard Huffman tables (JPEG standard sections K.3.3)
* For table K.5 (for luminance AC values)
*/
const uint8_t luminance_ac_values[JPEG_HUFFMAN_AC_VALUE_TABLE_LEN] = {
0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
0xf9, 0xfa
};
/**
* @brief Setup the standard Huffman tables (JPEG standard sections K.3.3)
* For table K.4 (for chrominance DC coefficients), the 16 bytes which specify the list of code lengths for the table are
* X'00 03 01 01 01 01 01 01 01 01 01 00 00 00 00 00'
*/
const uint8_t chrominance_dc_coefficients[JPEG_HUFFMAN_BITS_LEN_TABLE_LEN] = {
0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
};
/**
* @brief Setup the standard Huffman tables (JPEG standard sections K.3.3)
* For table K.4 (for luminance DC coefficients), the set of values following this list is
* X'00 01 02 03 04 05 06 07 08 09 0A 0B'
*/
const uint8_t chrominance_dc_values[JPEG_HUFFMAN_DC_VALUE_TABLE_LEN] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
};
/**
* @brief Setup the standard Huffman tables (JPEG standard sections K.3.3)
* For table K.5 (for luminance AC coefficients), the 16 bytes which specify the list of code lengths for the table are
* X'00 02 01 02 04 04 03 04 07 05 04 04 00 01 02 77'
*/
const uint8_t chrominance_ac_coefficients[JPEG_HUFFMAN_BITS_LEN_TABLE_LEN] = {
0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77
};
/**
* @brief Setup the standard Huffman tables (JPEG standard sections K.3.3)
* For table K.5 (for chrominance AC values)
*/
const uint8_t chrominance_ac_values[JPEG_HUFFMAN_AC_VALUE_TABLE_LEN] = {
0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
0xf9, 0xfa
};
/**
* @brief This array stores the luminance quantization values for each block in an image.(JPEG standard sections K.1)
* The luminance_quantization_table array is of type uint32_t and has a size of 64 elements.
*
* These values are part of the quantization table used in the JPEG image compression standard.
* They are employed during the process of quantizing the discrete cosine transform (DCT) coefficients
* of an image's luminance component, allowing for lossy compression.
*
* The quantization process involves dividing the DCT coefficients by these values to reduce the precision of the data,
* which results in higher compression ratios but also introduces some loss of image quality.
*
* Each value in the array corresponds to a specific position in the 8x8 luminance quantization matrix used in JPEG compression.
*
* These specific values are critical for achieving a balance between compression efficiency and visual quality
* in JPEG image compression, and they have become a fundamental component of the standard.
*/
const uint32_t luminance_quantization_table[JPEG_QUANTIZATION_TABLE_LEN] = {
16, 11, 10, 16, 24, 40, 51, 61,
12, 12, 14, 19, 26, 58, 60, 55,
14, 13, 16, 24, 40, 57, 69, 56,
14, 17, 22, 29, 51, 87, 80, 62,
18, 22, 37, 56, 68, 109, 103, 77,
24, 35, 55, 64, 81, 104, 113, 92,
49, 64, 78, 87, 103, 121, 120, 101,
72, 92, 95, 98, 112, 100, 103, 99
};
/**
* @brief This array stores the chrominance quantization values for each block in an image.(JPEG standard sections K.2)
* The chrominance_quantization_table array is of type uint32_t and has a size of 64 elements.
*
* These values are part of the quantization table used in the JPEG image compression standard.
* They are employed during the process of quantizing the discrete cosine transform (DCT) coefficients
* of an image's chrominance component, allowing for lossy compression.
*
* The quantization process involves dividing the DCT coefficients by these values to reduce the precision of the data,
* which results in higher compression ratios but also introduces some loss of image quality.
*
* Each value in the array corresponds to a specific position in the 8x8 chrominance quantization matrix used in JPEG compression.
*
* These specific values are critical for achieving a balance between compression efficiency and visual quality
* in JPEG image compression, and they have become a fundamental component of the standard.
*/
const uint32_t chrominance_quantization_table[JPEG_QUANTIZATION_TABLE_LEN] = {
17, 18, 24, 47, 99, 99, 99, 99,
18, 21, 26, 66, 99, 99, 99, 99,
24, 26, 56, 99, 99, 99, 99, 99,
47, 66, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99
};

View File

@ -30,7 +30,10 @@ extern "C" {
// JPEG encoder and decoder shares same interrupt ID.
#define JPEG_INTR_ALLOC_FLAG (ESP_INTR_FLAG_SHARED)
#define JPEG_ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
typedef struct jpeg_decoder_t jpeg_decoder_t;
typedef struct jpeg_encoder_t jpeg_encoder_t;
typedef struct jpeg_codec_t jpeg_codec_t;
typedef struct jpeg_codec_t *jpeg_codec_handle_t;
@ -122,6 +125,52 @@ typedef struct {
uint32_t jpgd_status; // jpeg decoder status, (triggered from jpeg interrupt)
} jpeg_dma2d_dec_evt_t;
typedef enum {
JPEG_ENC_SRC_RGB888_HB = 0, // Input RGB888 format
// TODO: Support encoder source format for yuv422
// JPEG_ENC_SRC_YUV422_HB = 1, // Input YUV422 format
JPEG_ENC_SRC_RGB565_HB = 2, // Input RGB565 format
JPEG_ENC_SRC_GRAY_HB = 3, // Input GRAY format
JPEG_ENC_BEST_HB_MAX,
} jpeg_enc_format_hb_t;
typedef struct {
jpeg_dma2d_evt_enum_t dma_evt; // jpeg-2ddma event, (triggered from 2ddma interrupt)
uint32_t encoder_status; // jpeg encoder status, (triggered from jpeg interrupt)
} jpeg_enc_dma2d_evt_t;
typedef struct {
uint8_t *header_buf; // Pointer to the header of jpeg header buffer
uint32_t header_len; // Record for header length
uint32_t m_quantization_tables[2][JPEG_QUANTIZATION_TABLE_LEN]; // quantization tables
uint8_t num_components; // number of components
uint32_t origin_h; // horizontal of original picture
uint32_t origin_v; // vertical of original picture
uint32_t quality; // JPEG compressed quality.
jpeg_down_sampling_type_t sub_sample; // Picture sub-sampling method
} jpeg_enc_header_info_t;
struct jpeg_encoder_t {
jpeg_codec_t *codec_base; // Pointer to jpeg codec hardware base
jpeg_enc_src_type_t color_space; // Picture source color space
jpeg_enc_input_format_t picture_format; // Source picture format
jpeg_enc_header_info_t *header_info; // Pointer to header buffer information
uint32_t bytes_per_pixel; // Bytes per pixel of source image format
uint8_t mcux; // the best value of minimum coding unit horizontal unit
uint8_t mcuy; // minimum coding unit vertical unit
jpeg_isr_handler_t *intr_handle; // jpeg encoder interrupt handler
TickType_t timeout_tick; // timeout value for jpeg decoder (in cpu tick).
QueueHandle_t evt_queue; // jpeg event from 2DDMA and JPEG engine
// dma_handles
dma2d_pool_handle_t dma2d_group_handle; // 2D-DMA group handle
dma2d_descriptor_t *rxlink; // Pointer to 2D-DMA rx descriptor
dma2d_descriptor_t *txlink; // Pointer to 2D-DMA tx descriptor
uint32_t dma_desc_size; // tx and rx linker alignment
dma2d_trans_t* trans_desc; // DMA2D transaction descriptor
dma2d_channel_handle_t dma2d_rx_channel; // DMA2D RX channel handle
dma2d_channel_handle_t dma2d_tx_channel; // DMA2D TX channel handle
};
#define JPEG_DMA2D_2D_ENABLE (1) // DMA2D two dimension enable
#define JPEG_DMA2D_2D_DISABLE (0) // DMA2D one dimension enable
#define JPEG_DMA2D_MAX_SIZE (0x3fff) // DMA2D max size (low 14 bit)

View File

@ -0,0 +1,130 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "esp_log.h"
#include "esp_attr.h"
#include "../jpeg_private.h"
#include "driver/jpeg_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Emit Start of Image (SOI) marker.
*
* This function emits the Start of Image (SOI) marker, which indicates the beginning of a JPEG image.
* It writes the SOI marker to the output buffer specified in the `header_info` structure.
*
* @param[in] header_info Pointer to the structure containing JPEG encoding header information.
*
* @return
* - ESP_OK: Successfully emitted SOI marker.
* - ESP_ERR_INVALID_ARG: Invalid argument passed.
* - ESP_FAIL: Error occurred while writing SOI marker.
*/
esp_err_t emit_soi_marker(jpeg_enc_header_info_t *header_info);
/**
* @brief Emit Application 0 (APP0) marker.
*
* This function emits the Application 0 (APP0) marker, which is used to provide information about the JFIF (JPEG File Interchange Format)
* or other application-specific data. It writes the APP0 marker and the corresponding data segment to the output buffer specified
* in the `header_info` structure.
*
* @param[in] header_info Pointer to the structure containing JPEG encoding header information.
*
* @return
* - ESP_OK: Successfully emitted APP0 marker.
* - ESP_ERR_INVALID_ARG: Invalid argument passed.
* - ESP_FAIL: Error occurred while writing APP0 marker.
*/
esp_err_t emit_app0_marker(jpeg_enc_header_info_t *header_info);
/**
* @brief Emit Define Quantization Table (DQT) marker.
*
* This function emits the Define Quantization Table (DQT) marker, which is used to specify the quantization table(s)
* used for encoding the image data. It writes the DQT marker and the corresponding quantization table(s) to the output buffer
* specified in the `header_info` structure.
*
* @param[in] header_info Pointer to the structure containing JPEG encoding header information.
*
* @return
* - ESP_OK: Successfully emitted DQT marker.
* - ESP_ERR_INVALID_ARG: Invalid argument passed.
* - ESP_FAIL: Error occurred while writing DQT marker.
*/
esp_err_t emit_dqt_marker(jpeg_enc_header_info_t *header_info);
/**
* @brief Emit Start of Frame (SOF) marker.
*
* This function emits the Start of Frame (SOF) marker, which is used to define the basic parameters of the image frame,
* such as the image dimensions and the number of color components. It writes the SOF marker and the corresponding
* frame header data to the output buffer specified in the `header_info` structure.
*
* @param[in] header_info Pointer to the structure containing JPEG encoding header information.
*
* @return
* - ESP_OK: Successfully emitted SOF marker.
* - ESP_ERR_INVALID_ARG: Invalid argument passed.
* - ESP_FAIL: Error occurred while writing SOF marker.
*/
esp_err_t emit_sof_marker(jpeg_enc_header_info_t *header_info);
/**
* @brief Emit Define Huffman Table (DHT) marker.
*
* This function emits the Define Huffman Table (DHT) marker, which is used to specify the Huffman coding tables
* used for encoding the image data. It writes the DHT marker and the corresponding Huffman coding table(s) to the
* output buffer specified in the `header_info` structure.
*
* @param[in] header_info Pointer to the structure containing JPEG encoding header information.
*
* @return
* - ESP_OK: Successfully emitted DHT marker.
* - ESP_ERR_INVALID_ARG: Invalid argument passed.
* - ESP_FAIL: Error occurred while writing DHT marker.
*/
esp_err_t emit_dht_marker(jpeg_enc_header_info_t *header_info);
/**
* @brief Emit Start of Scan (SOS) marker.
*
* This function emits the Start of Scan (SOS) marker, which is used to specify the image component layout and
* the Huffman coding tables used for encoding the image data. It writes the SOS marker and the corresponding scan
* header data to the output buffer specified in the `header_info` structure.
*
* @param[in] header_info Pointer to the structure containing JPEG encoding header information.
*
* @return
* - ESP_OK: Successfully emitted SOS marker.
* - ESP_ERR_INVALID_ARG: Invalid argument passed.
* - ESP_FAIL: Error occurred while writing SOS marker.
*/
esp_err_t emit_sos_marker(jpeg_enc_header_info_t *header_info);
/**
* @brief Emit Comment (COM) marker.
*
* This function is used for adjust picture header size. Picture body follows alignment rules. So in header emit stage,
* We add bytes in COM sector to adjust picture header size.
*
* @param[in] header_info Pointer to the structure containing JPEG encoding header information.
*
* @return
* - ESP_OK: Successfully emitted SOS marker.
* - ESP_ERR_INVALID_ARG: Invalid argument passed.
* - ESP_FAIL: Error occurred while writing SOS marker.
*/
esp_err_t emit_com_marker(jpeg_enc_header_info_t *header_info);
#ifdef __cplusplus
}
#endif

View File

@ -38,6 +38,105 @@ extern const uint8_t zigzag_arr[64];
*/
extern const uint32_t dec_hb_tbl[JPEG_DOWN_SAMPLING_MAX][JPEG_DEC_BEST_HB_MAX];
/**
* @brief DMA2D best hb value table for JPEG compression.
*
* This two-dimensional array represents a Huffman encoding table for JPEG
* compression. It is used to decode the Huffman-coded symbols in the compressed
* data stream during the encoding process.
*/
extern const uint32_t enc_hb_tbl[JPEG_ENC_BEST_HB_MAX][JPEG_DOWN_SAMPLING_MAX];
/**
* @brief Setup the standard Huffman tables (JPEG standard sections K.3.3)
* For table K.3 (for luminance DC coefficients), the 16 bytes which specify the list of code lengths for the table are
* X'00 01 05 01 01 01 01 01 01 00 00 00 00 00 00 00'
*/
extern const uint8_t luminance_dc_coefficients[JPEG_HUFFMAN_BITS_LEN_TABLE_LEN];
/**
* @brief Setup the standard Huffman tables (JPEG standard sections K.3.3)
* For table K.3 (for luminance DC coefficients), the set of values following this list is
* X'00 01 02 03 04 05 06 07 08 09 0A 0B'
*/
extern const uint8_t luminance_dc_values[JPEG_HUFFMAN_DC_VALUE_TABLE_LEN];
/**
* @brief Setup the standard Huffman tables (JPEG standard sections K.3.3)
* For table K.5 (for luminance AC coefficients), the 16 bytes which specify the list of code lengths for the table are
* X'00 02 01 03 03 02 04 03 05 05 04 04 00 00 01 7D'
*/
extern const uint8_t luminance_ac_coefficients[JPEG_HUFFMAN_BITS_LEN_TABLE_LEN];
/**
* @brief Setup the standard Huffman tables (JPEG standard sections K.3.3)
* For table K.5 (for luminance AC values)
*/
extern const uint8_t luminance_ac_values[JPEG_HUFFMAN_AC_VALUE_TABLE_LEN];
/**
* @brief Setup the standard Huffman tables (JPEG standard sections K.3.3)
* For table K.4 (for chrominance DC coefficients), the 16 bytes which specify the list of code lengths for the table are
* X'00 03 01 01 01 01 01 01 01 01 01 00 00 00 00 00'
*/
extern const uint8_t chrominance_dc_coefficients[JPEG_HUFFMAN_BITS_LEN_TABLE_LEN];
/**
* @brief Setup the standard Huffman tables (JPEG standard sections K.3.3)
* For table K.4 (for luminance DC coefficients), the set of values following this list is
* X'00 01 02 03 04 05 06 07 08 09 0A 0B'
*/
extern const uint8_t chrominance_dc_values[JPEG_HUFFMAN_DC_VALUE_TABLE_LEN];
/**
* @brief Setup the standard Huffman tables (JPEG standard sections K.3.3)
* For table K.5 (for luminance AC coefficients), the 16 bytes which specify the list of code lengths for the table are
* X'00 02 01 02 04 04 03 04 07 05 04 04 00 01 02 77'
*/
extern const uint8_t chrominance_ac_coefficients[JPEG_HUFFMAN_BITS_LEN_TABLE_LEN];
/**
* @brief Setup the standard Huffman tables (JPEG standard sections K.3.3)
* For table K.5 (for chrominance AC values)
*/
extern const uint8_t chrominance_ac_values[JPEG_HUFFMAN_AC_VALUE_TABLE_LEN];
/**
* @brief This array stores the luminance quantization values for each block in an image.(JPEG standard sections K.1)
* The luminance_quantization_table array is of type uint32_t and has a size of 64 elements.
*
* These values are part of the quantization table used in the JPEG image compression standard.
* They are employed during the process of quantizing the discrete cosine transform (DCT) coefficients
* of an image's luminance component, allowing for lossy compression.
*
* The quantization process involves dividing the DCT coefficients by these values to reduce the precision of the data,
* which results in higher compression ratios but also introduces some loss of image quality.
*
* Each value in the array corresponds to a specific position in the 8x8 luminance quantization matrix used in JPEG compression.
*
* These specific values are critical for achieving a balance between compression efficiency and visual quality
* in JPEG image compression, and they have become a fundamental component of the standard.
*/
extern const uint32_t luminance_quantization_table[JPEG_QUANTIZATION_TABLE_LEN];
/**
* @brief This array stores the chrominance quantization values for each block in an image.(JPEG standard sections K.2)
* The chrominance_quantization_table array is of type uint32_t and has a size of 64 elements.
*
* These values are part of the quantization table used in the JPEG image compression standard.
* They are employed during the process of quantizing the discrete cosine transform (DCT) coefficients
* of an image's chrominance component, allowing for lossy compression.
*
* The quantization process involves dividing the DCT coefficients by these values to reduce the precision of the data,
* which results in higher compression ratios but also introduces some loss of image quality.
*
* Each value in the array corresponds to a specific position in the 8x8 chrominance quantization matrix used in JPEG compression.
*
* These specific values are critical for achieving a balance between compression efficiency and visual quality
* in JPEG image compression, and they have become a fundamental component of the standard.
*/
extern const uint32_t chrominance_quantization_table[JPEG_QUANTIZATION_TABLE_LEN];
#ifdef __cplusplus
}
#endif

View File

@ -506,7 +506,7 @@ static inline void jpeg_ll_sample_mode_select(jpeg_dev_t *hw, jpeg_sample_mode_t
sample_sel = 1;
break;
case JPEG_SAMPLE_MODE_YUV420:
sample_sel = 0;
sample_sel = 2;
break;
default:
HAL_ASSERT(false);
@ -632,6 +632,28 @@ static inline uint32_t jpeg_ll_get_intr_status(jpeg_dev_t *hw)
return hw->int_st.val;
}
static inline void jpeg_ll_config_picture_color_space(jpeg_dev_t *hw, jpeg_enc_src_type_t color_space)
{
uint8_t cs = 0;
switch (color_space) {
case JPEG_ENC_SRC_RGB888:
cs = 0;
break;
case JPEG_ENC_SRC_YUV422:
cs = 1;
break;
case JPEG_ENC_SRC_RGB565:
cs = 2;
break;
case JPEG_ENC_SRC_GRAY:
cs = 3;
break;
default:
abort();
}
hw->config.color_space = cs;
}
#ifdef __cplusplus
}
#endif

View File

@ -103,6 +103,15 @@ typedef void (*jpeg_config_quantization_coefficient_t)(jpeg_soc_handle_t hw, uin
*/
extern jpeg_config_quantization_coefficient_t dqt_func[JPEG_COMPONENT_NUMBER_MAX];
/**
* Set the quantization coefficients for luminance and chrominance in the JPEG hardware accelerator context.
*
* @param hal Pointer to the JPEG hardware accelerator context.
* @param lqnr Pointer to an array of luminance quantization coefficients.
* @param cqnr Pointer to an array of chrominance quantization coefficients.
*/
void jpeg_hal_set_quantization_coefficient(jpeg_hal_context_t *hal, uint32_t *lqnr, uint32_t *cqnr);
#ifdef __cplusplus
}
#endif

View File

@ -71,6 +71,16 @@ typedef enum {
JPEG_DOWN_SAMPLING_MAX, /*!< Max value of sample enumeration */
} jpeg_down_sampling_type_t;
/**
* @brief JPEG encoder source formats.
*/
typedef enum {
JPEG_ENC_SRC_RGB888 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB888), /*!< JPEG encoder source RGB888 */
JPEG_ENC_SRC_YUV422 = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV422), /*!< JPEG encoder source YUV422 */
JPEG_ENC_SRC_RGB565 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB565), /*!< JPEG encoder source RGB565 */
JPEG_ENC_SRC_GRAY = COLOR_TYPE_ID(COLOR_SPACE_GRAY, COLOR_PIXEL_GRAY8), /*!< JPEG encoder source GRAY */
} jpeg_enc_src_type_t;
#ifdef __cplusplus
}
#endif

View File

@ -95,3 +95,14 @@ jpeg_config_quantization_coefficient_t dqt_func[JPEG_COMPONENT_NUMBER_MAX] = {
jpeg_ll_write_quantization_coefficient_t2,
jpeg_ll_write_quantization_coefficient_t3,
};
void jpeg_hal_set_quantization_coefficient(jpeg_hal_context_t *hal, uint32_t *lqnr, uint32_t *cqnr)
{
jpeg_ll_set_access_qnr_ram_mode(hal->dev, 1);
jpeg_ll_luminance_qnr_table_id(hal->dev, 0);
jpeg_ll_chrominance_qnr_table_id(hal->dev, 1);
jpeg_ll_write_quantization_coefficient_t0(hal->dev, lqnr);
jpeg_ll_write_quantization_coefficient_t1(hal->dev, cqnr);
jpeg_ll_write_quantization_coefficient_t2(hal->dev, lqnr);
jpeg_ll_write_quantization_coefficient_t3(hal->dev, cqnr);
}

View File

@ -1534,3 +1534,7 @@ config SOC_JPEG_CODEC_SUPPORTED
config SOC_JPEG_DECODE_SUPPORTED
bool
default y
config SOC_JPEG_ENCODE_SUPPORTED
bool
default y

View File

@ -625,4 +625,4 @@
/*--------------------------- JPEG --------------------------------*/
#define SOC_JPEG_CODEC_SUPPORTED (1)
#define SOC_JPEG_DECODE_SUPPORTED (1)
// #define SOC_JPEG_ENCODE_SUPPORTED (1) // TODO: IDF-6512
#define SOC_JPEG_ENCODE_SUPPORTED (1)