Files
xiaozhi-esp32/main/display/lvgl_display/gif/lvgl_gif.cc
Xiaoxia 147d71b9f1 feat: add snapshot mcp tool (#1196)
* use main task to execute tool calls

* feat: add snapshot mcp tool

* fix compiling errors

* 取消 audio input 的 pin core,core1留给显示,可能会对aec性能有影响

* update ml307 version

* remove v1 theme colors
2025-09-14 15:16:49 +08:00

209 lines
4.5 KiB
C++

#include "lvgl_gif.h"
#include <esp_log.h>
#include <cstring>
#define TAG "LvglGif"
LvglGif::LvglGif(const lv_img_dsc_t* img_dsc)
: gif_(nullptr), timer_(nullptr), last_call_(0), playing_(false), loaded_(false) {
if (!img_dsc || !img_dsc->data) {
ESP_LOGE(TAG, "Invalid image descriptor");
return;
}
gif_ = gd_open_gif_data(img_dsc->data);
if (!gif_) {
ESP_LOGE(TAG, "Failed to open GIF from image descriptor");
return;
}
// Setup LVGL image descriptor
memset(&img_dsc_, 0, sizeof(img_dsc_));
img_dsc_.header.magic = LV_IMAGE_HEADER_MAGIC;
img_dsc_.header.flags = LV_IMAGE_FLAGS_MODIFIABLE;
img_dsc_.header.cf = LV_COLOR_FORMAT_ARGB8888;
img_dsc_.header.w = gif_->width;
img_dsc_.header.h = gif_->height;
img_dsc_.header.stride = gif_->width * 4;
img_dsc_.data = gif_->canvas;
img_dsc_.data_size = gif_->width * gif_->height * 4;
// Render first frame
if (gif_->canvas) {
gd_render_frame(gif_, gif_->canvas);
}
loaded_ = true;
ESP_LOGD(TAG, "GIF loaded from image descriptor: %dx%d", gif_->width, gif_->height);
}
// Destructor
LvglGif::~LvglGif() {
Cleanup();
}
// LvglImage interface implementation
const lv_img_dsc_t* LvglGif::image_dsc() const {
if (!loaded_) {
return nullptr;
}
return &img_dsc_;
}
// Animation control methods
void LvglGif::Start() {
if (!loaded_ || !gif_) {
ESP_LOGW(TAG, "GIF not loaded, cannot start");
return;
}
if (!timer_) {
timer_ = lv_timer_create([](lv_timer_t* timer) {
LvglGif* gif_obj = static_cast<LvglGif*>(lv_timer_get_user_data(timer));
gif_obj->NextFrame();
}, 10, this);
}
if (timer_) {
playing_ = true;
last_call_ = lv_tick_get();
lv_timer_resume(timer_);
lv_timer_reset(timer_);
// Render first frame
NextFrame();
ESP_LOGD(TAG, "GIF animation started");
}
}
void LvglGif::Pause() {
if (timer_) {
playing_ = false;
lv_timer_pause(timer_);
ESP_LOGD(TAG, "GIF animation paused");
}
}
void LvglGif::Resume() {
if (!loaded_ || !gif_) {
ESP_LOGW(TAG, "GIF not loaded, cannot resume");
return;
}
if (timer_) {
playing_ = true;
lv_timer_resume(timer_);
ESP_LOGD(TAG, "GIF animation resumed");
}
}
void LvglGif::Stop() {
if (timer_) {
playing_ = false;
lv_timer_pause(timer_);
}
if (gif_) {
gd_rewind(gif_);
NextFrame();
ESP_LOGD(TAG, "GIF animation stopped and rewound");
}
}
bool LvglGif::IsPlaying() const {
return playing_;
}
bool LvglGif::IsLoaded() const {
return loaded_;
}
int32_t LvglGif::GetLoopCount() const {
if (!loaded_ || !gif_) {
return -1;
}
return gif_->loop_count;
}
void LvglGif::SetLoopCount(int32_t count) {
if (!loaded_ || !gif_) {
ESP_LOGW(TAG, "GIF not loaded, cannot set loop count");
return;
}
gif_->loop_count = count;
}
uint16_t LvglGif::width() const {
if (!loaded_ || !gif_) {
return 0;
}
return gif_->width;
}
uint16_t LvglGif::height() const {
if (!loaded_ || !gif_) {
return 0;
}
return gif_->height;
}
void LvglGif::SetFrameCallback(std::function<void()> callback) {
frame_callback_ = callback;
}
void LvglGif::NextFrame() {
if (!loaded_ || !gif_ || !playing_) {
return;
}
// Check if enough time has passed for the next frame
uint32_t elapsed = lv_tick_elaps(last_call_);
if (elapsed < gif_->gce.delay * 10) {
return;
}
last_call_ = lv_tick_get();
// Get next frame
int has_next = gd_get_frame(gif_);
if (has_next == 0) {
// Animation finished, pause timer
playing_ = false;
if (timer_) {
lv_timer_pause(timer_);
}
ESP_LOGD(TAG, "GIF animation completed");
}
// Render current frame
if (gif_->canvas) {
gd_render_frame(gif_, gif_->canvas);
// Call frame callback if set
if (frame_callback_) {
frame_callback_();
}
}
}
void LvglGif::Cleanup() {
// Stop and delete timer
if (timer_) {
lv_timer_delete(timer_);
timer_ = nullptr;
}
// Close GIF decoder
if (gif_) {
gd_close_gif(gif_);
gif_ = nullptr;
}
playing_ = false;
loaded_ = false;
// Clear image descriptor
memset(&img_dsc_, 0, sizeof(img_dsc_));
}