arduino-audio-tools
JpegTFT.h
1 #pragma once
2 #include "AudioBasic/Collections/Vector.h"
3 #include "JPEGDecoder.h" // https://github.com/Bodmer/JPEGDecoder
4 #include "TFT_eSPI.h" // https://github.com/Bodmer/TFT_eSPI
5 #include "Video/Video.h"
6 #include <algorithm> // std::min
7 
8 namespace audio_tools {
9 
17 class JpegTFT : public VideoOutput {
18 public:
19  JpegTFT(TFT_eSPI &TFTscreen) { p_screen = &TFTscreen; }
20 
21  // Allocate memory and create window
22  void beginFrame(size_t jpegSize) override {
23  if (start == 0l)
24  start = millis();
25  LOGI("jpegSize: %d", (int)jpegSize);
26  // prevent memory fragmentation, change size only if more memory is needed
27  if (img_vector.size() < jpegSize) {
28  img_vector.resize(jpegSize);
29  }
30  this->pos = 0;
31  this->open = jpegSize;
32  this->size = jpegSize;
33  }
34 
37  uint32_t endFrame() override {
38  assert(open == 0);
39  jpeg_decoder.decodeArray((const uint8_t *)&img_vector[0], size);
40  renderJPEG(0, 0);
41  return millis() - start;
42  }
43 
44  // Add some more data to the image vector
45  size_t write(const uint8_t *buffer, size_t byteCount) override {
46  memcpy(&img_vector[pos], buffer, byteCount);
47  pos += byteCount;
48  open -= byteCount;
49  return byteCount;
50  }
51 
52 protected:
53  Vector<uint8_t> img_vector;
54  size_t pos = 0;
55  size_t size = 0;
56  int open = 0;
57  uint64_t start = 0;
58  JPEGDecoder jpeg_decoder;
59  TFT_eSPI *p_screen = nullptr;
60 
61  //====================================================================================
62  // Decode and paint onto the TFT screen
63  //====================================================================================
64  uint32_t renderJPEG(int xpos, int ypos) {
65  // retrieve infomration about the image
66  uint16_t *pImg;
67  uint16_t mcu_w = jpeg_decoder.MCUWidth;
68  uint16_t mcu_h = jpeg_decoder.MCUHeight;
69  uint32_t max_x = jpeg_decoder.width;
70  uint32_t max_y = jpeg_decoder.height;
71 
72  // Jpeg images are draw as a set of image block (tiles) called Minimum
73  // Coding Units (MCUs) Typically these MCUs are 16x16 pixel blocks Determine
74  // the width and height of the right and bottom edge image blocks
75  uint32_t min_w = std::min((uint32_t)mcu_w, max_x % mcu_w);
76  uint32_t min_h = std::min((uint32_t)mcu_h, max_y % mcu_h);
77 
78  // save the current image block size
79  uint32_t win_w = mcu_w;
80  uint32_t win_h = mcu_h;
81 
82  // record the current time so we can measure how long it takes to draw an
83  // image
84  uint32_t drawTime = millis();
85 
86  // save the coordinate of the right and bottom edges to assist image
87  // cropping to the screen size
88  max_x += xpos;
89  max_y += ypos;
90 
91  // read each MCU block until there are no more
92  while (jpeg_decoder.read()) {
93  // save a pointer to the image block
94  pImg = jpeg_decoder.pImage;
95 
96  // calculate where the image block should be drawn on the screen
97  int mcu_x = jpeg_decoder.MCUx * mcu_w + xpos;
98  int mcu_y = jpeg_decoder.MCUy * mcu_h + ypos;
99 
100  // check if the image block size needs to be changed for the right and
101  // bottom edges
102  if (mcu_x + mcu_w <= max_x)
103  win_w = mcu_w;
104  else
105  win_w = min_w;
106  if (mcu_y + mcu_h <= max_y)
107  win_h = mcu_h;
108  else
109  win_h = min_h;
110 
111  // calculate how many pixels must be drawn
112  uint32_t mcu_pixels = win_w * win_h;
113 
114  // draw image block if it will fit on the screen
115  if ((mcu_x + win_w) <= p_screen->width() &&
116  (mcu_y + win_h) <= p_screen->height()) {
117  // open a window onto the screen to paint the pixels into
118  // p_screen->setAddrWindow(mcu_x, mcu_y, mcu_x + win_w - 1, mcu_y +
119  // win_h - 1);
120  p_screen->setAddrWindow(mcu_x, mcu_y, mcu_x + win_w - 1,
121  mcu_y + win_h - 1);
122  // push all the image block pixels to the screen
123  while (mcu_pixels--)
124  p_screen->pushColor(*pImg++); // Send to TFT 16 bits at a time
125  }
126 
127  // stop drawing blocks if the bottom of the screen has been reached
128  // the abort function will close the file
129  else if ((mcu_y + win_h) >= p_screen->height())
130  jpeg_decoder.abort();
131  }
132 
133  // calculate how long it took to draw the image
134  drawTime = millis() - drawTime; // Calculate the time it took
135  return drawTime;
136  }
137 }; // JpegTFT
138 
139 } // namespace audio_tools
Display jpeg image using https://github.com/Bodmer/TFT_eSPI and https://github.com/Bodmer/JPEGDecoder...
Definition: JpegTFT.h:17
uint32_t endFrame() override
Definition: JpegTFT.h:37
Abstract class for video playback. This class is used to assemble a complete video frame in memory.
Definition: Video.h:21
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition: AnalogAudio.h:10
uint32_t millis()
Returns the milliseconds since the start.
Definition: Millis.h:18