Support both esp_video and esp32_camera (#1671)

* Update project version to 2.2.1 and refactor camera component handling

- Incremented project version from 2.2.0 to 2.2.1 in CMakeLists.txt.
- Removed legacy esp32_camera component and replaced it with esp_video for ESP32-S3 and ESP32-P4 boards.
- Updated board implementations to utilize the new esp_video component, ensuring compatibility and improved functionality.
- Cleaned up Kconfig options related to camera selection, streamlining the configuration process.
- Enhanced camera initialization logic across various board files to support the new component structure.

* Refactor camera handling in AtomS3R CAM/M12 EchoBase board

- Replaced the legacy EspVideo component with the new Esp32Camera class for improved camera functionality.
- Updated camera initialization logic to utilize a more structured configuration approach, enhancing clarity and maintainability.
- Removed outdated comments and code related to the previous camera implementation in the README file.

* Update camera configuration for atoms3r-cam-m12-echo-base

- Removed outdated camera configuration options from config.json to streamline the setup.
- Retained essential partition table configuration for improved clarity.

* Enhance Esp32Camera functionality and memory management

- Added esp_timer.h for improved timing functionality.
- Streamlined camera initialization by removing redundant frame buffer setup and logging.
- Improved memory allocation for JPEG encoding and added error handling for unsupported pixel formats.
- Updated comments for clarity and consistency, ensuring better understanding of the code flow.
This commit is contained in:
Xiaoxia
2026-01-20 22:44:37 +08:00
committed by GitHub
parent d5ec8f7081
commit 734b5b410a
41 changed files with 1348 additions and 1581 deletions

View File

@ -9,5 +9,5 @@ include($ENV{IDF_PATH}/tools/cmake/project.cmake)
# "Trim" the build. Include the minimal set of components, main, and anything it depends on. # "Trim" the build. Include the minimal set of components, main, and anything it depends on.
idf_build_set_property(MINIMAL_BUILD ON) idf_build_set_property(MINIMAL_BUILD ON)
set(PROJECT_VER "2.2.0") set(PROJECT_VER "2.2.1")
project(xiaozhi) project(xiaozhi)

View File

@ -52,8 +52,6 @@ list(APPEND SOURCES
"boards/common/axp2101.cc" "boards/common/axp2101.cc"
"boards/common/backlight.cc" "boards/common/backlight.cc"
"boards/common/button.cc" "boards/common/button.cc"
"boards/common/esp32_camera.cc"
"boards/common/esp32s3_camera.cc"
"boards/common/i2c_device.cc" "boards/common/i2c_device.cc"
"boards/common/knob.cc" "boards/common/knob.cc"
"boards/common/power_save_timer.cc" "boards/common/power_save_timer.cc"
@ -758,29 +756,18 @@ if(CONFIG_IDF_TARGET_ESP32)
"led/gpio_led.cc" "led/gpio_led.cc"
"display/lvgl_display/jpg/image_to_jpeg.cpp" "display/lvgl_display/jpg/image_to_jpeg.cpp"
"display/lvgl_display/jpg/jpeg_to_image.c" "display/lvgl_display/jpg/jpeg_to_image.c"
"boards/common/esp32_camera.cc"
"boards/common/esp32s3_camera.cc"
"boards/common/nt26_board.cc" "boards/common/nt26_board.cc"
) )
endif() endif()
# ESP32-S3: 根据 Kconfig 选择使用哪个摄像头组件 # Include EspVideo if target is ESP32S3 or ESP32P4
if(CONFIG_IDF_TARGET_ESP32S3) if(CONFIG_IDF_TARGET_ESP32S3 OR CONFIG_IDF_TARGET_ESP32P4)
if(CONFIG_XIAOZHI_USE_ESP_CAMERA) list(APPEND SOURCES "boards/common/esp_video.cc")
# 使用 esp_camera 组件,排除 esp32_camera.cc
list(REMOVE_ITEM SOURCES "boards/common/esp32_camera.cc")
elseif(CONFIG_XIAOZHI_USE_ESP_VIDEO)
# 使用 esp_video 组件,排除 esp32s3_camera.cc
list(REMOVE_ITEM SOURCES "boards/common/esp32s3_camera.cc")
else()
# 默认使用 esp_camera 组件
list(REMOVE_ITEM SOURCES "boards/common/esp32_camera.cc")
endif()
endif() endif()
# ESP32-P4: 只能使用 esp_video 组件,排除 esp32s3_camera.cc # Include Esp32Camera if target is ESP32S3
if(CONFIG_IDF_TARGET_ESP32P4) if(CONFIG_IDF_TARGET_ESP32S3)
list(REMOVE_ITEM SOURCES "boards/common/esp32s3_camera.cc") list(APPEND SOURCES "boards/common/esp32_camera.cc")
endif() endif()
idf_component_register(SRCS ${SOURCES} idf_component_register(SRCS ${SOURCES}

View File

@ -737,31 +737,6 @@ menu "Camera Configuration"
comment "Warning: Please read the help text before modifying these settings." comment "Warning: Please read the help text before modifying these settings."
choice XIAOZHI_CAMERA_COMPONENT
prompt "Camera Component Selection"
default XIAOZHI_USE_ESP_VIDEO if IDF_TARGET_ESP32S3
default XIAOZHI_USE_ESP_VIDEO if IDF_TARGET_ESP32P4
help
Select the camera component to use.
ESP32-S3 can choose between esp_camera (legacy) or esp_video (new).
ESP32-P4 only supports esp_video.
config XIAOZHI_USE_ESP_CAMERA
bool "Use esp_camera (legacy component)"
depends on IDF_TARGET_ESP32S3
help
Use the legacy esp32-camera component.
This is the traditional camera driver for ESP32-S3.
config XIAOZHI_USE_ESP_VIDEO
bool "Use esp_video (new component)"
depends on IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32P4
help
Use the new esp_video component.
This component provides V4L2-like interface and is required for ESP32-P4.
On ESP32-S3, it provides additional features but may require different camera configuration.
endchoice
config XIAOZHI_CAMERA_ALLOW_JPEG_INPUT config XIAOZHI_CAMERA_ALLOW_JPEG_INPUT
bool "Allow JPEG Input" bool "Allow JPEG Input"
default n default n

View File

@ -6,7 +6,7 @@
#include "config.h" #include "config.h"
#include "i2c_device.h" #include "i2c_device.h"
#include "led/single_led.h" #include "led/single_led.h"
#include "esp32_camera.h" #include "esp_video.h"
#include <esp_log.h> #include <esp_log.h>
#include <esp_lcd_panel_vendor.h> #include <esp_lcd_panel_vendor.h>
@ -49,7 +49,7 @@ private:
Button boot_button_; Button boot_button_;
LcdDisplay* display_; LcdDisplay* display_;
XL9555* xl9555_; XL9555* xl9555_;
Esp32Camera* camera_; EspVideo* camera_;
void InitializeI2c() { void InitializeI2c() {
// Initialize I2C peripheral // Initialize I2C peripheral
@ -179,7 +179,7 @@ private:
.dvp = &dvp_config, .dvp = &dvp_config,
}; };
camera_ = new Esp32Camera(video_config); camera_ = new EspVideo(video_config);
} }
public: public:

View File

@ -14,12 +14,6 @@ AtomS3R CAM、AtomS3R M12 是 M5Stack 推出的基于 ESP32-S3-PICO-1-N8R8 的
两款开发版均**不带屏幕、不带额外按键**,需要使用语音唤醒。必要时,需要使用 `idf.py monitor` 查看 log 以确定运行状态。 两款开发版均**不带屏幕、不带额外按键**,需要使用语音唤醒。必要时,需要使用 `idf.py monitor` 查看 log 以确定运行状态。
> ![NOTE]
>
> 自版本 [待定] 起,由于依赖库不支持 OV3660 传感器AtomS3R M12 无法使用摄像头识别功能。
>
> AtomS3R CAM 不受影响;使用旧版本小智固件的 AtomS3R M12 不受影响。
## 配置、编译命令 ## 配置、编译命令
**配置编译目标为 ESP32S3** **配置编译目标为 ESP32S3**

