mirror of
https://github.com/esphome/esphome.git
synced 2026-09-11 23:37:34 +00:00
[runtime_image] keep decoder allocated (#18488)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Co-authored-by: J. Nick Koston <nick@home-assistant.io> Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
co-authored by
pre-commit-ci-lite[bot]
J. Nick Koston
J. Nick Koston
parent
ece90ee97b
commit
5177972c04
@@ -172,33 +172,38 @@ void RuntimeImage::draw(int x, int y, display::Display *display, Color color_on,
|
||||
}
|
||||
|
||||
bool RuntimeImage::begin_decode(size_t expected_size) {
|
||||
if (this->decoder_) {
|
||||
if (this->is_decoding()) {
|
||||
ESP_LOGW(TAG, "Decoding already in progress");
|
||||
return false;
|
||||
}
|
||||
|
||||
this->decoder_ = this->create_decoder_();
|
||||
// An idle decoder for a different format cannot be reused
|
||||
if (this->decoder_ != nullptr && this->decoder_->get_format() != this->format_) {
|
||||
ESP_LOGD(TAG, "Decoder format mismatch: current: %d, new: %d", this->decoder_->get_format(), this->format_);
|
||||
this->decoder_ = nullptr;
|
||||
}
|
||||
|
||||
if (!this->decoder_) {
|
||||
ESP_LOGE(TAG, "Failed to create decoder for format %d", this->format_);
|
||||
return false;
|
||||
this->decoder_ = this->create_decoder_(this->format_);
|
||||
if (!this->decoder_) {
|
||||
ESP_LOGE(TAG, "Failed to create decoder for format %d", this->format_);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
this->total_size_ = expected_size;
|
||||
this->decoded_bytes_ = 0;
|
||||
|
||||
// Initialize decoder
|
||||
int result = this->decoder_->prepare(expected_size);
|
||||
if (result < 0) {
|
||||
ESP_LOGE(TAG, "Failed to prepare decoder: %d", result);
|
||||
this->decoder_ = nullptr;
|
||||
this->decoder_ = nullptr; // If prepare fails, a full reset is needed
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int RuntimeImage::feed_data(uint8_t *data, size_t len) {
|
||||
if (!this->decoder_) {
|
||||
if (!this->is_decoding()) {
|
||||
ESP_LOGE(TAG, "No decoder initialized");
|
||||
return -1;
|
||||
}
|
||||
@@ -212,7 +217,7 @@ int RuntimeImage::feed_data(uint8_t *data, size_t len) {
|
||||
}
|
||||
|
||||
bool RuntimeImage::end_decode() {
|
||||
if (!this->decoder_) {
|
||||
if (!this->is_decoding()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -224,26 +229,23 @@ bool RuntimeImage::end_decode() {
|
||||
this->data_start_ = this->buffer_;
|
||||
}
|
||||
|
||||
// Clean up decoder
|
||||
this->decoder_ = nullptr;
|
||||
// End the session; the decoder object stays warm so the next decode can
|
||||
// reuse it (and its buffers) without churning the heap.
|
||||
this->decoder_->reset();
|
||||
|
||||
ESP_LOGD(TAG, "Decoding complete: %dx%d, %zu bytes", this->width_, this->height_, this->decoded_bytes_);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RuntimeImage::is_decode_finished() const {
|
||||
if (!this->decoder_) {
|
||||
return false;
|
||||
}
|
||||
return this->decoder_->is_finished();
|
||||
}
|
||||
bool RuntimeImage::is_decode_finished() const { return this->is_decoding() && this->decoder_->is_finished(); }
|
||||
|
||||
void RuntimeImage::release() {
|
||||
this->release_buffer_();
|
||||
// Reset decoder separately — release() can be called from within the decoder
|
||||
// (via set_size -> resize -> resize_buffer_), so we must not destroy the decoder here.
|
||||
// The decoder lifecycle is managed by begin_decode()/end_decode().
|
||||
this->decoder_ = nullptr;
|
||||
// End any active decode session; decoders free the format-specific working buffers
|
||||
// they can (PNG), while the decoder object itself is kept warm for the next decode.
|
||||
if (this->decoder_) {
|
||||
this->decoder_->reset();
|
||||
}
|
||||
}
|
||||
|
||||
void RuntimeImage::release_buffer_() {
|
||||
@@ -347,8 +349,9 @@ size_t RuntimeImage::get_buffer_size(int width, int height) const {
|
||||
|
||||
int RuntimeImage::get_position_(int x, int y) const { return (x + y * this->buffer_width_) * this->get_bpp() / 8; }
|
||||
|
||||
std::unique_ptr<ImageDecoder> RuntimeImage::create_decoder_() {
|
||||
switch (this->format_) {
|
||||
std::unique_ptr<ImageDecoder> RuntimeImage::create_decoder_(ImageFormat format) {
|
||||
ESP_LOGV(TAG, "Creating decoder for format %d", format);
|
||||
switch (format) {
|
||||
#ifdef USE_RUNTIME_IMAGE_BMP
|
||||
case BMP:
|
||||
return make_unique<BmpDecoder>(this);
|
||||
@@ -362,7 +365,7 @@ std::unique_ptr<ImageDecoder> RuntimeImage::create_decoder_() {
|
||||
return make_unique<PngDecoder>(this);
|
||||
#endif
|
||||
default:
|
||||
ESP_LOGE(TAG, "Unsupported image format: %d", this->format_);
|
||||
ESP_LOGE(TAG, "Unsupported image format: %d", format);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user