mirror of
https://github.com/esphome/esphome.git
synced 2026-10-05 10:31:29 +00:00
[runtime_image] Allow decoding into a caller-owned buffer (#17936)
This commit is contained in:
@@ -248,9 +248,15 @@ void RuntimeImage::release() {
|
||||
|
||||
void RuntimeImage::release_buffer_() {
|
||||
if (this->buffer_) {
|
||||
ESP_LOGV(TAG, "Releasing buffer of size %zu", this->get_buffer_size_(this->buffer_width_, this->buffer_height_));
|
||||
RAMAllocator<uint8_t> allocator;
|
||||
allocator.deallocate(this->buffer_, this->get_buffer_size_(this->buffer_width_, this->buffer_height_));
|
||||
if (this->external_buffer_) {
|
||||
// The caller owns this memory and goes on using it after the image lets go of it.
|
||||
ESP_LOGV(TAG, "Letting go of the external %dx%d buffer", this->buffer_width_, this->buffer_height_);
|
||||
this->external_buffer_ = false;
|
||||
} else {
|
||||
ESP_LOGV(TAG, "Releasing buffer of size %zu", this->get_buffer_size(this->buffer_width_, this->buffer_height_));
|
||||
RAMAllocator<uint8_t> allocator;
|
||||
allocator.deallocate(this->buffer_, this->get_buffer_size(this->buffer_width_, this->buffer_height_));
|
||||
}
|
||||
this->buffer_ = nullptr;
|
||||
this->data_start_ = nullptr;
|
||||
this->width_ = 0;
|
||||
@@ -263,19 +269,46 @@ void RuntimeImage::release_buffer_() {
|
||||
}
|
||||
}
|
||||
|
||||
bool RuntimeImage::set_external_buffer(uint8_t *buffer, int width, int height) {
|
||||
this->release_buffer_();
|
||||
if (buffer == nullptr || this->get_buffer_size(width, height) == 0) {
|
||||
// Keep the released state rather than remembering a buffer that cannot be decoded into: an
|
||||
// external buffer that is never handed back would otherwise block every later allocation.
|
||||
ESP_LOGE(TAG, "Refusing an invalid external buffer for %dx%d", width, height);
|
||||
return false;
|
||||
}
|
||||
this->buffer_ = buffer;
|
||||
this->external_buffer_ = true;
|
||||
this->buffer_width_ = width;
|
||||
this->buffer_height_ = height;
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t RuntimeImage::resize_buffer_(int width, int height) {
|
||||
size_t new_size = this->get_buffer_size_(width, height);
|
||||
size_t new_size = this->get_buffer_size(width, height);
|
||||
|
||||
// A buffer only ever exists with dimensions the image can decode at, so a match here means
|
||||
// new_size is non-zero. Checking it before the invalid dimension case below lets the external
|
||||
// buffer be let go of for every decode it cannot serve, not just for valid other dimensions.
|
||||
if (this->buffer_ && this->buffer_width_ == width && this->buffer_height_ == height) {
|
||||
// Buffer already allocated with correct size
|
||||
return new_size;
|
||||
}
|
||||
|
||||
if (this->external_buffer_) {
|
||||
ESP_LOGE(TAG, "Image decoded to %dx%d, but the external buffer is %dx%d", width, height, this->buffer_width_,
|
||||
this->buffer_height_);
|
||||
// Let the buffer go rather than free memory that belongs to the caller. Dropping it also stops
|
||||
// a decoder that ignores this failure from publishing a picture it never painted.
|
||||
this->release_buffer_();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (new_size == 0) {
|
||||
ESP_LOGE(TAG, "Refusing to allocate buffer for invalid image dimensions %dx%d", width, height);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (this->buffer_ && this->buffer_width_ == width && this->buffer_height_ == height) {
|
||||
// Buffer already allocated with correct size
|
||||
return new_size;
|
||||
}
|
||||
|
||||
// Release old buffer if dimensions changed
|
||||
if (this->buffer_) {
|
||||
this->release_buffer_();
|
||||
@@ -300,7 +333,7 @@ size_t RuntimeImage::resize_buffer_(int width, int height) {
|
||||
return new_size;
|
||||
}
|
||||
|
||||
size_t RuntimeImage::get_buffer_size_(int width, int height) const {
|
||||
size_t RuntimeImage::get_buffer_size(int width, int height) const {
|
||||
// Dimensions come from a remote image header; reject absurd values so the size math cannot overflow
|
||||
if (width <= 0 || height <= 0 || width > MAX_IMAGE_DIMENSION || height > MAX_IMAGE_DIMENSION) {
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user