View File

@ -126,47 +126,33 @@ private:
} }
void InitializeCamera() { void InitializeCamera() {
static esp_cam_ctlr_dvp_pin_config_t dvp_pin_config = { camera_config_t config = {};
.data_width = CAM_CTLR_DATA_WIDTH_8, config.pin_d0 = CAMERA_PIN_D0;
.data_io = { config.pin_d1 = CAMERA_PIN_D1;
[0] = CAMERA_PIN_D0, config.pin_d2 = CAMERA_PIN_D2;
[1] = CAMERA_PIN_D1, config.pin_d3 = CAMERA_PIN_D3;
[2] = CAMERA_PIN_D2, config.pin_d4 = CAMERA_PIN_D4;
[3] = CAMERA_PIN_D3, config.pin_d5 = CAMERA_PIN_D5;
[4] = CAMERA_PIN_D4, config.pin_d6 = CAMERA_PIN_D6;
[5] = CAMERA_PIN_D5, config.pin_d7 = CAMERA_PIN_D7;
[6] = CAMERA_PIN_D6, config.pin_xclk = CAMERA_PIN_XCLK;
[7] = CAMERA_PIN_D7, config.pin_pclk = CAMERA_PIN_PCLK;
}, config.pin_vsync = CAMERA_PIN_VSYNC;
.vsync_io = CAMERA_PIN_VSYNC, config.pin_href = CAMERA_PIN_HREF;
.de_io = CAMERA_PIN_HREF, config.pin_sccb_sda = CAMERA_PIN_SIOD;
.pclk_io = CAMERA_PIN_PCLK, config.pin_sccb_scl = CAMERA_PIN_SIOC;
.xclk_io = CAMERA_PIN_XCLK, config.sccb_i2c_port = 1;
}; config.pin_pwdn = CAMERA_PIN_PWDN;
config.pin_reset = CAMERA_PIN_RESET;
config.xclk_freq_hz = XCLK_FREQ_HZ;
config.pixel_format = PIXFORMAT_RGB565;
config.frame_size = FRAMESIZE_QVGA;
config.jpeg_quality = 12;
config.fb_count = 1;
config.fb_location = CAMERA_FB_IN_PSRAM;
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
esp_video_init_sccb_config_t sccb_config = { camera_ = new Esp32Camera(config);
.init_sccb = true,
.i2c_config = {
.port = 1,
.scl_pin = CAMERA_PIN_SIOC,
.sda_pin = CAMERA_PIN_SIOD,
},
.freq = 100000,
};
esp_video_init_dvp_config_t dvp_config = {
.sccb_config = sccb_config,
.reset_pin = CAMERA_PIN_RESET,
.pwdn_pin = CAMERA_PIN_PWDN,
.dvp_pin = dvp_pin_config,
.xclk_freq = XCLK_FREQ_HZ,
};
esp_video_init_config_t video_config = {
.dvp = &dvp_config,
};
camera_ = new Esp32Camera(video_config);
camera_->SetHMirror(false); camera_->SetHMirror(false);
} }

View File

@ -5,10 +5,7 @@
"name": "atoms3r-cam-m12-echo-base", "name": "atoms3r-cam-m12-echo-base",
"sdkconfig_append": [ "sdkconfig_append": [
"CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y", "CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y",
"CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions/v2/8m.csv\"", "CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions/v2/8m.csv\""
"CONFIG_CAMERA_GC0308=y",
"CONFIG_CAMERA_GC0308_AUTO_DETECT_DVP_INTERFACE_SENSOR=y",
"CONFIG_CAMERA_GC0308_DVP_YUV422_320X240_20FPS=y"
] ]
} }
] ]

View File

@ -8,7 +8,7 @@
#include "mcp_server.h" #include "mcp_server.h"
#include "lamp_controller.h" #include "lamp_controller.h"
#include "led/single_led.h" #include "led/single_led.h"
#include "esp32_camera.h" #include "esp_video.h"
#include <esp_log.h> #include <esp_log.h>
#include <driver/i2c_master.h> #include <driver/i2c_master.h>
@ -65,7 +65,7 @@ private:
Button boot_button_; Button boot_button_;
LcdDisplay* display_; LcdDisplay* display_;
Esp32Camera* camera_; EspVideo* camera_;
void InitializeSpi() { void InitializeSpi() {
spi_bus_config_t buscfg = {}; spi_bus_config_t buscfg = {};
@ -165,7 +165,7 @@ private:
.dvp = &dvp_config, .dvp = &dvp_config,
}; };
camera_ = new Esp32Camera(video_config); camera_ = new EspVideo(video_config);
camera_->SetHMirror(false); camera_->SetHMirror(false);
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,5 @@
#pragma once #pragma once
#include "sdkconfig.h" #include "sdkconfig.h"
// esp32_camera (使用 esp_video 组件) 用于 ESP32-P4或 ESP32-S3 选择使用 esp_video 时
#if defined(CONFIG_IDF_TARGET_ESP32P4) || (defined(CONFIG_IDF_TARGET_ESP32S3) && defined(CONFIG_XIAOZHI_USE_ESP_VIDEO))
#include <lvgl.h> #include <lvgl.h>
#include <thread> #include <thread>
@ -12,46 +10,31 @@
#include <freertos/queue.h> #include <freertos/queue.h>
#include "camera.h" #include "camera.h"
#include "esp_camera.h"
#include "jpg/image_to_jpeg.h" #include "jpg/image_to_jpeg.h"
#include "esp_video_init.h"
struct JpegChunk { struct JpegChunk
{
uint8_t *data; uint8_t *data;
size_t len; size_t len;
}; };
class Esp32Camera : public Camera { class Esp32Camera : public Camera
{
private: private:
struct FrameBuffer {
uint8_t *data = nullptr;
size_t len = 0;
uint16_t width = 0;
uint16_t height = 0;
v4l2_pix_fmt_t format = 0;
} frame_;
v4l2_pix_fmt_t sensor_format_ = 0;
#ifdef CONFIG_XIAOZHI_ENABLE_ROTATE_CAMERA_IMAGE
uint16_t sensor_width_ = 0;
uint16_t sensor_height_ = 0;
#endif // CONFIG_XIAOZHI_ENABLE_ROTATE_CAMERA_IMAGE
int video_fd_ = -1;
bool streaming_on_ = false; bool streaming_on_ = false;
struct MmapBuffer { void *start = nullptr; size_t length = 0; };
std::vector<MmapBuffer> mmap_buffers_;
std::string explain_url_; std::string explain_url_;
std::string explain_token_; std::string explain_token_;
std::thread encoder_thread_; std::thread encoder_thread_;
camera_fb_t *current_fb_ = nullptr;
public: public:
Esp32Camera(const esp_video_init_config_t& config); Esp32Camera(const camera_config_t &config);
~Esp32Camera(); ~Esp32Camera();
virtual void SetExplainUrl(const std::string& url, const std::string& token); virtual void SetExplainUrl(const std::string &url, const std::string &token) override;
virtual bool Capture(); virtual bool Capture() override;
// 翻转控制函数
virtual bool SetHMirror(bool enabled) override; virtual bool SetHMirror(bool enabled) override;
virtual bool SetVFlip(bool enabled) override; virtual bool SetVFlip(bool enabled) override;
virtual std::string Explain(const std::string& question); virtual std::string Explain(const std::string &question) override;
}; };
#endif // ndef CONFIG_IDF_TARGET_ESP32

View File

