3#if defined(USE_ESP32) && defined(USE_SENDSPIN_ARTWORK)
11static const char *
const TAG =
"sendspin.image";
15static constexpr uint32_t TRANSITION_ACK_WARNING_MS = 10000;
20 if (frame_size == 0) {
23 ESP_LOGE(TAG,
"Cannot decode artwork at %dx%d", this->
width_, this->
height_);
29 for (uint8_t *&buffer : this->
buffers_) {
30 buffer = allocator.
allocate(frame_size);
31 if (buffer ==
nullptr) {
32 ESP_LOGE(TAG,
"Could not allocate %zu bytes for an artwork frame. Largest free block: %zu", frame_size,
34 for (uint8_t *&allocated : this->buffers_) {
43 memset(buffer, 0, frame_size);
53 this->
parent_->add_image_decode_callback(
54 [
this](uint8_t slot,
const uint8_t *data,
size_t length, sendspin::SendspinImageFormat) {
55 if (slot == this->
slot_)
58 this->
parent_->add_image_display_callback([
this](uint8_t slot,
uint32_t lateness_ms) {
59 if (slot == this->
slot_)
62 this->
parent_->add_image_clear_callback([
this](uint8_t slot) {
63 if (slot == this->
slot_)
107 ESP_LOGE(TAG,
"Could not start decode");
111 size_t total_consumed = 0;
112 while (total_consumed <
length) {
116 ESP_LOGE(TAG,
"Decode failed at offset %zu (result %d)", total_consumed, consumed);
119 total_consumed += consumed;
123 ESP_LOGE(TAG,
"Could not finalize decode");
166 this->
set_timeout(
"transition_ack", TRANSITION_ACK_WARNING_MS, [
this]() {
169 "Slot %u: displayed artwork was never acknowledged; no new artwork will arrive until "
170 "sendspin.image.transition_finished runs or the stream is cleared",
235 " Dimensions: %dx%d\n"
236 " Frame buffers: 2 x %zu bytes\n"
237 " Transition image: %s",
void mark_failed()
Mark this component as failed.
void set_timeout(const char *name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a const char* name.
void defer(const char *name, std::function< void()> &&f)
Defer a callback to the next loop() call with a const char* name.
Helper class that wraps a mutex with a RAII-style API.
An STL allocator that uses SPI or internal RAM.
void deallocate(T *p, size_t n)
size_t get_max_free_block_size() const
Return the maximum size block this allocator could allocate.
size_t get_buffer_size(int width, int height) const
Get the buffer size in bytes needed for a picture of the given dimensions.
bool end_decode()
Complete the decoding process.
int feed_data(uint8_t *data, size_t len)
Feed data to the decoder.
void release()
Release the image buffer and free memory.
bool set_external_buffer(uint8_t *buffer, int width, int height)
Decode into a buffer the caller owns, instead of one allocated here.
bool begin_decode(size_t expected_size=0)
Begin decoding an image.
bool decoded_into(const uint8_t *buffer) const
True when the decode ended with the given buffer still in place.
void set_frame(const uint8_t *data, int width, int height)
void set_showing_artwork(bool showing_artwork)
Records whether the frame on show is real artwork rather than the black it starts as.
LazyCallbackManager< void()> image_error_callback_
void on_display_(uint32_t lateness_ms)
ArtworkDecodeSink decode_sink_
void transition_finished()
Signals that the display transition for the last frame has finished.
ArtworkImageView * current_image_
void on_decode_(const uint8_t *data, size_t length)
void apply_frames_(bool transition_is_artwork)
void finish_transition_()
void dump_config() override
LazyCallbackManager< void()> image_clear_callback_
bool decode_frame_(const uint8_t *data, size_t length, const uint8_t *target)
ArtworkImageView * transition_image_
LazyCallbackManager< void(uint32_t)> image_display_callback_
std::array< uint8_t *, 2 > buffers_