Skip to content

Commit 60ad1c5

Browse files
authored
Refactor: Use esp_video component (#1245)
* refactor: migrate camera module to esp-video library * refactor: migrate boards to esp-video API (1/2) * refactor: migrate boards to esp-video API (2/2) * fix: use ESP-IDF 5.5 * refactor: migrate the JPEG encoder to `esp_new_jpeg` * feat: add YUV422 support * feat: improve pixelformat and device selection process * feat: use ESP32-P4 Hardware JPEG Encoder
1 parent 4854bda commit 60ad1c5

File tree

39 files changed

+1719
-1767
lines changed

39 files changed

+1719
-1767
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ jobs:
9292
include: ${{ fromJson(needs.prepare.outputs.variants) }}
9393
runs-on: ubuntu-latest
9494
container:
95-
image: espressif/idf:release-v5.4
95+
image: espressif/idf:release-v5.5
9696
steps:
9797
- name: Checkout
9898
uses: actions/checkout@v4

main/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ set(SOURCES "audio/audio_codec.cc"
2424
"display/lvgl_display/gif/lvgl_gif.cc"
2525
"display/lvgl_display/gif/gifdec.c"
2626
"display/lvgl_display/jpg/image_to_jpeg.cpp"
27-
"display/lvgl_display/jpg/jpeg_encoder.cpp"
2827
"protocols/protocol.cc"
2928
"protocols/mqtt_protocol.cc"
3029
"protocols/websocket_protocol.cc"
@@ -594,6 +593,8 @@ if(CONFIG_IDF_TARGET_ESP32)
594593
"audio/codecs/es8388_audio_codec.cc"
595594
"audio/codecs/es8389_audio_codec.cc"
596595
"led/gpio_led.cc"
596+
"${CMAKE_CURRENT_SOURCE_DIR}/boards/common/esp32_camera.cc"
597+
"display/lvgl_display/jpg/image_to_jpeg.cpp"
597598
)
598599
endif()
599600

main/Kconfig.projbuild

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,38 @@ config RECEIVE_CUSTOM_MESSAGE
635635
help
636636
Enable custom message reception, allow the device to receive custom messages from the server (preferably through the MQTT protocol)
637637

638+
menu "Camera Configuration"
639+
depends on !IDF_TARGET_ESP32
640+
641+
config XIAOZHI_ENABLE_HARDWARE_JPEG_ENCODER
642+
bool "Enable Hardware JPEG Encoder"
643+
default y
644+
depends on SOC_JPEG_ENCODE_SUPPORTED
645+
help
646+
Use hardware JPEG encoder on ESP32-P4 to encode image to JPEG.
647+
See https://docs.espressif.com/projects/esp-idf/en/stable/esp32p4/api-reference/peripherals/jpeg.html for more details.
648+
649+
config XIAOZHI_ENABLE_CAMERA_DEBUG_MODE
650+
bool "Enable Camera Debug Mode"
651+
default n
652+
help
653+
Enable camera debug mode, print camera debug information to the console.
654+
Only works on boards that support camera.
655+
656+
config XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP
657+
bool "Enable software camera buffer endianness swapping (USE WITH CAUTION)"
658+
default n
659+
depends on !CAMERA_SENSOR_SWAP_PIXEL_BYTE_ORDER
660+
help
661+
This option treats the camera buffer as a uint16_t[] array and performs byte-swapping (endianness conversion) on each element.
662+
663+
Should only be modified by development board integration engineers.
664+
665+
**Incorrect usage may result in incorrect image colors!**
666+
667+
ATTENTION: If the option CAMERA_SENSOR_SWAP_PIXEL_BYTE_ORDER is available for your sensor, please use that instead.
668+
endmenu
669+
638670
menu "TAIJIPAI_S3_CONFIG"
639671
depends on BOARD_TYPE_ESP32S3_Taiji_Pi
640672
choice I2S_TYPE_TAIJIPI_S3

main/boards/atk-dnesp32s3/atk_dnesp32s3.cc

Lines changed: 41 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -133,58 +133,53 @@ class atk_dnesp32s3 : public WifiBoard {
133133
// 初始化摄像头:ov2640;
134134
// 根据正点原子官方示例参数
135135
void InitializeCamera() {
136-
137136
xl9555_->SetOutputState(OV_PWDN_IO, 0); // PWDN=低 (上电)
138137
xl9555_->SetOutputState(OV_RESET_IO, 0); // 确保复位
139138
vTaskDelay(pdMS_TO_TICKS(50)); // 延长复位保持时间
140139
xl9555_->SetOutputState(OV_RESET_IO, 1); // 释放复位
141140
vTaskDelay(pdMS_TO_TICKS(50)); // 延长 50ms
142141

143-
camera_config_t config = {};
144-
145-
config.pin_pwdn = CAM_PIN_PWDN; // 实际由 XL9555 控制
146-
config.pin_reset = CAM_PIN_RESET;// 实际由 XL9555 控制
147-
config.pin_xclk = CAM_PIN_XCLK;
148-
config.pin_sccb_sda = CAM_PIN_SIOD;
149-
config.pin_sccb_scl = CAM_PIN_SIOC;
150-
151-
config.pin_d7 = CAM_PIN_D7;
152-
config.pin_d6 = CAM_PIN_D6;
153-
config.pin_d5 = CAM_PIN_D5;
154-
config.pin_d4 = CAM_PIN_D4;
155-
config.pin_d3 = CAM_PIN_D3;
156-
config.pin_d2 = CAM_PIN_D2;
157-
config.pin_d1 = CAM_PIN_D1;
158-
config.pin_d0 = CAM_PIN_D0;
159-
config.pin_vsync = CAM_PIN_VSYNC;
160-
config.pin_href = CAM_PIN_HREF;
161-
config.pin_pclk = CAM_PIN_PCLK;
162-
163-
/* XCLK 20MHz or 10MHz for OV2640 double FPS (Experimental) */
164-
config.xclk_freq_hz = 24000000;
165-
config.ledc_timer = LEDC_TIMER_0;
166-
config.ledc_channel = LEDC_CHANNEL_0;
167-
168-
config.pixel_format = PIXFORMAT_RGB565; /* YUV422,GRAYSCALE,RGB565,JPEG */
169-
config.frame_size = FRAMESIZE_QVGA; /* QQVGA-UXGA, For ESP32, do not use sizes above QVGA when not JPEG. The performance of the ESP32-S series has improved a lot, but JPEG mode always gives better frame rates */
170-
171-
config.jpeg_quality = 12; /* 0-63, for OV series camera sensors, lower number means higher quality */
172-
config.fb_count = 2; /* When jpeg mode is used, if fb_count more than one, the driver will work in continuous mode */
173-
config.fb_location = CAMERA_FB_IN_PSRAM;
174-
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
175-
176-
esp_err_t err = esp_camera_init(&config); // 测试相机是否存在
177-
if (err != ESP_OK) {
178-
ESP_LOGE(TAG, "Camera is not plugged in or not supported, error: %s", esp_err_to_name(err));
179-
// 如果摄像头初始化失败,设置 camera_ 为 nullptr
180-
camera_ = nullptr;
181-
return;
182-
}else
183-
{
184-
esp_camera_deinit();// 释放之前的摄像头资源,为正确初始化做准备
185-
camera_ = new Esp32Camera(config);
186-
}
187-
142+
static esp_cam_ctlr_dvp_pin_config_t dvp_pin_config = {
143+
.data_width = CAM_CTLR_DATA_WIDTH_8,
144+
.data_io = {
145+
[0] = CAM_PIN_D0,
146+
[1] = CAM_PIN_D1,
147+
[2] = CAM_PIN_D2,
148+
[3] = CAM_PIN_D3,
149+
[4] = CAM_PIN_D4,
150+
[5] = CAM_PIN_D5,
151+
[6] = CAM_PIN_D6,
152+
[7] = CAM_PIN_D7,
153+
},
154+
.vsync_io = CAM_PIN_VSYNC,
155+
.de_io = CAM_PIN_HREF,
156+
.pclk_io = CAM_PIN_PCLK,
157+
.xclk_io = CAM_PIN_XCLK,
158+
};
159+
160+
esp_video_init_sccb_config_t sccb_config = {
161+
.init_sccb = true,
162+
.i2c_config = {
163+
.port = 1,
164+
.scl_pin = CAM_PIN_SIOC,
165+
.sda_pin = CAM_PIN_SIOD,
166+
},
167+
.freq = 100000,
168+
};
169+
170+
esp_video_init_dvp_config_t dvp_config = {
171+
.sccb_config = sccb_config,
172+
.reset_pin = CAM_PIN_RESET, // 实际由 XL9555 控制
173+
.pwdn_pin = CAM_PIN_PWDN, // 实际由 XL9555 控制
174+
.dvp_pin = dvp_pin_config,
175+
.xclk_freq = 24000000,
176+
};
177+
178+
esp_video_init_config_t video_config = {
179+
.dvp = &dvp_config,
180+
};
181+
182+
camera_ = new Esp32Camera(video_config);
188183
}
189184

190185
public:

main/boards/atoms3r-cam-m12-echo-base/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ AtomS3R CAM、AtomS3R M12 是 M5Stack 推出的基于 ESP32-S3-PICO-1-N8R8 的
1414

1515
两款开发版均**不带屏幕、不带额外按键**,需要使用语音唤醒。必要时,需要使用 `idf.py monitor` 查看 log 以确定运行状态。
1616

17+
> ![NOTE]
18+
>
19+
> 自版本 [待定] 起,由于依赖库不支持 OV3660 传感器,AtomS3R M12 无法使用摄像头识别功能。
20+
>
21+
> AtomS3R CAM 不受影响;使用旧版本小智固件的 AtomS3R M12 不受影响。
22+
1723
## 配置、编译命令
1824

1925
**配置编译目标为 ESP32S3**

main/boards/atoms3r-cam-m12-echo-base/atoms3r_cam_m12_echo_base.cc

Lines changed: 43 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -123,36 +123,51 @@ class AtomS3rCamM12EchoBaseBoard : public WifiBoard {
123123

124124
ESP_LOGI(TAG, "Camera Power Enabled");
125125

126-
vTaskDelay(pdMS_TO_TICKS(300));
126+
vTaskDelay(pdMS_TO_TICKS(1000));
127127
}
128128

129-
void InitializeCamera() {
130-
camera_config_t config = {};
131-
config.pin_d0 = CAMERA_PIN_D0;
132-
config.pin_d1 = CAMERA_PIN_D1;
133-
config.pin_d2 = CAMERA_PIN_D2;
134-
config.pin_d3 = CAMERA_PIN_D3;
135-
config.pin_d4 = CAMERA_PIN_D4;
136-
config.pin_d5 = CAMERA_PIN_D5;
137-
config.pin_d6 = CAMERA_PIN_D6;
138-
config.pin_d7 = CAMERA_PIN_D7;
139-
config.pin_xclk = CAMERA_PIN_XCLK;
140-
config.pin_pclk = CAMERA_PIN_PCLK;
141-
config.pin_vsync = CAMERA_PIN_VSYNC;
142-
config.pin_href = CAMERA_PIN_HREF;
143-
config.pin_sccb_sda = CAMERA_PIN_SIOD;
144-
config.pin_sccb_scl = CAMERA_PIN_SIOC;
145-
config.sccb_i2c_port = 1;
146-
config.pin_pwdn = CAMERA_PIN_PWDN;
147-
config.pin_reset = CAMERA_PIN_RESET;
148-
config.xclk_freq_hz = XCLK_FREQ_HZ;
149-
config.pixel_format = PIXFORMAT_RGB565;
150-
config.frame_size = FRAMESIZE_QVGA;
151-
config.jpeg_quality = 12;
152-
config.fb_count = 1;
153-
config.fb_location = CAMERA_FB_IN_PSRAM;
154-
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
155-
camera_ = new Esp32Camera(config);
129+
void InitializeCamera() {
130+
static esp_cam_ctlr_dvp_pin_config_t dvp_pin_config = {
131+
.data_width = CAM_CTLR_DATA_WIDTH_8,
132+
.data_io = {
133+
[0] = CAMERA_PIN_D0,
134+
[1] = CAMERA_PIN_D1,
135+
[2] = CAMERA_PIN_D2,
136+
[3] = CAMERA_PIN_D3,
137+
[4] = CAMERA_PIN_D4,
138+
[5] = CAMERA_PIN_D5,
139+
[6] = CAMERA_PIN_D6,
140+
[7] = CAMERA_PIN_D7,
141+
},
142+
.vsync_io = CAMERA_PIN_VSYNC,
143+
.de_io = CAMERA_PIN_HREF,
144+
.pclk_io = CAMERA_PIN_PCLK,
145+
.xclk_io = CAMERA_PIN_XCLK,
146+
};
147+
148+
esp_video_init_sccb_config_t sccb_config = {
149+
.init_sccb = true,
150+
.i2c_config = {
151+
.port = 1,
152+
.scl_pin = CAMERA_PIN_SIOC,
153+
.sda_pin = CAMERA_PIN_SIOD,
154+
},
155+
.freq = 100000,
156+
};
157+
158+
esp_video_init_dvp_config_t dvp_config = {
159+
.sccb_config = sccb_config,
160+
.reset_pin = CAMERA_PIN_RESET,
161+
.pwdn_pin = CAMERA_PIN_PWDN,
162+
.dvp_pin = dvp_pin_config,
163+
.xclk_freq = XCLK_FREQ_HZ,
164+
};
165+
166+
esp_video_init_config_t video_config = {
167+
.dvp = &dvp_config,
168+
};
169+
170+
camera_ = new Esp32Camera(video_config);
156171
camera_->SetHMirror(false);
157172
}
158173

main/boards/atoms3r-cam-m12-echo-base/config.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
"name": "atoms3r-cam-m12-echo-base",
66
"sdkconfig_append": [
77
"CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y",
8-
"CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions/v2/8m.csv\""
8+
"CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions/v2/8m.csv\"",
9+
"CONFIG_CAMERA_GC0308=y",
10+
"CONFIG_CAMERA_GC0308_AUTO_DETECT_DVP_INTERFACE_SENSOR=y",
11+
"CONFIG_CAMERA_GC0308_DVP_YUV422_320X240_20FPS=y"
912
]
1013
}
1114
]

main/boards/bread-compact-wifi-s3cam/compact_wifi_board_s3cam.cc

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -126,32 +126,47 @@ class CompactWifiBoardS3Cam : public WifiBoard {
126126
}
127127

128128
void InitializeCamera() {
129-
camera_config_t config = {};
130-
config.pin_d0 = CAMERA_PIN_D0;
131-
config.pin_d1 = CAMERA_PIN_D1;
132-
config.pin_d2 = CAMERA_PIN_D2;
133-
config.pin_d3 = CAMERA_PIN_D3;
134-
config.pin_d4 = CAMERA_PIN_D4;
135-
config.pin_d5 = CAMERA_PIN_D5;
136-
config.pin_d6 = CAMERA_PIN_D6;
137-
config.pin_d7 = CAMERA_PIN_D7;
138-
config.pin_xclk = CAMERA_PIN_XCLK;
139-
config.pin_pclk = CAMERA_PIN_PCLK;
140-
config.pin_vsync = CAMERA_PIN_VSYNC;
141-
config.pin_href = CAMERA_PIN_HREF;
142-
config.pin_sccb_sda = CAMERA_PIN_SIOD;
143-
config.pin_sccb_scl = CAMERA_PIN_SIOC;
144-
config.sccb_i2c_port = 0;
145-
config.pin_pwdn = CAMERA_PIN_PWDN;
146-
config.pin_reset = CAMERA_PIN_RESET;
147-
config.xclk_freq_hz = XCLK_FREQ_HZ;
148-
config.pixel_format = PIXFORMAT_RGB565;
149-
config.frame_size = FRAMESIZE_QVGA;
150-
config.jpeg_quality = 12;
151-
config.fb_count = 1;
152-
config.fb_location = CAMERA_FB_IN_PSRAM;
153-
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
154-
camera_ = new Esp32Camera(config);
129+
static esp_cam_ctlr_dvp_pin_config_t dvp_pin_config = {
130+
.data_width = CAM_CTLR_DATA_WIDTH_8,
131+
.data_io = {
132+
[0] = CAMERA_PIN_D0,
133+
[1] = CAMERA_PIN_D1,
134+
[2] = CAMERA_PIN_D2,
135+
[3] = CAMERA_PIN_D3,
136+
[4] = CAMERA_PIN_D4,
137+
[5] = CAMERA_PIN_D5,
138+
[6] = CAMERA_PIN_D6,
139+
[7] = CAMERA_PIN_D7,
140+
},
141+
.vsync_io = CAMERA_PIN_VSYNC,
142+
.de_io = CAMERA_PIN_HREF,
143+
.pclk_io = CAMERA_PIN_PCLK,
144+
.xclk_io = CAMERA_PIN_XCLK,
145+
};
146+
147+
esp_video_init_sccb_config_t sccb_config = {
148+
.init_sccb = true,
149+
.i2c_config = {
150+
.port = 0,
151+
.scl_pin = CAMERA_PIN_SIOC,
152+
.sda_pin = CAMERA_PIN_SIOD,
153+
},
154+
.freq = 100000,
155+
};
156+
157+
esp_video_init_dvp_config_t dvp_config = {
158+
.sccb_config = sccb_config,
159+
.reset_pin = CAMERA_PIN_RESET,
160+
.pwdn_pin = CAMERA_PIN_PWDN,
161+
.dvp_pin = dvp_pin_config,
162+
.xclk_freq = XCLK_FREQ_HZ,
163+
};
164+
165+
esp_video_init_config_t video_config = {
166+
.dvp = &dvp_config,
167+
};
168+
169+
camera_ = new Esp32Camera(video_config);
155170
camera_->SetHMirror(false);
156171
}
157172

0 commit comments

Comments
 (0)