@ -1,413 +0,0 @@
#include "sdkconfig.h"
// esp32s3_camera (使用 esp_camera 组件) 仅用于 ESP32-S3 且选择使用 esp_camera 时
#if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(CONFIG_XIAOZHI_USE_ESP_CAMERA)
#include <esp_heap_caps.h>
#include <cstdio>
#include <cstring>
#include <esp_log.h>
#include "esp32s3_camera.h"
#include "board.h"
#include "display.h"
#include "lvgl_display.h"
#include "mcp_server.h"
#include "system_info.h"
#include "jpg/image_to_jpeg.h"
#define TAG "Esp32S3Camera"
// V4L2 兼容的格式定义
#define V4L2_PIX_FMT_RGB565 0x50424752 // 'RGBP'
#define V4L2_PIX_FMT_YUYV 0x56595559 // 'YUYV'
#define V4L2_PIX_FMT_JPEG 0x4745504A // 'JPEG'
#define V4L2_PIX_FMT_RGB24 0x33424752 // 'RGB3'
#define V4L2_PIX_FMT_GREY 0x59455247 // 'GREY'
static uint32_t pixformat_to_v4l2(pixformat_t fmt)
{
switch (fmt)
{
case PIXFORMAT_RGB565:
return V4L2_PIX_FMT_RGB565;
case PIXFORMAT_YUV422:
return V4L2_PIX_FMT_YUYV;
case PIXFORMAT_JPEG:
return V4L2_PIX_FMT_JPEG;
case PIXFORMAT_RGB888:
return V4L2_PIX_FMT_RGB24;
case PIXFORMAT_GRAYSCALE:
return V4L2_PIX_FMT_GREY;
default:
return 0;
}
}
Esp32S3Camera::Esp32S3Camera(const camera_config_t &config)
{
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK)
{
ESP_LOGE(TAG, "esp_camera_init failed with error 0x%x", err);
return;
}
sensor_t *s = esp_camera_sensor_get();
if (s)
{
frame_.width = config.frame_size == FRAMESIZE_QVGA ? 320 : config.frame_size == FRAMESIZE_VGA ? 640
: config.frame_size == FRAMESIZE_SVGA ? 800
: config.frame_size == FRAMESIZE_XGA ? 1024
: config.frame_size == FRAMESIZE_HD ? 1280
: config.frame_size == FRAMESIZE_SXGA ? 1280
: config.frame_size == FRAMESIZE_UXGA ? 1600
: 320;
frame_.height = config.frame_size == FRAMESIZE_QVGA ? 240 : config.frame_size == FRAMESIZE_VGA ? 480
: config.frame_size == FRAMESIZE_SVGA ? 600
: config.frame_size == FRAMESIZE_XGA ? 768
: config.frame_size == FRAMESIZE_HD ? 720
: config.frame_size == FRAMESIZE_SXGA ? 1024
: config.frame_size == FRAMESIZE_UXGA ? 1200
: 240;
frame_.format = config.pixel_format;
ESP_LOGI(TAG, "Camera initialized: %dx%d, format=%d", frame_.width, frame_.height, config.pixel_format);
}
streaming_on_ = true;
ESP_LOGI(TAG, "ESP32-S3 Camera init success");
}
Esp32S3Camera::~Esp32S3Camera()
{
if (streaming_on_)
{
if (current_fb_)
{
esp_camera_fb_return(current_fb_);
current_fb_ = nullptr;
}
esp_camera_deinit();
streaming_on_ = false;
}
if (frame_.data)
{
heap_caps_free(frame_.data);
frame_.data = nullptr;
}
}
void Esp32S3Camera::SetExplainUrl(const std::string &url, const std::string &token)
{
explain_url_ = url;
explain_token_ = token;
}
bool Esp32S3Camera::Capture()
{
if (encoder_thread_.joinable())
{
encoder_thread_.join();
}
if (!streaming_on_)
{
return false;
}
// 释放之前的帧
if (current_fb_)
{
esp_camera_fb_return(current_fb_);
current_fb_ = nullptr;
}
// 丢弃前两帧,获取最新帧
for (int i = 0; i < 3; i++)
{
camera_fb_t *fb = esp_camera_fb_get();
if (!fb)
{
ESP_LOGE(TAG, "Camera capture failed");
return false;
}
if (i < 2)
{
esp_camera_fb_return(fb);
}
else
{
current_fb_ = fb;
}
}
if (!current_fb_)
{
ESP_LOGE(TAG, "Failed to get frame buffer");
return false;
}
// 保存帧副本到 PSRAM
if (frame_.data)
{
heap_caps_free(frame_.data);
frame_.data = nullptr;
}
frame_.len = current_fb_->len;
frame_.width = current_fb_->width;
frame_.height = current_fb_->height;
frame_.format = current_fb_->format;
frame_.data = (uint8_t *)heap_caps_malloc(frame_.len, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
if (!frame_.data)
{
ESP_LOGE(TAG, "Failed to allocate %zu bytes for frame copy", frame_.len);
esp_camera_fb_return(current_fb_);
current_fb_ = nullptr;
return false;
}
memcpy(frame_.data, current_fb_->buf, frame_.len);
// 释放原始帧
esp_camera_fb_return(current_fb_);
current_fb_ = nullptr;
// 对 RGB565 格式进行字节交换 (Big Endian <-> Little Endian)
// 这样 frame_.data 就是已交换的数据,显示和上传都使用相同的数据
if (frame_.format == PIXFORMAT_RGB565)
{
uint8_t *data = frame_.data;
size_t pixel_count = frame_.width * frame_.height;
for (size_t i = 0; i < pixel_count; i++)
{
uint8_t temp = data[2 * i];
data[2 * i] = data[2 * i + 1];
data[2 * i + 1] = temp;
}
}
ESP_LOGD(TAG, "Captured frame: %dx%d, len=%zu, format=%d",
frame_.width, frame_.height, frame_.len, frame_.format);
// 显示预览图片
auto display = dynamic_cast<LvglDisplay *>(Board::GetInstance().GetDisplay());
if (display != nullptr)
{
if (!frame_.data)
{
ESP_LOGE(TAG, "frame.data is null");
return false;
}
uint16_t w = frame_.width;
uint16_t h = frame_.height;
size_t lvgl_image_size = frame_.len;
size_t stride = ((w * 2) + 3) & ~3; // 4字节对齐
lv_color_format_t color_format = LV_COLOR_FORMAT_RGB565;
uint8_t *data = nullptr;
switch (frame_.format)
{
case PIXFORMAT_RGB565:
// frame_.data 已经在捕获阶段完成了字节交换,直接复制即可
data = (uint8_t *)heap_caps_malloc(w * h * 2, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
if (data == nullptr)
{
ESP_LOGE(TAG, "Failed to allocate memory for preview image");
return false;
}
memcpy(data, frame_.data, frame_.len);
lvgl_image_size = frame_.len;
break;
case PIXFORMAT_JPEG:
// JPEG 格式需要解码 - 跳过预览显示
ESP_LOGD(TAG, "JPEG format preview not supported, skipping display");
return true;
default:
ESP_LOGE(TAG, "Unsupported frame format for preview: %d", frame_.format);
return true; // 仍然返回 true因为捕获成功
}
if (data)
{
auto image = std::make_unique<LvglAllocatedImage>(data, lvgl_image_size, w, h, stride, color_format);
display->SetPreviewImage(std::move(image));
}
}
return true;
}
bool Esp32S3Camera::SetHMirror(bool enabled)
{
sensor_t *s = esp_camera_sensor_get();
if (!s)
{
return false;
}
s->set_hmirror(s, enabled ? 1 : 0);
return true;
}
bool Esp32S3Camera::SetVFlip(bool enabled)
{
sensor_t *s = esp_camera_sensor_get();
if (!s)
{
return false;
}
s->set_vflip(s, enabled ? 1 : 0);
return true;
}
std::string Esp32S3Camera::Explain(const std::string &question)
{
if (explain_url_.empty())
{
throw std::runtime_error("Image explain URL or token is not set");
}
// 创建局部的 JPEG 队列
QueueHandle_t jpeg_queue = xQueueCreate(40, sizeof(JpegChunk));
if (jpeg_queue == nullptr)
{
ESP_LOGE(TAG, "Failed to create JPEG queue");
throw std::runtime_error("Failed to create JPEG queue");
}
// 转换格式为 v4l2 兼容格式
uint32_t v4l2_format = pixformat_to_v4l2(frame_.format);
// 启动编码线程
encoder_thread_ = std::thread([this, jpeg_queue, v4l2_format]()
{
uint16_t w = frame_.width ? frame_.width : 320;
uint16_t h = frame_.height ? frame_.height : 240;
bool ok = image_to_jpeg_cb(
frame_.data, frame_.len, w, h, static_cast<v4l2_pix_fmt_t>(v4l2_format), 80,
[](void* arg, size_t index, const void* data, size_t len) -> size_t {
auto jpeg_queue = static_cast<QueueHandle_t>(arg);
JpegChunk chunk = {.data = nullptr, .len = len};
if (index == 0 && data != nullptr && len > 0) {
chunk.data = (uint8_t*)heap_caps_aligned_alloc(16, len, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
if (chunk.data == nullptr) {
ESP_LOGE(TAG, "Failed to allocate %zu bytes for JPEG chunk", len);
chunk.len = 0;
} else {
memcpy(chunk.data, data, len);
}
} else {
chunk.len = 0;
}
xQueueSend(jpeg_queue, &chunk, portMAX_DELAY);
return len;
},
jpeg_queue);
if (!ok) {
JpegChunk chunk = {.data = nullptr, .len = 0};
xQueueSend(jpeg_queue, &chunk, portMAX_DELAY);
} });
auto network = Board::GetInstance().GetNetwork();
auto http = network->CreateHttp(3);
std::string boundary = "----ESP32_CAMERA_BOUNDARY";
http->SetHeader("Device-Id", SystemInfo::GetMacAddress().c_str());
http->SetHeader("Client-Id", Board::GetInstance().GetUuid().c_str());
if (!explain_token_.empty())
{
http->SetHeader("Authorization", "Bearer " + explain_token_);
}
http->SetHeader("Content-Type", "multipart/form-data; boundary=" + boundary);
http->SetHeader("Transfer-Encoding", "chunked");
if (!http->Open("POST", explain_url_))
{
ESP_LOGE(TAG, "Failed to connect to explain URL");
encoder_thread_.join();
JpegChunk chunk;
while (xQueueReceive(jpeg_queue, &chunk, portMAX_DELAY) == pdPASS)
{
if (chunk.data != nullptr)
{
heap_caps_free(chunk.data);
}
else
{
break;
}
}
vQueueDelete(jpeg_queue);
throw std::runtime_error("Failed to connect to explain URL");
}
{
std::string question_field;
question_field += "--" + boundary + "\r\n";
question_field += "Content-Disposition: form-data; name=\"question\"\r\n";
question_field += "\r\n";
question_field += question + "\r\n";
http->Write(question_field.c_str(), question_field.size());
}
{
std::string file_header;
file_header += "--" + boundary + "\r\n";
file_header += "Content-Disposition: form-data; name=\"file\"; filename=\"camera.jpg\"\r\n";
file_header += "Content-Type: image/jpeg\r\n";
file_header += "\r\n";
http->Write(file_header.c_str(), file_header.size());
}
size_t total_sent = 0;
bool saw_terminator = false;
while (true)
{
JpegChunk chunk;
if (xQueueReceive(jpeg_queue, &chunk, portMAX_DELAY) != pdPASS)
{
ESP_LOGE(TAG, "Failed to receive JPEG chunk");
break;
}
if (chunk.data == nullptr)
{
saw_terminator = true;
break;
}
http->Write((const char *)chunk.data, chunk.len);
total_sent += chunk.len;
heap_caps_free(chunk.data);
}
encoder_thread_.join();
vQueueDelete(jpeg_queue);
if (!saw_terminator || total_sent == 0)
{
ESP_LOGE(TAG, "JPEG encoder failed or produced empty output");
throw std::runtime_error("Failed to encode image to JPEG");
}
{
std::string multipart_footer;
multipart_footer += "\r\n--" + boundary + "--\r\n";
http->Write(multipart_footer.c_str(), multipart_footer.size());
}
http->Write("", 0);
if (http->GetStatusCode() != 200)
{
ESP_LOGE(TAG, "Failed to upload photo, status code: %d", http->GetStatusCode());
throw std::runtime_error("Failed to upload photo");
}
std::string result = http->ReadAll();
http->Close();
size_t remain_stack_size = uxTaskGetStackHighWaterMark(nullptr);
ESP_LOGI(TAG, "Explain image size=%d bytes, compressed size=%d, remain stack size=%d, question=%s\n%s",
(int)frame_.len, (int)total_sent, (int)remain_stack_size, question.c_str(), result.c_str());
return result;
}
#endif // CONFIG_IDF_TARGET_ESP32S3 && CONFIG_XIAOZHI_USE_ESP_CAMERA

View File

@ -1,53 +0,0 @@
#pragma once
#include "sdkconfig.h"
// esp32s3_camera (使用 esp_camera 组件) 仅用于 ESP32-S3 且选择使用 esp_camera 时
#if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(CONFIG_XIAOZHI_USE_ESP_CAMERA)
#include <lvgl.h>
#include <thread>
#include <memory>
#include <vector>
#include <freertos/FreeRTOS.h>
#include <freertos/queue.h>
#include "camera.h"
#include "esp_camera.h"
struct JpegChunk
{
uint8_t *data;
size_t len;
};
class Esp32S3Camera : public Camera
{
private:
struct FrameBuffer
{
uint8_t *data = nullptr;
size_t len = 0;
uint16_t width = 0;
uint16_t height = 0;
pixformat_t format = PIXFORMAT_RGB565;
} frame_;
bool streaming_on_ = false;
std::string explain_url_;
std::string explain_token_;
std::thread encoder_thread_;
camera_fb_t *current_fb_ = nullptr;
public:
Esp32S3Camera(const camera_config_t &config);
~Esp32S3Camera();
virtual void SetExplainUrl(const std::string &url, const std::string &token) override;
virtual bool Capture() override;
virtual bool SetHMirror(bool enabled) override;
virtual bool SetVFlip(bool enabled) override;
virtual std::string Explain(const std::string &question) override;
};
#endif // CONFIG_IDF_TARGET_ESP32S3 && CONFIG_XIAOZHI_USE_ESP_CAMERA

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,53 @@
#pragma once
#include "sdkconfig.h"
#include <lvgl.h>
#include <thread>
#include <memory>
#include <vector>
#include <freertos/FreeRTOS.h>
#include <freertos/queue.h>
#include "camera.h"
#include "jpg/image_to_jpeg.h"
#include "esp_video_init.h"
struct JpegChunk {
uint8_t* data;
size_t len;
};
class EspVideo : public Camera {
private:
struct FrameBuffer {
uint8_t *data = nullptr;
size_t len = 0;
uint16_t width = 0;
uint16_t height = 0;
v4l2_pix_fmt_t format = 0;
} frame_;
v4l2_pix_fmt_t sensor_format_ = 0;
#ifdef CONFIG_XIAOZHI_ENABLE_ROTATE_CAMERA_IMAGE
uint16_t sensor_width_ = 0;
uint16_t sensor_height_ = 0;
#endif // CONFIG_XIAOZHI_ENABLE_ROTATE_CAMERA_IMAGE
int video_fd_ = -1;
bool streaming_on_ = false;
struct MmapBuffer { void *start = nullptr; size_t length = 0; };
std::vector<MmapBuffer> mmap_buffers_;
std::string explain_url_;
std::string explain_token_;
std::thread encoder_thread_;
public:
EspVideo(const esp_video_init_config_t& config);
~EspVideo();
virtual void SetExplainUrl(const std::string& url, const std::string& token);
virtual bool Capture();
// 翻转控制函数
virtual bool SetHMirror(bool enabled) override;
virtual bool SetVFlip(bool enabled) override;
virtual std::string Explain(const std::string& question);
};

View File

@ -6,7 +6,7 @@
#include "application.h" #include "application.h"
#include "button.h" #include "button.h"
#include "config.h" #include "config.h"
#include "esp32_camera.h" #include "esp_video.h"
#include "led/circular_strip.h" #include "led/circular_strip.h"
#include "assets/lang_config.h" #include "assets/lang_config.h"
@ -27,7 +27,7 @@ private:
LcdDisplay *display_; LcdDisplay *display_;
button_handle_t btn_a; button_handle_t btn_a;
button_handle_t btn_b; button_handle_t btn_b;
Esp32Camera* camera_; EspVideo* camera_;
button_driver_t* btn_a_driver_ = nullptr; button_driver_t* btn_a_driver_ = nullptr;
button_driver_t* btn_b_driver_ = nullptr; button_driver_t* btn_b_driver_ = nullptr;
@ -209,7 +209,7 @@ private:
.dvp = &dvp_config, .dvp = &dvp_config,
}; };
camera_ = new Esp32Camera(video_config); camera_ = new EspVideo(video_config);
} }
void InitializeIli9341Display() { void InitializeIli9341Display() {

View File

@ -4,7 +4,7 @@
#include "application.h" #include "application.h"
#include "button.h" #include "button.h"
#include "config.h" #include "config.h"
#include "esp32_camera.h" #include "esp_video.h"
#include "led/gpio_led.h" #include "led/gpio_led.h"
#include <esp_log.h> #include <esp_log.h>
@ -16,7 +16,7 @@
class DfrobotEsp32S3AiCam : public WifiBoard { class DfrobotEsp32S3AiCam : public WifiBoard {
private: private:
Button boot_button_; Button boot_button_;
Esp32Camera* camera_; EspVideo* camera_;
void InitializeButtons() { void InitializeButtons() {
boot_button_.OnClick([this]() { boot_button_.OnClick([this]() {
@ -70,7 +70,7 @@ class DfrobotEsp32S3AiCam : public WifiBoard {
.dvp = &dvp_config, .dvp = &dvp_config,
}; };
camera_ = new Esp32Camera(video_config); camera_ = new EspVideo(video_config);
camera_->SetVFlip(1); camera_->SetVFlip(1);
} }

View File

@ -6,7 +6,7 @@
#include "button.h" #include "button.h"
#include "config.h" #include "config.h"
#include "backlight.h" #include "backlight.h"
#include "esp32_camera.h" #include "esp_video.h"
#include <esp_log.h> #include <esp_log.h>
@ -390,7 +390,7 @@ private:
PwmBacklight* backlight_ = nullptr; PwmBacklight* backlight_ = nullptr;
esp_timer_handle_t touchpad_timer_; esp_timer_handle_t touchpad_timer_;
esp_lcd_touch_handle_t tp; // LCD touch handle esp_lcd_touch_handle_t tp; // LCD touch handle
Esp32Camera* camera_ = nullptr; EspVideo* camera_ = nullptr;
void InitializeI2c() void InitializeI2c()
{ {
@ -605,7 +605,7 @@ private:
.usb_uvc = &usb_uvc_config, .usb_uvc = &usb_uvc_config,
}; };
camera_ = new Esp32Camera(video_config); camera_ = new EspVideo(video_config);
} }
#endif // CONFIG_ESP_VIDEO_ENABLE_USB_UVC_VIDEO_DEVICE #endif // CONFIG_ESP_VIDEO_ENABLE_USB_UVC_VIDEO_DEVICE

View File

@ -10,7 +10,7 @@
#include "application.h" #include "application.h"
#include "button.h" #include "button.h"
#include "config.h" #include "config.h"
#include "esp32_camera.h" #include "esp_video.h"
#include <esp_log.h> #include <esp_log.h>
#include <inttypes.h> #include <inttypes.h>
@ -45,7 +45,7 @@ private:
Button boot_button_; Button boot_button_;
LcdDisplay *display_ = nullptr; LcdDisplay *display_ = nullptr;
esp_lcd_touch_handle_t tp_ = nullptr; esp_lcd_touch_handle_t tp_ = nullptr;
Esp32Camera* camera_ = nullptr; EspVideo* camera_ = nullptr;
void InitializeI2cBuses() void InitializeI2cBuses()
{ {
@ -115,7 +115,7 @@ private:
ESP_LOGE(TAG, "Failed to initialize BSP camera: %s", esp_err_to_name(ret)); ESP_LOGE(TAG, "Failed to initialize BSP camera: %s", esp_err_to_name(ret));
ESP_LOGI(TAG, "Attempting alternative camera initialization"); ESP_LOGI(TAG, "Attempting alternative camera initialization");
// Alternative: Direct Esp32Camera initialization if BSP fails // Alternative: Direct EspVideo initialization if BSP fails
// This provides more control over camera configuration // This provides more control over camera configuration
static esp_cam_ctlr_dvp_pin_config_t dvp_pin_config = { static esp_cam_ctlr_dvp_pin_config_t dvp_pin_config = {
.data_width = CAM_CTLR_DATA_WIDTH_8, .data_width = CAM_CTLR_DATA_WIDTH_8,
@ -154,7 +154,7 @@ private:
}; };
// Try to create camera with direct configuration // Try to create camera with direct configuration
camera_ = new Esp32Camera(video_config); camera_ = new EspVideo(video_config);
ESP_LOGI(TAG, "Camera initialized with direct configuration"); ESP_LOGI(TAG, "Camera initialized with direct configuration");
} else { } else {
ESP_LOGI(TAG, "Camera initialized successfully via BSP"); ESP_LOGI(TAG, "Camera initialized successfully via BSP");

View File

@ -5,7 +5,7 @@
#include "button.h" #include "button.h"
#include "led/single_led.h" #include "led/single_led.h"
#include "pin_config.h" #include "pin_config.h"
#include "esp32_camera.h" #include "esp_video.h"
#include "config.h" #include "config.h"
@ -27,7 +27,7 @@ private:
i2c_master_bus_handle_t i2c_bus_; i2c_master_bus_handle_t i2c_bus_;
Button boot_button_; Button boot_button_;
LcdDisplay* display_; LcdDisplay* display_;
Esp32Camera* camera_; EspVideo* camera_;
//add support ev board lcd //add support ev board lcd
esp_io_expander_handle_t expander = NULL; esp_io_expander_handle_t expander = NULL;
@ -218,7 +218,7 @@ private:
esp_video_init_config_t video_config = { esp_video_init_config_t video_config = {
.usb_uvc = &usb_uvc_config, .usb_uvc = &usb_uvc_config,
}; };
camera_ = new Esp32Camera(video_config); camera_ = new EspVideo(video_config);
} }
#endif // CONFIG_ESP_VIDEO_ENABLE_USB_UVC_VIDEO_DEVICE #endif // CONFIG_ESP_VIDEO_ENABLE_USB_UVC_VIDEO_DEVICE

View File

@ -5,7 +5,7 @@
#include "button.h" #include "button.h"
#include "led/single_led.h" #include "led/single_led.h"
#include "pin_config.h" #include "pin_config.h"
#include "esp32_camera.h" #include "esp_video.h"
#include "config.h" #include "config.h"
@ -25,7 +25,7 @@ private:
i2c_master_bus_handle_t codec_i2c_bus_; i2c_master_bus_handle_t codec_i2c_bus_;
Button boot_button_; Button boot_button_;
LcdDisplay* display_; LcdDisplay* display_;
Esp32Camera* camera_; EspVideo* camera_;
//add support ev board lcd //add support ev board lcd
esp_io_expander_handle_t expander = NULL; esp_io_expander_handle_t expander = NULL;
@ -188,7 +188,7 @@ private:
.usb_uvc = &usb_uvc_config, .usb_uvc = &usb_uvc_config,
}; };
camera_ = new Esp32Camera(video_config); camera_ = new EspVideo(video_config);
} }
#endif // CONFIG_ESP_VIDEO_ENABLE_USB_UVC_VIDEO_DEVICE #endif // CONFIG_ESP_VIDEO_ENABLE_USB_UVC_VIDEO_DEVICE

View File

@ -14,7 +14,7 @@
#include <driver/uart.h> #include <driver/uart.h>
#include <cstring> #include <cstring>
#include "esp32_camera.h" #include "esp_video.h"
#define TAG "esp_sparkbot" #define TAG "esp_sparkbot"
@ -45,7 +45,7 @@ private:
i2c_master_bus_handle_t i2c_bus_; i2c_master_bus_handle_t i2c_bus_;
Button boot_button_; Button boot_button_;
Display* display_; Display* display_;
Esp32Camera* camera_; EspVideo* camera_;
light_mode_t light_mode_ = LIGHT_MODE_ALWAYS_ON; light_mode_t light_mode_ = LIGHT_MODE_ALWAYS_ON;
void InitializeI2c() { void InitializeI2c() {
@ -162,7 +162,7 @@ private:
.dvp = &dvp_config, .dvp = &dvp_config,
}; };
camera_ = new Esp32Camera(video_config); camera_ = new EspVideo(video_config);
Settings settings("sparkbot", false); Settings settings("sparkbot", false);
// 考虑到部分复刻使用了不可动摄像头的设计,默认启用翻转 // 考虑到部分复刻使用了不可动摄像头的设计,默认启用翻转

View File

@ -24,7 +24,7 @@
#include <esp_lcd_touch_ft5x06.h> #include <esp_lcd_touch_ft5x06.h>
#include <esp_lvgl_port.h> #include <esp_lvgl_port.h>
#include "esp32_camera.h" #include "esp_video.h"
#define TAG "waveshare_lcd_3_5" #define TAG "waveshare_lcd_3_5"
@ -106,7 +106,7 @@ private:
esp_io_expander_handle_t io_expander = NULL; esp_io_expander_handle_t io_expander = NULL;
LcdDisplay* display_; LcdDisplay* display_;
PowerSaveTimer* power_save_timer_; PowerSaveTimer* power_save_timer_;
Esp32Camera* camera_; EspVideo* camera_;
void InitializePowerSaveTimer() { void InitializePowerSaveTimer() {
power_save_timer_ = new PowerSaveTimer(-1, 60, 300); power_save_timer_ = new PowerSaveTimer(-1, 60, 300);
@ -209,7 +209,7 @@ private:
.dvp = &dvp_config, .dvp = &dvp_config,
}; };
camera_ = new Esp32Camera(video_config); camera_ = new EspVideo(video_config);
} }

