2024-04-01 07:58:07 -04:00
/*
* 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 " ) ;
2024-04-17 02:38:12 -04:00
if ( encode_cfg - > src_type = = JPEG_ENCODE_IN_FORMAT_YUV422 ) {
ESP_RETURN_ON_FALSE ( encode_cfg - > sub_sample = = JPEG_DOWN_SAMPLING_YUV422 , ESP_ERR_INVALID_ARG , TAG , " Sub sampling is not supported under this source type " ) ;
}
2024-04-01 07:58:07 -04:00
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 ;
2024-04-17 02:38:12 -04:00
case JPEG_ENCODE_IN_FORMAT_YUV422 :
encoder_engine - > color_space = JPEG_ENC_SRC_YUV422 ;
best_hb_idx = JPEG_ENC_SRC_YUV422_HB ;
break ;
2024-04-01 07:58:07 -04:00
default :
ESP_LOGE ( TAG , " wrong, we don't support encode from such format. " ) ;
ret = ESP_ERR_NOT_SUPPORTED ;
2024-05-29 22:19:44 -04:00
goto err2 ;
2024-04-01 07:58:07 -04:00
}
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 ) ;
2024-05-29 22:19:44 -04:00
ESP_GOTO_ON_ERROR ( s_jpeg_set_header_info ( encoder_engine ) , err2 , TAG , " set header failed " ) ;
2024-04-01 07:58:07 -04:00
jpeg_hal_set_quantization_coefficient ( hal , encoder_engine - > header_info - > m_quantization_tables [ 0 ] , encoder_engine - > header_info - > m_quantization_tables [ 1 ] ) ;
2024-04-17 02:38:12 -04:00
uint8_t sample_method_idx = 0 ;
switch ( encoder_engine - > header_info - > sub_sample ) {
case JPEG_DOWN_SAMPLING_YUV444 :
sample_method_idx = 0 ;
break ;
case JPEG_DOWN_SAMPLING_YUV422 :
sample_method_idx = 1 ;
break ;
case JPEG_DOWN_SAMPLING_YUV420 :
sample_method_idx = 2 ;
break ;
case JPEG_DOWN_SAMPLING_GRAY :
sample_method_idx = 3 ;
break ;
default :
ESP_LOGE ( TAG , " wrong, we don't support such sampling mode. " ) ;
return ESP_ERR_NOT_SUPPORTED ;
}
uint32_t dma_hb = enc_hb_tbl [ best_hb_idx ] [ sample_method_idx ] ;
2024-04-01 07:58:07 -04:00
uint32_t dma_vb = encoder_engine - > mcuy ;
2024-05-29 22:19:44 -04:00
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 , err2 , TAG , " The header is not cache line aligned, please check " ) ;
2024-04-01 07:58:07 -04:00
// 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 ,
} ;
2024-05-29 22:19:44 -04:00
ESP_GOTO_ON_ERROR ( dma2d_enqueue ( encoder_engine - > dma2d_group_handle , & trans_desc , encoder_engine - > trans_desc ) , err2 , TAG , " DMA2D enqueue failed " ) ;
2024-05-28 00:28:32 -04:00
bool need_yield ;
2024-04-01 07:58:07 -04:00
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 ) ;
2024-05-29 22:19:44 -04:00
ESP_GOTO_ON_FALSE ( ret_val = = pdTRUE , ESP_ERR_TIMEOUT , err1 , TAG , " jpeg-dma2d handle jpeg decode timeout, please check image accuracy and `timeout_ms` " ) ;
2024-04-01 07:58:07 -04:00
if ( s_rcv_event . encoder_status ! = 0 ) {
s_encoder_error_log_print ( s_rcv_event . encoder_status ) ;
ret = ESP_ERR_INVALID_STATE ;
2024-05-29 22:19:44 -04:00
goto err1 ;
2024-04-01 07:58:07 -04:00
}
if ( s_rcv_event . dma_evt & JPEG_DMA2D_RX_EOF ) {
2024-05-29 22:19:44 -04:00
ESP_GOTO_ON_ERROR ( esp_cache_msync ( ( void * ) encoder_engine - > rxlink , encoder_engine - > dma_desc_size , ESP_CACHE_MSYNC_FLAG_DIR_M2C ) , err1 , TAG , " sync memory to cache failed " ) ;
2024-04-01 07:58:07 -04:00
compressed_size = s_dma_desc_get_len ( encoder_engine - > rxlink ) ;
2024-04-18 00:39:09 -04:00
uint32_t _compressed_size = JPEG_ALIGN_UP ( compressed_size , cache_hal_get_cache_line_size ( CACHE_LL_LEVEL_EXT_MEM , CACHE_TYPE_DATA ) ) ;
2024-05-29 22:19:44 -04:00
ESP_GOTO_ON_ERROR ( esp_cache_msync ( ( void * ) ( bit_stream + encoder_engine - > header_info - > header_len ) , _compressed_size , ESP_CACHE_MSYNC_FLAG_DIR_M2C ) , err1 , TAG , " sync memory to cache failed " ) ;
2024-04-01 07:58:07 -04:00
break ;
}
}
compressed_size + = encoder_engine - > header_info - > header_len ;
* out_size = compressed_size ;
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 " ) ;
}
2024-05-28 00:28:32 -04:00
return ESP_OK ;
2024-05-29 22:19:44 -04:00
err1 :
2024-05-28 00:28:32 -04:00
dma2d_force_end ( encoder_engine - > trans_desc , & need_yield ) ;
2024-05-29 22:19:44 -04:00
err2 :
2024-05-28 00:28:32 -04:00
xSemaphoreGive ( encoder_engine - > codec_base - > codec_mutex ) ;
if ( encoder_engine - > codec_base - > pm_lock ) {
esp_pm_lock_release ( encoder_engine - > codec_base - > pm_lock ) ;
}
2024-04-01 07:58:07 -04:00
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 " ) ;
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 ) ;
}
2024-04-28 03:16:08 -04:00
ESP_RETURN_ON_ERROR ( jpeg_release_codec_handle ( encoder_engine - > codec_base ) , TAG , " release codec failed " ) ;
2024-04-01 07:58:07 -04:00
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 2 DDMA write to PSRAM ) , both address and size should be aligned according to cache invalidate .
For input buffer ( for decoder is PSRAM write to 2 DDMA ) , no restriction for any align ( both cache writeback and requirement from 2 DDMA ) .
*/
size_t cache_align = 0 ;
2024-04-07 23:01:05 -04:00
esp_cache_get_alignment ( MALLOC_CAP_SPIRAM , & cache_align ) ;
2024-04-01 07:58:07 -04:00
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 ;
2024-04-07 05:11:41 -04:00
jpeg_ll_config_picture_pixel_format ( hal - > dev , encoder_engine - > color_space ) ;
2024-04-01 07:58:07 -04:00
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 " ) ;
}
}