Revert "camera 优化:在原有的RGB565处理下,容易超时改为JPEG格式 (#1029)" (#1085)

This reverts commit d6b1414967.
This commit is contained in:
Xiaoxia
2025-08-14 22:23:29 +08:00
committed by GitHub
parent cf4afde88e
commit cc07ef447e
3 changed files with 31 additions and 79 deletions

View File

@@ -158,9 +158,9 @@ private:
config.pin_pwdn = CAMERA_PIN_PWDN;
config.pin_reset = CAMERA_PIN_RESET;
config.xclk_freq_hz = XCLK_FREQ_HZ;
config.pixel_format = PIXFORMAT_JPEG;
config.pixel_format = PIXFORMAT_RGB565;
config.frame_size = FRAMESIZE_QVGA;
config.jpeg_quality = 10;
config.jpeg_quality = 12;
config.fb_count = 1;
config.fb_location = CAMERA_FB_IN_PSRAM;
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;

View File

@@ -51,7 +51,7 @@
#define CAMERA_PIN_SIOD GPIO_NUM_4
#define CAMERA_PIN_PWDN GPIO_NUM_NC
#define CAMERA_PIN_RESET GPIO_NUM_NC
#define XCLK_FREQ_HZ 50000000
#define XCLK_FREQ_HZ 20000000
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_38

View File

@@ -65,7 +65,6 @@ Esp32Camera::Esp32Camera(const camera_config_t& config) {
ESP_LOGE(TAG, "Failed to allocate memory for preview image");
return;
}
}
Esp32Camera::~Esp32Camera() {
@@ -116,27 +115,14 @@ bool Esp32Camera::Capture() {
// 显示预览图片
auto display = Board::GetInstance().GetDisplay();
if (display != nullptr) {
// 检查摄像头输出格式
if (fb_->format == PIXFORMAT_JPEG) {
// JPEG格式需要先解码为RGB565
// 分配足够的缓冲区用于RGB565数据
bool converted = jpg2rgb565(fb_->buf, fb_->len, preview_image_.data, JPG_SCALE_NONE);
if (converted) {
display->SetPreviewImage(&preview_image_);
} else {
ESP_LOGE(TAG, "Failed to convert JPEG to RGB565 for preview");
}
} else {
// RGB565等格式需要进行字节交换处理
auto src = (uint16_t*)fb_->buf;
auto dst = (uint16_t*)preview_image_.data;
size_t pixel_count = fb_->len / 2;
for (size_t i = 0; i < pixel_count; i++) {
// 交换每个16位字内的字节
dst[i] = __builtin_bswap16(src[i]);
}
display->SetPreviewImage(&preview_image_);
auto src = (uint16_t*)fb_->buf;
auto dst = (uint16_t*)preview_image_.data;
size_t pixel_count = fb_->len / 2;
for (size_t i = 0; i < pixel_count; i++) {
// 交换每个16位字内的字节
dst[i] = __builtin_bswap16(src[i]);
}
display->SetPreviewImage(&preview_image_);
}
return true;
}
@@ -202,57 +188,27 @@ std::string Esp32Camera::Explain(const std::string& question) {
return "{\"success\": false, \"message\": \"Image explain URL or token is not set\"}";
}
QueueHandle_t jpeg_queue = nullptr;
// If the format is not JPEG, we need to convert it to JPEG first
if (fb_->format != PIXFORMAT_JPEG) {
// 创建局部的 JPEG 队列, 40 entries is about to store 512 * 40 = 20480 bytes of JPEG data
jpeg_queue = xQueueCreate(40, sizeof(JpegChunk));
if (jpeg_queue == nullptr) {
ESP_LOGE(TAG, "Failed to create JPEG queue");
return "{\"success\": false, \"message\": \"Failed to create JPEG queue\"}";
}
// We spawn a thread to encode the image to JPEG
encoder_thread_ = std::thread([this, jpeg_queue]() {
frame2jpg_cb(fb_, 80, [](void* arg, size_t index, const void* data, size_t len) -> unsigned int {
auto jpeg_queue = (QueueHandle_t)arg;
JpegChunk chunk = {
.data = (uint8_t*)heap_caps_aligned_alloc(16, len, MALLOC_CAP_SPIRAM),
.len = len
};
if (chunk.data != nullptr) {
memcpy(chunk.data, data, len);
xQueueSend(jpeg_queue, &chunk, portMAX_DELAY);
}
return len;
}, jpeg_queue);
// Add a null chunk to indicate the end of the queue
JpegChunk null_chunk = { .data = nullptr, .len = 0 };
xQueueSend(jpeg_queue, &null_chunk, portMAX_DELAY);
});
} else {
// JPEG format, we can send it directly
// To keep the logic consistent, we still use a queue to send the data
jpeg_queue = xQueueCreate(2, sizeof(JpegChunk));
if (jpeg_queue == nullptr) {
ESP_LOGE(TAG, "Failed to create JPEG queue");
return "{\"success\": false, \"message\": \"Failed to create JPEG queue\"}";
}
JpegChunk chunk = {
.data = (uint8_t*)heap_caps_aligned_alloc(16, fb_->len, MALLOC_CAP_SPIRAM),
.len = fb_->len
};
if (chunk.data != nullptr) {
memcpy(chunk.data, fb_->buf, fb_->len);
xQueueSend(jpeg_queue, &chunk, portMAX_DELAY);
} else {
ESP_LOGE(TAG, "Failed to allocate memory for JPEG chunk");
}
// Add a null chunk to indicate the end of the queue
JpegChunk null_chunk = { .data = nullptr, .len = 0 };
xQueueSend(jpeg_queue, &null_chunk, portMAX_DELAY);
// 创建局部的 JPEG 队列, 40 entries is about to store 512 * 40 = 20480 bytes of JPEG data
QueueHandle_t jpeg_queue = xQueueCreate(40, sizeof(JpegChunk));
if (jpeg_queue == nullptr) {
ESP_LOGE(TAG, "Failed to create JPEG queue");
return "{\"success\": false, \"message\": \"Failed to create JPEG queue\"}";
}
// We spawn a thread to encode the image to JPEG
encoder_thread_ = std::thread([this, jpeg_queue]() {
frame2jpg_cb(fb_, 80, [](void* arg, size_t index, const void* data, size_t len) -> unsigned int {
auto jpeg_queue = (QueueHandle_t)arg;
JpegChunk chunk = {
.data = (uint8_t*)heap_caps_aligned_alloc(16, len, MALLOC_CAP_SPIRAM),
.len = len
};
memcpy(chunk.data, data, len);
xQueueSend(jpeg_queue, &chunk, portMAX_DELAY);
return len;
}, jpeg_queue);
});
auto network = Board::GetInstance().GetNetwork();
auto http = network->CreateHttp(3);
// 构造multipart/form-data请求体
@@ -269,9 +225,7 @@ std::string Esp32Camera::Explain(const std::string& question) {
if (!http->Open("POST", explain_url_)) {
ESP_LOGE(TAG, "Failed to connect to explain URL");
// Clear the queue
if (encoder_thread_.joinable()) {
encoder_thread_.join();
}
encoder_thread_.join();
JpegChunk chunk;
while (xQueueReceive(jpeg_queue, &chunk, portMAX_DELAY) == pdPASS) {
if (chunk.data != nullptr) {
@@ -319,9 +273,7 @@ std::string Esp32Camera::Explain(const std::string& question) {
heap_caps_free(chunk.data);
}
// Wait for the encoder thread to finish
if (encoder_thread_.joinable()) {
encoder_thread_.join();
}
encoder_thread_.join();
// 清理队列
vQueueDelete(jpeg_queue);