View File

@ -4,14 +4,6 @@
{ {
"name": "esp32s3-korvo2-v3", "name": "esp32s3-korvo2-v3",
"sdkconfig_append": [ "sdkconfig_append": [
"CONFIG_XIAOZHI_USE_ESP_CAMERA=y",
"CONFIG_CAMERA_OV2640=y",
"CONFIG_CAMERA_OV3660=y",
"CONFIG_CAMERA_OV3660_AUTO_DETECT_DVP_INTERFACE_SENSOR=y",
"CONFIG_CAMERA_OV3660_DVP_RGB565_240X240_24FPS=y",
"CONFIG_CAMERA_OV2640_AUTO_DETECT_DVP_INTERFACE_SENSOR=y",
"CONFIG_CAMERA_OV2640_DVP_RGB565_240X240_25FPS=y",
"CONFIG_XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP=y"
] ]
} }
] ]

View File

@ -13,7 +13,7 @@
#include <esp_lcd_ili9341.h> #include <esp_lcd_ili9341.h>
#include <driver/i2c_master.h> #include <driver/i2c_master.h>
#include <driver/spi_common.h> #include <driver/spi_common.h>
#include "esp32s3_camera.h" #include "esp32_camera.h"
#include "power_manager.h" #include "power_manager.h"
#include "power_save_timer.h" #include "power_save_timer.h"
@ -60,7 +60,7 @@ private:
i2c_master_bus_handle_t i2c_bus_; i2c_master_bus_handle_t i2c_bus_;
LcdDisplay* display_; LcdDisplay* display_;
esp_io_expander_handle_t io_expander_ = NULL; esp_io_expander_handle_t io_expander_ = NULL;
Esp32S3Camera* camera_; Esp32Camera* camera_;
PowerSaveTimer* power_save_timer_; PowerSaveTimer* power_save_timer_;
PowerManager* power_manager_; PowerManager* power_manager_;
void InitializePowerManager() { void InitializePowerManager() {
@ -385,7 +385,7 @@ private:
.sccb_i2c_port = (i2c_port_t)1, .sccb_i2c_port = (i2c_port_t)1,
}; };
camera_ = new Esp32S3Camera(camera_config); camera_ = new Esp32Camera(camera_config);
if(camera_ != nullptr) if(camera_ != nullptr)
{ {
camera_->SetVFlip(true); camera_->SetVFlip(true);

View File

@ -12,7 +12,7 @@
#include <esp_log.h> #include <esp_log.h>
#include <esp_lcd_panel_vendor.h> #include <esp_lcd_panel_vendor.h>
#include <driver/i2c_master.h> #include <driver/i2c_master.h>
#include "esp32s3_camera.h" #include "esp32_camera.h"
#define TAG "kevin-sp-v3" #define TAG "kevin-sp-v3"
@ -22,7 +22,7 @@ private:
i2c_master_bus_handle_t display_i2c_bus_; i2c_master_bus_handle_t display_i2c_bus_;
Button boot_button_; Button boot_button_;
LcdDisplay* display_; LcdDisplay* display_;
Esp32S3Camera* camera_; Esp32Camera* camera_;
void InitializeSpi() { void InitializeSpi() {
spi_bus_config_t buscfg = {}; spi_bus_config_t buscfg = {};
@ -116,7 +116,7 @@ private:
.sccb_i2c_port = (i2c_port_t)1, .sccb_i2c_port = (i2c_port_t)1,
}; };
camera_ = new Esp32S3Camera(camera_config); camera_ = new Esp32Camera(camera_config);
} }
public: public:

