feat(cam): support format conversion function

This commit is contained in:
gaoxu
2025-08-26 17:16:56 +08:00
committed by Gao Xu
parent 42b065bdce
commit 1e674fa044
14 changed files with 256 additions and 3 deletions

View File

@@ -52,6 +52,7 @@ static esp_err_t s_ctlr_csi_stop(esp_cam_ctlr_handle_t handle);
static esp_err_t s_csi_ctlr_disable(esp_cam_ctlr_handle_t ctlr);
static esp_err_t s_ctlr_csi_receive(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, uint32_t timeout_ms);
static void *s_csi_ctlr_alloc_buffer(esp_cam_ctlr_t *handle, size_t size, uint32_t buf_caps);
static esp_err_t s_csi_ctlr_format_conversion(esp_cam_ctlr_t *handle, const cam_ctlr_format_conv_config_t *config);
static esp_err_t s_csi_claim_controller(csi_controller_t *controller)
{
@@ -227,6 +228,7 @@ esp_err_t esp_cam_new_csi_ctlr(const esp_cam_ctlr_csi_config_t *config, esp_cam_
ctlr->base.get_internal_buffer = s_csi_ctlr_get_internal_buffer;
ctlr->base.get_buffer_len = s_csi_ctlr_get_buffer_length;
ctlr->base.alloc_buffer = s_csi_ctlr_alloc_buffer;
ctlr->base.format_conversion = s_csi_ctlr_format_conversion;
*ret_handle = &(ctlr->base);
@@ -560,3 +562,10 @@ static void *s_csi_ctlr_alloc_buffer(esp_cam_ctlr_t *handle, size_t size, uint32
return buffer;
}
static esp_err_t s_csi_ctlr_format_conversion(esp_cam_ctlr_t *handle, const cam_ctlr_format_conv_config_t *config)
{
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
// CSI controller doesn't support format conversion yet
return ESP_ERR_NOT_SUPPORTED;
}

View File

@@ -782,6 +782,31 @@ static void *esp_cam_ctlr_dvp_cam_alloc_buffer(esp_cam_ctlr_t *handle, size_t si
return buffer;
}
/**
* @brief Configure format conversion
*
* @param cam_handle Camera controller handle
* @param src_format Source format
* @param dst_format Destination format
* @return ESP_OK on success, ESP_FAIL on failure
*/
esp_err_t esp_cam_ctlr_dvp_format_conversion(esp_cam_ctlr_handle_t cam_handle,
const cam_ctlr_format_conv_config_t *config)
{
if (cam_handle == NULL) {
return ESP_ERR_INVALID_ARG;
}
esp_cam_ctlr_dvp_cam_t *ctlr = (esp_cam_ctlr_dvp_cam_t *)cam_handle;
ESP_LOGD(TAG, "Configure format conversion: %d -> %d", config->src_format, config->dst_format);
// Configure color format conversion
cam_hal_color_format_convert(&ctlr->hal, config);
return ESP_OK;
}
/**
* @brief New ESP CAM DVP controller
*
@@ -876,6 +901,7 @@ esp_err_t esp_cam_new_dvp_ctlr(const esp_cam_ctlr_dvp_config_t *config, esp_cam_
ctlr->base.get_internal_buffer = esp_cam_ctlr_dvp_cam_get_internal_buffer;
ctlr->base.get_buffer_len = esp_cam_ctlr_get_dvp_cam_frame_buffer_len;
ctlr->base.alloc_buffer = esp_cam_ctlr_dvp_cam_alloc_buffer;
ctlr->base.format_conversion = esp_cam_ctlr_dvp_format_conversion;
*ret_handle = &ctlr->base;

View File

@@ -99,3 +99,13 @@ void *esp_cam_ctlr_alloc_buffer(esp_cam_ctlr_handle_t handle, size_t size, uint3
return handle->alloc_buffer(handle, size, buf_caps);
}
esp_err_t esp_cam_ctlr_format_conversion(esp_cam_ctlr_handle_t handle,
const cam_ctlr_format_conv_config_t *conv_cfg)
{
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
ESP_RETURN_ON_FALSE(conv_cfg, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null conv_cfg");
ESP_RETURN_ON_FALSE(handle->format_conversion, ESP_ERR_NOT_SUPPORTED, TAG, "format conversion function not supported");
return handle->format_conversion(handle, conv_cfg);
}

View File

@@ -11,6 +11,7 @@
#include "esp_err.h"
#include "esp_heap_caps.h"
#include "esp_cam_ctlr_types.h"
#include "hal/cam_ctlr_types.h"
#ifdef __cplusplus
extern "C" {
@@ -150,6 +151,20 @@ esp_err_t esp_cam_ctlr_get_frame_buffer_len(esp_cam_ctlr_handle_t handle, size_t
*/
void *esp_cam_ctlr_alloc_buffer(esp_cam_ctlr_handle_t handle, size_t size, uint32_t buf_caps);
/**
* @brief Configure format conversion
*
* @param[in] handle ESP CAM controller handle
* @param[in] conv_cfg Color conversion configuration, contains source and destination formats
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG: Invalid argument
* - ESP_ERR_NOT_SUPPORTED: Format conversion not supported by this controller
*/
esp_err_t esp_cam_ctlr_format_conversion(esp_cam_ctlr_handle_t handle,
const cam_ctlr_format_conv_config_t *conv_cfg);
#ifdef __cplusplus
}
#endif

View File

@@ -8,6 +8,7 @@
#include <stdbool.h>
#include "esp_err.h"
#include "esp_cam_ctlr_types.h"
#include "hal/cam_ctlr_types.h"
#ifdef __cplusplus
extern "C" {
@@ -146,6 +147,19 @@ struct esp_cam_ctlr_t {
*/
void *(*alloc_buffer)(esp_cam_ctlr_t *, size_t, uint32_t);
/**
* @brief Configure format conversion
*
* @param[in] esp_cam_ctlr_t * ESP CAM controller handle
* @param[in] const cam_ctlr_format_conv_config_t * Color conversion configuration
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG: Invalid argument
* - ESP_ERR_NOT_SUPPORTED: Format conversion not supported by this controller
*/
esp_err_t (*format_conversion)(esp_cam_ctlr_t *, const cam_ctlr_format_conv_config_t *);
void *user_data; ///< User data
};

View File

@@ -86,6 +86,7 @@ static esp_err_t s_isp_dvp_stop(esp_cam_ctlr_handle_t handle);
static esp_err_t s_isp_dvp_receive(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, uint32_t timeout_ms);
static bool s_dvp_dma_trans_done_callback(dw_gdma_channel_handle_t chan, const dw_gdma_trans_done_event_data_t *event_data, void *user_data);
static void *s_isp_dvp_alloc_buffer(esp_cam_ctlr_t *handle, size_t size, uint32_t buf_caps);
static esp_err_t s_isp_dvp_format_conversion(esp_cam_ctlr_t *handle, const cam_ctlr_format_conv_config_t *config);
esp_err_t esp_cam_new_isp_dvp_ctlr(isp_proc_handle_t isp_proc, const esp_cam_ctlr_isp_dvp_cfg_t *ctlr_config, esp_cam_ctlr_handle_t *ret_handle)
{
@@ -202,6 +203,7 @@ esp_err_t esp_cam_new_isp_dvp_ctlr(isp_proc_handle_t isp_proc, const esp_cam_ctl
cam_ctlr->get_internal_buffer = s_isp_dvp_get_frame_buffer;
cam_ctlr->get_buffer_len = s_isp_dvp_get_frame_buffer_length;
cam_ctlr->alloc_buffer = s_isp_dvp_alloc_buffer;
cam_ctlr->format_conversion = s_isp_dvp_format_conversion;
*ret_handle = cam_ctlr;
return ESP_OK;
@@ -616,3 +618,10 @@ static void *s_isp_dvp_alloc_buffer(esp_cam_ctlr_t *handle, size_t size, uint32_
return buffer;
}
static esp_err_t s_isp_dvp_format_conversion(esp_cam_ctlr_t *handle, const cam_ctlr_format_conv_config_t *config)
{
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
// ISP DVP controller doesn't support format conversion yet
return ESP_ERR_NOT_SUPPORTED;
}

View File

@@ -1,14 +1,25 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "hal/cam_ll.h"
#include "hal/cam_hal.h"
#include "hal/color_types.h"
#include "soc/soc_caps.h"
#include "soc/cam_periph.h"
/**
* @brief Default format conversion configuration
*/
#define CAM_HAL_DEFAULT_FORMAT_CONV_CONFIG { \
.conv_std = COLOR_CONV_STD_RGB_YUV_BT601, \
.data_width = 8, \
.input_range = COLOR_RANGE_LIMIT, \
.output_range = COLOR_RANGE_LIMIT \
}
/**
* @brief Configure line number to trigger interrupt
*
@@ -119,3 +130,59 @@ void cam_hal_stop_streaming(cam_hal_context_t *hal)
{
cam_ll_stop(hal->hw);
}
/**
* @brief Configure color format conversion
*
* This function handles all types of color format conversions:
* - YUV to RGB conversion
* - RGB to YUV conversion
* - YUV to YUV conversion
*
* Color range support:
* - Full range: 0-255 for both RGB and YUV
* - Limited range: RGB 16-240, YUV Y:16-240, U-V:16-235
*
* @param hal CAM HAL context pointer
* @param config Color conversion configuration. If NULL, default config is used.
*/
void cam_hal_color_format_convert(cam_hal_context_t *hal,
const cam_ctlr_format_conv_config_t *config)
{
// Use provided config or default
const cam_ctlr_format_conv_config_t *cfg = config;
if (cfg == NULL) {
static const cam_ctlr_format_conv_config_t default_config = CAM_HAL_DEFAULT_FORMAT_CONV_CONFIG;
cfg = &default_config;
}
cam_ll_enable_rgb_yuv_convert(hal->hw, false);
// Extract color space from source and destination formats
color_space_t src_space = COLOR_SPACE_TYPE(cfg->src_format);
color_space_t dst_space = COLOR_SPACE_TYPE(cfg->dst_format);
// Configure conversion based on color space types
if (src_space == COLOR_SPACE_YUV && dst_space == COLOR_SPACE_RGB) {
// YUV to RGB conversion
color_pixel_yuv_format_t yuv_format = COLOR_PIXEL_FORMAT(cfg->src_format);
cam_ll_set_convert_mode_yuv_to_rgb(hal->hw, yuv_format);
} else if (src_space == COLOR_SPACE_RGB && dst_space == COLOR_SPACE_YUV) {
// RGB to YUV conversion
color_pixel_yuv_format_t yuv_format = COLOR_PIXEL_FORMAT(cfg->dst_format);
cam_ll_set_convert_mode_rgb_to_yuv(hal->hw, yuv_format);
} else if (src_space == COLOR_SPACE_YUV && dst_space == COLOR_SPACE_YUV) {
// YUV to YUV conversion
color_pixel_yuv_format_t src_yuv_format = COLOR_PIXEL_FORMAT(cfg->src_format);
color_pixel_yuv_format_t dst_yuv_format = COLOR_PIXEL_FORMAT(cfg->dst_format);
cam_ll_set_convert_mode_yuv_to_yuv(hal->hw, src_yuv_format, dst_yuv_format);
}
// Common configuration for all conversion types
cam_ll_set_yuv_convert_std(hal->hw, cfg->conv_std);
cam_ll_set_convert_data_width(hal->hw, cfg->data_width);
cam_ll_set_input_color_range(hal->hw, cfg->input_range);
cam_ll_set_output_color_range(hal->hw, cfg->output_range);
cam_ll_enable_rgb_yuv_convert(hal->hw, true);
}

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -39,6 +39,18 @@ typedef enum {
CAM_CTLR_DATA_WIDTH_16 = 16, ///< 16-bit data width
} cam_ctlr_data_width_t;
/**
* @brief Camera Controller format conversion configuration
*/
typedef struct {
cam_ctlr_color_t src_format; /*!< Source format */
cam_ctlr_color_t dst_format; /*!< Destination format */
color_conv_std_rgb_yuv_t conv_std; /*!< Conversion standard */
uint32_t data_width; /*!< Data width in bits */
color_range_t input_range; /*!< Input color range */
color_range_t output_range; /*!< Output color range */
} cam_ctlr_format_conv_config_t;
#ifdef __cplusplus
}
#endif

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -68,6 +68,24 @@ void cam_hal_start_streaming(cam_hal_context_t *hal);
*/
void cam_hal_stop_streaming(cam_hal_context_t *hal);
/**
* @brief Configure color format conversion
*
* This function handles all types of color format conversions:
* - YUV to RGB conversion
* - RGB to YUV conversion
* - YUV to YUV conversion
*
* Color range support:
* - Full range: 0-255 for both RGB and YUV
* - Limited range: RGB 16-240, YUV Y:16-240, U-V:16-235
*
* @param hal CAM HAL context pointer
* @param config Color conversion configuration. If NULL, default config is used.
*/
void cam_hal_color_format_convert(cam_hal_context_t *hal,
const cam_ctlr_format_conv_config_t *config);
#ifdef __cplusplus
}
#endif

View File

@@ -119,6 +119,16 @@ Camera controller driver can be implemented in one of following ways:
After calling :cpp:func:`esp_cam_new_dvp_ctlr`, you should allocate a camera buffer that meets the alignment constraints, or call :cpp:func:`esp_cam_ctlr_alloc_buffer` to automatically allocate.
You can call :cpp:func:`esp_cam_ctlr_format_conversion` to configure format conversion. The driver supports the following conversion types:
* YUV to RGB conversion
* RGB to YUV conversion
* YUV to YUV conversion
Color range support:
* Full range: 0-255 for both RGB and YUV
* Limited range: RGB 16-240, YUV Y:16-240, U-V:16-235
.. code:: c
esp_cam_ctlr_handle_t cam_handle = NULL;
@@ -153,6 +163,16 @@ Camera controller driver can be implemented in one of following ways:
ESP_ERROR_CHECK(esp_cam_new_dvp_ctlr(&dvp_config, &cam_handle));
const cam_ctlr_format_conv_config_t conv_cfg = {
.src_format = CAM_CTLR_COLOR_YUV422, // Source format: YUV422
.dst_format = CAM_CTLR_COLOR_RGB565, // Destination format: RGB565
.conv_std = COLOR_CONV_STD_RGB_YUV_BT601,
.data_width = 8,
.input_range = COLOR_RANGE_LIMIT,
.output_range = COLOR_RANGE_LIMIT,
};
ESP_ERROR_CHECK(esp_cam_ctlr_format_conversion(cam_handle, &conv_cfg));
Uninstall Camera Controller Driver
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@@ -120,6 +120,16 @@
在调用 :cpp:func:`esp_cam_new_dvp_ctlr` 之后,需要分配符合对齐约束的摄像头缓冲区,或调用 :cpp:func:`esp_cam_ctlr_alloc_buffer` 来自动分配。
可以调用 :cpp:func:`esp_cam_ctlr_format_conversion` 来配置格式转换。驱动程序支持以下转换类型:
* YUV 到 RGB 转换
* RGB 到 YUV 转换
* YUV 到 YUV 转换
色彩空间范围支持:
* 全色彩空间RGB 和 YUV 的取值范围为 0-255
* 有限色彩空间RGB 取值范围为 16-240YUV Y 分量取值范围为 16-240U-V 分量取值范围为 16-235
.. code:: c
esp_cam_ctlr_handle_t cam_handle = NULL;
@@ -154,6 +164,16 @@
ESP_ERROR_CHECK(esp_cam_new_dvp_ctlr(&dvp_config, &cam_handle));
const cam_ctlr_format_conv_config_t conv_cfg = {
.src_format = CAM_CTLR_COLOR_YUV422, // 源格式YUV422
.dst_format = CAM_CTLR_COLOR_RGB565, // 目标格式RGB565
.conv_std = COLOR_CONV_STD_RGB_YUV_BT601,
.data_width = 8,
.input_range = COLOR_RANGE_LIMIT,
.output_range = COLOR_RANGE_LIMIT,
};
ESP_ERROR_CHECK(esp_cam_ctlr_format_conversion(cam_handle, &conv_cfg));
卸载摄像头控制器驱动程序
~~~~~~~~~~~~~~~~~~~~~~~~

View File

@@ -30,4 +30,15 @@ menu "Example Configuration"
int
default 480 if EXAMPLE_CAM_VRES_480
default 240 if EXAMPLE_CAM_VRES_240
choice EXAMPLE_CAM_INPUT_FORMAT
bool "Set camera input format"
default EXAMPLE_CAM_INPUT_FORMAT_YUV422
config EXAMPLE_CAM_INPUT_FORMAT_RGB565
bool "RGB565"
config EXAMPLE_CAM_INPUT_FORMAT_YUV422
bool "YUV422"
endchoice
endmenu

View File

@@ -146,7 +146,11 @@ void app_main(void)
.clk_src = CAM_CLK_SRC_DEFAULT,
.h_res = CONFIG_EXAMPLE_CAM_HRES,
.v_res = CONFIG_EXAMPLE_CAM_VRES,
#if CONFIG_EXAMPLE_CAM_INPUT_FORMAT_YUV422
.input_data_color_type = CAM_CTLR_COLOR_YUV422,
#else
.input_data_color_type = CAM_CTLR_COLOR_RGB565,
#endif
.dma_burst_size = 64,
.pin = &pin_cfg,
.bk_buffer_dis = 1,
@@ -200,6 +204,20 @@ void app_main(void)
//--------Enable and start Camera Controller----------//
ESP_ERROR_CHECK(esp_cam_ctlr_enable(cam_handle));
#if CONFIG_EXAMPLE_CAM_INPUT_FORMAT_YUV422
ESP_LOGI(TAG, "Configure format conversion: YUV422 -> RGB565");
// Configure format conversion
const cam_ctlr_format_conv_config_t conv_cfg = {
.src_format = CAM_CTLR_COLOR_YUV422, // Source format: YUV422
.dst_format = CAM_CTLR_COLOR_RGB565, // Destination format: RGB565
.conv_std = COLOR_CONV_STD_RGB_YUV_BT601,
.data_width = 8,
.input_range = COLOR_RANGE_LIMIT,
.output_range = COLOR_RANGE_LIMIT,
};
ESP_ERROR_CHECK(esp_cam_ctlr_format_conversion(cam_handle, &conv_cfg));
#endif
if (esp_cam_ctlr_start(cam_handle) != ESP_OK) {
ESP_LOGE(TAG, "Driver start fail");
return;

View File

@@ -43,7 +43,11 @@ extern "C" {
#define EXAMPLE_DVP_CAM_BUF_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA)
#endif
#if CONFIG_EXAMPLE_CAM_INPUT_FORMAT_YUV422
#define EXAMPLE_CAM_FORMAT "DVP_8bit_20Minput_YUV422_240x240_25fps" // ov2640
#elif CONFIG_EXAMPLE_CAM_INPUT_FORMAT_RGB565
#define EXAMPLE_CAM_FORMAT "DVP_8bit_20Minput_RGB565_240x240_25fps" // ov2640
#endif
#ifndef EXAMPLE_CAM_FORMAT
#error "Unsupported camera format! Please adjust EXAMPLE_CAM_HRES and EXAMPLE_CAM_VRES in menuconfig"