View File

@ -4,14 +4,6 @@
{ {
"name": "kevin-sp-v4-dev", "name": "kevin-sp-v4-dev",
"sdkconfig_append": [ "sdkconfig_append": [
"CONFIG_XIAOZHI_USE_ESP_CAMERA=y",
"CONFIG_CAMERA_OV2640=y",
"CONFIG_CAMERA_OV3660=y",
"CONFIG_CAMERA_OV3660_AUTO_DETECT_DVP_INTERFACE_SENSOR=y",
"CONFIG_CAMERA_OV3660_DVP_RGB565_240X240_24FPS=y",
"CONFIG_CAMERA_OV2640_AUTO_DETECT_DVP_INTERFACE_SENSOR=y",
"CONFIG_CAMERA_OV2640_DVP_RGB565_240X240_25FPS=y",
"CONFIG_XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP=y"
] ]
} }
] ]

View File

@ -10,7 +10,7 @@
#include <esp_log.h> #include <esp_log.h>
#include <esp_lcd_panel_vendor.h> #include <esp_lcd_panel_vendor.h>
#include <driver/i2c_master.h> #include <driver/i2c_master.h>
#include "esp32s3_camera.h" #include "esp32_camera.h"
#define TAG "kevin-sp-v4" #define TAG "kevin-sp-v4"
@ -19,7 +19,7 @@ private:
Button boot_button_; Button boot_button_;
LcdDisplay* display_; LcdDisplay* display_;
i2c_master_bus_handle_t i2c_bus_; i2c_master_bus_handle_t i2c_bus_;
Esp32S3Camera* camera_; Esp32Camera* camera_;
void InitializeCodecI2c() { void InitializeCodecI2c() {
// Initialize I2C peripheral // Initialize I2C peripheral
@ -130,7 +130,7 @@ private:
.sccb_i2c_port = (i2c_port_t)1, .sccb_i2c_port = (i2c_port_t)1,
}; };
camera_ = new Esp32S3Camera(camera_config); camera_ = new Esp32Camera(camera_config);
} }
public: public:

View File

@ -4,10 +4,7 @@
{ {
"name": "lichuang-dev", "name": "lichuang-dev",
"sdkconfig_append": [ "sdkconfig_append": [
"CONFIG_USE_DEVICE_AEC=y", "CONFIG_USE_DEVICE_AEC=y"
"CONFIG_CAMERA_GC0308=y",
"CONFIG_CAMERA_GC0308_AUTO_DETECT_DVP_INTERFACE_SENSOR=y",
"CONFIG_CAMERA_GC0308_DVP_YUV422_640X480_16FPS=y"
] ]
} }
] ]

View File

@ -208,43 +208,35 @@ private:
// Open camera power // Open camera power
pca9557_->SetOutputState(2, 0); pca9557_->SetOutputState(2, 0);
static esp_cam_ctlr_dvp_pin_config_t dvp_pin_config = { camera_config_t config = {};
.data_width = CAM_CTLR_DATA_WIDTH_8, config.ledc_channel = LEDC_CHANNEL_2;
.data_io = { config.ledc_timer = LEDC_TIMER_2;
[0] = CAMERA_PIN_D0, config.pin_d0 = CAMERA_PIN_D0;
[1] = CAMERA_PIN_D1, config.pin_d1 = CAMERA_PIN_D1;
[2] = CAMERA_PIN_D2, config.pin_d2 = CAMERA_PIN_D2;
[3] = CAMERA_PIN_D3, config.pin_d3 = CAMERA_PIN_D3;
[4] = CAMERA_PIN_D4, config.pin_d4 = CAMERA_PIN_D4;
[5] = CAMERA_PIN_D5, config.pin_d5 = CAMERA_PIN_D5;
[6] = CAMERA_PIN_D6, config.pin_d6 = CAMERA_PIN_D6;
[7] = CAMERA_PIN_D7, config.pin_d7 = CAMERA_PIN_D7;
}, config.pin_xclk = CAMERA_PIN_XCLK;
.vsync_io = CAMERA_PIN_VSYNC, config.pin_pclk = CAMERA_PIN_PCLK;
.de_io = CAMERA_PIN_HREF, config.pin_vsync = CAMERA_PIN_VSYNC;
.pclk_io = CAMERA_PIN_PCLK, config.pin_href = CAMERA_PIN_HREF;
.xclk_io = CAMERA_PIN_XCLK, config.pin_sccb_sda = -1;
}; config.pin_sccb_scl = CAMERA_PIN_SIOC;
config.sccb_i2c_port = 1;
config.pin_pwdn = CAMERA_PIN_PWDN;
config.pin_reset = CAMERA_PIN_RESET;
config.xclk_freq_hz = XCLK_FREQ_HZ;
config.pixel_format = PIXFORMAT_RGB565;
config.frame_size = FRAMESIZE_VGA;
config.jpeg_quality = 12;
config.fb_count = 1;
config.fb_location = CAMERA_FB_IN_PSRAM;
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
esp_video_init_sccb_config_t sccb_config = { camera_ = new Esp32Camera(config);
.init_sccb = false,
.i2c_handle = i2c_bus_,
.freq = 100000,
};
esp_video_init_dvp_config_t dvp_config = {
.sccb_config = sccb_config,
.reset_pin = CAMERA_PIN_RESET,
.pwdn_pin = CAMERA_PIN_PWDN,
.dvp_pin = dvp_pin_config,
.xclk_freq = XCLK_FREQ_HZ,
};
esp_video_init_config_t video_config = {
.dvp = &dvp_config,
};
camera_ = new Esp32Camera(video_config);
} }
void InitializeTools() { void InitializeTools() {

View File

@ -8,7 +8,7 @@
#include "i2c_device.h" #include "i2c_device.h"
#include "sy6970.h" #include "sy6970.h"
#include "pin_config.h" #include "pin_config.h"
#include "esp32_camera.h" #include "esp_video.h"
#include "ir_filter_controller.h" #include "ir_filter_controller.h"
#include <esp_log.h> #include <esp_log.h>
@ -73,7 +73,7 @@ private:
Button boot_button_; Button boot_button_;
Button key1_button_; Button key1_button_;
PowerSaveTimer* power_save_timer_; PowerSaveTimer* power_save_timer_;
Esp32Camera* camera_; EspVideo* camera_;
void InitializePowerSaveTimer() { void InitializePowerSaveTimer() {
power_save_timer_ = new PowerSaveTimer(-1, 60, -1); power_save_timer_ = new PowerSaveTimer(-1, 60, -1);
@ -270,7 +270,7 @@ private:
.dvp = &dvp_config, .dvp = &dvp_config,
}; };
camera_ = new Esp32Camera(video_config); camera_ = new EspVideo(video_config);
camera_->SetVFlip(1); camera_->SetVFlip(1);
camera_->SetHMirror(1); camera_->SetHMirror(1);
} }

View File

@ -13,7 +13,7 @@
#include <esp_lcd_panel_ops.h> #include <esp_lcd_panel_ops.h>
#include <esp_lcd_ili9341.h> #include <esp_lcd_ili9341.h>
#include <esp_timer.h> #include <esp_timer.h>
#include "esp32_camera.h" #include "esp_video.h"
#define TAG "M5StackCoreS3Board" #define TAG "M5StackCoreS3Board"
@ -123,7 +123,7 @@ private:
Aw9523* aw9523_; Aw9523* aw9523_;
Ft6336* ft6336_; Ft6336* ft6336_;
LcdDisplay* display_; LcdDisplay* display_;
Esp32Camera* camera_; EspVideo* camera_;
esp_timer_handle_t touchpad_timer_; esp_timer_handle_t touchpad_timer_;
PowerSaveTimer* power_save_timer_; PowerSaveTimer* power_save_timer_;
@ -326,7 +326,7 @@ private:
.dvp = &dvp_config, .dvp = &dvp_config,
}; };
camera_ = new Esp32Camera(video_config); camera_ = new EspVideo(video_config);
camera_->SetHMirror(false); camera_->SetHMirror(false);
} }

View File

@ -7,7 +7,7 @@
#include "application.h" #include "application.h"
#include "button.h" #include "button.h"
#include "config.h" #include "config.h"
#include "esp32_camera.h" #include "esp_video.h"
#include "esp_video_init.h" #include "esp_video_init.h"
#include "esp_cam_sensor_xclk.h" #include "esp_cam_sensor_xclk.h"
@ -89,7 +89,7 @@ private:
i2c_master_bus_handle_t i2c_bus_; i2c_master_bus_handle_t i2c_bus_;
Button boot_button_; Button boot_button_;
LcdDisplay* display_; LcdDisplay* display_;
Esp32Camera* camera_ = nullptr; EspVideo* camera_ = nullptr;
Pi4ioe1* pi4ioe1_; Pi4ioe1* pi4ioe1_;
Pi4ioe2* pi4ioe2_; Pi4ioe2* pi4ioe2_;
esp_lcd_touch_handle_t touch_ = nullptr; esp_lcd_touch_handle_t touch_ = nullptr;
@ -463,7 +463,7 @@ private:
.csi = &csi_config, .csi = &csi_config,
}; };
camera_ = new Esp32Camera(video_config); camera_ = new EspVideo(video_config);
} }
public: public:

View File

@ -18,7 +18,7 @@
#include "power_manager.h" #include "power_manager.h"
#include "system_reset.h" #include "system_reset.h"
#include "wifi_board.h" #include "wifi_board.h"
#include "esp32_camera.h" #include "esp_video.h"
#include "websocket_control_server.h" #include "websocket_control_server.h"
#define TAG "OttoRobot" #define TAG "OttoRobot"
@ -34,7 +34,7 @@ private:
HardwareConfig hw_config_; HardwareConfig hw_config_;
AudioCodec* audio_codec_; AudioCodec* audio_codec_;
i2c_master_bus_handle_t i2c_bus_; i2c_master_bus_handle_t i2c_bus_;
Esp32Camera *camera_; EspVideo *camera_;
bool has_camera_; bool has_camera_;
bool DetectHardwareVersion() { bool DetectHardwareVersion() {
@ -247,7 +247,7 @@ private:
.dvp = &dvp_config, .dvp = &dvp_config,
}; };
camera_ = new Esp32Camera(video_config); camera_ = new EspVideo(video_config);
camera_->SetVFlip(true); camera_->SetVFlip(true);
return true; return true;
} catch (...) { } catch (...) {

View File

@ -6,7 +6,7 @@
#include "button.h" #include "button.h"
#include "config.h" #include "config.h"
#include "esp32_camera.h" #include "esp_video.h"
#include "esp_video_init.h" #include "esp_video_init.h"
#include "esp_cam_sensor_xclk.h" #include "esp_cam_sensor_xclk.h"
@ -69,7 +69,7 @@ private:
i2c_master_bus_handle_t codec_i2c_bus_; i2c_master_bus_handle_t codec_i2c_bus_;
Button boot_button_; Button boot_button_;
LcdDisplay *display__; LcdDisplay *display__;
Esp32Camera* camera_ = nullptr; EspVideo* camera_ = nullptr;
CustomBacklight *backlight_; CustomBacklight *backlight_;
void InitializeCodecI2c() { void InitializeCodecI2c() {
@ -215,7 +215,7 @@ private:
.csi = &base_csi_config, .csi = &base_csi_config,
}; };
camera_ = new Esp32Camera(cam_config); camera_ = new EspVideo(cam_config);
} }
void InitializeButtons() { void InitializeButtons() {
boot_button_.OnClick([this]() { boot_button_.OnClick([this]() {

View File

@ -6,7 +6,7 @@
#include "button.h" #include "button.h"
#include "config.h" #include "config.h"
#include "esp32_camera.h" #include "esp_video.h"
#include "esp_video_init.h" #include "esp_video_init.h"
#include "esp_cam_sensor_xclk.h" #include "esp_cam_sensor_xclk.h"
@ -27,7 +27,7 @@ private:
i2c_master_bus_handle_t i2c_bus_; i2c_master_bus_handle_t i2c_bus_;
Button boot_button_; Button boot_button_;
LcdDisplay *display_; LcdDisplay *display_;
Esp32Camera* camera_ = nullptr; EspVideo* camera_ = nullptr;
void InitializeCodecI2c() { void InitializeCodecI2c() {
// Initialize I2C peripheral // Initialize I2C peripheral
@ -168,7 +168,7 @@ private:
.csi = &base_csi_config, .csi = &base_csi_config,
}; };
camera_ = new Esp32Camera(cam_config); camera_ = new EspVideo(cam_config);
} }
void InitializeButtons() { void InitializeButtons() {
boot_button_.OnClick([this]() { boot_button_.OnClick([this]() {

View File

@ -6,7 +6,7 @@
#include "button.h" #include "button.h"
#include "config.h" #include "config.h"
#include "esp32_camera.h" #include "esp_video.h"
#include "esp_video_init.h" #include "esp_video_init.h"
#include "esp_cam_sensor_xclk.h" #include "esp_cam_sensor_xclk.h"
@ -27,7 +27,7 @@ private:
i2c_master_bus_handle_t i2c_bus_; i2c_master_bus_handle_t i2c_bus_;
Button boot_button_; Button boot_button_;
LcdDisplay *display_; LcdDisplay *display_;
Esp32Camera* camera_ = nullptr; EspVideo* camera_ = nullptr;
esp_err_t i2c_device_probe(uint8_t addr) { esp_err_t i2c_device_probe(uint8_t addr) {
return i2c_master_probe(i2c_bus_, addr, 100); return i2c_master_probe(i2c_bus_, addr, 100);
@ -189,7 +189,7 @@ private:
.csi = &base_csi_config, .csi = &base_csi_config,
}; };
camera_ = new Esp32Camera(cam_config); camera_ = new EspVideo(cam_config);
} }
void InitializeButtons() { void InitializeButtons() {
boot_button_.OnClick([this]() { boot_button_.OnClick([this]() {

View File

@ -5,7 +5,7 @@
// #include "display/no_display.h" // #include "display/no_display.h"
#include "button.h" #include "button.h"
#include "esp32_camera.h" #include "esp_video.h"
#include "esp_video_init.h" #include "esp_video_init.h"
#include "esp_cam_sensor_xclk.h" #include "esp_cam_sensor_xclk.h"
@ -27,7 +27,7 @@ private:
i2c_master_bus_handle_t i2c_bus_; i2c_master_bus_handle_t i2c_bus_;
Button boot_button_; Button boot_button_;
LcdDisplay *display_; LcdDisplay *display_;
Esp32Camera* camera_ = nullptr; EspVideo* camera_ = nullptr;
void InitializeCodecI2c() { void InitializeCodecI2c() {
// Initialize I2C peripheral // Initialize I2C peripheral
@ -170,7 +170,7 @@ private:
.csi = &base_csi_config, .csi = &base_csi_config,
}; };
camera_ = new Esp32Camera(cam_config); camera_ = new EspVideo(cam_config);
} }
void InitializeButtons() { void InitializeButtons() {
boot_button_.OnClick([this]() { boot_button_.OnClick([this]() {

View File

@ -15,7 +15,7 @@
#include <esp_lcd_st77916.h> #include <esp_lcd_st77916.h>
#include <esp_timer.h> #include <esp_timer.h>
#include "esp_io_expander_tca95xx_16bit.h" #include "esp_io_expander_tca95xx_16bit.h"
#include "esp32_camera.h" #include "esp_video.h"
#include "led/circular_strip.h" #include "led/circular_strip.h"
#include "esp_lcd_jd9853.h" #include "esp_lcd_jd9853.h"
@ -31,7 +31,7 @@ private:
i2c_master_bus_handle_t i2c_bus_; i2c_master_bus_handle_t i2c_bus_;
esp_io_expander_handle_t io_expander = NULL; esp_io_expander_handle_t io_expander = NULL;
LcdDisplay* display_; LcdDisplay* display_;
Esp32Camera* camera_; EspVideo* camera_;
void InitializeI2c() { void InitializeI2c() {
// Initialize I2C peripheral // Initialize I2C peripheral
@ -192,7 +192,7 @@ private:
.dvp = &dvp_config, .dvp = &dvp_config,
}; };
camera_ = new Esp32Camera(video_config); camera_ = new EspVideo(video_config);
} }
public: public:

View File

@ -28,7 +28,7 @@
#include <esp_lvgl_port.h> #include <esp_lvgl_port.h>
#include <lvgl.h> #include <lvgl.h>
#include "esp32_camera.h" #include "esp_video.h"
#define TAG "waveshare_lcd_3_5b" #define TAG "waveshare_lcd_3_5b"
@ -108,7 +108,7 @@ private:
esp_io_expander_handle_t io_expander = NULL; esp_io_expander_handle_t io_expander = NULL;
LcdDisplay* display_; LcdDisplay* display_;
PowerSaveTimer* power_save_timer_; PowerSaveTimer* power_save_timer_;
Esp32Camera* camera_; EspVideo* camera_;
void InitializePowerSaveTimer() { void InitializePowerSaveTimer() {
power_save_timer_ = new PowerSaveTimer(-1, 60, 300); power_save_timer_ = new PowerSaveTimer(-1, 60, 300);
@ -212,7 +212,7 @@ private:
.dvp = &dvp_config, .dvp = &dvp_config,
}; };
camera_ = new Esp32Camera(video_config); camera_ = new EspVideo(video_config);
} }

View File

@ -7,7 +7,7 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#if defined(CONFIG_IDF_TARGET_ESP32P4) #if defined(CONFIG_IDF_TARGET_ESP32P4) || defined(CONFIG_IDF_TARGET_ESP32S3)
// ESP32-P4 使用 esp_video 组件提供的 V4L2 头文件 // ESP32-P4 使用 esp_video 组件提供的 V4L2 头文件
#include <linux/videodev2.h> #include <linux/videodev2.h>
#else #else

View File

@ -100,7 +100,7 @@ void McpServer::AddCommonTools() {
auto camera = board.GetCamera(); auto camera = board.GetCamera();
if (camera) { if (camera) {
AddTool("self.camera.take_photo", AddTool("self.camera.take_photo",
"Take a photo and explain it. Use this tool after the user asks you to see something.\n" "Always remember you have a camera. If the user asks you to see something, use this tool to take a photo and then explain it.\n"
"Args:\n" "Args:\n"
" `question`: The question that you want to ask about the photo.\n" " `question`: The question that you want to ask about the photo.\n"
"Return:\n" "Return:\n"